bind - Removed version tag from contrib directory and updated README.DRAGONFLY.
[dragonfly.git] / contrib / bind / lib / lwres / lwres_gnba.c
1 /*
2  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2002  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: lwres_gnba.c,v 1.28 2007/09/24 17:18:25 each Exp $ */
19
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.
23
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.       
33
34    These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown
35    below.
36
37 \code
38 #define LWRES_OPCODE_GETNAMEBYADDR      0x00010002U
39
40 typedef struct {
41         lwres_uint32_t  flags;
42         lwres_addr_t    addr;
43 } lwres_gnbarequest_t;
44
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
56
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.
64
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.
72
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.
78
79 \section lwres_gbna_return Return Values
80
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.
94
95 \section lwres_gbna_see See Also
96
97    \link lwpacket.c lwres_packet\endlink
98
99  */
100
101 #include <config.h>
102
103 #include <assert.h>
104 #include <stdlib.h>
105 #include <string.h>
106
107 #include <lwres/lwbuffer.h>
108 #include <lwres/lwpacket.h>
109 #include <lwres/lwres.h>
110 #include <lwres/result.h>
111
112 #include "context_p.h"
113 #include "assert_p.h"
114
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)
119 {
120         unsigned char *buf;
121         size_t buflen;
122         int ret;
123         size_t payload_length;
124
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);
131
132         payload_length = 4 + 4 + 2 + + req->addr.length;
133
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);
139
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;
147
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);
153         }
154
155         INSIST(SPACE_OK(b, payload_length));
156
157         /*
158          * Put the length and the data.  We know this will fit because we
159          * just checked for it.
160          */
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);
166
167         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
168
169         return (LWRES_R_SUCCESS);
170 }
171
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)
176 {
177         unsigned char *buf;
178         size_t buflen;
179         int ret;
180         size_t payload_length;
181         lwres_uint16_t datalen;
182         int x;
183
184         REQUIRE(ctx != NULL);
185         REQUIRE(req != NULL);
186         REQUIRE(pkt != NULL);
187         REQUIRE(b != NULL);
188
189         /*
190          * Calculate packet size.
191          */
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;
197
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);
203
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;
210
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);
216         }
217
218         INSIST(SPACE_OK(b, payload_length));
219         lwres_buffer_putuint32(b, req->flags);
220
221         /* encode naliases */
222         lwres_buffer_putuint16(b, req->naliases);
223
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);
229
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);
237         }
238
239         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
240
241         return (LWRES_R_SUCCESS);
242 }
243
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)
248 {
249         int ret;
250         lwres_gnbarequest_t *gnba;
251
252         REQUIRE(ctx != NULL);
253         REQUIRE(pkt != NULL);
254         REQUIRE(b != NULL);
255         REQUIRE(structp != NULL && *structp == NULL);
256
257         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
258                 return (LWRES_R_FAILURE);
259
260         if (!SPACE_REMAINING(b, 4))
261                 return (LWRES_R_UNEXPECTEDEND);
262
263         gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t));
264         if (gnba == NULL)
265                 return (LWRES_R_NOMEMORY);
266
267         gnba->flags = lwres_buffer_getuint32(b);
268
269         ret = lwres_addr_parse(b, &gnba->addr);
270         if (ret != LWRES_R_SUCCESS)
271                 goto out;
272
273         if (LWRES_BUFFER_REMAINING(b) != 0) {
274                 ret = LWRES_R_TRAILINGDATA;
275                 goto out;
276         }
277
278         *structp = gnba;
279         return (LWRES_R_SUCCESS);
280
281  out:
282         if (gnba != NULL)
283                 lwres_gnbarequest_free(ctx, &gnba);
284
285         return (ret);
286 }
287
288 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
289
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)
293 {
294         int ret;
295         unsigned int x;
296         lwres_uint32_t flags;
297         lwres_uint16_t naliases;
298         lwres_gnbaresponse_t *gnba;
299
300         REQUIRE(ctx != NULL);
301         REQUIRE(pkt != NULL);
302         REQUIRE(b != NULL);
303         REQUIRE(structp != NULL && *structp == NULL);
304
305         gnba = NULL;
306
307         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
308                 return (LWRES_R_FAILURE);
309
310         /*
311          * Pull off flags & naliases
312          */
313         if (!SPACE_REMAINING(b, 4 + 2))
314                 return (LWRES_R_UNEXPECTEDEND);
315         flags = lwres_buffer_getuint32(b);
316         naliases = lwres_buffer_getuint16(b);
317
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;
324
325         gnba->flags = flags;
326         gnba->naliases = naliases;
327
328         if (naliases > 0) {
329                 gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
330                 if (gnba->aliases == NULL) {
331                         ret = LWRES_R_NOMEMORY;
332                         goto out;
333                 }
334
335                 gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
336                 if (gnba->aliaslen == NULL) {
337                         ret = LWRES_R_NOMEMORY;
338                         goto out;
339                 }
340         }
341
342         /*
343          * Now, pull off the real name.
344          */
345         ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
346         if (ret != LWRES_R_SUCCESS)
347                 goto out;
348
349         /*
350          * Parse off the aliases.
351          */
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;
357         }
358
359         if (LWRES_BUFFER_REMAINING(b) != 0) {
360                 ret = LWRES_R_TRAILINGDATA;
361                 goto out;
362         }
363
364         *structp = gnba;
365         return (LWRES_R_SUCCESS);
366
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));
375         }
376
377         return (ret);
378 }
379
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)
383 {
384         lwres_gnbarequest_t *gnba;
385
386         REQUIRE(ctx != NULL);
387         REQUIRE(structp != NULL && *structp != NULL);
388
389         gnba = *structp;
390         *structp = NULL;
391
392         CTXFREE(gnba, sizeof(lwres_gnbarequest_t));
393 }
394
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)
398 {
399         lwres_gnbaresponse_t *gnba;
400
401         REQUIRE(ctx != NULL);
402         REQUIRE(structp != NULL && *structp != NULL);
403
404         gnba = *structp;
405         *structp = NULL;
406
407         if (gnba->naliases > 0) {
408                 CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
409                 CTXFREE(gnba->aliaslen,
410                         sizeof(lwres_uint16_t) * gnba->naliases);
411         }
412         if (gnba->base != NULL)
413                 CTXFREE(gnba->base, gnba->baselen);
414         CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
415 }