Import of bind-9.3.2-P1
[dragonfly.git] / contrib / bind-9.3 / lib / lwres / lwresutil.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  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: lwresutil.c,v 1.29.206.1 2004/03/06 08:15:33 marka Exp $ */
19
20 #include <config.h>
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <lwres/lwbuffer.h>
28 #include <lwres/lwres.h>
29 #include <lwres/result.h>
30
31 #include "assert_p.h"
32 #include "context_p.h"
33
34 /*
35  * Requires:
36  *
37  *      The "current" pointer in "b" points to encoded raw data.
38  *
39  * Ensures:
40  *
41  *      The address of the first byte of the data is returned via "p",
42  *      and the length is returned via "len".  If NULL, they are not
43  *      set.
44  *
45  *      On return, the current pointer of "b" will point to the character
46  *      following the data length and the data.
47  *
48  */
49 lwres_result_t
50 lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
51 {
52         lwres_uint16_t datalen;
53         unsigned char *data;
54
55         REQUIRE(b != NULL);
56
57         /*
58          * Pull off the length (2 bytes)
59          */
60         if (!SPACE_REMAINING(b, 2))
61                 return (LWRES_R_UNEXPECTEDEND);
62         datalen = lwres_buffer_getuint16(b);
63
64         /*
65          * Set the pointer to this string to the right place, then
66          * advance the buffer pointer.
67          */
68         if (!SPACE_REMAINING(b, datalen))
69                 return (LWRES_R_UNEXPECTEDEND);
70         data = b->base + b->current;
71         lwres_buffer_forward(b, datalen);
72
73         if (len != NULL)
74                 *len = datalen;
75         if (p != NULL)
76                 *p = data;
77
78         return (LWRES_R_SUCCESS);
79 }
80
81 /*
82  * Requires:
83  *
84  *      The "current" pointer in "b" point to an encoded string.
85  *
86  * Ensures:
87  *
88  *      The address of the first byte of the string is returned via "c",
89  *      and the length is returned via "len".  If NULL, they are not
90  *      set.
91  *
92  *      On return, the current pointer of "b" will point to the character
93  *      following the string length, the string, and the trailing NULL.
94  *
95  */
96 lwres_result_t
97 lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
98 {
99         lwres_uint16_t datalen;
100         char *string;
101
102         REQUIRE(b != NULL);
103
104         /*
105          * Pull off the length (2 bytes)
106          */
107         if (!SPACE_REMAINING(b, 2))
108                 return (LWRES_R_UNEXPECTEDEND);
109         datalen = lwres_buffer_getuint16(b);
110
111         /*
112          * Set the pointer to this string to the right place, then
113          * advance the buffer pointer.
114          */
115         if (!SPACE_REMAINING(b, datalen))
116                 return (LWRES_R_UNEXPECTEDEND);
117         string = (char *)b->base + b->current;
118         lwres_buffer_forward(b, datalen);
119
120         /*
121          * Skip the "must be zero" byte.
122          */
123         if (!SPACE_REMAINING(b, 1))
124                 return (LWRES_R_UNEXPECTEDEND);
125         if (0 != lwres_buffer_getuint8(b))
126                 return (LWRES_R_FAILURE);
127
128         if (len != NULL)
129                 *len = datalen;
130         if (c != NULL)
131                 *c = string;
132
133         return (LWRES_R_SUCCESS);
134 }
135
136 lwres_result_t
137 lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
138 {
139         REQUIRE(addr != NULL);
140
141         if (!SPACE_REMAINING(b, 6))
142                 return (LWRES_R_UNEXPECTEDEND);
143
144         addr->family = lwres_buffer_getuint32(b);
145         addr->length = lwres_buffer_getuint16(b);
146
147         if (!SPACE_REMAINING(b, addr->length))
148                 return (LWRES_R_UNEXPECTEDEND);
149         if (addr->length > LWRES_ADDR_MAXLEN)
150                 return (LWRES_R_FAILURE);
151
152         lwres_buffer_getmem(b, addr->address, addr->length);
153
154         return (LWRES_R_SUCCESS);
155 }
156
157 lwres_result_t
158 lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
159                      lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp)
160 {
161         lwres_gabnrequest_t request;
162         lwres_gabnresponse_t *response;
163         int ret;
164         int recvlen;
165         lwres_buffer_t b_in, b_out;
166         lwres_lwpacket_t pkt;
167         lwres_uint32_t serial;
168         char *buffer;
169         char target_name[1024];
170         unsigned int target_length;
171
172         REQUIRE(ctx != NULL);
173         REQUIRE(name != NULL);
174         REQUIRE(addrtypes != 0);
175         REQUIRE(structp != NULL && *structp == NULL);
176
177         b_in.base = NULL;
178         b_out.base = NULL;
179         response = NULL;
180         buffer = NULL;
181         serial = lwres_context_nextserial(ctx);
182
183         buffer = CTXMALLOC(LWRES_RECVLENGTH);
184         if (buffer == NULL) {
185                 ret = LWRES_R_NOMEMORY;
186                 goto out;
187         }
188
189         target_length = strlen(name);
190         if (target_length >= sizeof(target_name))
191                 return (LWRES_R_FAILURE);
192         strcpy(target_name, name); /* strcpy is safe */
193
194         /*
195          * Set up our request and render it to a buffer.
196          */
197         request.flags = 0;
198         request.addrtypes = addrtypes;
199         request.name = target_name;
200         request.namelen = target_length;
201         pkt.pktflags = 0;
202         pkt.serial = serial;
203         pkt.result = 0;
204         pkt.recvlength = LWRES_RECVLENGTH;
205
206  again:
207         ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
208         if (ret != LWRES_R_SUCCESS)
209                 goto out;
210
211         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
212                                      LWRES_RECVLENGTH, &recvlen);
213         if (ret != LWRES_R_SUCCESS)
214                 goto out;
215
216         lwres_buffer_init(&b_in, buffer, recvlen);
217         b_in.used = recvlen;
218
219         /*
220          * Parse the packet header.
221          */
222         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
223         if (ret != LWRES_R_SUCCESS)
224                 goto out;
225
226         /*
227          * Sanity check.
228          */
229         if (pkt.serial != serial)
230                 goto again;
231         if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
232                 goto again;
233
234         /*
235          * Free what we've transmitted
236          */
237         CTXFREE(b_out.base, b_out.length);
238         b_out.base = NULL;
239         b_out.length = 0;
240
241         if (pkt.result != LWRES_R_SUCCESS) {
242                 ret = pkt.result;
243                 goto out;
244         }
245
246         /*
247          * Parse the response.
248          */
249         ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);
250         if (ret != LWRES_R_SUCCESS)
251                 goto out;
252         response->base = buffer;
253         response->baselen = LWRES_RECVLENGTH;
254         buffer = NULL; /* don't free this below */
255
256         *structp = response;
257         return (LWRES_R_SUCCESS);
258
259  out:
260         if (b_out.base != NULL)
261                 CTXFREE(b_out.base, b_out.length);
262         if (buffer != NULL)
263                 CTXFREE(buffer, LWRES_RECVLENGTH);
264         if (response != NULL)
265                 lwres_gabnresponse_free(ctx, &response);
266
267         return (ret);
268 }
269
270
271 lwres_result_t
272 lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
273                     lwres_uint16_t addrlen, const unsigned char *addr,
274                     lwres_gnbaresponse_t **structp)
275 {
276         lwres_gnbarequest_t request;
277         lwres_gnbaresponse_t *response;
278         int ret;
279         int recvlen;
280         lwres_buffer_t b_in, b_out;
281         lwres_lwpacket_t pkt;
282         lwres_uint32_t serial;
283         char *buffer;
284
285         REQUIRE(ctx != NULL);
286         REQUIRE(addrtype != 0);
287         REQUIRE(addrlen != 0);
288         REQUIRE(addr != NULL);
289         REQUIRE(structp != NULL && *structp == NULL);
290
291         b_in.base = NULL;
292         b_out.base = NULL;
293         response = NULL;
294         buffer = NULL;
295         serial = lwres_context_nextserial(ctx);
296
297         buffer = CTXMALLOC(LWRES_RECVLENGTH);
298         if (buffer == NULL) {
299                 ret = LWRES_R_NOMEMORY;
300                 goto out;
301         }
302
303         /*
304          * Set up our request and render it to a buffer.
305          */
306         request.flags = 0;
307         request.addr.family = addrtype;
308         request.addr.length = addrlen;
309         memcpy(request.addr.address, addr, addrlen);
310         pkt.pktflags = 0;
311         pkt.serial = serial;
312         pkt.result = 0;
313         pkt.recvlength = LWRES_RECVLENGTH;
314
315  again:
316         ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
317         if (ret != LWRES_R_SUCCESS)
318                 goto out;
319
320         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
321                                      LWRES_RECVLENGTH, &recvlen);
322         if (ret != LWRES_R_SUCCESS)
323                 goto out;
324
325         lwres_buffer_init(&b_in, buffer, recvlen);
326         b_in.used = recvlen;
327
328         /*
329          * Parse the packet header.
330          */
331         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
332         if (ret != LWRES_R_SUCCESS)
333                 goto out;
334
335         /*
336          * Sanity check.
337          */
338         if (pkt.serial != serial)
339                 goto again;
340         if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
341                 goto again;
342
343         /*
344          * Free what we've transmitted
345          */
346         CTXFREE(b_out.base, b_out.length);
347         b_out.base = NULL;
348         b_out.length = 0;
349
350         if (pkt.result != LWRES_R_SUCCESS) {
351                 ret = pkt.result;
352                 goto out;
353         }
354
355         /*
356          * Parse the response.
357          */
358         ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);
359         if (ret != LWRES_R_SUCCESS)
360                 goto out;
361         response->base = buffer;
362         response->baselen = LWRES_RECVLENGTH;
363         buffer = NULL; /* don't free this below */
364
365         *structp = response;
366         return (LWRES_R_SUCCESS);
367
368  out:
369         if (b_out.base != NULL)
370                 CTXFREE(b_out.base, b_out.length);
371         if (buffer != NULL)
372                 CTXFREE(buffer, LWRES_RECVLENGTH);
373         if (response != NULL)
374                 lwres_gnbaresponse_free(ctx, &response);
375
376         return (ret);
377 }
378
379 lwres_result_t
380 lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
381                      lwres_uint16_t rdclass, lwres_uint16_t rdtype,
382                      lwres_uint32_t flags, lwres_grbnresponse_t **structp)
383 {
384         int ret;
385         int recvlen;
386         lwres_buffer_t b_in, b_out;
387         lwres_lwpacket_t pkt;
388         lwres_uint32_t serial;
389         char *buffer;
390         lwres_grbnrequest_t request;
391         lwres_grbnresponse_t *response;
392         char target_name[1024];
393         unsigned int target_length;
394
395         REQUIRE(ctx != NULL);
396         REQUIRE(name != NULL);
397         REQUIRE(structp != NULL && *structp == NULL);
398
399         b_in.base = NULL;
400         b_out.base = NULL;
401         response = NULL;
402         buffer = NULL;
403         serial = lwres_context_nextserial(ctx);
404
405         buffer = CTXMALLOC(LWRES_RECVLENGTH);
406         if (buffer == NULL) {
407                 ret = LWRES_R_NOMEMORY;
408                 goto out;
409         }
410
411         target_length = strlen(name);
412         if (target_length >= sizeof(target_name))
413                 return (LWRES_R_FAILURE);
414         strcpy(target_name, name); /* strcpy is safe */
415
416         /*
417          * Set up our request and render it to a buffer.
418          */
419         request.rdclass = rdclass;
420         request.rdtype = rdtype;
421         request.flags = flags;
422         request.name = target_name;
423         request.namelen = target_length;
424         pkt.pktflags = 0;
425         pkt.serial = serial;
426         pkt.result = 0;
427         pkt.recvlength = LWRES_RECVLENGTH;
428
429  again:
430         ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
431         if (ret != LWRES_R_SUCCESS)
432                 goto out;
433
434         ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
435                                      LWRES_RECVLENGTH, &recvlen);
436         if (ret != LWRES_R_SUCCESS)
437                 goto out;
438
439         lwres_buffer_init(&b_in, buffer, recvlen);
440         b_in.used = recvlen;
441
442         /*
443          * Parse the packet header.
444          */
445         ret = lwres_lwpacket_parseheader(&b_in, &pkt);
446         if (ret != LWRES_R_SUCCESS)
447                 goto out;
448
449         /*
450          * Sanity check.
451          */
452         if (pkt.serial != serial)
453                 goto again;
454         if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
455                 goto again;
456
457         /*
458          * Free what we've transmitted
459          */
460         CTXFREE(b_out.base, b_out.length);
461         b_out.base = NULL;
462         b_out.length = 0;
463
464         if (pkt.result != LWRES_R_SUCCESS) {
465                 ret = pkt.result;
466                 goto out;
467         }
468
469         /*
470          * Parse the response.
471          */
472         ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
473         if (ret != LWRES_R_SUCCESS)
474                 goto out;
475         response->base = buffer;
476         response->baselen = LWRES_RECVLENGTH;
477         buffer = NULL; /* don't free this below */
478
479         *structp = response;
480         return (LWRES_R_SUCCESS);
481
482  out:
483         if (b_out.base != NULL)
484                 CTXFREE(b_out.base, b_out.length);
485         if (buffer != NULL)
486                 CTXFREE(buffer, LWRES_RECVLENGTH);
487         if (response != NULL)
488                 lwres_grbnresponse_free(ctx, &response);
489
490         return (ret);
491 }