lwresutil.c revision 135446
1/*
2 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and 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: lwresutil.c,v 1.29.206.1 2004/03/06 08:15:33 marka Exp $ */
19
20#include <config.h>
21
22#include <assert.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26
27#include <lwres/lwbuffer.h>
28#include <lwres/lwres.h>
29#include <lwres/result.h>
30
31#include "assert_p.h"
32#include "context_p.h"
33
34/*
35 * Requires:
36 *
37 *	The "current" pointer in "b" points to encoded raw data.
38 *
39 * Ensures:
40 *
41 *	The address of the first byte of the data is returned via "p",
42 *	and the length is returned via "len".  If NULL, they are not
43 *	set.
44 *
45 *	On return, the current pointer of "b" will point to the character
46 *	following the data length and the data.
47 *
48 */
49lwres_result_t
50lwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len)
51{
52	lwres_uint16_t datalen;
53	unsigned char *data;
54
55	REQUIRE(b != NULL);
56
57	/*
58	 * Pull off the length (2 bytes)
59	 */
60	if (!SPACE_REMAINING(b, 2))
61		return (LWRES_R_UNEXPECTEDEND);
62	datalen = lwres_buffer_getuint16(b);
63
64	/*
65	 * Set the pointer to this string to the right place, then
66	 * advance the buffer pointer.
67	 */
68	if (!SPACE_REMAINING(b, datalen))
69		return (LWRES_R_UNEXPECTEDEND);
70	data = b->base + b->current;
71	lwres_buffer_forward(b, datalen);
72
73	if (len != NULL)
74		*len = datalen;
75	if (p != NULL)
76		*p = data;
77
78	return (LWRES_R_SUCCESS);
79}
80
81/*
82 * Requires:
83 *
84 *	The "current" pointer in "b" point to an encoded string.
85 *
86 * Ensures:
87 *
88 *	The address of the first byte of the string is returned via "c",
89 *	and the length is returned via "len".  If NULL, they are not
90 *	set.
91 *
92 *	On return, the current pointer of "b" will point to the character
93 *	following the string length, the string, and the trailing NULL.
94 *
95 */
96lwres_result_t
97lwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len)
98{
99	lwres_uint16_t datalen;
100	char *string;
101
102	REQUIRE(b != NULL);
103
104	/*
105	 * Pull off the length (2 bytes)
106	 */
107	if (!SPACE_REMAINING(b, 2))
108		return (LWRES_R_UNEXPECTEDEND);
109	datalen = lwres_buffer_getuint16(b);
110
111	/*
112	 * Set the pointer to this string to the right place, then
113	 * advance the buffer pointer.
114	 */
115	if (!SPACE_REMAINING(b, datalen))
116		return (LWRES_R_UNEXPECTEDEND);
117	string = (char *)b->base + b->current;
118	lwres_buffer_forward(b, datalen);
119
120	/*
121	 * Skip the "must be zero" byte.
122	 */
123	if (!SPACE_REMAINING(b, 1))
124		return (LWRES_R_UNEXPECTEDEND);
125	if (0 != lwres_buffer_getuint8(b))
126		return (LWRES_R_FAILURE);
127
128	if (len != NULL)
129		*len = datalen;
130	if (c != NULL)
131		*c = string;
132
133	return (LWRES_R_SUCCESS);
134}
135
136lwres_result_t
137lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
138{
139	REQUIRE(addr != NULL);
140
141	if (!SPACE_REMAINING(b, 6))
142		return (LWRES_R_UNEXPECTEDEND);
143
144	addr->family = lwres_buffer_getuint32(b);
145	addr->length = lwres_buffer_getuint16(b);
146
147	if (!SPACE_REMAINING(b, addr->length))
148		return (LWRES_R_UNEXPECTEDEND);
149	if (addr->length > LWRES_ADDR_MAXLEN)
150		return (LWRES_R_FAILURE);
151
152	lwres_buffer_getmem(b, addr->address, addr->length);
153
154	return (LWRES_R_SUCCESS);
155}
156
157lwres_result_t
158lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
159		     lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp)
160{
161	lwres_gabnrequest_t request;
162	lwres_gabnresponse_t *response;
163	int ret;
164	int recvlen;
165	lwres_buffer_t b_in, b_out;
166	lwres_lwpacket_t pkt;
167	lwres_uint32_t serial;
168	char *buffer;
169	char target_name[1024];
170	unsigned int target_length;
171
172	REQUIRE(ctx != NULL);
173	REQUIRE(name != NULL);
174	REQUIRE(addrtypes != 0);
175	REQUIRE(structp != NULL && *structp == NULL);
176
177	b_in.base = NULL;
178	b_out.base = NULL;
179	response = NULL;
180	buffer = NULL;
181	serial = lwres_context_nextserial(ctx);
182
183	buffer = CTXMALLOC(LWRES_RECVLENGTH);
184	if (buffer == NULL) {
185		ret = LWRES_R_NOMEMORY;
186		goto out;
187	}
188
189	target_length = strlen(name);
190	if (target_length >= sizeof(target_name))
191		return (LWRES_R_FAILURE);
192	strcpy(target_name, name); /* strcpy is safe */
193
194	/*
195	 * Set up our request and render it to a buffer.
196	 */
197	request.flags = 0;
198	request.addrtypes = addrtypes;
199	request.name = target_name;
200	request.namelen = target_length;
201	pkt.pktflags = 0;
202	pkt.serial = serial;
203	pkt.result = 0;
204	pkt.recvlength = LWRES_RECVLENGTH;
205
206 again:
207	ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);
208	if (ret != LWRES_R_SUCCESS)
209		goto out;
210
211	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
212				     LWRES_RECVLENGTH, &recvlen);
213	if (ret != LWRES_R_SUCCESS)
214		goto out;
215
216	lwres_buffer_init(&b_in, buffer, recvlen);
217	b_in.used = recvlen;
218
219	/*
220	 * Parse the packet header.
221	 */
222	ret = lwres_lwpacket_parseheader(&b_in, &pkt);
223	if (ret != LWRES_R_SUCCESS)
224		goto out;
225
226	/*
227	 * Sanity check.
228	 */
229	if (pkt.serial != serial)
230		goto again;
231	if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)
232		goto again;
233
234	/*
235	 * Free what we've transmitted
236	 */
237	CTXFREE(b_out.base, b_out.length);
238	b_out.base = NULL;
239	b_out.length = 0;
240
241	if (pkt.result != LWRES_R_SUCCESS) {
242		ret = pkt.result;
243		goto out;
244	}
245
246	/*
247	 * Parse the response.
248	 */
249	ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);
250	if (ret != LWRES_R_SUCCESS)
251		goto out;
252	response->base = buffer;
253	response->baselen = LWRES_RECVLENGTH;
254	buffer = NULL; /* don't free this below */
255
256	*structp = response;
257	return (LWRES_R_SUCCESS);
258
259 out:
260	if (b_out.base != NULL)
261		CTXFREE(b_out.base, b_out.length);
262	if (buffer != NULL)
263		CTXFREE(buffer, LWRES_RECVLENGTH);
264	if (response != NULL)
265		lwres_gabnresponse_free(ctx, &response);
266
267	return (ret);
268}
269
270
271lwres_result_t
272lwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,
273		    lwres_uint16_t addrlen, const unsigned char *addr,
274		    lwres_gnbaresponse_t **structp)
275{
276	lwres_gnbarequest_t request;
277	lwres_gnbaresponse_t *response;
278	int ret;
279	int recvlen;
280	lwres_buffer_t b_in, b_out;
281	lwres_lwpacket_t pkt;
282	lwres_uint32_t serial;
283	char *buffer;
284
285	REQUIRE(ctx != NULL);
286	REQUIRE(addrtype != 0);
287	REQUIRE(addrlen != 0);
288	REQUIRE(addr != NULL);
289	REQUIRE(structp != NULL && *structp == NULL);
290
291	b_in.base = NULL;
292	b_out.base = NULL;
293	response = NULL;
294	buffer = NULL;
295	serial = lwres_context_nextserial(ctx);
296
297	buffer = CTXMALLOC(LWRES_RECVLENGTH);
298	if (buffer == NULL) {
299		ret = LWRES_R_NOMEMORY;
300		goto out;
301	}
302
303	/*
304	 * Set up our request and render it to a buffer.
305	 */
306	request.flags = 0;
307	request.addr.family = addrtype;
308	request.addr.length = addrlen;
309	memcpy(request.addr.address, addr, addrlen);
310	pkt.pktflags = 0;
311	pkt.serial = serial;
312	pkt.result = 0;
313	pkt.recvlength = LWRES_RECVLENGTH;
314
315 again:
316	ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);
317	if (ret != LWRES_R_SUCCESS)
318		goto out;
319
320	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
321				     LWRES_RECVLENGTH, &recvlen);
322	if (ret != LWRES_R_SUCCESS)
323		goto out;
324
325	lwres_buffer_init(&b_in, buffer, recvlen);
326	b_in.used = recvlen;
327
328	/*
329	 * Parse the packet header.
330	 */
331	ret = lwres_lwpacket_parseheader(&b_in, &pkt);
332	if (ret != LWRES_R_SUCCESS)
333		goto out;
334
335	/*
336	 * Sanity check.
337	 */
338	if (pkt.serial != serial)
339		goto again;
340	if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)
341		goto again;
342
343	/*
344	 * Free what we've transmitted
345	 */
346	CTXFREE(b_out.base, b_out.length);
347	b_out.base = NULL;
348	b_out.length = 0;
349
350	if (pkt.result != LWRES_R_SUCCESS) {
351		ret = pkt.result;
352		goto out;
353	}
354
355	/*
356	 * Parse the response.
357	 */
358	ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);
359	if (ret != LWRES_R_SUCCESS)
360		goto out;
361	response->base = buffer;
362	response->baselen = LWRES_RECVLENGTH;
363	buffer = NULL; /* don't free this below */
364
365	*structp = response;
366	return (LWRES_R_SUCCESS);
367
368 out:
369	if (b_out.base != NULL)
370		CTXFREE(b_out.base, b_out.length);
371	if (buffer != NULL)
372		CTXFREE(buffer, LWRES_RECVLENGTH);
373	if (response != NULL)
374		lwres_gnbaresponse_free(ctx, &response);
375
376	return (ret);
377}
378
379lwres_result_t
380lwres_getrdatabyname(lwres_context_t *ctx, const char *name,
381		     lwres_uint16_t rdclass, lwres_uint16_t rdtype,
382		     lwres_uint32_t flags, lwres_grbnresponse_t **structp)
383{
384	int ret;
385	int recvlen;
386	lwres_buffer_t b_in, b_out;
387	lwres_lwpacket_t pkt;
388	lwres_uint32_t serial;
389	char *buffer;
390	lwres_grbnrequest_t request;
391	lwres_grbnresponse_t *response;
392	char target_name[1024];
393	unsigned int target_length;
394
395	REQUIRE(ctx != NULL);
396	REQUIRE(name != NULL);
397	REQUIRE(structp != NULL && *structp == NULL);
398
399	b_in.base = NULL;
400	b_out.base = NULL;
401	response = NULL;
402	buffer = NULL;
403	serial = lwres_context_nextserial(ctx);
404
405	buffer = CTXMALLOC(LWRES_RECVLENGTH);
406	if (buffer == NULL) {
407		ret = LWRES_R_NOMEMORY;
408		goto out;
409	}
410
411	target_length = strlen(name);
412	if (target_length >= sizeof(target_name))
413		return (LWRES_R_FAILURE);
414	strcpy(target_name, name); /* strcpy is safe */
415
416	/*
417	 * Set up our request and render it to a buffer.
418	 */
419	request.rdclass = rdclass;
420	request.rdtype = rdtype;
421	request.flags = flags;
422	request.name = target_name;
423	request.namelen = target_length;
424	pkt.pktflags = 0;
425	pkt.serial = serial;
426	pkt.result = 0;
427	pkt.recvlength = LWRES_RECVLENGTH;
428
429 again:
430	ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);
431	if (ret != LWRES_R_SUCCESS)
432		goto out;
433
434	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,
435				     LWRES_RECVLENGTH, &recvlen);
436	if (ret != LWRES_R_SUCCESS)
437		goto out;
438
439	lwres_buffer_init(&b_in, buffer, recvlen);
440	b_in.used = recvlen;
441
442	/*
443	 * Parse the packet header.
444	 */
445	ret = lwres_lwpacket_parseheader(&b_in, &pkt);
446	if (ret != LWRES_R_SUCCESS)
447		goto out;
448
449	/*
450	 * Sanity check.
451	 */
452	if (pkt.serial != serial)
453		goto again;
454	if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)
455		goto again;
456
457	/*
458	 * Free what we've transmitted
459	 */
460	CTXFREE(b_out.base, b_out.length);
461	b_out.base = NULL;
462	b_out.length = 0;
463
464	if (pkt.result != LWRES_R_SUCCESS) {
465		ret = pkt.result;
466		goto out;
467	}
468
469	/*
470	 * Parse the response.
471	 */
472	ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);
473	if (ret != LWRES_R_SUCCESS)
474		goto out;
475	response->base = buffer;
476	response->baselen = LWRES_RECVLENGTH;
477	buffer = NULL; /* don't free this below */
478
479	*structp = response;
480	return (LWRES_R_SUCCESS);
481
482 out:
483	if (b_out.base != NULL)
484		CTXFREE(b_out.base, b_out.length);
485	if (buffer != NULL)
486		CTXFREE(buffer, LWRES_RECVLENGTH);
487	if (response != NULL)
488		lwres_grbnresponse_free(ctx, &response);
489
490	return (ret);
491}
492