]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/lwres/lwres_gnba.c
This commit was generated by cvs2svn to compensate for changes in r171827,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / lwres / lwres_gnba.c
1 /*
2  * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.23.18.2 2005/04/29 00:17:20 marka 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(req->addr.address != NULL);
130         REQUIRE(pkt != NULL);
131         REQUIRE(b != NULL);
132
133         payload_length = 4 + 4 + 2 + + req->addr.length;
134
135         buflen = LWRES_LWPACKET_LENGTH + payload_length;
136         buf = CTXMALLOC(buflen);
137         if (buf == NULL)
138                 return (LWRES_R_NOMEMORY);
139         lwres_buffer_init(b, buf, buflen);
140
141         pkt->length = buflen;
142         pkt->version = LWRES_LWPACKETVERSION_0;
143         pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
144         pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
145         pkt->result = 0;
146         pkt->authtype = 0;
147         pkt->authlength = 0;
148
149         ret = lwres_lwpacket_renderheader(b, pkt);
150         if (ret != LWRES_R_SUCCESS) {
151                 lwres_buffer_invalidate(b);
152                 CTXFREE(buf, buflen);
153                 return (ret);
154         }
155
156         INSIST(SPACE_OK(b, payload_length));
157
158         /*
159          * Put the length and the data.  We know this will fit because we
160          * just checked for it.
161          */
162         lwres_buffer_putuint32(b, req->flags);
163         lwres_buffer_putuint32(b, req->addr.family);
164         lwres_buffer_putuint16(b, req->addr.length);
165         lwres_buffer_putmem(b, (unsigned char *)req->addr.address,
166                             req->addr.length);
167
168         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
169
170         return (LWRES_R_SUCCESS);
171 }
172
173 /*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */
174 lwres_result_t
175 lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
176                           lwres_lwpacket_t *pkt, lwres_buffer_t *b)
177 {
178         unsigned char *buf;
179         size_t buflen;
180         int ret;
181         size_t payload_length;
182         lwres_uint16_t datalen;
183         int x;
184
185         REQUIRE(ctx != NULL);
186         REQUIRE(req != NULL);
187         REQUIRE(pkt != NULL);
188         REQUIRE(b != NULL);
189
190         /*
191          * Calculate packet size.
192          */
193         payload_length = 4;                            /* flags */
194         payload_length += 2;                           /* naliases */
195         payload_length += 2 + req->realnamelen + 1;    /* real name encoding */
196         for (x = 0; x < req->naliases; x++)            /* each alias */
197                 payload_length += 2 + req->aliaslen[x] + 1;
198
199         buflen = LWRES_LWPACKET_LENGTH + payload_length;
200         buf = CTXMALLOC(buflen);
201         if (buf == NULL)
202                 return (LWRES_R_NOMEMORY);
203         lwres_buffer_init(b, buf, buflen);
204
205         pkt->length = buflen;
206         pkt->version = LWRES_LWPACKETVERSION_0;
207         pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
208         pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
209         pkt->authtype = 0;
210         pkt->authlength = 0;
211
212         ret = lwres_lwpacket_renderheader(b, pkt);
213         if (ret != LWRES_R_SUCCESS) {
214                 lwres_buffer_invalidate(b);
215                 CTXFREE(buf, buflen);
216                 return (ret);
217         }
218
219         INSIST(SPACE_OK(b, payload_length));
220         lwres_buffer_putuint32(b, req->flags);
221
222         /* encode naliases */
223         lwres_buffer_putuint16(b, req->naliases);
224
225         /* encode the real name */
226         datalen = req->realnamelen;
227         lwres_buffer_putuint16(b, datalen);
228         lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
229         lwres_buffer_putuint8(b, 0);
230
231         /* encode the aliases */
232         for (x = 0; x < req->naliases; x++) {
233                 datalen = req->aliaslen[x];
234                 lwres_buffer_putuint16(b, datalen);
235                 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
236                                     datalen);
237                 lwres_buffer_putuint8(b, 0);
238         }
239
240         INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
241
242         return (LWRES_R_SUCCESS);
243 }
244
245 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */
246 lwres_result_t
247 lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
248                         lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp)
249 {
250         int ret;
251         lwres_gnbarequest_t *gnba;
252
253         REQUIRE(ctx != NULL);
254         REQUIRE(pkt != NULL);
255         REQUIRE(b != NULL);
256         REQUIRE(structp != NULL && *structp == NULL);
257
258         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
259                 return (LWRES_R_FAILURE);
260
261         if (!SPACE_REMAINING(b, 4))
262                 return (LWRES_R_UNEXPECTEDEND);
263
264         gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t));
265         if (gnba == NULL)
266                 return (LWRES_R_NOMEMORY);
267
268         gnba->flags = lwres_buffer_getuint32(b);
269
270         ret = lwres_addr_parse(b, &gnba->addr);
271         if (ret != LWRES_R_SUCCESS)
272                 goto out;
273
274         if (LWRES_BUFFER_REMAINING(b) != 0) {
275                 ret = LWRES_R_TRAILINGDATA;
276                 goto out;
277         }
278
279         *structp = gnba;
280         return (LWRES_R_SUCCESS);
281
282  out:
283         if (gnba != NULL)
284                 lwres_gnbarequest_free(ctx, &gnba);
285
286         return (ret);
287 }
288
289 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
290
291 lwres_result_t
292 lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
293                          lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp)
294 {
295         int ret;
296         unsigned int x;
297         lwres_uint32_t flags;
298         lwres_uint16_t naliases;
299         lwres_gnbaresponse_t *gnba;
300
301         REQUIRE(ctx != NULL);
302         REQUIRE(pkt != NULL);
303         REQUIRE(b != NULL);
304         REQUIRE(structp != NULL && *structp == NULL);
305
306         gnba = NULL;
307
308         if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
309                 return (LWRES_R_FAILURE);
310
311         /*
312          * Pull off flags & naliases
313          */
314         if (!SPACE_REMAINING(b, 4 + 2))
315                 return (LWRES_R_UNEXPECTEDEND);
316         flags = lwres_buffer_getuint32(b);
317         naliases = lwres_buffer_getuint16(b);
318
319         gnba = CTXMALLOC(sizeof(lwres_gnbaresponse_t));
320         if (gnba == NULL)
321                 return (LWRES_R_NOMEMORY);
322         gnba->base = NULL;
323         gnba->aliases = NULL;
324         gnba->aliaslen = NULL;
325
326         gnba->flags = flags;
327         gnba->naliases = naliases;
328
329         if (naliases > 0) {
330                 gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
331                 if (gnba->aliases == NULL) {
332                         ret = LWRES_R_NOMEMORY;
333                         goto out;
334                 }
335
336                 gnba->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
337                 if (gnba->aliaslen == NULL) {
338                         ret = LWRES_R_NOMEMORY;
339                         goto out;
340                 }
341         }
342
343         /*
344          * Now, pull off the real name.
345          */
346         ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
347         if (ret != LWRES_R_SUCCESS)
348                 goto out;
349
350         /*
351          * Parse off the aliases.
352          */
353         for (x = 0; x < gnba->naliases; x++) {
354                 ret = lwres_string_parse(b, &gnba->aliases[x],
355                                          &gnba->aliaslen[x]);
356                 if (ret != LWRES_R_SUCCESS)
357                         goto out;
358         }
359
360         if (LWRES_BUFFER_REMAINING(b) != 0) {
361                 ret = LWRES_R_TRAILINGDATA;
362                 goto out;
363         }
364
365         *structp = gnba;
366         return (LWRES_R_SUCCESS);
367
368  out:
369         if (gnba != NULL) {
370                 if (gnba->aliases != NULL)
371                         CTXFREE(gnba->aliases, sizeof(char *) * naliases);
372                 if (gnba->aliaslen != NULL)
373                         CTXFREE(gnba->aliaslen,
374                                 sizeof(lwres_uint16_t) * naliases);
375                 CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
376         }
377
378         return (ret);
379 }
380
381 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
382 void
383 lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp)
384 {
385         lwres_gnbarequest_t *gnba;
386
387         REQUIRE(ctx != NULL);
388         REQUIRE(structp != NULL && *structp != NULL);
389
390         gnba = *structp;
391         *structp = NULL;
392
393         CTXFREE(gnba, sizeof(lwres_gnbarequest_t));
394 }
395
396 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */
397 void
398 lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp)
399 {
400         lwres_gnbaresponse_t *gnba;
401
402         REQUIRE(ctx != NULL);
403         REQUIRE(structp != NULL && *structp != NULL);
404
405         gnba = *structp;
406         *structp = NULL;
407
408         if (gnba->naliases > 0) {
409                 CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
410                 CTXFREE(gnba->aliaslen,
411                         sizeof(lwres_uint16_t) * gnba->naliases);
412         }
413         if (gnba->base != NULL)
414                 CTXFREE(gnba->base, gnba->baselen);
415         CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
416 }