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