2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 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_gnba.c,v 1.28 2007/09/24 17:18:25 each Exp $ */
20 /*! \file lwres_gnba.c
21 These are low-level routines for creating and parsing lightweight
22 resolver address-to-name lookup request and response messages.
24 There are four main functions for the getnamebyaddr opcode. One
25 render function converts a getnamebyaddr request structure --
26 lwres_gnbarequest_t -- to the lightweight resolver's canonical
27 format. It is complemented by a parse function that converts a
28 packet in this canonical format to a getnamebyaddr request
29 structure. Another render function converts the getnamebyaddr
30 response structure -- lwres_gnbaresponse_t to the canonical format.
31 This is complemented by a parse function which converts a packet in
32 canonical format to a getnamebyaddr response structure.
34 These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown
38 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
43 } lwres_gnbarequest_t;
47 lwres_uint16_t naliases;
50 lwres_uint16_t realnamelen;
51 lwres_uint16_t *aliaslen;
54 } lwres_gnbaresponse_t;
57 lwres_gnbarequest_render() uses resolver context ctx to convert
58 getnamebyaddr request structure req to canonical format. The packet
59 header structure pkt is initialised and transferred to buffer b.
60 The contents of *req are then appended to the buffer in canonical
61 format. lwres_gnbaresponse_render() performs the same task, except
62 it converts a getnamebyaddr response structure lwres_gnbaresponse_t
63 to the lightweight resolver's canonical format.
65 lwres_gnbarequest_parse() uses context ctx to convert the contents
66 of packet pkt to a lwres_gnbarequest_t structure. Buffer b provides
67 space to be used for storing this structure. When the function
68 succeeds, the resulting lwres_gnbarequest_t is made available
69 through *structp. lwres_gnbaresponse_parse() offers the same
70 semantics as lwres_gnbarequest_parse() except it yields a
71 lwres_gnbaresponse_t structure.
73 lwres_gnbaresponse_free() and lwres_gnbarequest_free() release the
74 memory in resolver context ctx that was allocated to the
75 lwres_gnbaresponse_t or lwres_gnbarequest_t structures referenced
76 via structp. Any memory associated with ancillary buffers and
77 strings for those structures is also discarded.
79 \section lwres_gbna_return Return Values
81 The getnamebyaddr opcode functions lwres_gnbarequest_render(),
82 lwres_gnbaresponse_render() lwres_gnbarequest_parse() and
83 lwres_gnbaresponse_parse() all return #LWRES_R_SUCCESS on success.
84 They return #LWRES_R_NOMEMORY if memory allocation fails.
85 #LWRES_R_UNEXPECTEDEND is returned if the available space in the
86 buffer b is too small to accommodate the packet header or the
87 lwres_gnbarequest_t and lwres_gnbaresponse_t structures.
88 lwres_gnbarequest_parse() and lwres_gnbaresponse_parse() will
89 return #LWRES_R_UNEXPECTEDEND if the buffer is not empty after
90 decoding the received packet. These functions will return
91 #LWRES_R_FAILURE if pktflags in the packet header structure
92 #lwres_lwpacket_t indicate that the packet is not a response to an
95 \section lwres_gbna_see See Also
97 \link lwpacket.c lwres_packet\endlink
107 #include <lwres/lwbuffer.h>
108 #include <lwres/lwpacket.h>
109 #include <lwres/lwres.h>
110 #include <lwres/result.h>
112 #include "context_p.h"
113 #include "assert_p.h"
115 /*% Uses resolver context ctx to convert getnamebyaddr request structure req to canonical format. */
117 lwres_gnbarequest_render(lwres_context_t
*ctx
, lwres_gnbarequest_t
*req
,
118 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
123 size_t payload_length
;
125 REQUIRE(ctx
!= NULL
);
126 REQUIRE(req
!= NULL
);
127 REQUIRE(req
->addr
.family
!= 0);
128 REQUIRE(req
->addr
.length
!= 0);
129 REQUIRE(pkt
!= NULL
);
132 payload_length
= 4 + 4 + 2 + + req
->addr
.length
;
134 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
135 buf
= CTXMALLOC(buflen
);
137 return (LWRES_R_NOMEMORY
);
138 lwres_buffer_init(b
, buf
, buflen
);
140 pkt
->length
= buflen
;
141 pkt
->version
= LWRES_LWPACKETVERSION_0
;
142 pkt
->pktflags
&= ~LWRES_LWPACKETFLAG_RESPONSE
;
143 pkt
->opcode
= LWRES_OPCODE_GETNAMEBYADDR
;
148 ret
= lwres_lwpacket_renderheader(b
, pkt
);
149 if (ret
!= LWRES_R_SUCCESS
) {
150 lwres_buffer_invalidate(b
);
151 CTXFREE(buf
, buflen
);
155 INSIST(SPACE_OK(b
, payload_length
));
158 * Put the length and the data. We know this will fit because we
159 * just checked for it.
161 lwres_buffer_putuint32(b
, req
->flags
);
162 lwres_buffer_putuint32(b
, req
->addr
.family
);
163 lwres_buffer_putuint16(b
, req
->addr
.length
);
164 lwres_buffer_putmem(b
, (unsigned char *)req
->addr
.address
,
167 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
169 return (LWRES_R_SUCCESS
);
172 /*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */
174 lwres_gnbaresponse_render(lwres_context_t
*ctx
, lwres_gnbaresponse_t
*req
,
175 lwres_lwpacket_t
*pkt
, lwres_buffer_t
*b
)
180 size_t payload_length
;
181 lwres_uint16_t datalen
;
184 REQUIRE(ctx
!= NULL
);
185 REQUIRE(req
!= NULL
);
186 REQUIRE(pkt
!= NULL
);
190 * Calculate packet size.
192 payload_length
= 4; /* flags */
193 payload_length
+= 2; /* naliases */
194 payload_length
+= 2 + req
->realnamelen
+ 1; /* real name encoding */
195 for (x
= 0; x
< req
->naliases
; x
++) /* each alias */
196 payload_length
+= 2 + req
->aliaslen
[x
] + 1;
198 buflen
= LWRES_LWPACKET_LENGTH
+ payload_length
;
199 buf
= CTXMALLOC(buflen
);
201 return (LWRES_R_NOMEMORY
);
202 lwres_buffer_init(b
, buf
, buflen
);
204 pkt
->length
= buflen
;
205 pkt
->version
= LWRES_LWPACKETVERSION_0
;
206 pkt
->pktflags
|= LWRES_LWPACKETFLAG_RESPONSE
;
207 pkt
->opcode
= LWRES_OPCODE_GETNAMEBYADDR
;
211 ret
= lwres_lwpacket_renderheader(b
, pkt
);
212 if (ret
!= LWRES_R_SUCCESS
) {
213 lwres_buffer_invalidate(b
);
214 CTXFREE(buf
, buflen
);
218 INSIST(SPACE_OK(b
, payload_length
));
219 lwres_buffer_putuint32(b
, req
->flags
);
221 /* encode naliases */
222 lwres_buffer_putuint16(b
, req
->naliases
);
224 /* encode the real name */
225 datalen
= req
->realnamelen
;
226 lwres_buffer_putuint16(b
, datalen
);
227 lwres_buffer_putmem(b
, (unsigned char *)req
->realname
, datalen
);
228 lwres_buffer_putuint8(b
, 0);
230 /* encode the aliases */
231 for (x
= 0; x
< req
->naliases
; x
++) {
232 datalen
= req
->aliaslen
[x
];
233 lwres_buffer_putuint16(b
, datalen
);
234 lwres_buffer_putmem(b
, (unsigned char *)req
->aliases
[x
],
236 lwres_buffer_putuint8(b
, 0);
239 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b
) == 0);
241 return (LWRES_R_SUCCESS
);
244 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */
246 lwres_gnbarequest_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
247 lwres_lwpacket_t
*pkt
, lwres_gnbarequest_t
**structp
)
250 lwres_gnbarequest_t
*gnba
;
252 REQUIRE(ctx
!= NULL
);
253 REQUIRE(pkt
!= NULL
);
255 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
257 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) != 0)
258 return (LWRES_R_FAILURE
);
260 if (!SPACE_REMAINING(b
, 4))
261 return (LWRES_R_UNEXPECTEDEND
);
263 gnba
= CTXMALLOC(sizeof(lwres_gnbarequest_t
));
265 return (LWRES_R_NOMEMORY
);
267 gnba
->flags
= lwres_buffer_getuint32(b
);
269 ret
= lwres_addr_parse(b
, &gnba
->addr
);
270 if (ret
!= LWRES_R_SUCCESS
)
273 if (LWRES_BUFFER_REMAINING(b
) != 0) {
274 ret
= LWRES_R_TRAILINGDATA
;
279 return (LWRES_R_SUCCESS
);
283 lwres_gnbarequest_free(ctx
, &gnba
);
288 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
291 lwres_gnbaresponse_parse(lwres_context_t
*ctx
, lwres_buffer_t
*b
,
292 lwres_lwpacket_t
*pkt
, lwres_gnbaresponse_t
**structp
)
296 lwres_uint32_t flags
;
297 lwres_uint16_t naliases
;
298 lwres_gnbaresponse_t
*gnba
;
300 REQUIRE(ctx
!= NULL
);
301 REQUIRE(pkt
!= NULL
);
303 REQUIRE(structp
!= NULL
&& *structp
== NULL
);
307 if ((pkt
->pktflags
& LWRES_LWPACKETFLAG_RESPONSE
) == 0)
308 return (LWRES_R_FAILURE
);
311 * Pull off flags & naliases
313 if (!SPACE_REMAINING(b
, 4 + 2))
314 return (LWRES_R_UNEXPECTEDEND
);
315 flags
= lwres_buffer_getuint32(b
);
316 naliases
= lwres_buffer_getuint16(b
);
318 gnba
= CTXMALLOC(sizeof(lwres_gnbaresponse_t
));
320 return (LWRES_R_NOMEMORY
);
322 gnba
->aliases
= NULL
;
323 gnba
->aliaslen
= NULL
;
326 gnba
->naliases
= naliases
;
329 gnba
->aliases
= CTXMALLOC(sizeof(char *) * naliases
);
330 if (gnba
->aliases
== NULL
) {
331 ret
= LWRES_R_NOMEMORY
;
335 gnba
->aliaslen
= CTXMALLOC(sizeof(lwres_uint16_t
) * naliases
);
336 if (gnba
->aliaslen
== NULL
) {
337 ret
= LWRES_R_NOMEMORY
;
343 * Now, pull off the real name.
345 ret
= lwres_string_parse(b
, &gnba
->realname
, &gnba
->realnamelen
);
346 if (ret
!= LWRES_R_SUCCESS
)
350 * Parse off the aliases.
352 for (x
= 0; x
< gnba
->naliases
; x
++) {
353 ret
= lwres_string_parse(b
, &gnba
->aliases
[x
],
355 if (ret
!= LWRES_R_SUCCESS
)
359 if (LWRES_BUFFER_REMAINING(b
) != 0) {
360 ret
= LWRES_R_TRAILINGDATA
;
365 return (LWRES_R_SUCCESS
);
369 if (gnba
->aliases
!= NULL
)
370 CTXFREE(gnba
->aliases
, sizeof(char *) * naliases
);
371 if (gnba
->aliaslen
!= NULL
)
372 CTXFREE(gnba
->aliaslen
,
373 sizeof(lwres_uint16_t
) * naliases
);
374 CTXFREE(gnba
, sizeof(lwres_gnbaresponse_t
));
380 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
382 lwres_gnbarequest_free(lwres_context_t
*ctx
, lwres_gnbarequest_t
**structp
)
384 lwres_gnbarequest_t
*gnba
;
386 REQUIRE(ctx
!= NULL
);
387 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
392 CTXFREE(gnba
, sizeof(lwres_gnbarequest_t
));
395 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */
397 lwres_gnbaresponse_free(lwres_context_t
*ctx
, lwres_gnbaresponse_t
**structp
)
399 lwres_gnbaresponse_t
*gnba
;
401 REQUIRE(ctx
!= NULL
);
402 REQUIRE(structp
!= NULL
&& *structp
!= NULL
);
407 if (gnba
->naliases
> 0) {
408 CTXFREE(gnba
->aliases
, sizeof(char *) * gnba
->naliases
);
409 CTXFREE(gnba
->aliaslen
,
410 sizeof(lwres_uint16_t
) * gnba
->naliases
);
412 if (gnba
->base
!= NULL
)
413 CTXFREE(gnba
->base
, gnba
->baselen
);
414 CTXFREE(gnba
, sizeof(lwres_gnbaresponse_t
));