Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / lwres / lwres_gnba.c
blobd18ae153f23e0314fba8877eff738e95e1744750
1 /*
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
35 below.
37 \code
38 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
40 typedef struct {
41 lwres_uint32_t flags;
42 lwres_addr_t addr;
43 } lwres_gnbarequest_t;
45 typedef struct {
46 lwres_uint32_t flags;
47 lwres_uint16_t naliases;
48 char *realname;
49 char **aliases;
50 lwres_uint16_t realnamelen;
51 lwres_uint16_t *aliaslen;
52 void *base;
53 size_t baselen;
54 } lwres_gnbaresponse_t;
55 \endcode
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
93 earlier query.
95 \section lwres_gbna_see See Also
97 \link lwpacket.c lwres_packet\endlink
101 #include <config.h>
103 #include <assert.h>
104 #include <stdlib.h>
105 #include <string.h>
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. */
116 lwres_result_t
117 lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
118 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
120 unsigned char *buf;
121 size_t buflen;
122 int ret;
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);
130 REQUIRE(b != NULL);
132 payload_length = 4 + 4 + 2 + + req->addr.length;
134 buflen = LWRES_LWPACKET_LENGTH + payload_length;
135 buf = CTXMALLOC(buflen);
136 if (buf == NULL)
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;
144 pkt->result = 0;
145 pkt->authtype = 0;
146 pkt->authlength = 0;
148 ret = lwres_lwpacket_renderheader(b, pkt);
149 if (ret != LWRES_R_SUCCESS) {
150 lwres_buffer_invalidate(b);
151 CTXFREE(buf, buflen);
152 return (ret);
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,
165 req->addr.length);
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. */
173 lwres_result_t
174 lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
175 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
177 unsigned char *buf;
178 size_t buflen;
179 int ret;
180 size_t payload_length;
181 lwres_uint16_t datalen;
182 int x;
184 REQUIRE(ctx != NULL);
185 REQUIRE(req != NULL);
186 REQUIRE(pkt != NULL);
187 REQUIRE(b != 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);
200 if (buf == NULL)
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;
208 pkt->authtype = 0;
209 pkt->authlength = 0;
211 ret = lwres_lwpacket_renderheader(b, pkt);
212 if (ret != LWRES_R_SUCCESS) {
213 lwres_buffer_invalidate(b);
214 CTXFREE(buf, buflen);
215 return (ret);
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],
235 datalen);
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. */
245 lwres_result_t
246 lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
247 lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp)
249 int ret;
250 lwres_gnbarequest_t *gnba;
252 REQUIRE(ctx != NULL);
253 REQUIRE(pkt != NULL);
254 REQUIRE(b != 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));
264 if (gnba == NULL)
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)
271 goto out;
273 if (LWRES_BUFFER_REMAINING(b) != 0) {
274 ret = LWRES_R_TRAILINGDATA;
275 goto out;
278 *structp = gnba;
279 return (LWRES_R_SUCCESS);
281 out:
282 if (gnba != NULL)
283 lwres_gnbarequest_free(ctx, &gnba);
285 return (ret);
288 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
290 lwres_result_t
291 lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
292 lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp)
294 int ret;
295 unsigned int x;
296 lwres_uint32_t flags;
297 lwres_uint16_t naliases;
298 lwres_gnbaresponse_t *gnba;
300 REQUIRE(ctx != NULL);
301 REQUIRE(pkt != NULL);
302 REQUIRE(b != NULL);
303 REQUIRE(structp != NULL && *structp == NULL);
305 gnba = 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));
319 if (gnba == NULL)
320 return (LWRES_R_NOMEMORY);
321 gnba->base = NULL;
322 gnba->aliases = NULL;
323 gnba->aliaslen = NULL;
325 gnba->flags = flags;
326 gnba->naliases = naliases;
328 if (naliases > 0) {
329 gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
330 if (gnba->aliases == NULL) {
331 ret = LWRES_R_NOMEMORY;
332 goto out;
335 gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
336 if (gnba->aliaslen == NULL) {
337 ret = LWRES_R_NOMEMORY;
338 goto out;
343 * Now, pull off the real name.
345 ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
346 if (ret != LWRES_R_SUCCESS)
347 goto out;
350 * Parse off the aliases.
352 for (x = 0; x < gnba->naliases; x++) {
353 ret = lwres_string_parse(b, &gnba->aliases[x],
354 &gnba->aliaslen[x]);
355 if (ret != LWRES_R_SUCCESS)
356 goto out;
359 if (LWRES_BUFFER_REMAINING(b) != 0) {
360 ret = LWRES_R_TRAILINGDATA;
361 goto out;
364 *structp = gnba;
365 return (LWRES_R_SUCCESS);
367 out:
368 if (gnba != NULL) {
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));
377 return (ret);
380 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
381 void
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);
389 gnba = *structp;
390 *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. */
396 void
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);
404 gnba = *structp;
405 *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));