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_gnba.c
13 These are low-level routines for creating and parsing lightweight
14 resolver address-to-name lookup request and response messages.
15
16 There are four main functions for the getnamebyaddr opcode. One
17 render function converts a getnamebyaddr request structure --
18 lwres_gnbarequest_t -- to the lightweight resolver's canonical
19 format. It is complemented by a parse function that converts a
20 packet in this canonical format to a getnamebyaddr request
21 structure. Another render function converts the getnamebyaddr
22 response structure -- lwres_gnbaresponse_t to the canonical format.
23 This is complemented by a parse function which converts a packet in
24 canonical format to a getnamebyaddr response structure.
25
26 These structures are defined in \link lwres.h <lwres/lwres.h.>\endlink They are shown
27 below.
28
29 \code
30 #define LWRES_OPCODE_GETNAMEBYADDR 0x00010002U
31
32 typedef struct {
33 uint32_t flags;
34 lwres_addr_t addr;
35 } lwres_gnbarequest_t;
36
37 typedef struct {
38 uint32_t flags;
39 uint16_t naliases;
40 char *realname;
41 char **aliases;
42 uint16_t realnamelen;
43 uint16_t *aliaslen;
44 void *base;
45 size_t baselen;
46 } lwres_gnbaresponse_t;
47 \endcode
48
49 lwres_gnbarequest_render() uses resolver context ctx to convert
50 getnamebyaddr request structure req to canonical format. The packet
51 header structure pkt is initialised and transferred to buffer b.
52 The contents of *req are then appended to the buffer in canonical
53 format. lwres_gnbaresponse_render() performs the same task, except
54 it converts a getnamebyaddr response structure lwres_gnbaresponse_t
55 to the lightweight resolver's canonical format.
56
57 lwres_gnbarequest_parse() uses context ctx to convert the contents
58 of packet pkt to a lwres_gnbarequest_t structure. Buffer b provides
59 space to be used for storing this structure. When the function
60 succeeds, the resulting lwres_gnbarequest_t is made available
61 through *structp. lwres_gnbaresponse_parse() offers the same
62 semantics as lwres_gnbarequest_parse() except it yields a
63 lwres_gnbaresponse_t structure.
64
65 lwres_gnbaresponse_free() and lwres_gnbarequest_free() release the
66 memory in resolver context ctx that was allocated to the
67 lwres_gnbaresponse_t or lwres_gnbarequest_t structures referenced
68 via structp. Any memory associated with ancillary buffers and
69 strings for those structures is also discarded.
70
71 \section lwres_gbna_return Return Values
72
73 The getnamebyaddr opcode functions lwres_gnbarequest_render(),
74 lwres_gnbaresponse_render() lwres_gnbarequest_parse() and
75 lwres_gnbaresponse_parse() all return #LWRES_R_SUCCESS on success.
76 They return #LWRES_R_NOMEMORY if memory allocation fails.
77 #LWRES_R_UNEXPECTEDEND is returned if the available space in the
78 buffer b is too small to accommodate the packet header or the
79 lwres_gnbarequest_t and lwres_gnbaresponse_t structures.
80 lwres_gnbarequest_parse() and lwres_gnbaresponse_parse() will
81 return #LWRES_R_UNEXPECTEDEND if the buffer is not empty after
82 decoding the received packet. These functions will return
83 #LWRES_R_FAILURE if pktflags in the packet header structure
84 #lwres_lwpacket_t indicate that the packet is not a response to an
85 earlier query.
86
87 \section lwres_gbna_see See Also
88
89 \link lwpacket.c lwres_packet\endlink
90
91 */
92
93 #include <config.h>
94
95 #include <assert.h>
96 #include <inttypes.h>
97 #include <stdlib.h>
98 #include <string.h>
99
100 #include <lwres/lwbuffer.h>
101 #include <lwres/lwpacket.h>
102 #include <lwres/lwres.h>
103 #include <lwres/result.h>
104
105 #include "context_p.h"
106 #include "assert_p.h"
107
108 /*% Uses resolver context ctx to convert getnamebyaddr request structure req to canonical format. */
109 lwres_result_t
lwres_gnbarequest_render(lwres_context_t * ctx,lwres_gnbarequest_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)110 lwres_gnbarequest_render(lwres_context_t *ctx, lwres_gnbarequest_t *req,
111 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
112 {
113 unsigned char *buf;
114 size_t buflen;
115 int ret;
116 size_t payload_length;
117
118 REQUIRE(ctx != NULL);
119 REQUIRE(req != NULL);
120 REQUIRE(req->addr.family != 0);
121 REQUIRE(req->addr.length != 0);
122 REQUIRE(pkt != NULL);
123 REQUIRE(b != NULL);
124
125 payload_length = 4 + 4 + 2 + + req->addr.length;
126
127 buflen = LWRES_LWPACKET_LENGTH + payload_length;
128 buf = CTXMALLOC(buflen);
129 if (buf == NULL)
130 return (LWRES_R_NOMEMORY);
131 lwres_buffer_init(b, buf, (unsigned int)buflen);
132
133 pkt->length = (uint32_t)buflen;
134 pkt->version = LWRES_LWPACKETVERSION_0;
135 pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
136 pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
137 pkt->result = 0;
138 pkt->authtype = 0;
139 pkt->authlength = 0;
140
141 ret = lwres_lwpacket_renderheader(b, pkt);
142 if (ret != LWRES_R_SUCCESS) {
143 lwres_buffer_invalidate(b);
144 CTXFREE(buf, buflen);
145 return (ret);
146 }
147
148 INSIST(SPACE_OK(b, payload_length));
149
150 /*
151 * Put the length and the data. We know this will fit because we
152 * just checked for it.
153 */
154 lwres_buffer_putuint32(b, req->flags);
155 lwres_buffer_putuint32(b, req->addr.family);
156 lwres_buffer_putuint16(b, req->addr.length);
157 lwres_buffer_putmem(b, (unsigned char *)req->addr.address,
158 req->addr.length);
159
160 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
161
162 return (LWRES_R_SUCCESS);
163 }
164
165 /*% Converts a getnamebyaddr response structure lwres_gnbaresponse_t to the lightweight resolver's canonical format. */
166 lwres_result_t
lwres_gnbaresponse_render(lwres_context_t * ctx,lwres_gnbaresponse_t * req,lwres_lwpacket_t * pkt,lwres_buffer_t * b)167 lwres_gnbaresponse_render(lwres_context_t *ctx, lwres_gnbaresponse_t *req,
168 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
169 {
170 unsigned char *buf;
171 size_t buflen;
172 int ret;
173 size_t payload_length;
174 uint16_t datalen;
175 int x;
176
177 REQUIRE(ctx != NULL);
178 REQUIRE(req != NULL);
179 REQUIRE(pkt != NULL);
180 REQUIRE(b != NULL);
181
182 /*
183 * Calculate packet size.
184 */
185 payload_length = 4; /* flags */
186 payload_length += 2; /* naliases */
187 payload_length += 2 + req->realnamelen + 1; /* real name encoding */
188 for (x = 0; x < req->naliases; x++) /* each alias */
189 payload_length += 2 + req->aliaslen[x] + 1;
190
191 buflen = LWRES_LWPACKET_LENGTH + payload_length;
192 buf = CTXMALLOC(buflen);
193 if (buf == NULL)
194 return (LWRES_R_NOMEMORY);
195 lwres_buffer_init(b, buf, (unsigned int)buflen);
196
197 pkt->length = (uint32_t)buflen;
198 pkt->version = LWRES_LWPACKETVERSION_0;
199 pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
200 pkt->opcode = LWRES_OPCODE_GETNAMEBYADDR;
201 pkt->authtype = 0;
202 pkt->authlength = 0;
203
204 ret = lwres_lwpacket_renderheader(b, pkt);
205 if (ret != LWRES_R_SUCCESS) {
206 lwres_buffer_invalidate(b);
207 CTXFREE(buf, buflen);
208 return (ret);
209 }
210
211 INSIST(SPACE_OK(b, payload_length));
212 lwres_buffer_putuint32(b, req->flags);
213
214 /* encode naliases */
215 lwres_buffer_putuint16(b, req->naliases);
216
217 /* encode the real name */
218 datalen = req->realnamelen;
219 lwres_buffer_putuint16(b, datalen);
220 lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
221 lwres_buffer_putuint8(b, 0);
222
223 /* encode the aliases */
224 for (x = 0; x < req->naliases; x++) {
225 datalen = req->aliaslen[x];
226 lwres_buffer_putuint16(b, datalen);
227 lwres_buffer_putmem(b, (unsigned char *)req->aliases[x],
228 datalen);
229 lwres_buffer_putuint8(b, 0);
230 }
231
232 INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
233
234 return (LWRES_R_SUCCESS);
235 }
236
237 /*% Uses context ctx to convert the contents of packet pkt to a lwres_gnbarequest_t structure. */
238 lwres_result_t
lwres_gnbarequest_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gnbarequest_t ** structp)239 lwres_gnbarequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
240 lwres_lwpacket_t *pkt, lwres_gnbarequest_t **structp)
241 {
242 int ret;
243 lwres_gnbarequest_t *gnba;
244
245 REQUIRE(ctx != NULL);
246 REQUIRE(pkt != NULL);
247 REQUIRE(b != NULL);
248 REQUIRE(structp != NULL && *structp == NULL);
249
250 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
251 return (LWRES_R_FAILURE);
252
253 if (!SPACE_REMAINING(b, 4))
254 return (LWRES_R_UNEXPECTEDEND);
255
256 gnba = CTXMALLOC(sizeof(lwres_gnbarequest_t));
257 if (gnba == NULL)
258 return (LWRES_R_NOMEMORY);
259
260 gnba->flags = lwres_buffer_getuint32(b);
261
262 ret = lwres_addr_parse(b, &gnba->addr);
263 if (ret != LWRES_R_SUCCESS)
264 goto out;
265
266 if (LWRES_BUFFER_REMAINING(b) != 0) {
267 ret = LWRES_R_TRAILINGDATA;
268 goto out;
269 }
270
271 *structp = gnba;
272 return (LWRES_R_SUCCESS);
273
274 out:
275 if (gnba != NULL)
276 lwres_gnbarequest_free(ctx, &gnba);
277
278 return (ret);
279 }
280
281 /*% Offers the same semantics as lwres_gnbarequest_parse() except it yields a lwres_gnbaresponse_t structure. */
282
283 lwres_result_t
lwres_gnbaresponse_parse(lwres_context_t * ctx,lwres_buffer_t * b,lwres_lwpacket_t * pkt,lwres_gnbaresponse_t ** structp)284 lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
285 lwres_lwpacket_t *pkt, lwres_gnbaresponse_t **structp)
286 {
287 int ret;
288 unsigned int x;
289 uint32_t flags;
290 uint16_t naliases;
291 lwres_gnbaresponse_t *gnba;
292
293 REQUIRE(ctx != NULL);
294 REQUIRE(pkt != NULL);
295 REQUIRE(b != NULL);
296 REQUIRE(structp != NULL && *structp == NULL);
297
298 gnba = NULL;
299
300 if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
301 return (LWRES_R_FAILURE);
302
303 /*
304 * Pull off flags & naliases
305 */
306 if (!SPACE_REMAINING(b, 4 + 2))
307 return (LWRES_R_UNEXPECTEDEND);
308 flags = lwres_buffer_getuint32(b);
309 naliases = lwres_buffer_getuint16(b);
310
311 gnba = CTXMALLOC(sizeof(lwres_gnbaresponse_t));
312 if (gnba == NULL)
313 return (LWRES_R_NOMEMORY);
314 gnba->base = NULL;
315 gnba->aliases = NULL;
316 gnba->aliaslen = NULL;
317
318 gnba->flags = flags;
319 gnba->naliases = naliases;
320
321 if (naliases > 0) {
322 gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
323 if (gnba->aliases == NULL) {
324 ret = LWRES_R_NOMEMORY;
325 goto out;
326 }
327
328 gnba->aliaslen = CTXMALLOC(sizeof(uint16_t) * naliases);
329 if (gnba->aliaslen == NULL) {
330 ret = LWRES_R_NOMEMORY;
331 goto out;
332 }
333 }
334
335 /*
336 * Now, pull off the real name.
337 */
338 ret = lwres_string_parse(b, &gnba->realname, &gnba->realnamelen);
339 if (ret != LWRES_R_SUCCESS)
340 goto out;
341
342 /*
343 * Parse off the aliases.
344 */
345 for (x = 0; x < gnba->naliases; x++) {
346 ret = lwres_string_parse(b, &gnba->aliases[x],
347 &gnba->aliaslen[x]);
348 if (ret != LWRES_R_SUCCESS)
349 goto out;
350 }
351
352 if (LWRES_BUFFER_REMAINING(b) != 0) {
353 ret = LWRES_R_TRAILINGDATA;
354 goto out;
355 }
356
357 *structp = gnba;
358 return (LWRES_R_SUCCESS);
359
360 out:
361 if (gnba != NULL) {
362 if (gnba->aliases != NULL)
363 CTXFREE(gnba->aliases, sizeof(char *) * naliases);
364 if (gnba->aliaslen != NULL)
365 CTXFREE(gnba->aliaslen,
366 sizeof(uint16_t) * naliases);
367 CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
368 }
369
370 return (ret);
371 }
372
373 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbarequest_t. */
374 void
lwres_gnbarequest_free(lwres_context_t * ctx,lwres_gnbarequest_t ** structp)375 lwres_gnbarequest_free(lwres_context_t *ctx, lwres_gnbarequest_t **structp)
376 {
377 lwres_gnbarequest_t *gnba;
378
379 REQUIRE(ctx != NULL);
380 REQUIRE(structp != NULL && *structp != NULL);
381
382 gnba = *structp;
383 *structp = NULL;
384
385 CTXFREE(gnba, sizeof(lwres_gnbarequest_t));
386 }
387
388 /*% Release the memory in resolver context ctx that was allocated to the lwres_gnbaresponse_t. */
389 void
lwres_gnbaresponse_free(lwres_context_t * ctx,lwres_gnbaresponse_t ** structp)390 lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp)
391 {
392 lwres_gnbaresponse_t *gnba;
393
394 REQUIRE(ctx != NULL);
395 REQUIRE(structp != NULL && *structp != NULL);
396
397 gnba = *structp;
398 *structp = NULL;
399
400 if (gnba->naliases > 0) {
401 CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
402 CTXFREE(gnba->aliaslen,
403 sizeof(uint16_t) * gnba->naliases);
404 }
405 if (gnba->base != NULL)
406 CTXFREE(gnba->base, gnba->baselen);
407 CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
408 }
409