xref: /minix/external/bsd/bind/dist/lib/lwres/lwres_gabn.c (revision 00b67f09)
1 /*	$NetBSD: lwres_gabn.c,v 1.5 2014/12/10 04:38:02 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007, 2013  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 
41 typedef struct lwres_addr lwres_addr_t;
42 typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
43 
44 typedef struct {
45 	lwres_uint32_t  flags;
46 	lwres_uint32_t  addrtypes;
47 	lwres_uint16_t  namelen;
48 	char           *name;
49 } lwres_gabnrequest_t;
50 
51 typedef 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. */
122 lwres_result_t
lwres_gabnrequest_render(lwres_context_t * ctx,lwres_gabnrequest_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)123 lwres_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, (unsigned int)buflen);
148 
149 	pkt->length = (lwres_uint32_t)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. */
189 lwres_result_t
lwres_gabnresponse_render(lwres_context_t * ctx,lwres_gabnresponse_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)190 lwres_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, (unsigned int)buflen);
229 
230 	pkt->length = (lwres_uint32_t)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. */
286 lwres_result_t
lwres_gabnrequest_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gabnrequest_t ** structp)287 lwres_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 
336 lwres_result_t
lwres_gabnresponse_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gabnresponse_t ** structp)337 lwres_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. */
466 void
lwres_gabnrequest_free(lwres_context_t * ctx,lwres_gabnrequest_t ** structp)467 lwres_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. */
481 void
lwres_gabnresponse_free(lwres_context_t * ctx,lwres_gabnresponse_t ** structp)482 lwres_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