1 /* $NetBSD: lwresutil.c,v 1.5 2014/12/10 04:38:02 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
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.
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.
20 /* Id: lwresutil.c,v 1.34 2007/06/19 23:47:22 tbox Exp */
25 * lwres_string_parse() retrieves a DNS-encoded string starting the
26 * current pointer of lightweight resolver buffer b: i.e. b->current.
27 * When the function returns, the address of the first byte of the
28 * encoded string is returned via *c and the length of that string is
29 * given by *len. The buffer's current pointer is advanced to point at
30 * the character following the string length, the encoded string, and
31 * the trailing NULL character.
33 * lwres_addr_parse() extracts an address from the buffer b. The
34 * buffer's current pointer b->current is presumed to point at an
35 * encoded address: the address preceded by a 32-bit protocol family
36 * identifier and a 16-bit length field. The encoded address is copied
37 * to addr->address and addr->length indicates the size in bytes of
38 * the address that was copied. b->current is advanced to point at the
39 * next byte of available data in the buffer following the encoded
42 * lwres_getaddrsbyname() and lwres_getnamebyaddr() use the
43 * lwres_gnbaresponse_t structure defined below:
47 * lwres_uint32_t flags;
48 * lwres_uint16_t naliases;
49 * lwres_uint16_t naddrs;
52 * lwres_uint16_t realnamelen;
53 * lwres_uint16_t *aliaslen;
54 * lwres_addrlist_t addrs;
57 * } lwres_gabnresponse_t;
60 * The contents of this structure are not manipulated directly but
61 * they are controlled through the \link lwres_gabn.c lwres_gabn*\endlink functions.
63 * The lightweight resolver uses lwres_getaddrsbyname() to perform
64 * foward lookups. Hostname name is looked up using the resolver
65 * context ctx for memory allocation. addrtypes is a bitmask
66 * indicating which type of addresses are to be looked up. Current
67 * values for this bitmask are #LWRES_ADDRTYPE_V4 for IPv4 addresses
68 * and #LWRES_ADDRTYPE_V6 for IPv6 addresses. Results of the lookup are
69 * returned in *structp.
71 * lwres_getnamebyaddr() performs reverse lookups. Resolver context
72 * ctx is used for memory allocation. The address type is indicated by
73 * addrtype: #LWRES_ADDRTYPE_V4 or #LWRES_ADDRTYPE_V6. The address to be
74 * looked up is given by addr and its length is addrlen bytes. The
75 * result of the function call is made available through *structp.
77 * \section lwresutil_return Return Values
79 * Successful calls to lwres_string_parse() and lwres_addr_parse()
80 * return #LWRES_R_SUCCESS. Both functions return #LWRES_R_FAILURE if
81 * the buffer is corrupt or #LWRES_R_UNEXPECTEDEND if the buffer has
82 * less space than expected for the components of the encoded string
85 * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it
86 * returns #LWRES_R_NOTFOUND if the hostname name could not be found.
88 * #LWRES_R_SUCCESS is returned by a successful call to
89 * lwres_getnamebyaddr().
91 * Both lwres_getaddrsbyname() and lwres_getnamebyaddr() return
92 * #LWRES_R_NOMEMORY when memory allocation requests fail and
93 * #LWRES_R_UNEXPECTEDEND if the buffers used for sending queries and
94 * receiving replies are too small.
96 * \section lwresutil_see See Also
98 * lwbuffer.c, lwres_gabn.c
108 #include <lwres/lwbuffer.h>
109 #include <lwres/lwres.h>
110 #include <lwres/result.h>
112 #include "assert_p.h"
113 #include "context_p.h"
119 * The "current" pointer in "b" points to encoded raw data.
123 * The address of the first byte of the data is returned via "p",
124 * and the length is returned via "len". If NULL, they are not
127 * On return, the current pointer of "b" will point to the character
128 * following the data length and the data.
132 lwres_data_parse(lwres_buffer_t
*b
, unsigned char **p
, lwres_uint16_t
*len
)
134 lwres_uint16_t datalen
;
140 * Pull off the length (2 bytes)
142 if (!SPACE_REMAINING(b
, 2))
143 return (LWRES_R_UNEXPECTEDEND
);
144 datalen
= lwres_buffer_getuint16(b
);
147 * Set the pointer to this string to the right place, then
148 * advance the buffer pointer.
150 if (!SPACE_REMAINING(b
, datalen
))
151 return (LWRES_R_UNEXPECTEDEND
);
152 data
= b
->base
+ b
->current
;
153 lwres_buffer_forward(b
, datalen
);
160 return (LWRES_R_SUCCESS
);
163 /*% Retrieves a DNS-encoded string. */
167 * The "current" pointer in "b" point to an encoded string.
171 * The address of the first byte of the string is returned via "c",
172 * and the length is returned via "len". If NULL, they are not
175 * On return, the current pointer of "b" will point to the character
176 * following the string length, the string, and the trailing NULL.
180 lwres_string_parse(lwres_buffer_t
*b
, char **c
, lwres_uint16_t
*len
)
182 lwres_uint16_t datalen
;
188 * Pull off the length (2 bytes)
190 if (!SPACE_REMAINING(b
, 2))
191 return (LWRES_R_UNEXPECTEDEND
);
192 datalen
= lwres_buffer_getuint16(b
);
195 * Set the pointer to this string to the right place, then
196 * advance the buffer pointer.
198 if (!SPACE_REMAINING(b
, datalen
))
199 return (LWRES_R_UNEXPECTEDEND
);
200 string
= (char *)b
->base
+ b
->current
;
201 lwres_buffer_forward(b
, datalen
);
204 * Skip the "must be zero" byte.
206 if (!SPACE_REMAINING(b
, 1))
207 return (LWRES_R_UNEXPECTEDEND
);
208 if (0 != lwres_buffer_getuint8(b
))
209 return (LWRES_R_FAILURE
);
216 return (LWRES_R_SUCCESS
);
219 /*% Extracts an address from the buffer b. */
221 lwres_addr_parse(lwres_buffer_t
*b
, lwres_addr_t
*addr
)
223 REQUIRE(addr
!= NULL
);
225 if (!SPACE_REMAINING(b
, 6))
226 return (LWRES_R_UNEXPECTEDEND
);
228 addr
->family
= lwres_buffer_getuint32(b
);
229 addr
->length
= lwres_buffer_getuint16(b
);
231 if (!SPACE_REMAINING(b
, addr
->length
))
232 return (LWRES_R_UNEXPECTEDEND
);
233 if (addr
->length
> LWRES_ADDR_MAXLEN
)
234 return (LWRES_R_FAILURE
);
236 lwres_buffer_getmem(b
, addr
->address
, addr
->length
);
238 return (LWRES_R_SUCCESS
);
241 /*% Used to perform forward lookups. */
243 lwres_getaddrsbyname(lwres_context_t
*ctx
, const char *name
,
244 lwres_uint32_t addrtypes
, lwres_gabnresponse_t
**structp
)
246 lwres_gabnrequest_t request
;
247 lwres_gabnresponse_t
*response
;
250 lwres_buffer_t b_in
, b_out
;
251 lwres_lwpacket_t pkt
;
252 lwres_uint32_t serial
;
254 char target_name
[1024];
255 unsigned int target_length
;
257 REQUIRE(ctx
!= NULL
);
258 REQUIRE(name
!= NULL
);
259 REQUIRE(addrtypes
!= 0);
260 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
266 serial
= lwres_context_nextserial(ctx
);
268 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
269 if (buffer
== NULL
) {
270 ret
= LWRES_R_NOMEMORY
;
274 target_length
= strlen(name
);
275 if (target_length
>= sizeof(target_name
))
276 return (LWRES_R_FAILURE
);
277 strcpy(target_name
, name
); /* strcpy is safe */
280 * Set up our request and render it to a buffer.
283 request
.addrtypes
= addrtypes
;
284 request
.name
= target_name
;
285 request
.namelen
= target_length
;
289 pkt
.recvlength
= LWRES_RECVLENGTH
;
292 ret
= lwres_gabnrequest_render(ctx
, &request
, &pkt
, &b_out
);
293 if (ret
!= LWRES_R_SUCCESS
)
296 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
297 LWRES_RECVLENGTH
, &recvlen
);
298 if (ret
!= LWRES_R_SUCCESS
)
301 lwres_buffer_init(&b_in
, buffer
, recvlen
);
305 * Parse the packet header.
307 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
308 if (ret
!= LWRES_R_SUCCESS
)
314 if (pkt
.serial
!= serial
)
316 if (pkt
.opcode
!= LWRES_OPCODE_GETADDRSBYNAME
)
320 * Free what we've transmitted
322 CTXFREE(b_out
.base
, b_out
.length
);
326 if (pkt
.result
!= LWRES_R_SUCCESS
) {
332 * Parse the response.
334 ret
= lwres_gabnresponse_parse(ctx
, &b_in
, &pkt
, &response
);
335 if (ret
!= LWRES_R_SUCCESS
)
337 response
->base
= buffer
;
338 response
->baselen
= LWRES_RECVLENGTH
;
339 buffer
= NULL
; /* don't free this below */
342 return (LWRES_R_SUCCESS
);
345 if (b_out
.base
!= NULL
)
346 CTXFREE(b_out
.base
, b_out
.length
);
348 CTXFREE(buffer
, LWRES_RECVLENGTH
);
349 if (response
!= NULL
)
350 lwres_gabnresponse_free(ctx
, &response
);
356 /*% Used to perform reverse lookups. */
358 lwres_getnamebyaddr(lwres_context_t
*ctx
, lwres_uint32_t addrtype
,
359 lwres_uint16_t addrlen
, const unsigned char *addr
,
360 lwres_gnbaresponse_t
**structp
)
362 lwres_gnbarequest_t request
;
363 lwres_gnbaresponse_t
*response
;
366 lwres_buffer_t b_in
, b_out
;
367 lwres_lwpacket_t pkt
;
368 lwres_uint32_t serial
;
371 REQUIRE(ctx
!= NULL
);
372 REQUIRE(addrtype
!= 0);
373 REQUIRE(addrlen
!= 0);
374 REQUIRE(addr
!= NULL
);
375 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
381 serial
= lwres_context_nextserial(ctx
);
383 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
384 if (buffer
== NULL
) {
385 ret
= LWRES_R_NOMEMORY
;
390 * Set up our request and render it to a buffer.
393 request
.addr
.family
= addrtype
;
394 request
.addr
.length
= addrlen
;
395 memmove(request
.addr
.address
, addr
, addrlen
);
399 pkt
.recvlength
= LWRES_RECVLENGTH
;
402 ret
= lwres_gnbarequest_render(ctx
, &request
, &pkt
, &b_out
);
403 if (ret
!= LWRES_R_SUCCESS
)
406 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
407 LWRES_RECVLENGTH
, &recvlen
);
408 if (ret
!= LWRES_R_SUCCESS
)
411 lwres_buffer_init(&b_in
, buffer
, recvlen
);
415 * Parse the packet header.
417 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
418 if (ret
!= LWRES_R_SUCCESS
)
424 if (pkt
.serial
!= serial
)
426 if (pkt
.opcode
!= LWRES_OPCODE_GETNAMEBYADDR
)
430 * Free what we've transmitted
432 CTXFREE(b_out
.base
, b_out
.length
);
436 if (pkt
.result
!= LWRES_R_SUCCESS
) {
442 * Parse the response.
444 ret
= lwres_gnbaresponse_parse(ctx
, &b_in
, &pkt
, &response
);
445 if (ret
!= LWRES_R_SUCCESS
)
447 response
->base
= buffer
;
448 response
->baselen
= LWRES_RECVLENGTH
;
449 buffer
= NULL
; /* don't free this below */
452 return (LWRES_R_SUCCESS
);
455 if (b_out
.base
!= NULL
)
456 CTXFREE(b_out
.base
, b_out
.length
);
458 CTXFREE(buffer
, LWRES_RECVLENGTH
);
459 if (response
!= NULL
)
460 lwres_gnbaresponse_free(ctx
, &response
);
465 /*% Get rdata by name. */
467 lwres_getrdatabyname(lwres_context_t
*ctx
, const char *name
,
468 lwres_uint16_t rdclass
, lwres_uint16_t rdtype
,
469 lwres_uint32_t flags
, lwres_grbnresponse_t
**structp
)
473 lwres_buffer_t b_in
, b_out
;
474 lwres_lwpacket_t pkt
;
475 lwres_uint32_t serial
;
477 lwres_grbnrequest_t request
;
478 lwres_grbnresponse_t
*response
;
479 char target_name
[1024];
480 unsigned int target_length
;
482 REQUIRE(ctx
!= NULL
);
483 REQUIRE(name
!= NULL
);
484 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
490 serial
= lwres_context_nextserial(ctx
);
492 buffer
= CTXMALLOC(LWRES_RECVLENGTH
);
493 if (buffer
== NULL
) {
494 ret
= LWRES_R_NOMEMORY
;
498 target_length
= strlen(name
);
499 if (target_length
>= sizeof(target_name
))
500 return (LWRES_R_FAILURE
);
501 strcpy(target_name
, name
); /* strcpy is safe */
504 * Set up our request and render it to a buffer.
506 request
.rdclass
= rdclass
;
507 request
.rdtype
= rdtype
;
508 request
.flags
= flags
;
509 request
.name
= target_name
;
510 request
.namelen
= target_length
;
514 pkt
.recvlength
= LWRES_RECVLENGTH
;
517 ret
= lwres_grbnrequest_render(ctx
, &request
, &pkt
, &b_out
);
518 if (ret
!= LWRES_R_SUCCESS
)
521 ret
= lwres_context_sendrecv(ctx
, b_out
.base
, b_out
.length
, buffer
,
522 LWRES_RECVLENGTH
, &recvlen
);
523 if (ret
!= LWRES_R_SUCCESS
)
526 lwres_buffer_init(&b_in
, buffer
, recvlen
);
530 * Parse the packet header.
532 ret
= lwres_lwpacket_parseheader(&b_in
, &pkt
);
533 if (ret
!= LWRES_R_SUCCESS
)
539 if (pkt
.serial
!= serial
)
541 if (pkt
.opcode
!= LWRES_OPCODE_GETRDATABYNAME
)
545 * Free what we've transmitted
547 CTXFREE(b_out
.base
, b_out
.length
);
551 if (pkt
.result
!= LWRES_R_SUCCESS
) {
557 * Parse the response.
559 ret
= lwres_grbnresponse_parse(ctx
, &b_in
, &pkt
, &response
);
560 if (ret
!= LWRES_R_SUCCESS
)
562 response
->base
= buffer
;
563 response
->baselen
= LWRES_RECVLENGTH
;
564 buffer
= NULL
; /* don't free this below */
567 return (LWRES_R_SUCCESS
);
570 if (b_out
.base
!= NULL
)
571 CTXFREE(b_out
.base
, b_out
.length
);
573 CTXFREE(buffer
, LWRES_RECVLENGTH
);
574 if (response
!= NULL
)
575 lwres_grbnresponse_free(ctx
, &response
);