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 $ */
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
40 * lwres_getaddrsbyname() and lwres_getnamebyaddr() use the
41 * lwres_gnbaresponse_t structure defined below:
45 * lwres_uint32_t flags;
46 * lwres_uint16_t naliases;
47 * lwres_uint16_t naddrs;
50 * lwres_uint16_t realnamelen;
51 * lwres_uint16_t *aliaslen;
52 * lwres_addrlist_t addrs;
55 * } lwres_gabnresponse_t;
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
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
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"
117 * The "current" pointer in "b" points to encoded raw data.
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
125 * On return, the current pointer of "b" will point to the character
126 * following the data length and the data.
130 lwres_data_parse(lwres_buffer_t
*b
, unsigned char **p
, lwres_uint16_t
*len
)
132 lwres_uint16_t datalen
;
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
);
158 return (LWRES_R_SUCCESS
);
161 /*% Retrieves a DNS-encoded string. */
165 * The "current" pointer in "b" point to an encoded string.
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
173 * On return, the current pointer of "b" will point to the character
174 * following the string length, the string, and the trailing NULL.
178 lwres_string_parse(lwres_buffer_t
*b
, char **c
, lwres_uint16_t
*len
)
180 lwres_uint16_t datalen
;
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
);
214 return (LWRES_R_SUCCESS
);
217 /*% Extracts an address from the buffer b. */
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. */
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
;
248 lwres_buffer_t b_in
, b_out
;
249 lwres_lwpacket_t pkt
;
250 lwres_uint32_t serial
;
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
);
264 serial
= lwres_context_nextserial(ctx
);
266 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
267 if (buffer
== NULL
) {
268 ret
= LWRES_R_NOMEMORY
;
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.
281 request
.addrtypes
= addrtypes
;
282 request
.name
= target_name
;
283 request
.namelen
= target_length
;
287 pkt
.recvlength
= LWRES_RECVLENGTH
;
290 ret
= lwres_gabnrequest_render(ctx
, &request
, &pkt
, &b_out
);
291 if (ret
!= LWRES_R_SUCCESS
)
294 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
295 LWRES_RECVLENGTH
, &recvlen
);
296 if (ret
!= LWRES_R_SUCCESS
)
299 lwres_buffer_init(&b_in
, buffer
, recvlen
);
303 * Parse the packet header.
305 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
306 if (ret
!= LWRES_R_SUCCESS
)
312 if (pkt
.serial
!= serial
)
314 if (pkt
.opcode
!= LWRES_OPCODE_GETADDRSBYNAME
)
318 * Free what we've transmitted
320 CTXFREE(b_out
.base
, b_out
.length
);
324 if (pkt
.result
!= LWRES_R_SUCCESS
) {
330 * Parse the response.
332 ret
= lwres_gabnresponse_parse(ctx
, &b_in
, &pkt
, &response
);
333 if (ret
!= LWRES_R_SUCCESS
)
335 response
->base
= buffer
;
336 response
->baselen
= LWRES_RECVLENGTH
;
337 buffer
= NULL
; /* don't free this below */
340 return (LWRES_R_SUCCESS
);
343 if (b_out
.base
!= NULL
)
344 CTXFREE(b_out
.base
, b_out
.length
);
346 CTXFREE(buffer
, LWRES_RECVLENGTH
);
347 if (response
!= NULL
)
348 lwres_gabnresponse_free(ctx
, &response
);
354 /*% Used to perform reverse lookups. */
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
;
364 lwres_buffer_t b_in
, b_out
;
365 lwres_lwpacket_t pkt
;
366 lwres_uint32_t serial
;
369 REQUIRE(ctx
!= NULL
);
370 REQUIRE(addrtype
!= 0);
371 REQUIRE(addrlen
!= 0);
372 REQUIRE(addr
!= NULL
);
373 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
379 serial
= lwres_context_nextserial(ctx
);
381 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
382 if (buffer
== NULL
) {
383 ret
= LWRES_R_NOMEMORY
;
388 * Set up our request and render it to a buffer.
391 request
.addr
.family
= addrtype
;
392 request
.addr
.length
= addrlen
;
393 memcpy(request
.addr
.address
, addr
, addrlen
);
397 pkt
.recvlength
= LWRES_RECVLENGTH
;
400 ret
= lwres_gnbarequest_render(ctx
, &request
, &pkt
, &b_out
);
401 if (ret
!= LWRES_R_SUCCESS
)
404 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
405 LWRES_RECVLENGTH
, &recvlen
);
406 if (ret
!= LWRES_R_SUCCESS
)
409 lwres_buffer_init(&b_in
, buffer
, recvlen
);
413 * Parse the packet header.
415 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
416 if (ret
!= LWRES_R_SUCCESS
)
422 if (pkt
.serial
!= serial
)
424 if (pkt
.opcode
!= LWRES_OPCODE_GETNAMEBYADDR
)
428 * Free what we've transmitted
430 CTXFREE(b_out
.base
, b_out
.length
);
434 if (pkt
.result
!= LWRES_R_SUCCESS
) {
440 * Parse the response.
442 ret
= lwres_gnbaresponse_parse(ctx
, &b_in
, &pkt
, &response
);
443 if (ret
!= LWRES_R_SUCCESS
)
445 response
->base
= buffer
;
446 response
->baselen
= LWRES_RECVLENGTH
;
447 buffer
= NULL
; /* don't free this below */
450 return (LWRES_R_SUCCESS
);
453 if (b_out
.base
!= NULL
)
454 CTXFREE(b_out
.base
, b_out
.length
);
456 CTXFREE(buffer
, LWRES_RECVLENGTH
);
457 if (response
!= NULL
)
458 lwres_gnbaresponse_free(ctx
, &response
);
463 /*% Get rdata by name. */
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
)
471 lwres_buffer_t b_in
, b_out
;
472 lwres_lwpacket_t pkt
;
473 lwres_uint32_t serial
;
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
);
488 serial
= lwres_context_nextserial(ctx
);
490 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
491 if (buffer
== NULL
) {
492 ret
= LWRES_R_NOMEMORY
;
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
;
512 pkt
.recvlength
= LWRES_RECVLENGTH
;
515 ret
= lwres_grbnrequest_render(ctx
, &request
, &pkt
, &b_out
);
516 if (ret
!= LWRES_R_SUCCESS
)
519 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
520 LWRES_RECVLENGTH
, &recvlen
);
521 if (ret
!= LWRES_R_SUCCESS
)
524 lwres_buffer_init(&b_in
, buffer
, recvlen
);
528 * Parse the packet header.
530 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
531 if (ret
!= LWRES_R_SUCCESS
)
537 if (pkt
.serial
!= serial
)
539 if (pkt
.opcode
!= LWRES_OPCODE_GETRDATABYNAME
)
543 * Free what we've transmitted
545 CTXFREE(b_out
.base
, b_out
.length
);
549 if (pkt
.result
!= LWRES_R_SUCCESS
) {
555 * Parse the response.
557 ret
= lwres_grbnresponse_parse(ctx
, &b_in
, &pkt
, &response
);
558 if (ret
!= LWRES_R_SUCCESS
)
560 response
->base
= buffer
;
561 response
->baselen
= LWRES_RECVLENGTH
;
562 buffer
= NULL
; /* don't free this below */
565 return (LWRES_R_SUCCESS
);
568 if (b_out
.base
!= NULL
)
569 CTXFREE(b_out
.base
, b_out
.length
);
571 CTXFREE(buffer
, LWRES_RECVLENGTH
);
572 if (response
!= NULL
)
573 lwres_grbnresponse_free(ctx
, &response
);