1 /* $NetBSD: lwres_gabn.c,v 1.5 2014/12/10 04:38:02 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004, 2005, 2007, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Id: lwres_gabn.c,v 1.33 2007/06/19 23:47:22 tbox Exp */
21
22 /*! \file lwres_gabn.c
23 These are low-level routines for creating and parsing lightweight
24 resolver name-to-address lookup request and response messages.
25
26 There are four main functions for the getaddrbyname opcode. One render
27 function converts a getaddrbyname request structure --
28 lwres_gabnrequest_t -- to the lighweight resolver's canonical format.
29 It is complemented by a parse function that converts a packet in this
30 canonical format to a getaddrbyname request structure. Another render
31 function converts the getaddrbyname response structure --
32 lwres_gabnresponse_t -- to the canonical format. This is complemented
33 by a parse function which converts a packet in canonical format to a
34 getaddrbyname response structure.
35
36 These structures are defined in \link lwres.h <lwres/lwres.h>.\endlink They are shown below.
37
38 \code
39 #define LWRES_OPCODE_GETADDRSBYNAME 0x00010001U
40
41 typedef struct lwres_addr lwres_addr_t;
42 typedef LWRES_LIST(lwres_addr_t) lwres_addrlist_t;
43
44 typedef struct {
45 lwres_uint32_t flags;
46 lwres_uint32_t addrtypes;
47 lwres_uint16_t namelen;
48 char *name;
49 } lwres_gabnrequest_t;
50
51 typedef struct {
52 lwres_uint32_t flags;
53 lwres_uint16_t naliases;
54 lwres_uint16_t naddrs;
55 char *realname;
56 char **aliases;
57 lwres_uint16_t realnamelen;
58 lwres_uint16_t *aliaslen;
59 lwres_addrlist_t addrs;
60 void *base;
61 size_t baselen;
62 } lwres_gabnresponse_t;
63 \endcode
64
65 lwres_gabnrequest_render() uses resolver context ctx to convert
66 getaddrbyname request structure req to canonical format. The packet
67 header structure pkt is initialised and transferred to buffer b. The
68 contents of *req are then appended to the buffer in canonical format.
69 lwres_gabnresponse_render() performs the same task, except it converts
70 a getaddrbyname response structure lwres_gabnresponse_t to the
71 lightweight resolver's canonical format.
72
73 lwres_gabnrequest_parse() uses context ctx to convert the contents of
74 packet pkt to a lwres_gabnrequest_t structure. Buffer b provides space
75 to be used for storing this structure. When the function succeeds, the
76 resulting lwres_gabnrequest_t is made available through *structp.
77 lwres_gabnresponse_parse() offers the same semantics as
78 lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t
79 structure.
80
81 lwres_gabnresponse_free() and lwres_gabnrequest_free() release the
82 memory in resolver context ctx that was allocated to the
83 lwres_gabnresponse_t or lwres_gabnrequest_t structures referenced via
84 structp. Any memory associated with ancillary buffers and strings for
85 those structures is also discarded.
86
87 \section lwres_gabn_return Return Values
88
89 The getaddrbyname opcode functions lwres_gabnrequest_render(),
90 lwres_gabnresponse_render() lwres_gabnrequest_parse() and
91 lwres_gabnresponse_parse() all return #LWRES_R_SUCCESS on success. They
92 return #LWRES_R_NOMEMORY if memory allocation fails.
93 #LWRES_R_UNEXPECTEDEND is returned if the available space in the buffer
94 b is too small to accommodate the packet header or the
95 lwres_gabnrequest_t and lwres_gabnresponse_t structures.
96 lwres_gabnrequest_parse() and lwres_gabnresponse_parse() will return
97 #LWRES_R_UNEXPECTEDEND if the buffer is not empty after decoding the
98 received packet. These functions will return #LWRES_R_FAILURE if
99 pktflags in the packet header structure #lwres_lwpacket_t indicate that
100 the packet is not a response to an earlier query.
101
102 \section lwres_gabn_see See Also
103
104 \link lwpacket.c lwres_lwpacket \endlink
105 */
106
107 #include <config.h>
108
109 #include <assert.h>
110 #include <stdlib.h>
111 #include <string.h>
112
113 #include <lwres/lwbuffer.h>
114 #include <lwres/lwpacket.h>
115 #include <lwres/lwres.h>
116 #include <lwres/result.h>
117
118 #include "context_p.h"
119 #include "assert_p.h"
120
121 /*% uses resolver context ctx to convert getaddrbyname request structure req to canonical format. */
122 lwres_result_t
lwres_gabnrequest_render(lwres_context_t * ctx,lwres_gabnrequest_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)123 lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
124 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
125 {
126 unsigned char *buf;
127 size_t buflen;
128 int ret;
129 size_t payload_length;
130 lwres_uint16_t datalen;
131
132 REQUIRE(ctx != NULL);
133 REQUIRE(req != NULL);
134 REQUIRE(req->name != NULL);
135 REQUIRE(pkt != NULL);
136 REQUIRE(b != NULL);
137
138 datalen = strlen(req->name);
139
140 payload_length = 4 + 4 + 2 + req->namelen + 1;
141
142 buflen = LWRES_LWPACKET_LENGTH + payload_length;
143 buf = CTXMALLOC(buflen);
144 if (buf == NULL)
145 return (LWRES_R_NOMEMORY);
146
147 lwres_buffer_init(b, buf, (unsigned int)buflen);
148
149 pkt->length = (lwres_uint32_t)buflen;
150 pkt->version = LWRES_LWPACKETVERSION_0;
151 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
152 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
153 pkt->result = 0;
154 pkt->authtype = 0;
155 pkt->authlength = 0;
156
157 ret = lwres_lwpacket_renderheader(b, pkt);
158 if (ret != LWRES_R_SUCCESS) {
159 lwres_buffer_invalidate(b);
160 CTXFREE(buf, buflen);
161 return (ret);
162 }
163
164 INSIST(SPACE_OK(b, payload_length));
165
166 /*
167 * Flags.
168 */
169 lwres_buffer_putuint32(b, req->flags);
170
171 /*
172 * Address types we'll accept.
173 */
174 lwres_buffer_putuint32(b, req->addrtypes);
175
176 /*
177 * Put the length and the data. We know this will fit because we
178 * just checked for it.
179 */
180 lwres_buffer_putuint16(b, datalen);
181 lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
182 lwres_buffer_putuint8(b, 0); /* trailing NUL */
183
184 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
185
186 return (LWRES_R_SUCCESS);
187 }
188 /*% converts a getaddrbyname response structure lwres_gabnresponse_t to the lightweight resolver's canonical format. */
189 lwres_result_t
lwres_gabnresponse_render(lwres_context_t * ctx,lwres_gabnresponse_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)190 lwres_gabnresponse_render(lwres_context_t *ctx, lwres_gabnresponse_t *req,
191 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
192 {
193 unsigned char *buf;
194 size_t buflen;
195 int ret;
196 size_t payload_length;
197 lwres_uint16_t datalen;
198 lwres_addr_t *addr;
199 int x;
200
201 REQUIRE(ctx != NULL);
202 REQUIRE(req != NULL);
203 REQUIRE(pkt != NULL);
204 REQUIRE(b != NULL);
205
206 /* naliases, naddrs */
207 payload_length = 4 + 2 + 2;
208 /* real name encoding */
209 payload_length += 2 + req->realnamelen + 1;
210 /* each alias */
211 for (x = 0; x < req->naliases; x++)
212 payload_length += 2 + req->aliaslen[x] + 1;
213 /* each address */
214 x = 0;
215 addr = LWRES_LIST_HEAD(req->addrs);
216 while (addr != NULL) {
217 payload_length += 4 + 2;
218 payload_length += addr->length;
219 addr = LWRES_LIST_NEXT(addr, link);
220 x++;
221 }
222 INSIST(x == req->naddrs);
223
224 buflen = LWRES_LWPACKET_LENGTH + payload_length;
225 buf = CTXMALLOC(buflen);
226 if (buf == NULL)
227 return (LWRES_R_NOMEMORY);
228 lwres_buffer_init(b, buf, (unsigned int)buflen);
229
230 pkt->length = (lwres_uint32_t)buflen;
231 pkt->version = LWRES_LWPACKETVERSION_0;
232 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
233 pkt->opcode = LWRES_OPCODE_GETADDRSBYNAME;
234 pkt->authtype = 0;
235 pkt->authlength = 0;
236
237 ret = lwres_lwpacket_renderheader(b, pkt);
238 if (ret != LWRES_R_SUCCESS) {
239 lwres_buffer_invalidate(b);
240 CTXFREE(buf, buflen);
241 return (ret);
242 }
243
244 /*
245 * Check space needed here.
246 */
247 INSIST(SPACE_OK(b, payload_length));
248
249 /* Flags. */
250 lwres_buffer_putuint32(b, req->flags);
251
252 /* encode naliases and naddrs */
253 lwres_buffer_putuint16(b, req->naliases);
254 lwres_buffer_putuint16(b, req->naddrs);
255
256 /* encode the real name */
257 datalen = req->realnamelen;
258 lwres_buffer_putuint16(b, datalen);
259 lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
260 lwres_buffer_putuint8(b, 0);
261
262 /* encode the aliases */
263 for (x = 0; x < req->naliases; x++) {
264 datalen = req->aliaslen[x];
265 lwres_buffer_putuint16(b, datalen);
266 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
267 datalen);
268 lwres_buffer_putuint8(b, 0);
269 }
270
271 /* encode the addresses */
272 addr = LWRES_LIST_HEAD(req->addrs);
273 while (addr != NULL) {
274 lwres_buffer_putuint32(b, addr->family);
275 lwres_buffer_putuint16(b, addr->length);
276 lwres_buffer_putmem(b, addr->address, addr->length);
277 addr = LWRES_LIST_NEXT(addr, link);
278 }
279
280 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
281 INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
282
283 return (LWRES_R_SUCCESS);
284 }
285 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gabnrequest_t structure. */
286 lwres_result_t
lwres_gabnrequest_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gabnrequest_t ** structp)287 lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
288 lwres_lwpacket_t *pkt, lwres_gabnrequest_t **structp)
289 {
290 int ret;
291 char *name;
292 lwres_gabnrequest_t *gabn;
293 lwres_uint32_t addrtypes;
294 lwres_uint32_t flags;
295 lwres_uint16_t namelen;
296
297 REQUIRE(ctx != NULL);
298 REQUIRE(pkt != NULL);
299 REQUIRE(b != NULL);
300 REQUIRE(structp != NULL && *structp == NULL);
301
302 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
303 return (LWRES_R_FAILURE);
304
305 if (!SPACE_REMAINING(b, 4 + 4))
306 return (LWRES_R_UNEXPECTEDEND);
307
308 flags = lwres_buffer_getuint32(b);
309 addrtypes = lwres_buffer_getuint32(b);
310
311 /*
312 * Pull off the name itself
313 */
314 ret = lwres_string_parse(b, &name, &namelen);
315 if (ret != LWRES_R_SUCCESS)
316 return (ret);
317
318 if (LWRES_BUFFER_REMAINING(b) != 0)
319 return (LWRES_R_TRAILINGDATA);
320
321 gabn = CTXMALLOC(sizeof(lwres_gabnrequest_t));
322 if (gabn == NULL)
323 return (LWRES_R_NOMEMORY);
324
325 gabn->flags = flags;
326 gabn->addrtypes = addrtypes;
327 gabn->name = name;
328 gabn->namelen = namelen;
329
330 *structp = gabn;
331 return (LWRES_R_SUCCESS);
332 }
333
334 /*% Offers the same semantics as lwres_gabnrequest_parse() except it yields a lwres_gabnresponse_t structure. */
335
336 lwres_result_t
lwres_gabnresponse_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gabnresponse_t ** structp)337 lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
338 lwres_lwpacket_t *pkt, lwres_gabnresponse_t **structp)
339 {
340 lwres_result_t ret;
341 unsigned int x;
342 lwres_uint32_t flags;
343 lwres_uint16_t naliases;
344 lwres_uint16_t naddrs;
345 lwres_gabnresponse_t *gabn;
346 lwres_addrlist_t addrlist;
347 lwres_addr_t *addr;
348
349 REQUIRE(ctx != NULL);
350 REQUIRE(pkt != NULL);
351 REQUIRE(b != NULL);
352 REQUIRE(structp != NULL && *structp == NULL);
353
354 gabn = NULL;
355
356 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
357 return (LWRES_R_FAILURE);
358
359 /*
360 * Pull off the name itself
361 */
362 if (!SPACE_REMAINING(b, 4 + 2 + 2))
363 return (LWRES_R_UNEXPECTEDEND);
364 flags = lwres_buffer_getuint32(b);
365 naliases = lwres_buffer_getuint16(b);
366 naddrs = lwres_buffer_getuint16(b);
367
368 gabn = CTXMALLOC(sizeof(lwres_gabnresponse_t));
369 if (gabn == NULL)
370 return (LWRES_R_NOMEMORY);
371 gabn->aliases = NULL;
372 gabn->aliaslen = NULL;
373 LWRES_LIST_INIT(gabn->addrs);
374 gabn->base = NULL;
375
376 gabn->flags = flags;
377 gabn->naliases = naliases;
378 gabn->naddrs = naddrs;
379
380 LWRES_LIST_INIT(addrlist);
381
382 if (naliases > 0) {
383 gabn->aliases = CTXMALLOC(sizeof(char *) * naliases);
384 if (gabn->aliases == NULL) {
385 ret = LWRES_R_NOMEMORY;
386 goto out;
387 }
388
389 gabn->aliaslen = CTXMALLOC(sizeof(lwres_uint16_t) * naliases);
390 if (gabn->aliaslen == NULL) {
391 ret = LWRES_R_NOMEMORY;
392 goto out;
393 }
394 }
395
396 for (x = 0; x < naddrs; x++) {
397 addr = CTXMALLOC(sizeof(lwres_addr_t));
398 if (addr == NULL) {
399 ret = LWRES_R_NOMEMORY;
400 goto out;
401 }
402 LWRES_LINK_INIT(addr, link);
403 LWRES_LIST_APPEND(addrlist, addr, link);
404 }
405
406 /*
407 * Now, pull off the real name.
408 */
409 ret = lwres_string_parse(b, &gabn->realname, &gabn->realnamelen);
410 if (ret != LWRES_R_SUCCESS)
411 goto out;
412
413 /*
414 * Parse off the aliases.
415 */
416 for (x = 0; x < gabn->naliases; x++) {
417 ret = lwres_string_parse(b, &gabn->aliases[x],
418 &gabn->aliaslen[x]);
419 if (ret != LWRES_R_SUCCESS)
420 goto out;
421 }
422
423 /*
424 * Pull off the addresses. We already strung the linked list
425 * up above.
426 */
427 addr = LWRES_LIST_HEAD(addrlist);
428 for (x = 0; x < gabn->naddrs; x++) {
429 INSIST(addr != NULL);
430 ret = lwres_addr_parse(b, addr);
431 if (ret != LWRES_R_SUCCESS)
432 goto out;
433 addr = LWRES_LIST_NEXT(addr, link);
434 }
435
436 if (LWRES_BUFFER_REMAINING(b) != 0) {
437 ret = LWRES_R_TRAILINGDATA;
438 goto out;
439 }
440
441 gabn->addrs = addrlist;
442
443 *structp = gabn;
444 return (LWRES_R_SUCCESS);
445
446 out:
447 if (gabn != NULL) {
448 if (gabn->aliases != NULL)
449 CTXFREE(gabn->aliases, sizeof(char *) * naliases);
450 if (gabn->aliaslen != NULL)
451 CTXFREE(gabn->aliaslen,
452 sizeof(lwres_uint16_t) * naliases);
453 addr = LWRES_LIST_HEAD(addrlist);
454 while (addr != NULL) {
455 LWRES_LIST_UNLINK(addrlist, addr, link);
456 CTXFREE(addr, sizeof(lwres_addr_t));
457 addr = LWRES_LIST_HEAD(addrlist);
458 }
459 CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
460 }
461
462 return (ret);
463 }
464
465 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnrequest_t. */
466 void
lwres_gabnrequest_free(lwres_context_t * ctx,lwres_gabnrequest_t ** structp)467 lwres_gabnrequest_free(lwres_context_t *ctx, lwres_gabnrequest_t **structp)
468 {
469 lwres_gabnrequest_t *gabn;
470
471 REQUIRE(ctx != NULL);
472 REQUIRE(structp != NULL && *structp != NULL);
473
474 gabn = *structp;
475 *structp = NULL;
476
477 CTXFREE(gabn, sizeof(lwres_gabnrequest_t));
478 }
479
480 /*% Release the memory in resolver context ctx that was allocated to the lwres_gabnresponse_t. */
481 void
lwres_gabnresponse_free(lwres_context_t * ctx,lwres_gabnresponse_t ** structp)482 lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
483 {
484 lwres_gabnresponse_t *gabn;
485 lwres_addr_t *addr;
486
487 REQUIRE(ctx != NULL);
488 REQUIRE(structp != NULL && *structp != NULL);
489
490 gabn = *structp;
491 *structp = NULL;
492
493 if (gabn->naliases > 0) {
494 CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
495 CTXFREE(gabn->aliaslen,
496 sizeof(lwres_uint16_t) * gabn->naliases);
497 }
498 addr = LWRES_LIST_HEAD(gabn->addrs);
499 while (addr != NULL) {
500 LWRES_LIST_UNLINK(gabn->addrs, addr, link);
501 CTXFREE(addr, sizeof(lwres_addr_t));
502 addr = LWRES_LIST_HEAD(gabn->addrs);
503 }
504 if (gabn->base != NULL)
505 CTXFREE(gabn->base, gabn->baselen);
506 CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
507 }
508