1/*	$NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $	*/
2
3/*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and 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
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/cdefs.h>
21#ifndef lint
22#ifdef notdef
23static const char rcsid[] = "Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp";
24#else
25//__RCSID("$NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $");
26#endif
27#endif
28
29/* Import. */
30
31#include "port_before.h"
32
33#include <sys/types.h>
34
35#include <netinet/in.h>
36#include <arpa/nameser.h>
37
38#include <assert.h>
39#include <errno.h>
40#include <resolv.h>
41#include <string.h>
42
43#include "port_after.h"
44
45/* Forward. */
46
47static void	setsection(ns_msg *msg, ns_sect sect);
48
49/* Macros. */
50
51#if !defined(SOLARIS2) || defined(__COVERITY__)
52#define RETERR(err) do { errno = (err); return (-1); } while (/*NOTREACHED*//*CONSTCOND*/0)
53#else
54#define RETERR(err) \
55	do { errno = (err); if (errno == errno) return (-1); } while (0)
56#endif
57
58#define PARSE_FMT_PRESO 0	/* Parse using presentation-format names */
59#define PARSE_FMT_WIRE 1	/* Parse using network-format names */
60
61/* Public. */
62
63/* These need to be in the same order as the nres.h:ns_flag enum. */
64struct _ns_flagdata _ns_flagdata[16] = {
65	{ 0x8000, 15 },		/*%< qr. */
66	{ 0x7800, 11 },		/*%< opcode. */
67	{ 0x0400, 10 },		/*%< aa. */
68	{ 0x0200, 9 },		/*%< tc. */
69	{ 0x0100, 8 },		/*%< rd. */
70	{ 0x0080, 7 },		/*%< ra. */
71	{ 0x0040, 6 },		/*%< z. */
72	{ 0x0020, 5 },		/*%< ad. */
73	{ 0x0010, 4 },		/*%< cd. */
74	{ 0x000f, 0 },		/*%< rcode. */
75	{ 0x0000, 0 },		/*%< expansion (1/6). */
76	{ 0x0000, 0 },		/*%< expansion (2/6). */
77	{ 0x0000, 0 },		/*%< expansion (3/6). */
78	{ 0x0000, 0 },		/*%< expansion (4/6). */
79	{ 0x0000, 0 },		/*%< expansion (5/6). */
80	{ 0x0000, 0 },		/*%< expansion (6/6). */
81};
82
83int ns_msg_getflag(ns_msg handle, int flag) {
84	return((u_int32_t)((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
85}
86
87int
88ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
89	const u_char *optr = ptr;
90
91	for (; count > 0; count--) {
92		int b, rdlength;
93
94		b = dn_skipname(ptr, eom);
95		if (b < 0)
96			RETERR(EMSGSIZE);
97		ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
98		if (section != ns_s_qd) {
99			if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
100				RETERR(EMSGSIZE);
101			ptr += NS_INT32SZ/*TTL*/;
102			NS_GET16(rdlength, ptr);
103			ptr += rdlength/*RData*/;
104		}
105	}
106	if (ptr > eom)
107		RETERR(EMSGSIZE);
108	assert(INT_MIN <= (ptr - optr) && (ptr - optr) <= INT_MAX);
109	return (int)(ptr - optr);
110}
111
112int
113ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
114	const u_char *eom = msg + msglen;
115	int i;
116
117	handle->_msg = msg;
118	handle->_eom = eom;
119	if (msg + NS_INT16SZ > eom)
120		RETERR(EMSGSIZE);
121	NS_GET16(handle->_id, msg);
122	if (msg + NS_INT16SZ > eom)
123		RETERR(EMSGSIZE);
124	NS_GET16(handle->_flags, msg);
125	for (i = 0; i < ns_s_max; i++) {
126		if (msg + NS_INT16SZ > eom)
127			RETERR(EMSGSIZE);
128		NS_GET16(handle->_counts[i], msg);
129	}
130	for (i = 0; i < ns_s_max; i++)
131		if (handle->_counts[i] == 0)
132			handle->_sections[i] = NULL;
133		else {
134			int b = ns_skiprr(msg, eom, (ns_sect)i,
135					  handle->_counts[i]);
136
137			if (b < 0)
138				return (-1);
139			handle->_sections[i] = msg;
140			msg += b;
141		}
142	if (msg != eom)
143		RETERR(EMSGSIZE);
144	setsection(handle, ns_s_max);
145	return (0);
146}
147
148int
149ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
150	int b;
151	int tmp;
152
153	/* Make section right. */
154	tmp = section;
155	if (tmp < 0 || section >= ns_s_max)
156		RETERR(ENODEV);
157	if (section != handle->_sect)
158		setsection(handle, section);
159
160	/* Make rrnum right. */
161	if (rrnum == -1)
162		rrnum = handle->_rrnum;
163	if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
164		RETERR(ENODEV);
165	if (rrnum < handle->_rrnum)
166		setsection(handle, section);
167	if (rrnum > handle->_rrnum) {
168		b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
169			      rrnum - handle->_rrnum);
170
171		if (b < 0)
172			return (-1);
173		handle->_msg_ptr += b;
174		handle->_rrnum = rrnum;
175	}
176
177	/* Do the parse. */
178	b = dn_expand(handle->_msg, handle->_eom,
179		      handle->_msg_ptr, rr->name, NS_MAXDNAME);
180	if (b < 0)
181		return (-1);
182	handle->_msg_ptr += b;
183	if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
184		RETERR(EMSGSIZE);
185	NS_GET16(rr->type, handle->_msg_ptr);
186	NS_GET16(rr->rr_class, handle->_msg_ptr);
187	if (section == ns_s_qd) {
188		rr->ttl = 0;
189		rr->rdlength = 0;
190		rr->rdata = NULL;
191	} else {
192		if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
193			RETERR(EMSGSIZE);
194		NS_GET32(rr->ttl, handle->_msg_ptr);
195		NS_GET16(rr->rdlength, handle->_msg_ptr);
196		if (handle->_msg_ptr + rr->rdlength > handle->_eom)
197			RETERR(EMSGSIZE);
198		rr->rdata = handle->_msg_ptr;
199		handle->_msg_ptr += rr->rdlength;
200	}
201	if (++handle->_rrnum > handle->_counts[(int)section])
202		setsection(handle, (ns_sect)((int)section + 1));
203
204	/* All done. */
205	return (0);
206}
207
208/*
209 * This is identical to the above but uses network-format (uncompressed) names.
210 */
211int
212ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
213	int b;
214	int tmp;
215
216	/* Make section right. */
217	tmp = section;
218	if (tmp < 0 || section >= ns_s_max)
219		RETERR(ENODEV);
220	if (section != handle->_sect)
221		setsection(handle, section);
222
223	/* Make rrnum right. */
224	if (rrnum == -1)
225		rrnum = handle->_rrnum;
226	if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
227		RETERR(ENODEV);
228	if (rrnum < handle->_rrnum)
229		setsection(handle, section);
230	if (rrnum > handle->_rrnum) {
231		b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
232			      rrnum - handle->_rrnum);
233
234		if (b < 0)
235			return (-1);
236		handle->_msg_ptr += b;
237		handle->_rrnum = rrnum;
238	}
239
240	/* Do the parse. */
241	b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
242			    rr->nname, NS_MAXNNAME, &rr->nnamel);
243	if (b < 0)
244		return (-1);
245	handle->_msg_ptr += b;
246	if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
247		RETERR(EMSGSIZE);
248	NS_GET16(rr->type, handle->_msg_ptr);
249	NS_GET16(rr->rr_class, handle->_msg_ptr);
250	if (section == ns_s_qd) {
251		rr->ttl = 0;
252		rr->rdlength = 0;
253		rr->rdata = NULL;
254	} else {
255		if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
256			RETERR(EMSGSIZE);
257		NS_GET32(rr->ttl, handle->_msg_ptr);
258		NS_GET16(rr->rdlength, handle->_msg_ptr);
259		if (handle->_msg_ptr + rr->rdlength > handle->_eom)
260			RETERR(EMSGSIZE);
261		rr->rdata = handle->_msg_ptr;
262		handle->_msg_ptr += rr->rdlength;
263	}
264	if (++handle->_rrnum > handle->_counts[(int)section])
265		setsection(handle, (ns_sect)((int)section + 1));
266
267	/* All done. */
268	return (0);
269}
270
271/* Private. */
272
273static void
274setsection(ns_msg *msg, ns_sect sect) {
275	msg->_sect = sect;
276	if (sect == ns_s_max) {
277		msg->_rrnum = -1;
278		msg->_msg_ptr = NULL;
279	} else {
280		msg->_rrnum = 0;
281		msg->_msg_ptr = msg->_sections[(int)sect];
282	}
283}
284
285/*! \file */
286