Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / lwres / lwresutil.c
blob3bf5660f3da5fc78eaeb59713a317a2ac4e7b6fa
1 /*
2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001 Internet Software Consortium.
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.
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.
18 /* $Id: lwresutil.c,v 1.34 2007/06/19 23:47:22 tbox Exp $ */
20 /*! \file */
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.
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.
40 * lwres_getaddrsbyname() and lwres_getnamebyaddr() use the
41 * lwres_gnbaresponse_t structure defined below:
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
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.
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.
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.
75 * \section lwresutil_return Return Values
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.
83 * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it
84 * returns #LWRES_R_NOTFOUND if the hostname name could not be found.
86 * #LWRES_R_SUCCESS is returned by a successful call to
87 * lwres_getnamebyaddr().
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.
94 * \section lwresutil_see See Also
96 * lwbuffer.c, lwres_gabn.c
99 #include <config.h>
101 #include <assert.h>
102 #include <stdlib.h>
103 #include <string.h>
104 #include <unistd.h>
106 #include <lwres/lwbuffer.h>
107 #include <lwres/lwres.h>
108 #include <lwres/result.h>
110 #include "assert_p.h"
111 #include "context_p.h"
113 /*% Parse data. */
115 * Requires:
117 * The "current" pointer in "b" points to encoded raw data.
119 * Ensures:
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.
125 * On return, the current pointer of "b" will point to the character
126 * following the data length and the data.
129 lwres_result_t
130 lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
132 lwres_uint16_t datalen;
133 unsigned char *data;
135 REQUIRE(b != NULL);
138 * Pull off the length (2 bytes)
140 if (!SPACE_REMAINING(b, 2))
141 return (LWRES_R_UNEXPECTEDEND);
142 datalen = lwres_buffer_getuint16(b);
145 * Set the pointer to this string to the right place, then
146 * advance the buffer pointer.
148 if (!SPACE_REMAINING(b, datalen))
149 return (LWRES_R_UNEXPECTEDEND);
150 data = b->base + b->current;
151 lwres_buffer_forward(b, datalen);
153 if (len != NULL)
154 *len = datalen;
155 if (p != NULL)
156 *p = data;
158 return (LWRES_R_SUCCESS);
161 /*% Retrieves a DNS-encoded string. */
163 * Requires:
165 * The "current" pointer in "b" point to an encoded string.
167 * Ensures:
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.
173 * On return, the current pointer of "b" will point to the character
174 * following the string length, the string, and the trailing NULL.
177 lwres_result_t
178 lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
180 lwres_uint16_t datalen;
181 char *string;
183 REQUIRE(b != NULL);
186 * Pull off the length (2 bytes)
188 if (!SPACE_REMAINING(b, 2))
189 return (LWRES_R_UNEXPECTEDEND);
190 datalen = lwres_buffer_getuint16(b);
193 * Set the pointer to this string to the right place, then
194 * advance the buffer pointer.
196 if (!SPACE_REMAINING(b, datalen))
197 return (LWRES_R_UNEXPECTEDEND);
198 string = (char *)b->base + b->current;
199 lwres_buffer_forward(b, datalen);
202 * Skip the "must be zero" byte.
204 if (!SPACE_REMAINING(b, 1))
205 return (LWRES_R_UNEXPECTEDEND);
206 if (0 != lwres_buffer_getuint8(b))
207 return (LWRES_R_FAILURE);
209 if (len != NULL)
210 *len = datalen;
211 if (c != NULL)
212 *c = string;
214 return (LWRES_R_SUCCESS);
217 /*% Extracts an address from the buffer b. */
218 lwres_result_t
219 lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
221 REQUIRE(addr != NULL);
223 if (!SPACE_REMAINING(b, 6))
224 return (LWRES_R_UNEXPECTEDEND);
226 addr->family = lwres_buffer_getuint32(b);
227 addr->length = lwres_buffer_getuint16(b);
229 if (!SPACE_REMAINING(b, addr->length))
230 return (LWRES_R_UNEXPECTEDEND);
231 if (addr->length > LWRES_ADDR_MAXLEN)
232 return (LWRES_R_FAILURE);
234 lwres_buffer_getmem(b, addr->address, addr->length);
236 return (LWRES_R_SUCCESS);
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)
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;
255 REQUIRE(ctx != NULL);
256 REQUIRE(name != NULL);
257 REQUIRE(addrtypes != 0);
258 REQUIRE(structp != NULL && *structp == NULL);
260 b_in.base = NULL;
261 b_out.base = NULL;
262 response = NULL;
263 buffer = NULL;
264 serial = lwres_context_nextserial(ctx);
266 buffer = CTXMALLOC(LWRES_RECVLENGTH);
267 if (buffer == NULL) {
268 ret = LWRES_R_NOMEMORY;
269 goto out;
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 */
278 * Set up our request and render it to a buffer.
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;
289 again:
290 ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
291 if (ret != LWRES_R_SUCCESS)
292 goto out;
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;
299 lwres_buffer_init(&b_in, buffer, recvlen);
300 b_in.used = recvlen;
303 * Parse the packet header.
305 ret = lwres_lwpacket_parseheader(&b_in, &pkt);
306 if (ret != LWRES_R_SUCCESS)
307 goto out;
310 * Sanity check.
312 if (pkt.serial != serial)
313 goto again;
314 if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
315 goto again;
318 * Free what we've transmitted
320 CTXFREE(b_out.base, b_out.length);
321 b_out.base = NULL;
322 b_out.length = 0;
324 if (pkt.result != LWRES_R_SUCCESS) {
325 ret = pkt.result;
326 goto out;
330 * Parse the response.
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 */
339 *structp = response;
340 return (LWRES_R_SUCCESS);
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);
350 return (ret);
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)
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;
369 REQUIRE(ctx != NULL);
370 REQUIRE(addrtype != 0);
371 REQUIRE(addrlen != 0);
372 REQUIRE(addr != NULL);
373 REQUIRE(structp != NULL && *structp == NULL);
375 b_in.base = NULL;
376 b_out.base = NULL;
377 response = NULL;
378 buffer = NULL;
379 serial = lwres_context_nextserial(ctx);
381 buffer = CTXMALLOC(LWRES_RECVLENGTH);
382 if (buffer == NULL) {
383 ret = LWRES_R_NOMEMORY;
384 goto out;
388 * Set up our request and render it to a buffer.
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;
399 again:
400 ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
401 if (ret != LWRES_R_SUCCESS)
402 goto out;
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;
409 lwres_buffer_init(&b_in, buffer, recvlen);
410 b_in.used = recvlen;
413 * Parse the packet header.
415 ret = lwres_lwpacket_parseheader(&b_in, &pkt);
416 if (ret != LWRES_R_SUCCESS)
417 goto out;
420 * Sanity check.
422 if (pkt.serial != serial)
423 goto again;
424 if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
425 goto again;
428 * Free what we've transmitted
430 CTXFREE(b_out.base, b_out.length);
431 b_out.base = NULL;
432 b_out.length = 0;
434 if (pkt.result != LWRES_R_SUCCESS) {
435 ret = pkt.result;
436 goto out;
440 * Parse the response.
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 */
449 *structp = response;
450 return (LWRES_R_SUCCESS);
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);
460 return (ret);
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)
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;
480 REQUIRE(ctx != NULL);
481 REQUIRE(name != NULL);
482 REQUIRE(structp != NULL && *structp == NULL);
484 b_in.base = NULL;
485 b_out.base = NULL;
486 response = NULL;
487 buffer = NULL;
488 serial = lwres_context_nextserial(ctx);
490 buffer = CTXMALLOC(LWRES_RECVLENGTH);
491 if (buffer == NULL) {
492 ret = LWRES_R_NOMEMORY;
493 goto out;
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 */
502 * Set up our request and render it to a buffer.
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;
514 again:
515 ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
516 if (ret != LWRES_R_SUCCESS)
517 goto out;
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;
524 lwres_buffer_init(&b_in, buffer, recvlen);
525 b_in.used = recvlen;
528 * Parse the packet header.
530 ret = lwres_lwpacket_parseheader(&b_in, &pkt);
531 if (ret != LWRES_R_SUCCESS)
532 goto out;
535 * Sanity check.
537 if (pkt.serial != serial)
538 goto again;
539 if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
540 goto again;
543 * Free what we've transmitted
545 CTXFREE(b_out.base, b_out.length);
546 b_out.base = NULL;
547 b_out.length = 0;
549 if (pkt.result != LWRES_R_SUCCESS) {
550 ret = pkt.result;
551 goto out;
555 * Parse the response.
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 */
564 *structp = response;
565 return (LWRES_R_SUCCESS);
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);
575 return (ret);