1/*
2 * Copyright (C) 2004, 2005, 2007  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
40typedef struct {
41        lwres_uint32_t  flags;
42        lwres_addr_t    addr;
43} lwres_gnbarequest_t;
44
45typedef 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
70semantics 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. */
116lwres_result_t
117lwres_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, buflen);
139
140	pkt->length = 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. */
173lwres_result_t
174lwres_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, buflen);
203
204	pkt->length = 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. */
245lwres_result_t
246lwres_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
290lwres_result_t
291lwres_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. */
381void
382lwres_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. */
396void
397lwres_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