1*9525b14bSRao Shoaib /*
2*9525b14bSRao Shoaib  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3*9525b14bSRao Shoaib  * Use is subject to license terms.
4*9525b14bSRao Shoaib  */
5*9525b14bSRao Shoaib 
6*9525b14bSRao Shoaib 
7*9525b14bSRao Shoaib /*
8*9525b14bSRao Shoaib  * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
9*9525b14bSRao Shoaib  *
10*9525b14bSRao Shoaib  * Permission to use, copy, modify, and/or distribute this software for any
11*9525b14bSRao Shoaib  * purpose with or without fee is hereby granted, provided that the above
12*9525b14bSRao Shoaib  * copyright notice and this permission notice appear in all copies.
13*9525b14bSRao Shoaib  *
14*9525b14bSRao Shoaib  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
15*9525b14bSRao Shoaib  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
16*9525b14bSRao Shoaib  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
17*9525b14bSRao Shoaib  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
18*9525b14bSRao Shoaib  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
19*9525b14bSRao Shoaib  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20*9525b14bSRao Shoaib  * PERFORMANCE OF THIS SOFTWARE.
21*9525b14bSRao Shoaib  */
22*9525b14bSRao Shoaib 
23*9525b14bSRao Shoaib #include <port_before.h>
24*9525b14bSRao Shoaib 
25*9525b14bSRao Shoaib #include <arpa/nameser.h>
26*9525b14bSRao Shoaib 
27*9525b14bSRao Shoaib #include <assert.h>
28*9525b14bSRao Shoaib #include <errno.h>
29*9525b14bSRao Shoaib #include <string.h>
30*9525b14bSRao Shoaib 
31*9525b14bSRao Shoaib #include <port_after.h>
32*9525b14bSRao Shoaib 
33*9525b14bSRao Shoaib static int	rdcpy(ns_newmsg *, ns_type, const u_char *, size_t);
34*9525b14bSRao Shoaib 
35*9525b14bSRao Shoaib /* Initialize a "newmsg" object to empty.
36*9525b14bSRao Shoaib  */
37*9525b14bSRao Shoaib int
ns_newmsg_init(u_char * buffer,size_t bufsiz,ns_newmsg * handle)38*9525b14bSRao Shoaib ns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *handle) {
39*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
40*9525b14bSRao Shoaib 
41*9525b14bSRao Shoaib 	memset(handle, 0, sizeof *handle);
42*9525b14bSRao Shoaib 	msg->_msg = buffer;
43*9525b14bSRao Shoaib 	msg->_eom = buffer + bufsiz;
44*9525b14bSRao Shoaib 	msg->_sect = ns_s_qd;
45*9525b14bSRao Shoaib 	msg->_rrnum = 0;
46*9525b14bSRao Shoaib 	msg->_msg_ptr = buffer + NS_HFIXEDSZ;
47*9525b14bSRao Shoaib 	handle->dnptrs[0] = msg->_msg;
48*9525b14bSRao Shoaib 	handle->dnptrs[1] = NULL;
49*9525b14bSRao Shoaib 	handle->lastdnptr = &handle->dnptrs[sizeof handle->dnptrs /
50*9525b14bSRao Shoaib 					    sizeof handle->dnptrs[0] - 1];
51*9525b14bSRao Shoaib 	return (0);
52*9525b14bSRao Shoaib }
53*9525b14bSRao Shoaib 
54*9525b14bSRao Shoaib /* Initialize a "newmsg" object by copying an existing parsed message.
55*9525b14bSRao Shoaib  */
56*9525b14bSRao Shoaib int
ns_newmsg_copy(ns_newmsg * handle,ns_msg * msg)57*9525b14bSRao Shoaib ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
58*9525b14bSRao Shoaib 	ns_flag flag;
59*9525b14bSRao Shoaib 	ns_sect sect;
60*9525b14bSRao Shoaib 
61*9525b14bSRao Shoaib 	ns_newmsg_id(handle, ns_msg_id(*msg));
62*9525b14bSRao Shoaib 	for (flag = ns_f_qr; flag < ns_f_max; flag++)
63*9525b14bSRao Shoaib 		ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
64*9525b14bSRao Shoaib 	for (sect = ns_s_qd; sect < ns_s_max; sect++) {
65*9525b14bSRao Shoaib 		int i, count;
66*9525b14bSRao Shoaib 
67*9525b14bSRao Shoaib 		count = ns_msg_count(*msg, sect);
68*9525b14bSRao Shoaib 		for (i = 0; i < count; i++) {
69*9525b14bSRao Shoaib 			ns_rr2 rr;
70*9525b14bSRao Shoaib 			int x;
71*9525b14bSRao Shoaib 
72*9525b14bSRao Shoaib 			if (ns_parserr2(msg, sect, i, &rr) < 0)
73*9525b14bSRao Shoaib 				return (-1);
74*9525b14bSRao Shoaib 			if (sect == ns_s_qd)
75*9525b14bSRao Shoaib 				x = ns_newmsg_q(handle,
76*9525b14bSRao Shoaib 						ns_rr_nname(rr),
77*9525b14bSRao Shoaib 						ns_rr_type(rr),
78*9525b14bSRao Shoaib 						ns_rr_class(rr));
79*9525b14bSRao Shoaib 			else
80*9525b14bSRao Shoaib 				x = ns_newmsg_rr(handle, sect,
81*9525b14bSRao Shoaib 						 ns_rr_nname(rr),
82*9525b14bSRao Shoaib 						 ns_rr_type(rr),
83*9525b14bSRao Shoaib 						 ns_rr_class(rr),
84*9525b14bSRao Shoaib 						 ns_rr_ttl(rr),
85*9525b14bSRao Shoaib 						 ns_rr_rdlen(rr),
86*9525b14bSRao Shoaib 						 ns_rr_rdata(rr));
87*9525b14bSRao Shoaib 			if (x < 0)
88*9525b14bSRao Shoaib 				return (-1);
89*9525b14bSRao Shoaib 		}
90*9525b14bSRao Shoaib 	}
91*9525b14bSRao Shoaib 	return (0);
92*9525b14bSRao Shoaib }
93*9525b14bSRao Shoaib 
94*9525b14bSRao Shoaib /* Set the message-ID in a "newmsg" object.
95*9525b14bSRao Shoaib  */
96*9525b14bSRao Shoaib void
ns_newmsg_id(ns_newmsg * handle,u_int16_t id)97*9525b14bSRao Shoaib ns_newmsg_id(ns_newmsg *handle, u_int16_t id) {
98*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
99*9525b14bSRao Shoaib 
100*9525b14bSRao Shoaib 	msg->_id = id;
101*9525b14bSRao Shoaib }
102*9525b14bSRao Shoaib 
103*9525b14bSRao Shoaib /* Set a flag (including rcode or opcode) in a "newmsg" object.
104*9525b14bSRao Shoaib  */
105*9525b14bSRao Shoaib void
ns_newmsg_flag(ns_newmsg * handle,ns_flag flag,u_int value)106*9525b14bSRao Shoaib ns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value) {
107*9525b14bSRao Shoaib 	extern struct _ns_flagdata _ns_flagdata[16];
108*9525b14bSRao Shoaib 	struct _ns_flagdata *fd = &_ns_flagdata[flag];
109*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
110*9525b14bSRao Shoaib 
111*9525b14bSRao Shoaib 	assert(flag < ns_f_max);
112*9525b14bSRao Shoaib 	msg->_flags &= (~fd->mask);
113*9525b14bSRao Shoaib 	msg->_flags |= (value << fd->shift);
114*9525b14bSRao Shoaib }
115*9525b14bSRao Shoaib 
116*9525b14bSRao Shoaib /* Add a question (or zone, if it's an update) to a "newmsg" object.
117*9525b14bSRao Shoaib  */
118*9525b14bSRao Shoaib int
ns_newmsg_q(ns_newmsg * handle,ns_nname_ct qname,ns_type qtype,ns_class qclass)119*9525b14bSRao Shoaib ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname,
120*9525b14bSRao Shoaib 	    ns_type qtype, ns_class qclass)
121*9525b14bSRao Shoaib {
122*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
123*9525b14bSRao Shoaib 	u_char *t;
124*9525b14bSRao Shoaib 	int n;
125*9525b14bSRao Shoaib 
126*9525b14bSRao Shoaib 	if (msg->_sect != ns_s_qd) {
127*9525b14bSRao Shoaib 		errno = ENODEV;
128*9525b14bSRao Shoaib 		return (-1);
129*9525b14bSRao Shoaib 	}
130*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg_ptr;
131*9525b14bSRao Shoaib 	if (msg->_rrnum == 0)
132*9525b14bSRao Shoaib 		msg->_sections[ns_s_qd] = t;
133*9525b14bSRao Shoaib 	n = ns_name_pack(qname, t, msg->_eom - t,
134*9525b14bSRao Shoaib 			 handle->dnptrs, handle->lastdnptr);
135*9525b14bSRao Shoaib 	if (n < 0)
136*9525b14bSRao Shoaib 		return (-1);
137*9525b14bSRao Shoaib 	t += n;
138*9525b14bSRao Shoaib 	if (t + QFIXEDSZ >= msg->_eom) {
139*9525b14bSRao Shoaib 		errno = EMSGSIZE;
140*9525b14bSRao Shoaib 		return (-1);
141*9525b14bSRao Shoaib 	}
142*9525b14bSRao Shoaib 	NS_PUT16(qtype, t);
143*9525b14bSRao Shoaib 	NS_PUT16(qclass, t);
144*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
145*9525b14bSRao Shoaib 	msg->_counts[ns_s_qd] = ++msg->_rrnum;
146*9525b14bSRao Shoaib 	return (0);
147*9525b14bSRao Shoaib }
148*9525b14bSRao Shoaib 
149*9525b14bSRao Shoaib /* Add an RR to a "newmsg" object.
150*9525b14bSRao Shoaib  */
151*9525b14bSRao Shoaib int
ns_newmsg_rr(ns_newmsg * handle,ns_sect sect,ns_nname_ct name,ns_type type,ns_class rr_class,u_int32_t ttl,u_int16_t rdlen,const u_char * rdata)152*9525b14bSRao Shoaib ns_newmsg_rr(ns_newmsg *handle, ns_sect sect,
153*9525b14bSRao Shoaib 	     ns_nname_ct name, ns_type type,
154*9525b14bSRao Shoaib 	     ns_class rr_class, u_int32_t ttl,
155*9525b14bSRao Shoaib 	     u_int16_t rdlen, const u_char *rdata)
156*9525b14bSRao Shoaib {
157*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
158*9525b14bSRao Shoaib 	u_char *t;
159*9525b14bSRao Shoaib 	int n;
160*9525b14bSRao Shoaib 
161*9525b14bSRao Shoaib 	if (sect < msg->_sect) {
162*9525b14bSRao Shoaib 		errno = ENODEV;
163*9525b14bSRao Shoaib 		return (-1);
164*9525b14bSRao Shoaib 	}
165*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg_ptr;
166*9525b14bSRao Shoaib 	if (sect > msg->_sect) {
167*9525b14bSRao Shoaib 		msg->_sect = sect;
168*9525b14bSRao Shoaib 		msg->_sections[sect] = t;
169*9525b14bSRao Shoaib 		msg->_rrnum = 0;
170*9525b14bSRao Shoaib 	}
171*9525b14bSRao Shoaib 	n = ns_name_pack(name, t, msg->_eom - t,
172*9525b14bSRao Shoaib 			 handle->dnptrs, handle->lastdnptr);
173*9525b14bSRao Shoaib 	if (n < 0)
174*9525b14bSRao Shoaib 		return (-1);
175*9525b14bSRao Shoaib 	t += n;
176*9525b14bSRao Shoaib 	if (t + RRFIXEDSZ + rdlen >= msg->_eom) {
177*9525b14bSRao Shoaib 		errno = EMSGSIZE;
178*9525b14bSRao Shoaib 		return (-1);
179*9525b14bSRao Shoaib 	}
180*9525b14bSRao Shoaib 	NS_PUT16(type, t);
181*9525b14bSRao Shoaib 	NS_PUT16(rr_class, t);
182*9525b14bSRao Shoaib 	NS_PUT32(ttl, t);
183*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
184*9525b14bSRao Shoaib 	if (rdcpy(handle, type, rdata, rdlen) < 0)
185*9525b14bSRao Shoaib 		return (-1);
186*9525b14bSRao Shoaib 	msg->_counts[sect] = ++msg->_rrnum;
187*9525b14bSRao Shoaib 	return (0);
188*9525b14bSRao Shoaib }
189*9525b14bSRao Shoaib 
190*9525b14bSRao Shoaib /* Complete a "newmsg" object and return its size for use in write().
191*9525b14bSRao Shoaib  * (Note: the "newmsg" object is also made ready for ns_parserr() etc.)
192*9525b14bSRao Shoaib  */
193*9525b14bSRao Shoaib size_t
ns_newmsg_done(ns_newmsg * handle)194*9525b14bSRao Shoaib ns_newmsg_done(ns_newmsg *handle) {
195*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
196*9525b14bSRao Shoaib 	ns_sect sect;
197*9525b14bSRao Shoaib 	u_char *t;
198*9525b14bSRao Shoaib 
199*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg;
200*9525b14bSRao Shoaib 	NS_PUT16(msg->_id, t);
201*9525b14bSRao Shoaib 	NS_PUT16(msg->_flags, t);
202*9525b14bSRao Shoaib 	for (sect = 0; sect < ns_s_max; sect++)
203*9525b14bSRao Shoaib 		NS_PUT16(msg->_counts[sect], t);
204*9525b14bSRao Shoaib 	msg->_eom = msg->_msg_ptr;
205*9525b14bSRao Shoaib 	msg->_sect = ns_s_max;
206*9525b14bSRao Shoaib 	msg->_rrnum = -1;
207*9525b14bSRao Shoaib 	msg->_msg_ptr = NULL;
208*9525b14bSRao Shoaib 	return (msg->_eom - msg->_msg);
209*9525b14bSRao Shoaib }
210*9525b14bSRao Shoaib 
211*9525b14bSRao Shoaib /* Private. */
212*9525b14bSRao Shoaib 
213*9525b14bSRao Shoaib /* Copy an RDATA, using compression pointers where RFC1035 permits.
214*9525b14bSRao Shoaib  */
215*9525b14bSRao Shoaib static int
rdcpy(ns_newmsg * handle,ns_type type,const u_char * rdata,size_t rdlen)216*9525b14bSRao Shoaib rdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) {
217*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
218*9525b14bSRao Shoaib 	u_char *p = (u_char *) (unsigned long) msg->_msg_ptr;
219*9525b14bSRao Shoaib 	u_char *t = p + NS_INT16SZ;
220*9525b14bSRao Shoaib 	u_char *s = t;
221*9525b14bSRao Shoaib 	int n;
222*9525b14bSRao Shoaib 
223*9525b14bSRao Shoaib 	switch (type) {
224*9525b14bSRao Shoaib 	case ns_t_soa:
225*9525b14bSRao Shoaib 		/* MNAME. */
226*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
227*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
228*9525b14bSRao Shoaib 		if (n < 0)
229*9525b14bSRao Shoaib 			return (-1);
230*9525b14bSRao Shoaib 		t += n;
231*9525b14bSRao Shoaib 		if (ns_name_skip(&rdata, msg->_eom) < 0)
232*9525b14bSRao Shoaib 			return (-1);
233*9525b14bSRao Shoaib 
234*9525b14bSRao Shoaib 		/* ANAME. */
235*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
236*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
237*9525b14bSRao Shoaib 		if (n < 0)
238*9525b14bSRao Shoaib 			return (-1);
239*9525b14bSRao Shoaib 		t += n;
240*9525b14bSRao Shoaib 		if (ns_name_skip(&rdata, msg->_eom) < 0)
241*9525b14bSRao Shoaib 			return (-1);
242*9525b14bSRao Shoaib 
243*9525b14bSRao Shoaib 		/* Serial, Refresh, Retry, Expiry, and Minimum. */
244*9525b14bSRao Shoaib 		if ((msg->_eom - t) < (NS_INT32SZ * 5)) {
245*9525b14bSRao Shoaib 			errno = EMSGSIZE;
246*9525b14bSRao Shoaib 			return (-1);
247*9525b14bSRao Shoaib 		}
248*9525b14bSRao Shoaib 		memcpy(t, rdata, NS_INT32SZ * 5);
249*9525b14bSRao Shoaib 		t += (NS_INT32SZ * 5);
250*9525b14bSRao Shoaib 		break;
251*9525b14bSRao Shoaib 	case ns_t_ptr:
252*9525b14bSRao Shoaib 	case ns_t_cname:
253*9525b14bSRao Shoaib 	case ns_t_ns:
254*9525b14bSRao Shoaib 		/* PTRDNAME, CNAME, or NSDNAME. */
255*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
256*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
257*9525b14bSRao Shoaib 		if (n < 0)
258*9525b14bSRao Shoaib 			return (-1);
259*9525b14bSRao Shoaib 		t += n;
260*9525b14bSRao Shoaib 		break;
261*9525b14bSRao Shoaib 	default:
262*9525b14bSRao Shoaib 		memcpy(t, rdata, rdlen);
263*9525b14bSRao Shoaib 		t += rdlen;
264*9525b14bSRao Shoaib 	}
265*9525b14bSRao Shoaib 	NS_PUT16(t - s, p);
266*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
267*9525b14bSRao Shoaib 	return (0);
268*9525b14bSRao Shoaib }
269*9525b14bSRao Shoaib 
270