1/*
2 * Copyright (C) 2004, 2005, 2007, 2013  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001  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_grbn.c,v 1.10 2007/06/19 23:47:22 tbox Exp $ */
19
20/*! \file lwres_grbn.c
21
22 */
23
24#include <config.h>
25
26#include <assert.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include <lwres/lwbuffer.h>
31#include <lwres/lwpacket.h>
32#include <lwres/lwres.h>
33#include <lwres/result.h>
34
35#include "context_p.h"
36#include "assert_p.h"
37
38/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
39lwres_result_t
40lwres_grbnrequest_render(lwres_context_t *ctx, lwres_grbnrequest_t *req,
41			 lwres_lwpacket_t *pkt, lwres_buffer_t *b)
42{
43	unsigned char *buf;
44	size_t buflen;
45	int ret;
46	size_t payload_length;
47	lwres_uint16_t datalen;
48
49	REQUIRE(ctx != NULL);
50	REQUIRE(req != NULL);
51	REQUIRE(req->name != NULL);
52	REQUIRE(pkt != NULL);
53	REQUIRE(b != NULL);
54
55	datalen = strlen(req->name);
56
57	payload_length = 4 + 2 + 2 + 2 + req->namelen + 1;
58
59	buflen = LWRES_LWPACKET_LENGTH + payload_length;
60	buf = CTXMALLOC(buflen);
61	if (buf == NULL)
62		return (LWRES_R_NOMEMORY);
63
64	lwres_buffer_init(b, buf, (unsigned int)buflen);
65
66	pkt->length = (lwres_uint32_t)buflen;
67	pkt->version = LWRES_LWPACKETVERSION_0;
68	pkt->pktflags &= ~LWRES_LWPACKETFLAG_RESPONSE;
69	pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
70	pkt->result = 0;
71	pkt->authtype = 0;
72	pkt->authlength = 0;
73
74	ret = lwres_lwpacket_renderheader(b, pkt);
75	if (ret != LWRES_R_SUCCESS) {
76		lwres_buffer_invalidate(b);
77		CTXFREE(buf, buflen);
78		return (ret);
79	}
80
81	INSIST(SPACE_OK(b, payload_length));
82
83	/*
84	 * Flags.
85	 */
86	lwres_buffer_putuint32(b, req->flags);
87
88	/*
89	 * Class.
90	 */
91	lwres_buffer_putuint16(b, req->rdclass);
92
93	/*
94	 * Type.
95	 */
96	lwres_buffer_putuint16(b, req->rdtype);
97
98	/*
99	 * Put the length and the data.  We know this will fit because we
100	 * just checked for it.
101	 */
102	lwres_buffer_putuint16(b, datalen);
103	lwres_buffer_putmem(b, (unsigned char *)req->name, datalen);
104	lwres_buffer_putuint8(b, 0); /* trailing NUL */
105
106	INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
107
108	return (LWRES_R_SUCCESS);
109}
110
111/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
112lwres_result_t
113lwres_grbnresponse_render(lwres_context_t *ctx, lwres_grbnresponse_t *req,
114			  lwres_lwpacket_t *pkt, lwres_buffer_t *b)
115{
116	unsigned char *buf;
117	size_t buflen;
118	int ret;
119	size_t payload_length;
120	lwres_uint16_t datalen;
121	int x;
122
123	REQUIRE(ctx != NULL);
124	REQUIRE(req != NULL);
125	REQUIRE(pkt != NULL);
126	REQUIRE(b != NULL);
127
128	/* flags, class, type, ttl, nrdatas, nsigs */
129	payload_length = 4 + 2 + 2 + 4 + 2 + 2;
130	/* real name encoding */
131	payload_length += 2 + req->realnamelen + 1;
132	/* each rr */
133	for (x = 0; x < req->nrdatas; x++)
134		payload_length += 2 + req->rdatalen[x];
135	for (x = 0; x < req->nsigs; x++)
136		payload_length += 2 + req->siglen[x];
137
138	buflen = LWRES_LWPACKET_LENGTH + payload_length;
139	buf = CTXMALLOC(buflen);
140	if (buf == NULL)
141		return (LWRES_R_NOMEMORY);
142	lwres_buffer_init(b, buf, (unsigned int)buflen);
143
144	pkt->length = (lwres_uint32_t)buflen;
145	pkt->version = LWRES_LWPACKETVERSION_0;
146	pkt->pktflags |= LWRES_LWPACKETFLAG_RESPONSE;
147	pkt->opcode = LWRES_OPCODE_GETRDATABYNAME;
148	pkt->authtype = 0;
149	pkt->authlength = 0;
150
151	ret = lwres_lwpacket_renderheader(b, pkt);
152	if (ret != LWRES_R_SUCCESS) {
153		lwres_buffer_invalidate(b);
154		CTXFREE(buf, buflen);
155		return (ret);
156	}
157
158	/*
159	 * Check space needed here.
160	 */
161	INSIST(SPACE_OK(b, payload_length));
162
163	/* Flags. */
164	lwres_buffer_putuint32(b, req->flags);
165
166	/* encode class, type, ttl, and nrdatas */
167	lwres_buffer_putuint16(b, req->rdclass);
168	lwres_buffer_putuint16(b, req->rdtype);
169	lwres_buffer_putuint32(b, req->ttl);
170	lwres_buffer_putuint16(b, req->nrdatas);
171	lwres_buffer_putuint16(b, req->nsigs);
172
173	/* encode the real name */
174	datalen = req->realnamelen;
175	lwres_buffer_putuint16(b, datalen);
176	lwres_buffer_putmem(b, (unsigned char *)req->realname, datalen);
177	lwres_buffer_putuint8(b, 0);
178
179	/* encode the rdatas */
180	for (x = 0; x < req->nrdatas; x++) {
181		datalen = req->rdatalen[x];
182		lwres_buffer_putuint16(b, datalen);
183		lwres_buffer_putmem(b, req->rdatas[x], datalen);
184	}
185
186	/* encode the signatures */
187	for (x = 0; x < req->nsigs; x++) {
188		datalen = req->siglen[x];
189		lwres_buffer_putuint16(b, datalen);
190		lwres_buffer_putmem(b, req->sigs[x], datalen);
191	}
192
193	INSIST(LWRES_BUFFER_AVAILABLECOUNT(b) == 0);
194	INSIST(LWRES_BUFFER_USEDCOUNT(b) == pkt->length);
195
196	return (LWRES_R_SUCCESS);
197}
198
199/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
200lwres_result_t
201lwres_grbnrequest_parse(lwres_context_t *ctx, lwres_buffer_t *b,
202			lwres_lwpacket_t *pkt, lwres_grbnrequest_t **structp)
203{
204	int ret;
205	char *name;
206	lwres_grbnrequest_t *grbn;
207	lwres_uint32_t flags;
208	lwres_uint16_t rdclass, rdtype;
209	lwres_uint16_t namelen;
210
211	REQUIRE(ctx != NULL);
212	REQUIRE(pkt != NULL);
213	REQUIRE(b != NULL);
214	REQUIRE(structp != NULL && *structp == NULL);
215
216	if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) != 0)
217		return (LWRES_R_FAILURE);
218
219	if (!SPACE_REMAINING(b, 4 + 2 + 2))
220		return (LWRES_R_UNEXPECTEDEND);
221
222	/*
223	 * Pull off the flags, class, and type.
224	 */
225	flags = lwres_buffer_getuint32(b);
226	rdclass = lwres_buffer_getuint16(b);
227	rdtype = lwres_buffer_getuint16(b);
228
229	/*
230	 * Pull off the name itself
231	 */
232	ret = lwres_string_parse(b, &name, &namelen);
233	if (ret != LWRES_R_SUCCESS)
234		return (ret);
235
236	if (LWRES_BUFFER_REMAINING(b) != 0)
237		return (LWRES_R_TRAILINGDATA);
238
239	grbn = CTXMALLOC(sizeof(lwres_grbnrequest_t));
240	if (grbn == NULL)
241		return (LWRES_R_NOMEMORY);
242
243	grbn->flags = flags;
244	grbn->rdclass = rdclass;
245	grbn->rdtype = rdtype;
246	grbn->name = name;
247	grbn->namelen = namelen;
248
249	*structp = grbn;
250	return (LWRES_R_SUCCESS);
251}
252
253/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
254lwres_result_t
255lwres_grbnresponse_parse(lwres_context_t *ctx, lwres_buffer_t *b,
256			lwres_lwpacket_t *pkt, lwres_grbnresponse_t **structp)
257{
258	lwres_result_t ret;
259	unsigned int x;
260	lwres_uint32_t flags;
261	lwres_uint16_t rdclass, rdtype;
262	lwres_uint32_t ttl;
263	lwres_uint16_t nrdatas, nsigs;
264	lwres_grbnresponse_t *grbn;
265
266	REQUIRE(ctx != NULL);
267	REQUIRE(pkt != NULL);
268	REQUIRE(b != NULL);
269	REQUIRE(structp != NULL && *structp == NULL);
270
271	grbn = NULL;
272
273	if ((pkt->pktflags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
274		return (LWRES_R_FAILURE);
275
276	/*
277	 * Pull off the flags, class, type, ttl, nrdatas, and nsigs
278	 */
279	if (!SPACE_REMAINING(b, 4 + 2 + 2 + 4 + 2 + 2))
280		return (LWRES_R_UNEXPECTEDEND);
281	flags = lwres_buffer_getuint32(b);
282	rdclass = lwres_buffer_getuint16(b);
283	rdtype = lwres_buffer_getuint16(b);
284	ttl = lwres_buffer_getuint32(b);
285	nrdatas = lwres_buffer_getuint16(b);
286	nsigs = lwres_buffer_getuint16(b);
287
288	/*
289	 * Pull off the name itself
290	 */
291
292	grbn = CTXMALLOC(sizeof(lwres_grbnresponse_t));
293	if (grbn == NULL)
294		return (LWRES_R_NOMEMORY);
295	grbn->rdatas = NULL;
296	grbn->rdatalen = NULL;
297	grbn->sigs = NULL;
298	grbn->siglen = NULL;
299	grbn->base = NULL;
300
301	grbn->flags = flags;
302	grbn->rdclass = rdclass;
303	grbn->rdtype = rdtype;
304	grbn->ttl = ttl;
305	grbn->nrdatas = nrdatas;
306	grbn->nsigs = nsigs;
307
308	if (nrdatas > 0) {
309		grbn->rdatas = CTXMALLOC(sizeof(char *) * nrdatas);
310		if (grbn->rdatas == NULL) {
311			ret = LWRES_R_NOMEMORY;
312			goto out;
313		}
314
315		grbn->rdatalen = CTXMALLOC(sizeof(lwres_uint16_t) * nrdatas);
316		if (grbn->rdatalen == NULL) {
317			ret = LWRES_R_NOMEMORY;
318			goto out;
319		}
320	}
321
322	if (nsigs > 0) {
323		grbn->sigs = CTXMALLOC(sizeof(char *) * nsigs);
324		if (grbn->sigs == NULL) {
325			ret = LWRES_R_NOMEMORY;
326			goto out;
327		}
328
329		grbn->siglen = CTXMALLOC(sizeof(lwres_uint16_t) * nsigs);
330		if (grbn->siglen == NULL) {
331			ret = LWRES_R_NOMEMORY;
332			goto out;
333		}
334	}
335
336	/*
337	 * Now, pull off the real name.
338	 */
339	ret = lwres_string_parse(b, &grbn->realname, &grbn->realnamelen);
340	if (ret != LWRES_R_SUCCESS)
341		goto out;
342
343	/*
344	 * Parse off the rdatas.
345	 */
346	for (x = 0; x < grbn->nrdatas; x++) {
347		ret = lwres_data_parse(b, &grbn->rdatas[x],
348					 &grbn->rdatalen[x]);
349		if (ret != LWRES_R_SUCCESS)
350			goto out;
351	}
352
353	/*
354	 * Parse off the signatures.
355	 */
356	for (x = 0; x < grbn->nsigs; x++) {
357		ret = lwres_data_parse(b, &grbn->sigs[x], &grbn->siglen[x]);
358		if (ret != LWRES_R_SUCCESS)
359			goto out;
360	}
361
362	if (LWRES_BUFFER_REMAINING(b) != 0) {
363		ret = LWRES_R_TRAILINGDATA;
364		goto out;
365	}
366
367	*structp = grbn;
368	return (LWRES_R_SUCCESS);
369
370 out:
371	if (grbn != NULL) {
372		if (grbn->rdatas != NULL)
373			CTXFREE(grbn->rdatas, sizeof(char *) * nrdatas);
374		if (grbn->rdatalen != NULL)
375			CTXFREE(grbn->rdatalen,
376				sizeof(lwres_uint16_t) * nrdatas);
377		if (grbn->sigs != NULL)
378			CTXFREE(grbn->sigs, sizeof(char *) * nsigs);
379		if (grbn->siglen != NULL)
380			CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * nsigs);
381		CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
382	}
383
384	return (ret);
385}
386
387/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
388void
389lwres_grbnrequest_free(lwres_context_t *ctx, lwres_grbnrequest_t **structp)
390{
391	lwres_grbnrequest_t *grbn;
392
393	REQUIRE(ctx != NULL);
394	REQUIRE(structp != NULL && *structp != NULL);
395
396	grbn = *structp;
397	*structp = NULL;
398
399	CTXFREE(grbn, sizeof(lwres_grbnrequest_t));
400}
401
402/*% Thread-save equivalent to \link lwres_gabn.c lwres_gabn* \endlink routines. */
403void
404lwres_grbnresponse_free(lwres_context_t *ctx, lwres_grbnresponse_t **structp)
405{
406	lwres_grbnresponse_t *grbn;
407
408	REQUIRE(ctx != NULL);
409	REQUIRE(structp != NULL && *structp != NULL);
410
411	grbn = *structp;
412	*structp = NULL;
413
414	if (grbn->nrdatas > 0) {
415		CTXFREE(grbn->rdatas, sizeof(char *) * grbn->nrdatas);
416		CTXFREE(grbn->rdatalen,
417			sizeof(lwres_uint16_t) * grbn->nrdatas);
418	}
419	if (grbn->nsigs > 0) {
420		CTXFREE(grbn->sigs, sizeof(char *) * grbn->nsigs);
421		CTXFREE(grbn->siglen, sizeof(lwres_uint16_t) * grbn->nsigs);
422	}
423	if (grbn->base != NULL)
424		CTXFREE(grbn->base, grbn->baselen);
425	CTXFREE(grbn, sizeof(lwres_grbnresponse_t));
426}
427