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: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp $ */
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.
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.
34 These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
37 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
39 typedef struct lwres_addr lwres_addr_t;
40 typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
44 lwres_uint32_t addrtypes;
45 lwres_uint16_t namelen;
47 } lwres_gabnrequest_t;
51 lwres_uint16_t naliases;
52 lwres_uint16_t naddrs;
55 lwres_uint16_t realnamelen;
56 lwres_uint16_t *aliaslen;
57 lwres_addrlist_t addrs;
60 } lwres_gabnresponse_t;
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.
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
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.
85 \section lwres_gabn_return Return Values
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.
100 \section lwres_gabn_see See Also
102 \link lwpacket.c lwres_lwpacket \endlink
111 #include <lwres/lwbuffer.h>
112 #include <lwres/lwpacket.h>
113 #include <lwres/lwres.h>
114 #include <lwres/result.h>
116 #include "context_p.h"
117 #include "assert_p.h"
119 /*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
121 lwres_gabnrequest_render(lwres_context_t
*ctx
, lwres_gabnrequest_t
*req
,
122 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
127 size_t payload_length
;
128 lwres_uint16_t datalen
;
130 REQUIRE(ctx
!= NULL
);
131 REQUIRE(req
!= NULL
);
132 REQUIRE(req
->name
!= NULL
);
133 REQUIRE(pkt
!= NULL
);
136 datalen
= strlen(req
->name
);
138 payload_length
= 4 + 4 + 2 + req
->namelen
+ 1;
140 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
141 buf
= CTXMALLOC(buflen
);
143 return (LWRES_R_NOMEMORY
);
145 lwres_buffer_init(b
, buf
, buflen
);
147 pkt
->length
= buflen
;
148 pkt
->version
= LWRES_LWPACKETVERSION_0
;
149 pkt
->pktflags
&= ~LWRES_LWPACKETFLAG_RESPONSE
;
150 pkt
->opcode
= LWRES_OPCODE_GETADDRSBYNAME
;
155 ret
= lwres_lwpacket_renderheader(b
, pkt
);
156 if (ret
!= LWRES_R_SUCCESS
) {
157 lwres_buffer_invalidate(b
);
158 CTXFREE(buf
, buflen
);
162 INSIST(SPACE_OK(b
, payload_length
));
167 lwres_buffer_putuint32(b
, req
->flags
);
170 * Address types we'll accept.
172 lwres_buffer_putuint32(b
, req
->addrtypes
);
175 * Put the length and the data. We know this will fit because we
176 * just checked for it.
178 lwres_buffer_putuint16(b
, datalen
);
179 lwres_buffer_putmem(b
, (unsigned char *)req
->name
, datalen
);
180 lwres_buffer_putuint8(b
, 0); /* trailing NUL */
182 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
184 return (LWRES_R_SUCCESS
);
186 /*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
188 lwres_gabnresponse_render(lwres_context_t
*ctx
, lwres_gabnresponse_t
*req
,
189 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
194 size_t payload_length
;
195 lwres_uint16_t datalen
;
199 REQUIRE(ctx
!= NULL
);
200 REQUIRE(req
!= NULL
);
201 REQUIRE(pkt
!= NULL
);
204 /* naliases, naddrs */
205 payload_length
= 4 + 2 + 2;
206 /* real name encoding */
207 payload_length
+= 2 + req
->realnamelen
+ 1;
209 for (x
= 0; x
< req
->naliases
; x
++)
210 payload_length
+= 2 + req
->aliaslen
[x
] + 1;
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
);
220 INSIST(x
== req
->naddrs
);
222 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
223 buf
= CTXMALLOC(buflen
);
225 return (LWRES_R_NOMEMORY
);
226 lwres_buffer_init(b
, buf
, buflen
);
228 pkt
->length
= buflen
;
229 pkt
->version
= LWRES_LWPACKETVERSION_0
;
230 pkt
->pktflags
|= LWRES_LWPACKETFLAG_RESPONSE
;
231 pkt
->opcode
= LWRES_OPCODE_GETADDRSBYNAME
;
235 ret
= lwres_lwpacket_renderheader(b
, pkt
);
236 if (ret
!= LWRES_R_SUCCESS
) {
237 lwres_buffer_invalidate(b
);
238 CTXFREE(buf
, buflen
);
243 * Check space needed here.
245 INSIST(SPACE_OK(b
, payload_length
));
248 lwres_buffer_putuint32(b
, req
->flags
);
250 /* encode naliases and naddrs */
251 lwres_buffer_putuint16(b
, req
->naliases
);
252 lwres_buffer_putuint16(b
, req
->naddrs
);
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);
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
],
266 lwres_buffer_putuint8(b
, 0);
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
);
278 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
279 INSIST(LWRES_BUFFER_USEDCOUNT(b
) == pkt
->length
);
281 return (LWRES_R_SUCCESS
);
283 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
285 lwres_gabnrequest_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
286 lwres_lwpacket_t
*pkt
, lwres_gabnrequest_t
**structp
)
290 lwres_gabnrequest_t
*gabn
;
291 lwres_uint32_t addrtypes
;
292 lwres_uint32_t flags
;
293 lwres_uint16_t namelen
;
295 REQUIRE(ctx
!= NULL
);
296 REQUIRE(pkt
!= NULL
);
298 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
300 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) != 0)
301 return (LWRES_R_FAILURE
);
303 if (!SPACE_REMAINING(b
, 4 + 4))
304 return (LWRES_R_UNEXPECTEDEND
);
306 flags
= lwres_buffer_getuint32(b
);
307 addrtypes
= lwres_buffer_getuint32(b
);
310 * Pull off the name itself
312 ret
= lwres_string_parse(b
, &name
, &namelen
);
313 if (ret
!= LWRES_R_SUCCESS
)
316 if (LWRES_BUFFER_REMAINING(b
) != 0)
317 return (LWRES_R_TRAILINGDATA
);
319 gabn
= CTXMALLOC(sizeof(lwres_gabnrequest_t
));
321 return (LWRES_R_NOMEMORY
);
324 gabn
->addrtypes
= addrtypes
;
326 gabn
->namelen
= namelen
;
329 return (LWRES_R_SUCCESS
);
332 /*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
335 lwres_gabnresponse_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
336 lwres_lwpacket_t
*pkt
, lwres_gabnresponse_t
**structp
)
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
;
347 REQUIRE(ctx
!= NULL
);
348 REQUIRE(pkt
!= NULL
);
350 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
354 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) == 0)
355 return (LWRES_R_FAILURE
);
358 * Pull off the name itself
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
);
366 gabn
= CTXMALLOC(sizeof(lwres_gabnresponse_t
));
368 return (LWRES_R_NOMEMORY
);
369 gabn
->aliases
= NULL
;
370 gabn
->aliaslen
= NULL
;
371 LWRES_LIST_INIT(gabn
->addrs
);
375 gabn
->naliases
= naliases
;
376 gabn
->naddrs
= naddrs
;
378 LWRES_LIST_INIT(addrlist
);
381 gabn
->aliases
= CTXMALLOC(sizeof(char *) * naliases
);
382 if (gabn
->aliases
== NULL
) {
383 ret
= LWRES_R_NOMEMORY
;
387 gabn
->aliaslen
= CTXMALLOC(sizeof(lwres_uint16_t
) * naliases
);
388 if (gabn
->aliaslen
== NULL
) {
389 ret
= LWRES_R_NOMEMORY
;
394 for (x
= 0; x
< naddrs
; x
++) {
395 addr
= CTXMALLOC(sizeof(lwres_addr_t
));
397 ret
= LWRES_R_NOMEMORY
;
400 LWRES_LINK_INIT(addr
, link
);
401 LWRES_LIST_APPEND(addrlist
, addr
, link
);
405 * Now, pull off the real name.
407 ret
= lwres_string_parse(b
, &gabn
->realname
, &gabn
->realnamelen
);
408 if (ret
!= LWRES_R_SUCCESS
)
412 * Parse off the aliases.
414 for (x
= 0; x
< gabn
->naliases
; x
++) {
415 ret
= lwres_string_parse(b
, &gabn
->aliases
[x
],
417 if (ret
!= LWRES_R_SUCCESS
)
422 * Pull off the addresses. We already strung the linked list
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
)
431 addr
= LWRES_LIST_NEXT(addr
, link
);
434 if (LWRES_BUFFER_REMAINING(b
) != 0) {
435 ret
= LWRES_R_TRAILINGDATA
;
439 gabn
->addrs
= addrlist
;
442 return (LWRES_R_SUCCESS
);
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
);
457 CTXFREE(gabn
, sizeof(lwres_gabnresponse_t
));
463 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
465 lwres_gabnrequest_free(lwres_context_t
*ctx
, lwres_gabnrequest_t
**structp
)
467 lwres_gabnrequest_t
*gabn
;
469 REQUIRE(ctx
!= NULL
);
470 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
475 CTXFREE(gabn
, sizeof(lwres_gabnrequest_t
));
478 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
480 lwres_gabnresponse_free(lwres_context_t
*ctx
, lwres_gabnresponse_t
**structp
)
482 lwres_gabnresponse_t
*gabn
;
485 REQUIRE(ctx
!= NULL
);
486 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
491 if (gabn
->naliases
> 0) {
492 CTXFREE(gabn
->aliases
, sizeof(char *) * gabn
->naliases
);
493 CTXFREE(gabn
->aliaslen
,
494 sizeof(lwres_uint16_t
) * gabn
->naliases
);
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
);
502 if (gabn
->base
!= NULL
)
503 CTXFREE(gabn
->base
, gabn
->baselen
);
504 CTXFREE(gabn
, sizeof(lwres_gabnresponse_t
));