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