19525b14Rao Shoaib/*
29525b14Rao Shoaib * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
39525b14Rao Shoaib * Use is subject to license terms.
49525b14Rao Shoaib */
59525b14Rao Shoaib
69525b14Rao Shoaib
79525b14Rao Shoaib/*
89525b14Rao Shoaib * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
99525b14Rao Shoaib *
109525b14Rao Shoaib * Permission to use, copy, modify, and/or distribute this software for any
119525b14Rao Shoaib * purpose with or without fee is hereby granted, provided that the above
129525b14Rao Shoaib * copyright notice and this permission notice appear in all copies.
139525b14Rao Shoaib *
149525b14Rao Shoaib * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
159525b14Rao Shoaib * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
169525b14Rao Shoaib * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
179525b14Rao Shoaib * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
189525b14Rao Shoaib * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
199525b14Rao Shoaib * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
209525b14Rao Shoaib * PERFORMANCE OF THIS SOFTWARE.
219525b14Rao Shoaib */
229525b14Rao Shoaib
239525b14Rao Shoaib#include <port_before.h>
249525b14Rao Shoaib
259525b14Rao Shoaib#include <arpa/nameser.h>
269525b14Rao Shoaib
279525b14Rao Shoaib#include <assert.h>
289525b14Rao Shoaib#include <errno.h>
299525b14Rao Shoaib#include <string.h>
309525b14Rao Shoaib
319525b14Rao Shoaib#include <port_after.h>
329525b14Rao Shoaib
339525b14Rao Shoaibstatic int	rdcpy(ns_newmsg *, ns_type, const u_char *, size_t);
349525b14Rao Shoaib
359525b14Rao Shoaib/* Initialize a "newmsg" object to empty.
369525b14Rao Shoaib */
379525b14Rao Shoaibint
389525b14Rao Shoaibns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *handle) {
399525b14Rao Shoaib	ns_msg *msg = &handle->msg;
409525b14Rao Shoaib
419525b14Rao Shoaib	memset(handle, 0, sizeof *handle);
429525b14Rao Shoaib	msg->_msg = buffer;
439525b14Rao Shoaib	msg->_eom = buffer + bufsiz;
449525b14Rao Shoaib	msg->_sect = ns_s_qd;
459525b14Rao Shoaib	msg->_rrnum = 0;
469525b14Rao Shoaib	msg->_msg_ptr = buffer + NS_HFIXEDSZ;
479525b14Rao Shoaib	handle->dnptrs[0] = msg->_msg;
489525b14Rao Shoaib	handle->dnptrs[1] = NULL;
499525b14Rao Shoaib	handle->lastdnptr = &handle->dnptrs[sizeof handle->dnptrs /
509525b14Rao Shoaib					    sizeof handle->dnptrs[0] - 1];
519525b14Rao Shoaib	return (0);
529525b14Rao Shoaib}
539525b14Rao Shoaib
549525b14Rao Shoaib/* Initialize a "newmsg" object by copying an existing parsed message.
559525b14Rao Shoaib */
569525b14Rao Shoaibint
579525b14Rao Shoaibns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
589525b14Rao Shoaib	ns_flag flag;
599525b14Rao Shoaib	ns_sect sect;
609525b14Rao Shoaib
619525b14Rao Shoaib	ns_newmsg_id(handle, ns_msg_id(*msg));
629525b14Rao Shoaib	for (flag = ns_f_qr; flag < ns_f_max; flag++)
639525b14Rao Shoaib		ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
649525b14Rao Shoaib	for (sect = ns_s_qd; sect < ns_s_max; sect++) {
659525b14Rao Shoaib		int i, count;
669525b14Rao Shoaib
679525b14Rao Shoaib		count = ns_msg_count(*msg, sect);
689525b14Rao Shoaib		for (i = 0; i < count; i++) {
699525b14Rao Shoaib			ns_rr2 rr;
709525b14Rao Shoaib			int x;
719525b14Rao Shoaib
729525b14Rao Shoaib			if (ns_parserr2(msg, sect, i, &rr) < 0)
739525b14Rao Shoaib				return (-1);
749525b14Rao Shoaib			if (sect == ns_s_qd)
759525b14Rao Shoaib				x = ns_newmsg_q(handle,
769525b14Rao Shoaib						ns_rr_nname(rr),
779525b14Rao Shoaib						ns_rr_type(rr),
789525b14Rao Shoaib						ns_rr_class(rr));
799525b14Rao Shoaib			else
809525b14Rao Shoaib				x = ns_newmsg_rr(handle, sect,
819525b14Rao Shoaib						 ns_rr_nname(rr),
829525b14Rao Shoaib						 ns_rr_type(rr),
839525b14Rao Shoaib						 ns_rr_class(rr),
849525b14Rao Shoaib						 ns_rr_ttl(rr),
859525b14Rao Shoaib						 ns_rr_rdlen(rr),
869525b14Rao Shoaib						 ns_rr_rdata(rr));
879525b14Rao Shoaib			if (x < 0)
889525b14Rao Shoaib				return (-1);
899525b14Rao Shoaib		}
909525b14Rao Shoaib	}
919525b14Rao Shoaib	return (0);
929525b14Rao Shoaib}
939525b14Rao Shoaib
949525b14Rao Shoaib/* Set the message-ID in a "newmsg" object.
959525b14Rao Shoaib */
969525b14Rao Shoaibvoid
979525b14Rao Shoaibns_newmsg_id(ns_newmsg *handle, u_int16_t id) {
989525b14Rao Shoaib	ns_msg *msg = &handle->msg;
999525b14Rao Shoaib
1009525b14Rao Shoaib	msg->_id = id;
1019525b14Rao Shoaib}
1029525b14Rao Shoaib
1039525b14Rao Shoaib/* Set a flag (including rcode or opcode) in a "newmsg" object.
1049525b14Rao Shoaib */
1059525b14Rao Shoaibvoid
1069525b14Rao Shoaibns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value) {
1079525b14Rao Shoaib	extern struct _ns_flagdata _ns_flagdata[16];
1089525b14Rao Shoaib	struct _ns_flagdata *fd = &_ns_flagdata[flag];
1099525b14Rao Shoaib	ns_msg *msg = &handle->msg;
1109525b14Rao Shoaib
1119525b14Rao Shoaib	assert(flag < ns_f_max);
1129525b14Rao Shoaib	msg->_flags &= (~fd->mask);
1139525b14Rao Shoaib	msg->_flags |= (value << fd->shift);
1149525b14Rao Shoaib}
1159525b14Rao Shoaib
1169525b14Rao Shoaib/* Add a question (or zone, if it's an update) to a "newmsg" object.
1179525b14Rao Shoaib */
1189525b14Rao Shoaibint
1199525b14Rao Shoaibns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname,
1209525b14Rao Shoaib	    ns_type qtype, ns_class qclass)
1219525b14Rao Shoaib{
1229525b14Rao Shoaib	ns_msg *msg = &handle->msg;
1239525b14Rao Shoaib	u_char *t;
1249525b14Rao Shoaib	int n;
1259525b14Rao Shoaib
1269525b14Rao Shoaib	if (msg->_sect != ns_s_qd) {
1279525b14Rao Shoaib		errno = ENODEV;
1289525b14Rao Shoaib		return (-1);
1299525b14Rao Shoaib	}
1309525b14Rao Shoaib	t = (u_char *) (unsigned long) msg->_msg_ptr;
1319525b14Rao Shoaib	if (msg->_rrnum == 0)
1329525b14Rao Shoaib		msg->_sections[ns_s_qd] = t;
1339525b14Rao Shoaib	n = ns_name_pack(qname, t, msg->_eom - t,
1349525b14Rao Shoaib			 handle->dnptrs, handle->lastdnptr);
1359525b14Rao Shoaib	if (n < 0)
1369525b14Rao Shoaib		return (-1);
1379525b14Rao Shoaib	t += n;
1389525b14Rao Shoaib	if (t + QFIXEDSZ >= msg->_eom) {
1399525b14Rao Shoaib		errno = EMSGSIZE;
1409525b14Rao Shoaib		return (-1);
1419525b14Rao Shoaib	}
1429525b14Rao Shoaib	NS_PUT16(qtype, t);
1439525b14Rao Shoaib	NS_PUT16(qclass, t);
1449525b14Rao Shoaib	msg->_msg_ptr = t;
1459525b14Rao Shoaib	msg->_counts[ns_s_qd] = ++msg->_rrnum;
1469525b14Rao Shoaib	return (0);
1479525b14Rao Shoaib}
1489525b14Rao Shoaib
1499525b14Rao Shoaib/* Add an RR to a "newmsg" object.
1509525b14Rao Shoaib */
1519525b14Rao Shoaibint
1529525b14Rao Shoaibns_newmsg_rr(ns_newmsg *handle, ns_sect sect,
1539525b14Rao Shoaib	     ns_nname_ct name, ns_type type,
1549525b14Rao Shoaib	     ns_class rr_class, u_int32_t ttl,
1559525b14Rao Shoaib	     u_int16_t rdlen, const u_char *rdata)
1569525b14Rao Shoaib{
1579525b14Rao Shoaib	ns_msg *msg = &handle->msg;
1589525b14Rao Shoaib	u_char *t;
1599525b14Rao Shoaib	int n;
1609525b14Rao Shoaib
1619525b14Rao Shoaib	if (sect < msg->_sect) {
1629525b14Rao Shoaib		errno = ENODEV;
1639525b14Rao Shoaib		return (-1);
1649525b14Rao Shoaib	}
1659525b14Rao Shoaib	t = (u_char *) (unsigned long) msg->_msg_ptr;
1669525b14Rao Shoaib	if (sect > msg->_sect) {
1679525b14Rao Shoaib		msg->_sect = sect;
1689525b14Rao Shoaib		msg->_sections[sect] = t;
1699525b14Rao Shoaib		msg->_rrnum = 0;
1709525b14Rao Shoaib	}
1719525b14Rao Shoaib	n = ns_name_pack(name, t, msg->_eom - t,
1729525b14Rao Shoaib			 handle->dnptrs, handle->lastdnptr);
1739525b14Rao Shoaib	if (n < 0)
1749525b14Rao Shoaib		return (-1);
1759525b14Rao Shoaib	t += n;
1769525b14Rao Shoaib	if (t + RRFIXEDSZ + rdlen >= msg->_eom) {
1779525b14Rao Shoaib		errno = EMSGSIZE;
1789525b14Rao Shoaib		return (-1);
1799525b14Rao Shoaib	}
1809525b14Rao Shoaib	NS_PUT16(type, t);
1819525b14Rao Shoaib	NS_PUT16(rr_class, t);
1829525b14Rao Shoaib	NS_PUT32(ttl, t);
1839525b14Rao Shoaib	msg->_msg_ptr = t;
1849525b14Rao Shoaib	if (rdcpy(handle, type, rdata, rdlen) < 0)
1859525b14Rao Shoaib		return (-1);
1869525b14Rao Shoaib	msg->_counts[sect] = ++msg->_rrnum;
1879525b14Rao Shoaib	return (0);
1889525b14Rao Shoaib}
1899525b14Rao Shoaib
1909525b14Rao Shoaib/* Complete a "newmsg" object and return its size for use in write().
1919525b14Rao Shoaib * (Note: the "newmsg" object is also made ready for ns_parserr() etc.)
1929525b14Rao Shoaib */
1939525b14Rao Shoaibsize_t
1949525b14Rao Shoaibns_newmsg_done(ns_newmsg *handle) {
1959525b14Rao Shoaib	ns_msg *msg = &handle->msg;
1969525b14Rao Shoaib	ns_sect sect;
1979525b14Rao Shoaib	u_char *t;
1989525b14Rao Shoaib
1999525b14Rao Shoaib	t = (u_char *) (unsigned long) msg->_msg;
2009525b14Rao Shoaib	NS_PUT16(msg->_id, t);
2019525b14Rao Shoaib	NS_PUT16(msg->_flags, t);
2029525b14Rao Shoaib	for (sect = 0; sect < ns_s_max; sect++)
2039525b14Rao Shoaib		NS_PUT16(msg->_counts[sect], t);
2049525b14Rao Shoaib	msg->_eom = msg->_msg_ptr;
2059525b14Rao Shoaib	msg->_sect = ns_s_max;
2069525b14Rao Shoaib	msg->_rrnum = -1;
2079525b14Rao Shoaib	msg->_msg_ptr = NULL;
2089525b14Rao Shoaib	return (msg->_eom - msg->_msg);
2099525b14Rao Shoaib}
2109525b14Rao Shoaib
2119525b14Rao Shoaib/* Private. */
2129525b14Rao Shoaib
2139525b14Rao Shoaib/* Copy an RDATA, using compression pointers where RFC1035 permits.
2149525b14Rao Shoaib */
2159525b14Rao Shoaibstatic int
2169525b14Rao Shoaibrdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) {
2179525b14Rao Shoaib	ns_msg *msg = &handle->msg;
2189525b14Rao Shoaib	u_char *p = (u_char *) (unsigned long) msg->_msg_ptr;
2199525b14Rao Shoaib	u_char *t = p + NS_INT16SZ;
2209525b14Rao Shoaib	u_char *s = t;
2219525b14Rao Shoaib	int n;
2229525b14Rao Shoaib
2239525b14Rao Shoaib	switch (type) {
2249525b14Rao Shoaib	case ns_t_soa:
2259525b14Rao Shoaib		/* MNAME. */
2269525b14Rao Shoaib		n = ns_name_pack(rdata, t, msg->_eom - t,
2279525b14Rao Shoaib				 handle->dnptrs, handle->lastdnptr);
2289525b14Rao Shoaib		if (n < 0)
2299525b14Rao Shoaib			return (-1);
2309525b14Rao Shoaib		t += n;
2319525b14Rao Shoaib		if (ns_name_skip(&rdata, msg->_eom) < 0)
2329525b14Rao Shoaib			return (-1);
2339525b14Rao Shoaib
2349525b14Rao Shoaib		/* ANAME. */
2359525b14Rao Shoaib		n = ns_name_pack(rdata, t, msg->_eom - t,
2369525b14Rao Shoaib				 handle->dnptrs, handle->lastdnptr);
2379525b14Rao Shoaib		if (n < 0)
2389525b14Rao Shoaib			return (-1);
2399525b14Rao Shoaib		t += n;
2409525b14Rao Shoaib		if (ns_name_skip(&rdata, msg->_eom) < 0)
2419525b14Rao Shoaib			return (-1);
2429525b14Rao Shoaib
2439525b14Rao Shoaib		/* Serial, Refresh, Retry, Expiry, and Minimum. */
2449525b14Rao Shoaib		if ((msg->_eom - t) < (NS_INT32SZ * 5)) {
2459525b14Rao Shoaib			errno = EMSGSIZE;
2469525b14Rao Shoaib			return (-1);
2479525b14Rao Shoaib		}
2489525b14Rao Shoaib		memcpy(t, rdata, NS_INT32SZ * 5);
2499525b14Rao Shoaib		t += (NS_INT32SZ * 5);
2509525b14Rao Shoaib		break;
2519525b14Rao Shoaib	case ns_t_ptr:
2529525b14Rao Shoaib	case ns_t_cname:
2539525b14Rao Shoaib	case ns_t_ns:
2549525b14Rao Shoaib		/* PTRDNAME, CNAME, or NSDNAME. */
2559525b14Rao Shoaib		n = ns_name_pack(rdata, t, msg->_eom - t,
2569525b14Rao Shoaib				 handle->dnptrs, handle->lastdnptr);
2579525b14Rao Shoaib		if (n < 0)
2589525b14Rao Shoaib			return (-1);
2599525b14Rao Shoaib		t += n;
2609525b14Rao Shoaib		break;
2619525b14Rao Shoaib	default:
2629525b14Rao Shoaib		memcpy(t, rdata, rdlen);
2639525b14Rao Shoaib		t += rdlen;
2649525b14Rao Shoaib	}
2659525b14Rao Shoaib	NS_PUT16(t - s, p);
2669525b14Rao Shoaib	msg->_msg_ptr = t;
2679525b14Rao Shoaib	return (0);
2689525b14Rao Shoaib}
2699525b14Rao Shoaib
270