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