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