Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / lwres / lwresutil.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: lwresutil.c,v 1.34 2007/06/19 23:47:22 tbox Exp $ */
19
20 /*! \file */
21
22 /**
23  *    lwres_string_parse() retrieves a DNS-encoded string starting the
24  *    current pointer of lightweight resolver buffer b: i.e. b->current.
25  *    When the function returns, the address of the first byte of the
26  *    encoded string is returned via *c and the length of that string is
27  *    given by *len. The buffer's current pointer is advanced to point at
28  *    the character following the string length, the encoded string, and
29  *    the trailing NULL character.
30  * 
31  *    lwres_addr_parse() extracts an address from the buffer b. The
32  *    buffer's current pointer b->current is presumed to point at an
33  *    encoded address: the address preceded by a 32-bit protocol family
34  *    identifier and a 16-bit length field. The encoded address is copied
35  *    to addr->address and addr->length indicates the size in bytes of
36  *    the address that was copied. b->current is advanced to point at the
37  *  next byte of available data in the buffer following the encoded
38  *    address.
39  * 
40  *    lwres_getaddrsbyname() and lwres_getnamebyaddr() use the
41  *    lwres_gnbaresponse_t structure defined below:
42  * 
43  * \code
44  * typedef struct {
45  *         lwres_uint32_t          flags;
46  *         lwres_uint16_t          naliases;
47  *         lwres_uint16_t          naddrs;
48  *         char                   *realname;
49  *         char                  **aliases;
50  *         lwres_uint16_t          realnamelen;
51  *         lwres_uint16_t         *aliaslen;
52  *         lwres_addrlist_t        addrs;
53  *         void                   *base;
54  *         size_t                  baselen;
55  * } lwres_gabnresponse_t;
56  * \endcode
57  * 
58  *    The contents of this structure are not manipulated directly but
59  *    they are controlled through the \link lwres_gabn.c lwres_gabn*\endlink functions.  
60  * 
61  *    The lightweight resolver uses lwres_getaddrsbyname() to perform
62  *    foward lookups. Hostname name is looked up using the resolver
63  *    context ctx for memory allocation. addrtypes is a bitmask      
64  *    indicating which type of addresses are to be looked up. Current
65  *    values for this bitmask are #LWRES_ADDRTYPE_V4 for IPv4 addresses
66  *    and #LWRES_ADDRTYPE_V6 for IPv6 addresses. Results of the lookup are
67  *    returned in *structp.
68  * 
69  *    lwres_getnamebyaddr() performs reverse lookups. Resolver context  
70  *    ctx is used for memory allocation. The address type is indicated by
71  *    addrtype: #LWRES_ADDRTYPE_V4 or #LWRES_ADDRTYPE_V6. The address to be
72  *    looked up is given by addr and its length is addrlen bytes. The    
73  *    result of the function call is made available through *structp.   
74  * 
75  * \section lwresutil_return Return Values
76  * 
77  *    Successful calls to lwres_string_parse() and lwres_addr_parse()
78  *    return #LWRES_R_SUCCESS. Both functions return #LWRES_R_FAILURE if 
79  *    the buffer is corrupt or #LWRES_R_UNEXPECTEDEND if the buffer has   
80  *    less space than expected for the components of the encoded string
81  *    or address.
82  * 
83  * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it
84  *    returns #LWRES_R_NOTFOUND if the hostname name could not be found.
85  * 
86  *    #LWRES_R_SUCCESS is returned by a successful call to
87  *    lwres_getnamebyaddr().
88  * 
89  *    Both lwres_getaddrsbyname() and lwres_getnamebyaddr() return
90  *    #LWRES_R_NOMEMORY when memory allocation requests fail and
91  *    #LWRES_R_UNEXPECTEDEND if the buffers used for sending queries and
92  *    receiving replies are too small.     
93  * 
94  * \section lwresutil_see See Also
95  * 
96  *    lwbuffer.c, lwres_gabn.c
97  */
98
99 #include <config.h>
100
101 #include <assert.h>
102 #include <stdlib.h>
103 #include <string.h>
104 #include <unistd.h>
105
106 #include <lwres/lwbuffer.h>
107 #include <lwres/lwres.h>
108 #include <lwres/result.h>
109
110 #include "assert_p.h"
111 #include "context_p.h"
112
113 /*% Parse data. */
114 /*!
115  * Requires:
116  *
117  *      The "current" pointer in "b" points to encoded raw data.
118  *
119  * Ensures:
120  *
121  *      The address of the first byte of the data is returned via "p",
122  *      and the length is returned via "len".  If NULL, they are not
123  *      set.
124  *
125  *      On return, the current pointer of "b" will point to the character
126  *      following the data length and the data.
127  *
128  */
129 lwres_result_t
130 lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
131 {
132         lwres_uint16_t datalen;
133         unsigned char *data;
134
135         REQUIRE(b != NULL);
136
137         /*
138          * Pull off the length (2 bytes)
139          */
140         if (!SPACE_REMAINING(b, 2))
141                 return (LWRES_R_UNEXPECTEDEND);
142         datalen = lwres_buffer_getuint16(b);
143
144         /*
145          * Set the pointer to this string to the right place, then
146          * advance the buffer pointer.
147          */
148         if (!SPACE_REMAINING(b, datalen))
149                 return (LWRES_R_UNEXPECTEDEND);
150         data = b->base + b->current;
151         lwres_buffer_forward(b, datalen);
152
153         if (len != NULL)
154                 *len = datalen;
155         if (p != NULL)
156                 *p = data;
157
158         return (LWRES_R_SUCCESS);
159 }
160
161 /*% Retrieves a DNS-encoded string. */
162 /*!
163  * Requires:
164  *
165  *      The "current" pointer in "b" point to an encoded string.
166  *
167  * Ensures:
168  *
169  *      The address of the first byte of the string is returned via "c",
170  *      and the length is returned via "len".  If NULL, they are not
171  *      set.
172  *
173  *      On return, the current pointer of "b" will point to the character
174  *      following the string length, the string, and the trailing NULL.
175  *
176  */
177 lwres_result_t
178 lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
179 {
180         lwres_uint16_t datalen;
181         char *string;
182
183         REQUIRE(b != NULL);
184
185         /*
186          * Pull off the length (2 bytes)
187          */
188         if (!SPACE_REMAINING(b, 2))
189                 return (LWRES_R_UNEXPECTEDEND);
190         datalen = lwres_buffer_getuint16(b);
191
192         /*
193          * Set the pointer to this string to the right place, then
194          * advance the buffer pointer.
195          */
196         if (!SPACE_REMAINING(b, datalen))
197                 return (LWRES_R_UNEXPECTEDEND);
198         string = (char *)b->base + b->current;
199         lwres_buffer_forward(b, datalen);
200
201         /*
202          * Skip the "must be zero" byte.
203          */
204         if (!SPACE_REMAINING(b, 1))
205                 return (LWRES_R_UNEXPECTEDEND);
206         if (0 != lwres_buffer_getuint8(b))
207                 return (LWRES_R_FAILURE);
208
209         if (len != NULL)
210                 *len = datalen;
211         if (c != NULL)
212                 *c = string;
213
214         return (LWRES_R_SUCCESS);
215 }
216
217 /*% Extracts an address from the buffer b. */
218 lwres_result_t
219 lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
220 {
221         REQUIRE(addr != NULL);
222
223         if (!SPACE_REMAINING(b, 6))
224                 return (LWRES_R_UNEXPECTEDEND);
225
226         addr->family = lwres_buffer_getuint32(b);
227         addr->length = lwres_buffer_getuint16(b);
228
229         if (!SPACE_REMAINING(b, addr->length))
230                 return (LWRES_R_UNEXPECTEDEND);
231         if (addr->length > LWRES_ADDR_MAXLEN)
232                 return (LWRES_R_FAILURE);
233
234         lwres_buffer_getmem(b, addr->address, addr->length);
235
236         return (LWRES_R_SUCCESS);
237 }
238
239 /*% Used to perform forward lookups. */
240 lwres_result_t
241 lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
242                      lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp)
243 {
244         lwres_gabnrequest_t request;
245         lwres_gabnresponse_t *response;
246         int ret;
247         int recvlen;
248         lwres_buffer_t b_in, b_out;
249         lwres_lwpacket_t pkt;
250         lwres_uint32_t serial;
251         char *buffer;
252         char target_name[1024];
253         unsigned int target_length;
254
255         REQUIRE(ctx != NULL);
256         REQUIRE(name != NULL);
257         REQUIRE(addrtypes != 0);
258         REQUIRE(structp != NULL && *structp == NULL);
259
260         b_in.base = NULL;
261         b_out.base = NULL;
262         response = NULL;
263         buffer = NULL;
264         serial = lwres_context_nextserial(ctx);
265
266         buffer = CTXMALLOC(LWRES_RECVLENGTH);
267         if (buffer == NULL) {
268                 ret = LWRES_R_NOMEMORY;
269                 goto out;
270         }
271
272         target_length = strlen(name);
273         if (target_length >= sizeof(target_name))
274                 return (LWRES_R_FAILURE);
275         strcpy(target_name, name); /* strcpy is safe */
276
277         /*
278          * Set up our request and render it to a buffer.
279          */
280         request.flags = 0;
281         request.addrtypes = addrtypes;
282         request.name = target_name;
283         request.namelen = target_length;
284         pkt.pktflags = 0;
285         pkt.serial = serial;
286         pkt.result = 0;
287         pkt.recvlength = LWRES_RECVLENGTH;
288
289  again:
290         ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
291         if (ret != LWRES_R_SUCCESS)
292                 goto out;
293
294         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
295                                      LWRES_RECVLENGTH, &recvlen);
296         if (ret != LWRES_R_SUCCESS)
297                 goto out;
298
299         lwres_buffer_init(&b_in, buffer, recvlen);
300         b_in.used = recvlen;
301
302         /*
303          * Parse the packet header.
304          */
305         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
306         if (ret != LWRES_R_SUCCESS)
307                 goto out;
308
309         /*
310          * Sanity check.
311          */
312         if (pkt.serial != serial)
313                 goto again;
314         if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
315                 goto again;
316
317         /*
318          * Free what we've transmitted
319          */
320         CTXFREE(b_out.base, b_out.length);
321         b_out.base = NULL;
322         b_out.length = 0;
323
324         if (pkt.result != LWRES_R_SUCCESS) {
325                 ret = pkt.result;
326                 goto out;
327         }
328
329         /*
330          * Parse the response.
331          */
332         ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);
333         if (ret != LWRES_R_SUCCESS)
334                 goto out;
335         response->base = buffer;
336         response->baselen = LWRES_RECVLENGTH;
337         buffer = NULL; /* don't free this below */
338
339         *structp = response;
340         return (LWRES_R_SUCCESS);
341
342  out:
343         if (b_out.base != NULL)
344                 CTXFREE(b_out.base, b_out.length);
345         if (buffer != NULL)
346                 CTXFREE(buffer, LWRES_RECVLENGTH);
347         if (response != NULL)
348                 lwres_gabnresponse_free(ctx, &response);
349
350         return (ret);
351 }
352
353
354 /*% Used to perform reverse lookups. */
355 lwres_result_t
356 lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
357                     lwres_uint16_t addrlen, const unsigned char *addr,
358                     lwres_gnbaresponse_t **structp)
359 {
360         lwres_gnbarequest_t request;
361         lwres_gnbaresponse_t *response;
362         int ret;
363         int recvlen;
364         lwres_buffer_t b_in, b_out;
365         lwres_lwpacket_t pkt;
366         lwres_uint32_t serial;
367         char *buffer;
368
369         REQUIRE(ctx != NULL);
370         REQUIRE(addrtype != 0);
371         REQUIRE(addrlen != 0);
372         REQUIRE(addr != NULL);
373         REQUIRE(structp != NULL && *structp == NULL);
374
375         b_in.base = NULL;
376         b_out.base = NULL;
377         response = NULL;
378         buffer = NULL;
379         serial = lwres_context_nextserial(ctx);
380
381         buffer = CTXMALLOC(LWRES_RECVLENGTH);
382         if (buffer == NULL) {
383                 ret = LWRES_R_NOMEMORY;
384                 goto out;
385         }
386
387         /*
388          * Set up our request and render it to a buffer.
389          */
390         request.flags = 0;
391         request.addr.family = addrtype;
392         request.addr.length = addrlen;
393         memcpy(request.addr.address, addr, addrlen);
394         pkt.pktflags = 0;
395         pkt.serial = serial;
396         pkt.result = 0;
397         pkt.recvlength = LWRES_RECVLENGTH;
398
399  again:
400         ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
401         if (ret != LWRES_R_SUCCESS)
402                 goto out;
403
404         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
405                                      LWRES_RECVLENGTH, &recvlen);
406         if (ret != LWRES_R_SUCCESS)
407                 goto out;
408
409         lwres_buffer_init(&b_in, buffer, recvlen);
410         b_in.used = recvlen;
411
412         /*
413          * Parse the packet header.
414          */
415         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
416         if (ret != LWRES_R_SUCCESS)
417                 goto out;
418
419         /*
420          * Sanity check.
421          */
422         if (pkt.serial != serial)
423                 goto again;
424         if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
425                 goto again;
426
427         /*
428          * Free what we've transmitted
429          */
430         CTXFREE(b_out.base, b_out.length);
431         b_out.base = NULL;
432         b_out.length = 0;
433
434         if (pkt.result != LWRES_R_SUCCESS) {
435                 ret = pkt.result;
436                 goto out;
437         }
438
439         /*
440          * Parse the response.
441          */
442         ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);
443         if (ret != LWRES_R_SUCCESS)
444                 goto out;
445         response->base = buffer;
446         response->baselen = LWRES_RECVLENGTH;
447         buffer = NULL; /* don't free this below */
448
449         *structp = response;
450         return (LWRES_R_SUCCESS);
451
452  out:
453         if (b_out.base != NULL)
454                 CTXFREE(b_out.base, b_out.length);
455         if (buffer != NULL)
456                 CTXFREE(buffer, LWRES_RECVLENGTH);
457         if (response != NULL)
458                 lwres_gnbaresponse_free(ctx, &response);
459
460         return (ret);
461 }
462
463 /*% Get rdata by name. */
464 lwres_result_t
465 lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
466                      lwres_uint16_t rdclass, lwres_uint16_t rdtype,
467                      lwres_uint32_t flags, lwres_grbnresponse_t **structp)
468 {
469         int ret;
470         int recvlen;
471         lwres_buffer_t b_in, b_out;
472         lwres_lwpacket_t pkt;
473         lwres_uint32_t serial;
474         char *buffer;
475         lwres_grbnrequest_t request;
476         lwres_grbnresponse_t *response;
477         char target_name[1024];
478         unsigned int target_length;
479
480         REQUIRE(ctx != NULL);
481         REQUIRE(name != NULL);
482         REQUIRE(structp != NULL && *structp == NULL);
483
484         b_in.base = NULL;
485         b_out.base = NULL;
486         response = NULL;
487         buffer = NULL;
488         serial = lwres_context_nextserial(ctx);
489
490         buffer = CTXMALLOC(LWRES_RECVLENGTH);
491         if (buffer == NULL) {
492                 ret = LWRES_R_NOMEMORY;
493                 goto out;
494         }
495
496         target_length = strlen(name);
497         if (target_length >= sizeof(target_name))
498                 return (LWRES_R_FAILURE);
499         strcpy(target_name, name); /* strcpy is safe */
500
501         /*
502          * Set up our request and render it to a buffer.
503          */
504         request.rdclass = rdclass;
505         request.rdtype = rdtype;
506         request.flags = flags;
507         request.name = target_name;
508         request.namelen = target_length;
509         pkt.pktflags = 0;
510         pkt.serial = serial;
511         pkt.result = 0;
512         pkt.recvlength = LWRES_RECVLENGTH;
513
514  again:
515         ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
516         if (ret != LWRES_R_SUCCESS)
517                 goto out;
518
519         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
520                                      LWRES_RECVLENGTH, &recvlen);
521         if (ret != LWRES_R_SUCCESS)
522                 goto out;
523
524         lwres_buffer_init(&b_in, buffer, recvlen);
525         b_in.used = recvlen;
526
527         /*
528          * Parse the packet header.
529          */
530         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
531         if (ret != LWRES_R_SUCCESS)
532                 goto out;
533
534         /*
535          * Sanity check.
536          */
537         if (pkt.serial != serial)
538                 goto again;
539         if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
540                 goto again;
541
542         /*
543          * Free what we've transmitted
544          */
545         CTXFREE(b_out.base, b_out.length);
546         b_out.base = NULL;
547         b_out.length = 0;
548
549         if (pkt.result != LWRES_R_SUCCESS) {
550                 ret = pkt.result;
551                 goto out;
552         }
553
554         /*
555          * Parse the response.
556          */
557         ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
558         if (ret != LWRES_R_SUCCESS)
559                 goto out;
560         response->base = buffer;
561         response->baselen = LWRES_RECVLENGTH;
562         buffer = NULL; /* don't free this below */
563
564         *structp = response;
565         return (LWRES_R_SUCCESS);
566
567  out:
568         if (b_out.base != NULL)
569                 CTXFREE(b_out.base, b_out.length);
570         if (buffer != NULL)
571                 CTXFREE(buffer, LWRES_RECVLENGTH);
572         if (response != NULL)
573                 lwres_grbnresponse_free(ctx, &response);
574
575         return (ret);
576 }