xref: /netbsd-src/lib/libc/nameser/ns_parse.c (revision c5e820cae412164fcbee52f470436200af5358ea)
1*c5e820caSchristos /*	$NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $	*/
20c789e32Schristos 
30c789e32Schristos /*
40c789e32Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
50c789e32Schristos  * Copyright (c) 1996,1999 by Internet Software Consortium.
60c789e32Schristos  *
70c789e32Schristos  * Permission to use, copy, modify, and distribute this software for any
80c789e32Schristos  * purpose with or without fee is hereby granted, provided that the above
90c789e32Schristos  * copyright notice and this permission notice appear in all copies.
100c789e32Schristos  *
110c789e32Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
120c789e32Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
130c789e32Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
140c789e32Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
150c789e32Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
160c789e32Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
170c789e32Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
180c789e32Schristos  */
190c789e32Schristos 
20fd00db40Schristos #include <sys/cdefs.h>
210c789e32Schristos #ifndef lint
22fd00db40Schristos #ifdef notdef
2359a755a4Schristos static const char rcsid[] = "Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp";
24fd00db40Schristos #else
25*c5e820caSchristos __RCSID("$NetBSD: ns_parse.c,v 1.9 2012/03/13 21:13:39 christos Exp $");
26fd00db40Schristos #endif
270c789e32Schristos #endif
280c789e32Schristos 
290c789e32Schristos /* Import. */
300c789e32Schristos 
310c789e32Schristos #include "port_before.h"
320c789e32Schristos 
330c789e32Schristos #include <sys/types.h>
340c789e32Schristos 
350c789e32Schristos #include <netinet/in.h>
360c789e32Schristos #include <arpa/nameser.h>
370c789e32Schristos 
38*c5e820caSchristos #include <assert.h>
390c789e32Schristos #include <errno.h>
400c789e32Schristos #include <resolv.h>
410c789e32Schristos #include <string.h>
420c789e32Schristos 
430c789e32Schristos #include "port_after.h"
440c789e32Schristos 
450c789e32Schristos /* Forward. */
460c789e32Schristos 
470c789e32Schristos static void	setsection(ns_msg *msg, ns_sect sect);
480c789e32Schristos 
490c789e32Schristos /* Macros. */
500c789e32Schristos 
513873655bSchristos #if !defined(SOLARIS2) || defined(__COVERITY__)
52fd00db40Schristos #define RETERR(err) do { errno = (err); return (-1); } while (/*NOTREACHED*//*CONSTCOND*/0)
53d73eb73dSchristos #else
54d73eb73dSchristos #define RETERR(err) \
55d73eb73dSchristos 	do { errno = (err); if (errno == errno) return (-1); } while (0)
56d73eb73dSchristos #endif
570c789e32Schristos 
5859a755a4Schristos #define PARSE_FMT_PRESO 0	/* Parse using presentation-format names */
5959a755a4Schristos #define PARSE_FMT_WIRE 1	/* Parse using network-format names */
6059a755a4Schristos 
610c789e32Schristos /* Public. */
620c789e32Schristos 
630c789e32Schristos /* These need to be in the same order as the nres.h:ns_flag enum. */
640c789e32Schristos struct _ns_flagdata _ns_flagdata[16] = {
65d73eb73dSchristos 	{ 0x8000, 15 },		/*%< qr. */
66d73eb73dSchristos 	{ 0x7800, 11 },		/*%< opcode. */
67d73eb73dSchristos 	{ 0x0400, 10 },		/*%< aa. */
68d73eb73dSchristos 	{ 0x0200, 9 },		/*%< tc. */
69d73eb73dSchristos 	{ 0x0100, 8 },		/*%< rd. */
70d73eb73dSchristos 	{ 0x0080, 7 },		/*%< ra. */
71d73eb73dSchristos 	{ 0x0040, 6 },		/*%< z. */
72d73eb73dSchristos 	{ 0x0020, 5 },		/*%< ad. */
73d73eb73dSchristos 	{ 0x0010, 4 },		/*%< cd. */
74d73eb73dSchristos 	{ 0x000f, 0 },		/*%< rcode. */
75d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (1/6). */
76d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (2/6). */
77d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (3/6). */
78d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (4/6). */
79d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (5/6). */
80d73eb73dSchristos 	{ 0x0000, 0 },		/*%< expansion (6/6). */
810c789e32Schristos };
820c789e32Schristos 
ns_msg_getflag(ns_msg handle,int flag)830c789e32Schristos int ns_msg_getflag(ns_msg handle, int flag) {
84fd00db40Schristos 	return((u_int32_t)((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
850c789e32Schristos }
860c789e32Schristos 
870c789e32Schristos int
ns_skiprr(const u_char * ptr,const u_char * eom,ns_sect section,int count)880c789e32Schristos ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
890c789e32Schristos 	const u_char *optr = ptr;
900c789e32Schristos 
91fd00db40Schristos 	for (; count > 0; count--) {
920c789e32Schristos 		int b, rdlength;
930c789e32Schristos 
940c789e32Schristos 		b = dn_skipname(ptr, eom);
950c789e32Schristos 		if (b < 0)
960c789e32Schristos 			RETERR(EMSGSIZE);
970c789e32Schristos 		ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
980c789e32Schristos 		if (section != ns_s_qd) {
990c789e32Schristos 			if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
1000c789e32Schristos 				RETERR(EMSGSIZE);
1010c789e32Schristos 			ptr += NS_INT32SZ/*TTL*/;
1020c789e32Schristos 			NS_GET16(rdlength, ptr);
1030c789e32Schristos 			ptr += rdlength/*RData*/;
1040c789e32Schristos 		}
1050c789e32Schristos 	}
1060c789e32Schristos 	if (ptr > eom)
1070c789e32Schristos 		RETERR(EMSGSIZE);
108*c5e820caSchristos 	_DIAGASSERT(__type_fit(int, ptr - optr));
109*c5e820caSchristos 	return (int)(ptr - optr);
1100c789e32Schristos }
1110c789e32Schristos 
1120c789e32Schristos int
ns_initparse(const u_char * msg,int msglen,ns_msg * handle)1130c789e32Schristos ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
1140c789e32Schristos 	const u_char *eom = msg + msglen;
1150c789e32Schristos 	int i;
1160c789e32Schristos 
1170c789e32Schristos 	handle->_msg = msg;
1180c789e32Schristos 	handle->_eom = eom;
1190c789e32Schristos 	if (msg + NS_INT16SZ > eom)
1200c789e32Schristos 		RETERR(EMSGSIZE);
1210c789e32Schristos 	NS_GET16(handle->_id, msg);
1220c789e32Schristos 	if (msg + NS_INT16SZ > eom)
1230c789e32Schristos 		RETERR(EMSGSIZE);
1240c789e32Schristos 	NS_GET16(handle->_flags, msg);
1250c789e32Schristos 	for (i = 0; i < ns_s_max; i++) {
1260c789e32Schristos 		if (msg + NS_INT16SZ > eom)
1270c789e32Schristos 			RETERR(EMSGSIZE);
1280c789e32Schristos 		NS_GET16(handle->_counts[i], msg);
1290c789e32Schristos 	}
1300c789e32Schristos 	for (i = 0; i < ns_s_max; i++)
1310c789e32Schristos 		if (handle->_counts[i] == 0)
1320c789e32Schristos 			handle->_sections[i] = NULL;
1330c789e32Schristos 		else {
1340c789e32Schristos 			int b = ns_skiprr(msg, eom, (ns_sect)i,
1350c789e32Schristos 					  handle->_counts[i]);
1360c789e32Schristos 
1370c789e32Schristos 			if (b < 0)
1380c789e32Schristos 				return (-1);
1390c789e32Schristos 			handle->_sections[i] = msg;
1400c789e32Schristos 			msg += b;
1410c789e32Schristos 		}
1420c789e32Schristos 	if (msg != eom)
1430c789e32Schristos 		RETERR(EMSGSIZE);
1440c789e32Schristos 	setsection(handle, ns_s_max);
1450c789e32Schristos 	return (0);
1460c789e32Schristos }
1470c789e32Schristos 
1480c789e32Schristos int
ns_parserr(ns_msg * handle,ns_sect section,int rrnum,ns_rr * rr)1490c789e32Schristos ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
1500c789e32Schristos 	int b;
151d73eb73dSchristos 	int tmp;
1520c789e32Schristos 
1530c789e32Schristos 	/* Make section right. */
154d73eb73dSchristos 	tmp = section;
155d73eb73dSchristos 	if (tmp < 0 || section >= ns_s_max)
1560c789e32Schristos 		RETERR(ENODEV);
1570c789e32Schristos 	if (section != handle->_sect)
1580c789e32Schristos 		setsection(handle, section);
1590c789e32Schristos 
1600c789e32Schristos 	/* Make rrnum right. */
1610c789e32Schristos 	if (rrnum == -1)
1620c789e32Schristos 		rrnum = handle->_rrnum;
1630c789e32Schristos 	if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
1640c789e32Schristos 		RETERR(ENODEV);
1650c789e32Schristos 	if (rrnum < handle->_rrnum)
1660c789e32Schristos 		setsection(handle, section);
1670c789e32Schristos 	if (rrnum > handle->_rrnum) {
1680c789e32Schristos 		b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
1690c789e32Schristos 			      rrnum - handle->_rrnum);
1700c789e32Schristos 
1710c789e32Schristos 		if (b < 0)
1720c789e32Schristos 			return (-1);
1730c789e32Schristos 		handle->_msg_ptr += b;
1740c789e32Schristos 		handle->_rrnum = rrnum;
1750c789e32Schristos 	}
1760c789e32Schristos 
1770c789e32Schristos 	/* Do the parse. */
1780c789e32Schristos 	b = dn_expand(handle->_msg, handle->_eom,
1790c789e32Schristos 		      handle->_msg_ptr, rr->name, NS_MAXDNAME);
1800c789e32Schristos 	if (b < 0)
1810c789e32Schristos 		return (-1);
1820c789e32Schristos 	handle->_msg_ptr += b;
1830c789e32Schristos 	if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
1840c789e32Schristos 		RETERR(EMSGSIZE);
1850c789e32Schristos 	NS_GET16(rr->type, handle->_msg_ptr);
1860c789e32Schristos 	NS_GET16(rr->rr_class, handle->_msg_ptr);
1870c789e32Schristos 	if (section == ns_s_qd) {
1880c789e32Schristos 		rr->ttl = 0;
1890c789e32Schristos 		rr->rdlength = 0;
1900c789e32Schristos 		rr->rdata = NULL;
1910c789e32Schristos 	} else {
1920c789e32Schristos 		if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
1930c789e32Schristos 			RETERR(EMSGSIZE);
1940c789e32Schristos 		NS_GET32(rr->ttl, handle->_msg_ptr);
1950c789e32Schristos 		NS_GET16(rr->rdlength, handle->_msg_ptr);
1960c789e32Schristos 		if (handle->_msg_ptr + rr->rdlength > handle->_eom)
1970c789e32Schristos 			RETERR(EMSGSIZE);
1980c789e32Schristos 		rr->rdata = handle->_msg_ptr;
1990c789e32Schristos 		handle->_msg_ptr += rr->rdlength;
2000c789e32Schristos 	}
2010c789e32Schristos 	if (++handle->_rrnum > handle->_counts[(int)section])
2020c789e32Schristos 		setsection(handle, (ns_sect)((int)section + 1));
2030c789e32Schristos 
2040c789e32Schristos 	/* All done. */
2050c789e32Schristos 	return (0);
2060c789e32Schristos }
2070c789e32Schristos 
20859a755a4Schristos /*
20959a755a4Schristos  * This is identical to the above but uses network-format (uncompressed) names.
21059a755a4Schristos  */
21159a755a4Schristos int
ns_parserr2(ns_msg * handle,ns_sect section,int rrnum,ns_rr2 * rr)21259a755a4Schristos ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
21359a755a4Schristos 	int b;
21459a755a4Schristos 	int tmp;
21559a755a4Schristos 
21659a755a4Schristos 	/* Make section right. */
21750ce2a6bSchristos 	tmp = section;
21850ce2a6bSchristos 	if (tmp < 0 || section >= ns_s_max)
21959a755a4Schristos 		RETERR(ENODEV);
22059a755a4Schristos 	if (section != handle->_sect)
22159a755a4Schristos 		setsection(handle, section);
22259a755a4Schristos 
22359a755a4Schristos 	/* Make rrnum right. */
22459a755a4Schristos 	if (rrnum == -1)
22559a755a4Schristos 		rrnum = handle->_rrnum;
22659a755a4Schristos 	if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
22759a755a4Schristos 		RETERR(ENODEV);
22859a755a4Schristos 	if (rrnum < handle->_rrnum)
22959a755a4Schristos 		setsection(handle, section);
23059a755a4Schristos 	if (rrnum > handle->_rrnum) {
23159a755a4Schristos 		b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
23259a755a4Schristos 			      rrnum - handle->_rrnum);
23359a755a4Schristos 
23459a755a4Schristos 		if (b < 0)
23559a755a4Schristos 			return (-1);
23659a755a4Schristos 		handle->_msg_ptr += b;
23759a755a4Schristos 		handle->_rrnum = rrnum;
23859a755a4Schristos 	}
23959a755a4Schristos 
24059a755a4Schristos 	/* Do the parse. */
24159a755a4Schristos 	b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
24259a755a4Schristos 			    rr->nname, NS_MAXNNAME, &rr->nnamel);
24359a755a4Schristos 	if (b < 0)
24459a755a4Schristos 		return (-1);
24559a755a4Schristos 	handle->_msg_ptr += b;
24659a755a4Schristos 	if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
24759a755a4Schristos 		RETERR(EMSGSIZE);
24859a755a4Schristos 	NS_GET16(rr->type, handle->_msg_ptr);
24959a755a4Schristos 	NS_GET16(rr->rr_class, handle->_msg_ptr);
25059a755a4Schristos 	if (section == ns_s_qd) {
25159a755a4Schristos 		rr->ttl = 0;
25259a755a4Schristos 		rr->rdlength = 0;
25359a755a4Schristos 		rr->rdata = NULL;
25459a755a4Schristos 	} else {
25559a755a4Schristos 		if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
25659a755a4Schristos 			RETERR(EMSGSIZE);
25759a755a4Schristos 		NS_GET32(rr->ttl, handle->_msg_ptr);
25859a755a4Schristos 		NS_GET16(rr->rdlength, handle->_msg_ptr);
25959a755a4Schristos 		if (handle->_msg_ptr + rr->rdlength > handle->_eom)
26059a755a4Schristos 			RETERR(EMSGSIZE);
26159a755a4Schristos 		rr->rdata = handle->_msg_ptr;
26259a755a4Schristos 		handle->_msg_ptr += rr->rdlength;
26359a755a4Schristos 	}
26459a755a4Schristos 	if (++handle->_rrnum > handle->_counts[(int)section])
26559a755a4Schristos 		setsection(handle, (ns_sect)((int)section + 1));
26659a755a4Schristos 
26759a755a4Schristos 	/* All done. */
26859a755a4Schristos 	return (0);
26959a755a4Schristos }
27059a755a4Schristos 
2710c789e32Schristos /* Private. */
2720c789e32Schristos 
2730c789e32Schristos static void
setsection(ns_msg * msg,ns_sect sect)2740c789e32Schristos setsection(ns_msg *msg, ns_sect sect) {
2750c789e32Schristos 	msg->_sect = sect;
2760c789e32Schristos 	if (sect == ns_s_max) {
2770c789e32Schristos 		msg->_rrnum = -1;
2780c789e32Schristos 		msg->_msg_ptr = NULL;
2790c789e32Schristos 	} else {
2800c789e32Schristos 		msg->_rrnum = 0;
2810c789e32Schristos 		msg->_msg_ptr = msg->_sections[(int)sect];
2820c789e32Schristos 	}
2830c789e32Schristos }
284d73eb73dSchristos 
285d73eb73dSchristos /*! \file */
286