1/*	$NetBSD: lwres_gabn.c,v 1.2.6.1 2012/06/05 21:14:54 bouyer Exp $	*/
2
3/*
4 * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001  Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20/* Id: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp  */
21
22/*! \file lwres_gabn.c
23   These are low-level routines for creating and parsing lightweight
24   resolver name-to-address lookup request and response messages.
25
26   There are four main functions for the getaddrbyname opcode. One render
27   function converts a getaddrbyname request structure --
28   lwres_gabnrequest_t -- to the lighweight resolver's canonical format.
29   It is complemented by a parse function that converts a packet in this
30   canonical format to a getaddrbyname request structure. Another render
31   function converts the getaddrbyname response structure --
32   lwres_gabnresponse_t -- to the canonical format. This is complemented
33   by a parse function which converts a packet in canonical format to a
34   getaddrbyname response structure.
35
36   These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
37
38\code
39#define LWRES_OPCODE_GETADDRSBYNAME     0x00010001U
40
41typedef struct lwres_addr lwres_addr_t;
42typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
43
44typedef struct {
45        lwres_uint32_t  flags;
46        lwres_uint32_t  addrtypes;
47        lwres_uint16_t  namelen;
48        char           *name;
49} lwres_gabnrequest_t;
50
51typedef struct {
52        lwres_uint32_t          flags;
53        lwres_uint16_t          naliases;
54        lwres_uint16_t          naddrs;
55        char                   *realname;
56        char                  **aliases;
57        lwres_uint16_t          realnamelen;
58        lwres_uint16_t         *aliaslen;
59        lwres_addrlist_t        addrs;
60        void                   *base;
61        size_t                  baselen;
62} lwres_gabnresponse_t;
63\endcode
64
65   lwres_gabnrequest_render() uses resolver context ctx to convert
66   getaddrbyname request structure req to canonical format. The packet
67   header structure pkt is initialised and transferred to buffer b. The
68   contents of *req are then appended to the buffer in canonical format.
69   lwres_gabnresponse_render() performs the same task, except it converts
70   a getaddrbyname response structure lwres_gabnresponse_t to the
71   lightweight resolver's canonical format.
72
73   lwres_gabnrequest_parse() uses context ctx to convert the contents of
74   packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space
75   to be used for storing this structure. When the function succeeds, the
76   resulting lwres_gabnrequest_t is made available through *structp.
77   lwres_gabnresponse_parse() offers the same semantics as
78   lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t
79   structure.
80
81   lwres_gabnresponse_free() and lwres_gabnrequest_free() release the
82   memory in resolver context ctx that was allocated to the
83   lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via
84   structp. Any memory associated with ancillary buffers and strings for
85   those structures is also discarded.
86
87\section lwres_gabn_return Return Values
88
89   The getaddrbyname opcode functions lwres_gabnrequest_render(),
90   lwres_gabnresponse_render() lwres_gabnrequest_parse() and
91   lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They
92   return #LWRES_R_NOMEMORY if memory allocation fails.
93   #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
94   b is too small to accommodate the packet header or the
95   lwres_gabnrequest_t and lwres_gabnresponse_t structures.
96   lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return
97   #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
98   received packet. These functions will return #LWRES_R_FAILURE if
99   pktflags in the packet header structure #lwres_lwpacket_t indicate that
100   the packet is not a response to an earlier query.
101
102\section lwres_gabn_see See Also
103
104   \link lwpacket.c lwres_lwpacket \endlink
105 */
106
107#include <config.h>
108
109#include <assert.h>
110#include <stdlib.h>
111#include <string.h>
112
113#include <lwres/lwbuffer.h>
114#include <lwres/lwpacket.h>
115#include <lwres/lwres.h>
116#include <lwres/result.h>
117
118#include "context_p.h"
119#include "assert_p.h"
120
121/*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
122lwres_result_t
123lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
124			 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
125{
126	unsigned char *buf;
127	size_t buflen;
128	int ret;
129	size_t payload_length;
130	lwres_uint16_t datalen;
131
132	REQUIRE(ctx != NULL);
133	REQUIRE(req != NULL);
134	REQUIRE(req->name != NULL);
135	REQUIRE(pkt != NULL);
136	REQUIRE(b != NULL);
137
138	datalen = strlen(req->name);
139
140	payload_length = 4 + 4 + 2 + req->namelen + 1;
141
142	buflen = LWRES_LWPACKET_LENGTH + payload_length;
143	buf = CTXMALLOC(buflen);
144	if (buf == NULL)
145		return (LWRES_R_NOMEMORY);
146
147	lwres_buffer_init(b, buf, buflen);
148
149	pkt->length = buflen;
150	pkt->version = LWRES_LWPACKETVERSION_0;
151	pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
152	pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
153	pkt->result = 0;
154	pkt->authtype = 0;
155	pkt->authlength = 0;
156
157	ret = lwres_lwpacket_renderheader(b, pkt);
158	if (ret != LWRES_R_SUCCESS) {
159		lwres_buffer_invalidate(b);
160		CTXFREE(buf, buflen);
161		return (ret);
162	}
163
164	INSIST(SPACE_OK(b, payload_length));
165
166	/*
167	 * Flags.
168	 */
169	lwres_buffer_putuint32(b, req->flags);
170
171	/*
172	 * Address types we'll accept.
173	 */
174	lwres_buffer_putuint32(b, req->addrtypes);
175
176	/*
177	 * Put the length and the data.  We know this will fit because we
178	 * just checked for it.
179	 */
180	lwres_buffer_putuint16(b, datalen);
181	lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
182	lwres_buffer_putuint8(b, 0); /* trailing NUL */
183
184	INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
185
186	return (LWRES_R_SUCCESS);
187}
188/*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
189lwres_result_t
190lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
191			  lwres_lwpacket_t *pkt, lwres_buffer_t *b)
192{
193	unsigned char *buf;
194	size_t buflen;
195	int ret;
196	size_t payload_length;
197	lwres_uint16_t datalen;
198	lwres_addr_t *addr;
199	int x;
200
201	REQUIRE(ctx != NULL);
202	REQUIRE(req != NULL);
203	REQUIRE(pkt != NULL);
204	REQUIRE(b != NULL);
205
206	/* naliases, naddrs */
207	payload_length = 4 + 2 + 2;
208	/* real name encoding */
209	payload_length += 2 + req->realnamelen + 1;
210	/* each alias */
211	for (x = 0; x < req->naliases; x++)
212		payload_length += 2 + req->aliaslen[x] + 1;
213	/* each address */
214	x = 0;
215	addr = LWRES_LIST_HEAD(req->addrs);
216	while (addr != NULL) {
217		payload_length += 4 + 2;
218		payload_length += addr->length;
219		addr = LWRES_LIST_NEXT(addr, link);
220		x++;
221	}
222	INSIST(x == req->naddrs);
223
224	buflen = LWRES_LWPACKET_LENGTH + payload_length;
225	buf = CTXMALLOC(buflen);
226	if (buf == NULL)
227		return (LWRES_R_NOMEMORY);
228	lwres_buffer_init(b, buf, buflen);
229
230	pkt->length = buflen;
231	pkt->version = LWRES_LWPACKETVERSION_0;
232	pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
233	pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
234	pkt->authtype = 0;
235	pkt->authlength = 0;
236
237	ret = lwres_lwpacket_renderheader(b, pkt);
238	if (ret != LWRES_R_SUCCESS) {
239		lwres_buffer_invalidate(b);
240		CTXFREE(buf, buflen);
241		return (ret);
242	}
243
244	/*
245	 * Check space needed here.
246	 */
247	INSIST(SPACE_OK(b, payload_length));
248
249	/* Flags. */
250	lwres_buffer_putuint32(b, req->flags);
251
252	/* encode naliases and naddrs */
253	lwres_buffer_putuint16(b, req->naliases);
254	lwres_buffer_putuint16(b, req->naddrs);
255
256	/* encode the real name */
257	datalen = req->realnamelen;
258	lwres_buffer_putuint16(b, datalen);
259	lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
260	lwres_buffer_putuint8(b, 0);
261
262	/* encode the aliases */
263	for (x = 0; x < req->naliases; x++) {
264		datalen = req->aliaslen[x];
265		lwres_buffer_putuint16(b, datalen);
266		lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
267				    datalen);
268		lwres_buffer_putuint8(b, 0);
269	}
270
271	/* encode the addresses */
272	addr = LWRES_LIST_HEAD(req->addrs);
273	while (addr != NULL) {
274		lwres_buffer_putuint32(b, addr->family);
275		lwres_buffer_putuint16(b, addr->length);
276		lwres_buffer_putmem(b, addr->address, addr->length);
277		addr = LWRES_LIST_NEXT(addr, link);
278	}
279
280	INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
281	INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
282
283	return (LWRES_R_SUCCESS);
284}
285/*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
286lwres_result_t
287lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
288			lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
289{
290	int ret;
291	char *name;
292	lwres_gabnrequest_t *gabn;
293	lwres_uint32_t addrtypes;
294	lwres_uint32_t flags;
295	lwres_uint16_t namelen;
296
297	REQUIRE(ctx != NULL);
298	REQUIRE(pkt != NULL);
299	REQUIRE(b != NULL);
300	REQUIRE(structp != NULL && *structp == NULL);
301
302	if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
303		return (LWRES_R_FAILURE);
304
305	if (!SPACE_REMAINING(b, 4 + 4))
306		return (LWRES_R_UNEXPECTEDEND);
307
308	flags = lwres_buffer_getuint32(b);
309	addrtypes = lwres_buffer_getuint32(b);
310
311	/*
312	 * Pull off the name itself
313	 */
314	ret = lwres_string_parse(b, &name, &namelen);
315	if (ret != LWRES_R_SUCCESS)
316		return (ret);
317
318	if (LWRES_BUFFER_REMAINING(b) != 0)
319		return (LWRES_R_TRAILINGDATA);
320
321	gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
322	if (gabn == NULL)
323		return (LWRES_R_NOMEMORY);
324
325	gabn->flags = flags;
326	gabn->addrtypes = addrtypes;
327	gabn->name = name;
328	gabn->namelen = namelen;
329
330	*structp = gabn;
331	return (LWRES_R_SUCCESS);
332}
333
334/*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
335
336lwres_result_t
337lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
338			lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
339{
340	lwres_result_t ret;
341	unsigned int x;
342	lwres_uint32_t flags;
343	lwres_uint16_t naliases;
344	lwres_uint16_t naddrs;
345	lwres_gabnresponse_t *gabn;
346	lwres_addrlist_t addrlist;
347	lwres_addr_t *addr;
348
349	REQUIRE(ctx != NULL);
350	REQUIRE(pkt != NULL);
351	REQUIRE(b != NULL);
352	REQUIRE(structp != NULL && *structp == NULL);
353
354	gabn = NULL;
355
356	if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
357		return (LWRES_R_FAILURE);
358
359	/*
360	 * Pull off the name itself
361	 */
362	if (!SPACE_REMAINING(b, 4 + 2 + 2))
363		return (LWRES_R_UNEXPECTEDEND);
364	flags = lwres_buffer_getuint32(b);
365	naliases = lwres_buffer_getuint16(b);
366	naddrs = lwres_buffer_getuint16(b);
367
368	gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
369	if (gabn == NULL)
370		return (LWRES_R_NOMEMORY);
371	gabn->aliases = NULL;
372	gabn->aliaslen = NULL;
373	LWRES_LIST_INIT(gabn->addrs);
374	gabn->base = NULL;
375
376	gabn->flags = flags;
377	gabn->naliases = naliases;
378	gabn->naddrs = naddrs;
379
380	LWRES_LIST_INIT(addrlist);
381
382	if (naliases > 0) {
383		gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
384		if (gabn->aliases == NULL) {
385			ret = LWRES_R_NOMEMORY;
386			goto out;
387		}
388
389		gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
390		if (gabn->aliaslen == NULL) {
391			ret = LWRES_R_NOMEMORY;
392			goto out;
393		}
394	}
395
396	for (x = 0; x < naddrs; x++) {
397		addr = CTXMALLOC(sizeof(lwres_addr_t));
398		if (addr == NULL) {
399			ret = LWRES_R_NOMEMORY;
400			goto out;
401		}
402		LWRES_LINK_INIT(addr, link);
403		LWRES_LIST_APPEND(addrlist, addr, link);
404	}
405
406	/*
407	 * Now, pull off the real name.
408	 */
409	ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
410	if (ret != LWRES_R_SUCCESS)
411		goto out;
412
413	/*
414	 * Parse off the aliases.
415	 */
416	for (x = 0; x < gabn->naliases; x++) {
417		ret = lwres_string_parse(b, &gabn->aliases[x],
418					 &gabn->aliaslen[x]);
419		if (ret != LWRES_R_SUCCESS)
420			goto out;
421	}
422
423	/*
424	 * Pull off the addresses.  We already strung the linked list
425	 * up above.
426	 */
427	addr = LWRES_LIST_HEAD(addrlist);
428	for (x = 0; x < gabn->naddrs; x++) {
429		INSIST(addr != NULL);
430		ret = lwres_addr_parse(b, addr);
431		if (ret != LWRES_R_SUCCESS)
432			goto out;
433		addr = LWRES_LIST_NEXT(addr, link);
434	}
435
436	if (LWRES_BUFFER_REMAINING(b) != 0) {
437		ret = LWRES_R_TRAILINGDATA;
438		goto out;
439	}
440
441	gabn->addrs = addrlist;
442
443	*structp = gabn;
444	return (LWRES_R_SUCCESS);
445
446 out:
447	if (gabn != NULL) {
448		if (gabn->aliases != NULL)
449			CTXFREE(gabn->aliases, sizeof(char *) * naliases);
450		if (gabn->aliaslen != NULL)
451			CTXFREE(gabn->aliaslen,
452				sizeof(lwres_uint16_t) * naliases);
453		addr = LWRES_LIST_HEAD(addrlist);
454		while (addr != NULL) {
455			LWRES_LIST_UNLINK(addrlist, addr, link);
456			CTXFREE(addr, sizeof(lwres_addr_t));
457			addr = LWRES_LIST_HEAD(addrlist);
458		}
459		CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
460	}
461
462	return (ret);
463}
464
465/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
466void
467lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
468{
469	lwres_gabnrequest_t *gabn;
470
471	REQUIRE(ctx != NULL);
472	REQUIRE(structp != NULL && *structp != NULL);
473
474	gabn = *structp;
475	*structp = NULL;
476
477	CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
478}
479
480/*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
481void
482lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
483{
484	lwres_gabnresponse_t *gabn;
485	lwres_addr_t *addr;
486
487	REQUIRE(ctx != NULL);
488	REQUIRE(structp != NULL && *structp != NULL);
489
490	gabn = *structp;
491	*structp = NULL;
492
493	if (gabn->naliases > 0) {
494		CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
495		CTXFREE(gabn->aliaslen,
496			sizeof(lwres_uint16_t) * gabn->naliases);
497	}
498	addr = LWRES_LIST_HEAD(gabn->addrs);
499	while (addr != NULL) {
500		LWRES_LIST_UNLINK(gabn->addrs, addr, link);
501		CTXFREE(addr, sizeof(lwres_addr_t));
502		addr = LWRES_LIST_HEAD(gabn->addrs);
503	}
504	if (gabn->base != NULL)
505		CTXFREE(gabn->base, gabn->baselen);
506	CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
507}
508