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