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