4 * Copyright (C) 2004, 2005, 2007 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: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp */
22 /*! \file lwres_gabn.c
23 These are low-level routines for creating and parsing lightweight
24 resolver name-to-address lookup request and response messages.
26 There are four main functions for the getaddrbyname opcode. One render
27 function converts a getaddrbyname request structure --
28 lwres_gabnrequest_t -- to the lighweight resolver's canonical format.
29 It is complemented by a parse function that converts a packet in this
30 canonical format to a getaddrbyname request structure. Another render
31 function converts the getaddrbyname response structure --
32 lwres_gabnresponse_t -- to the canonical format. This is complemented
33 by a parse function which converts a packet in canonical format to a
34 getaddrbyname response structure.
36 These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
39 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
41 typedef struct lwres_addr lwres_addr_t;
42 typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
46 lwres_uint32_t addrtypes;
47 lwres_uint16_t namelen;
49 } lwres_gabnrequest_t;
53 lwres_uint16_t naliases;
54 lwres_uint16_t naddrs;
57 lwres_uint16_t realnamelen;
58 lwres_uint16_t *aliaslen;
59 lwres_addrlist_t addrs;
62 } lwres_gabnresponse_t;
65 lwres_gabnrequest_render() uses resolver context ctx to convert
66 getaddrbyname request structure req to canonical format. The packet
67 header structure pkt is initialised and transferred to buffer b. The
68 contents of *req are then appended to the buffer in canonical format.
69 lwres_gabnresponse_render() performs the same task, except it converts
70 a getaddrbyname response structure lwres_gabnresponse_t to the
71 lightweight resolver's canonical format.
73 lwres_gabnrequest_parse() uses context ctx to convert the contents of
74 packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space
75 to be used for storing this structure. When the function succeeds, the
76 resulting lwres_gabnrequest_t is made available through *structp.
77 lwres_gabnresponse_parse() offers the same semantics as
78 lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t
81 lwres_gabnresponse_free() and lwres_gabnrequest_free() release the
82 memory in resolver context ctx that was allocated to the
83 lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via
84 structp. Any memory associated with ancillary buffers and strings for
85 those structures is also discarded.
87 \section lwres_gabn_return Return Values
89 The getaddrbyname opcode functions lwres_gabnrequest_render(),
90 lwres_gabnresponse_render() lwres_gabnrequest_parse() and
91 lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They
92 return #LWRES_R_NOMEMORY if memory allocation fails.
93 #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
94 b is too small to accommodate the packet header or the
95 lwres_gabnrequest_t and lwres_gabnresponse_t structures.
96 lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return
97 #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
98 received packet. These functions will return #LWRES_R_FAILURE if
99 pktflags in the packet header structure #lwres_lwpacket_t indicate that
100 the packet is not a response to an earlier query.
102 \section lwres_gabn_see See Also
104 \link lwpacket.c lwres_lwpacket \endlink
113 #include <lwres/lwbuffer.h>
114 #include <lwres/lwpacket.h>
115 #include <lwres/lwres.h>
116 #include <lwres/result.h>
118 #include "context_p.h"
119 #include "assert_p.h"
121 /*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
123 lwres_gabnrequest_render(lwres_context_t
*ctx
, lwres_gabnrequest_t
*req
,
124 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
129 size_t payload_length
;
130 lwres_uint16_t datalen
;
132 REQUIRE(ctx
!= NULL
);
133 REQUIRE(req
!= NULL
);
134 REQUIRE(req
->name
!= NULL
);
135 REQUIRE(pkt
!= NULL
);
138 datalen
= strlen(req
->name
);
140 payload_length
= 4 + 4 + 2 + req
->namelen
+ 1;
142 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
143 buf
= CTXMALLOC(buflen
);
145 return (LWRES_R_NOMEMORY
);
147 lwres_buffer_init(b
, buf
, buflen
);
149 pkt
->length
= buflen
;
150 pkt
->version
= LWRES_LWPACKETVERSION_0
;
151 pkt
->pktflags
&= ~LWRES_LWPACKETFLAG_RESPONSE
;
152 pkt
->opcode
= LWRES_OPCODE_GETADDRSBYNAME
;
157 ret
= lwres_lwpacket_renderheader(b
, pkt
);
158 if (ret
!= LWRES_R_SUCCESS
) {
159 lwres_buffer_invalidate(b
);
160 CTXFREE(buf
, buflen
);
164 INSIST(SPACE_OK(b
, payload_length
));
169 lwres_buffer_putuint32(b
, req
->flags
);
172 * Address types we'll accept.
174 lwres_buffer_putuint32(b
, req
->addrtypes
);
177 * Put the length and the data. We know this will fit because we
178 * just checked for it.
180 lwres_buffer_putuint16(b
, datalen
);
181 lwres_buffer_putmem(b
, (unsigned char *)req
->name
, datalen
);
182 lwres_buffer_putuint8(b
, 0); /* trailing NUL */
184 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
186 return (LWRES_R_SUCCESS
);
188 /*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
190 lwres_gabnresponse_render(lwres_context_t
*ctx
, lwres_gabnresponse_t
*req
,
191 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
196 size_t payload_length
;
197 lwres_uint16_t datalen
;
201 REQUIRE(ctx
!= NULL
);
202 REQUIRE(req
!= NULL
);
203 REQUIRE(pkt
!= NULL
);
206 /* naliases, naddrs */
207 payload_length
= 4 + 2 + 2;
208 /* real name encoding */
209 payload_length
+= 2 + req
->realnamelen
+ 1;
211 for (x
= 0; x
< req
->naliases
; x
++)
212 payload_length
+= 2 + req
->aliaslen
[x
] + 1;
215 addr
= LWRES_LIST_HEAD(req
->addrs
);
216 while (addr
!= NULL
) {
217 payload_length
+= 4 + 2;
218 payload_length
+= addr
->length
;
219 addr
= LWRES_LIST_NEXT(addr
, link
);
222 INSIST(x
== req
->naddrs
);
224 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
225 buf
= CTXMALLOC(buflen
);
227 return (LWRES_R_NOMEMORY
);
228 lwres_buffer_init(b
, buf
, buflen
);
230 pkt
->length
= buflen
;
231 pkt
->version
= LWRES_LWPACKETVERSION_0
;
232 pkt
->pktflags
|= LWRES_LWPACKETFLAG_RESPONSE
;
233 pkt
->opcode
= LWRES_OPCODE_GETADDRSBYNAME
;
237 ret
= lwres_lwpacket_renderheader(b
, pkt
);
238 if (ret
!= LWRES_R_SUCCESS
) {
239 lwres_buffer_invalidate(b
);
240 CTXFREE(buf
, buflen
);
245 * Check space needed here.
247 INSIST(SPACE_OK(b
, payload_length
));
250 lwres_buffer_putuint32(b
, req
->flags
);
252 /* encode naliases and naddrs */
253 lwres_buffer_putuint16(b
, req
->naliases
);
254 lwres_buffer_putuint16(b
, req
->naddrs
);
256 /* encode the real name */
257 datalen
= req
->realnamelen
;
258 lwres_buffer_putuint16(b
, datalen
);
259 lwres_buffer_putmem(b
, (unsigned char *)req
->realname
, datalen
);
260 lwres_buffer_putuint8(b
, 0);
262 /* encode the aliases */
263 for (x
= 0; x
< req
->naliases
; x
++) {
264 datalen
= req
->aliaslen
[x
];
265 lwres_buffer_putuint16(b
, datalen
);
266 lwres_buffer_putmem(b
, (unsigned char *)req
->aliases
[x
],
268 lwres_buffer_putuint8(b
, 0);
271 /* encode the addresses */
272 addr
= LWRES_LIST_HEAD(req
->addrs
);
273 while (addr
!= NULL
) {
274 lwres_buffer_putuint32(b
, addr
->family
);
275 lwres_buffer_putuint16(b
, addr
->length
);
276 lwres_buffer_putmem(b
, addr
->address
, addr
->length
);
277 addr
= LWRES_LIST_NEXT(addr
, link
);
280 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
281 INSIST(LWRES_BUFFER_USEDCOUNT(b
) == pkt
->length
);
283 return (LWRES_R_SUCCESS
);
285 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
287 lwres_gabnrequest_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
288 lwres_lwpacket_t
*pkt
, lwres_gabnrequest_t
**structp
)
292 lwres_gabnrequest_t
*gabn
;
293 lwres_uint32_t addrtypes
;
294 lwres_uint32_t flags
;
295 lwres_uint16_t namelen
;
297 REQUIRE(ctx
!= NULL
);
298 REQUIRE(pkt
!= NULL
);
300 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
302 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) != 0)
303 return (LWRES_R_FAILURE
);
305 if (!SPACE_REMAINING(b
, 4 + 4))
306 return (LWRES_R_UNEXPECTEDEND
);
308 flags
= lwres_buffer_getuint32(b
);
309 addrtypes
= lwres_buffer_getuint32(b
);
312 * Pull off the name itself
314 ret
= lwres_string_parse(b
, &name
, &namelen
);
315 if (ret
!= LWRES_R_SUCCESS
)
318 if (LWRES_BUFFER_REMAINING(b
) != 0)
319 return (LWRES_R_TRAILINGDATA
);
321 gabn
= CTXMALLOC(sizeof(lwres_gabnrequest_t
));
323 return (LWRES_R_NOMEMORY
);
326 gabn
->addrtypes
= addrtypes
;
328 gabn
->namelen
= namelen
;
331 return (LWRES_R_SUCCESS
);
334 /*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
337 lwres_gabnresponse_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
338 lwres_lwpacket_t
*pkt
, lwres_gabnresponse_t
**structp
)
342 lwres_uint32_t flags
;
343 lwres_uint16_t naliases
;
344 lwres_uint16_t naddrs
;
345 lwres_gabnresponse_t
*gabn
;
346 lwres_addrlist_t addrlist
;
349 REQUIRE(ctx
!= NULL
);
350 REQUIRE(pkt
!= NULL
);
352 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
356 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) == 0)
357 return (LWRES_R_FAILURE
);
360 * Pull off the name itself
362 if (!SPACE_REMAINING(b
, 4 + 2 + 2))
363 return (LWRES_R_UNEXPECTEDEND
);
364 flags
= lwres_buffer_getuint32(b
);
365 naliases
= lwres_buffer_getuint16(b
);
366 naddrs
= lwres_buffer_getuint16(b
);
368 gabn
= CTXMALLOC(sizeof(lwres_gabnresponse_t
));
370 return (LWRES_R_NOMEMORY
);
371 gabn
->aliases
= NULL
;
372 gabn
->aliaslen
= NULL
;
373 LWRES_LIST_INIT(gabn
->addrs
);
377 gabn
->naliases
= naliases
;
378 gabn
->naddrs
= naddrs
;
380 LWRES_LIST_INIT(addrlist
);
383 gabn
->aliases
= CTXMALLOC(sizeof(char *) * naliases
);
384 if (gabn
->aliases
== NULL
) {
385 ret
= LWRES_R_NOMEMORY
;
389 gabn
->aliaslen
= CTXMALLOC(sizeof(lwres_uint16_t
) * naliases
);
390 if (gabn
->aliaslen
== NULL
) {
391 ret
= LWRES_R_NOMEMORY
;
396 for (x
= 0; x
< naddrs
; x
++) {
397 addr
= CTXMALLOC(sizeof(lwres_addr_t
));
399 ret
= LWRES_R_NOMEMORY
;
402 LWRES_LINK_INIT(addr
, link
);
403 LWRES_LIST_APPEND(addrlist
, addr
, link
);
407 * Now, pull off the real name.
409 ret
= lwres_string_parse(b
, &gabn
->realname
, &gabn
->realnamelen
);
410 if (ret
!= LWRES_R_SUCCESS
)
414 * Parse off the aliases.
416 for (x
= 0; x
< gabn
->naliases
; x
++) {
417 ret
= lwres_string_parse(b
, &gabn
->aliases
[x
],
419 if (ret
!= LWRES_R_SUCCESS
)
424 * Pull off the addresses. We already strung the linked list
427 addr
= LWRES_LIST_HEAD(addrlist
);
428 for (x
= 0; x
< gabn
->naddrs
; x
++) {
429 INSIST(addr
!= NULL
);
430 ret
= lwres_addr_parse(b
, addr
);
431 if (ret
!= LWRES_R_SUCCESS
)
433 addr
= LWRES_LIST_NEXT(addr
, link
);
436 if (LWRES_BUFFER_REMAINING(b
) != 0) {
437 ret
= LWRES_R_TRAILINGDATA
;
441 gabn
->addrs
= addrlist
;
444 return (LWRES_R_SUCCESS
);
448 if (gabn
->aliases
!= NULL
)
449 CTXFREE(gabn
->aliases
, sizeof(char *) * naliases
);
450 if (gabn
->aliaslen
!= NULL
)
451 CTXFREE(gabn
->aliaslen
,
452 sizeof(lwres_uint16_t
) * naliases
);
453 addr
= LWRES_LIST_HEAD(addrlist
);
454 while (addr
!= NULL
) {
455 LWRES_LIST_UNLINK(addrlist
, addr
, link
);
456 CTXFREE(addr
, sizeof(lwres_addr_t
));
457 addr
= LWRES_LIST_HEAD(addrlist
);
459 CTXFREE(gabn
, sizeof(lwres_gabnresponse_t
));
465 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
467 lwres_gabnrequest_free(lwres_context_t
*ctx
, lwres_gabnrequest_t
**structp
)
469 lwres_gabnrequest_t
*gabn
;
471 REQUIRE(ctx
!= NULL
);
472 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
477 CTXFREE(gabn
, sizeof(lwres_gabnrequest_t
));
480 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
482 lwres_gabnresponse_free(lwres_context_t
*ctx
, lwres_gabnresponse_t
**structp
)
484 lwres_gabnresponse_t
*gabn
;
487 REQUIRE(ctx
!= NULL
);
488 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
493 if (gabn
->naliases
> 0) {
494 CTXFREE(gabn
->aliases
, sizeof(char *) * gabn
->naliases
);
495 CTXFREE(gabn
->aliaslen
,
496 sizeof(lwres_uint16_t
) * gabn
->naliases
);
498 addr
= LWRES_LIST_HEAD(gabn
->addrs
);
499 while (addr
!= NULL
) {
500 LWRES_LIST_UNLINK(gabn
->addrs
, addr
, link
);
501 CTXFREE(addr
, sizeof(lwres_addr_t
));
502 addr
= LWRES_LIST_HEAD(gabn
->addrs
);
504 if (gabn
->base
!= NULL
)
505 CTXFREE(gabn
->base
, gabn
->baselen
);
506 CTXFREE(gabn
, sizeof(lwres_gabnresponse_t
));