xref: /titanic_51/usr/src/lib/libresolv2/common/nameser/ns_newmsg.c (revision 9525b14bcdeb5b5f6f95ab27c2f48f18bd2ec829)
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 #ifndef lint
24*9525b14bSRao Shoaib static const char rcsid[] = "$Id: ns_newmsg.c,v 1.3 2009/02/26 10:48:57 marka Exp $";
25*9525b14bSRao Shoaib #endif
26*9525b14bSRao Shoaib 
27*9525b14bSRao Shoaib #include <port_before.h>
28*9525b14bSRao Shoaib 
29*9525b14bSRao Shoaib #include <arpa/nameser.h>
30*9525b14bSRao Shoaib 
31*9525b14bSRao Shoaib #include <assert.h>
32*9525b14bSRao Shoaib #include <errno.h>
33*9525b14bSRao Shoaib #include <string.h>
34*9525b14bSRao Shoaib 
35*9525b14bSRao Shoaib #include <port_after.h>
36*9525b14bSRao Shoaib 
37*9525b14bSRao Shoaib static int	rdcpy(ns_newmsg *, ns_type, const u_char *, size_t);
38*9525b14bSRao Shoaib 
39*9525b14bSRao Shoaib /* Initialize a "newmsg" object to empty.
40*9525b14bSRao Shoaib  */
41*9525b14bSRao Shoaib int
42*9525b14bSRao Shoaib ns_newmsg_init(u_char *buffer, size_t bufsiz, ns_newmsg *handle) {
43*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
44*9525b14bSRao Shoaib 
45*9525b14bSRao Shoaib 	memset(handle, 0, sizeof *handle);
46*9525b14bSRao Shoaib 	msg->_msg = buffer;
47*9525b14bSRao Shoaib 	msg->_eom = buffer + bufsiz;
48*9525b14bSRao Shoaib 	msg->_sect = ns_s_qd;
49*9525b14bSRao Shoaib 	msg->_rrnum = 0;
50*9525b14bSRao Shoaib 	msg->_msg_ptr = buffer + NS_HFIXEDSZ;
51*9525b14bSRao Shoaib 	handle->dnptrs[0] = msg->_msg;
52*9525b14bSRao Shoaib 	handle->dnptrs[1] = NULL;
53*9525b14bSRao Shoaib 	handle->lastdnptr = &handle->dnptrs[sizeof handle->dnptrs /
54*9525b14bSRao Shoaib 					    sizeof handle->dnptrs[0] - 1];
55*9525b14bSRao Shoaib 	return (0);
56*9525b14bSRao Shoaib }
57*9525b14bSRao Shoaib 
58*9525b14bSRao Shoaib /* Initialize a "newmsg" object by copying an existing parsed message.
59*9525b14bSRao Shoaib  */
60*9525b14bSRao Shoaib int
61*9525b14bSRao Shoaib ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
62*9525b14bSRao Shoaib 	ns_flag flag;
63*9525b14bSRao Shoaib 	ns_sect sect;
64*9525b14bSRao Shoaib 
65*9525b14bSRao Shoaib 	ns_newmsg_id(handle, ns_msg_id(*msg));
66*9525b14bSRao Shoaib 	for (flag = ns_f_qr; flag < ns_f_max; flag++)
67*9525b14bSRao Shoaib 		ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
68*9525b14bSRao Shoaib 	for (sect = ns_s_qd; sect < ns_s_max; sect++) {
69*9525b14bSRao Shoaib 		int i, count;
70*9525b14bSRao Shoaib 
71*9525b14bSRao Shoaib 		count = ns_msg_count(*msg, sect);
72*9525b14bSRao Shoaib 		for (i = 0; i < count; i++) {
73*9525b14bSRao Shoaib 			ns_rr2 rr;
74*9525b14bSRao Shoaib 			int x;
75*9525b14bSRao Shoaib 
76*9525b14bSRao Shoaib 			if (ns_parserr2(msg, sect, i, &rr) < 0)
77*9525b14bSRao Shoaib 				return (-1);
78*9525b14bSRao Shoaib 			if (sect == ns_s_qd)
79*9525b14bSRao Shoaib 				x = ns_newmsg_q(handle,
80*9525b14bSRao Shoaib 						ns_rr_nname(rr),
81*9525b14bSRao Shoaib 						ns_rr_type(rr),
82*9525b14bSRao Shoaib 						ns_rr_class(rr));
83*9525b14bSRao Shoaib 			else
84*9525b14bSRao Shoaib 				x = ns_newmsg_rr(handle, sect,
85*9525b14bSRao Shoaib 						 ns_rr_nname(rr),
86*9525b14bSRao Shoaib 						 ns_rr_type(rr),
87*9525b14bSRao Shoaib 						 ns_rr_class(rr),
88*9525b14bSRao Shoaib 						 ns_rr_ttl(rr),
89*9525b14bSRao Shoaib 						 ns_rr_rdlen(rr),
90*9525b14bSRao Shoaib 						 ns_rr_rdata(rr));
91*9525b14bSRao Shoaib 			if (x < 0)
92*9525b14bSRao Shoaib 				return (-1);
93*9525b14bSRao Shoaib 		}
94*9525b14bSRao Shoaib 	}
95*9525b14bSRao Shoaib 	return (0);
96*9525b14bSRao Shoaib }
97*9525b14bSRao Shoaib 
98*9525b14bSRao Shoaib /* Set the message-ID in a "newmsg" object.
99*9525b14bSRao Shoaib  */
100*9525b14bSRao Shoaib void
101*9525b14bSRao Shoaib ns_newmsg_id(ns_newmsg *handle, u_int16_t id) {
102*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
103*9525b14bSRao Shoaib 
104*9525b14bSRao Shoaib 	msg->_id = id;
105*9525b14bSRao Shoaib }
106*9525b14bSRao Shoaib 
107*9525b14bSRao Shoaib /* Set a flag (including rcode or opcode) in a "newmsg" object.
108*9525b14bSRao Shoaib  */
109*9525b14bSRao Shoaib void
110*9525b14bSRao Shoaib ns_newmsg_flag(ns_newmsg *handle, ns_flag flag, u_int value) {
111*9525b14bSRao Shoaib 	extern struct _ns_flagdata _ns_flagdata[16];
112*9525b14bSRao Shoaib 	struct _ns_flagdata *fd = &_ns_flagdata[flag];
113*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
114*9525b14bSRao Shoaib 
115*9525b14bSRao Shoaib 	assert(flag < ns_f_max);
116*9525b14bSRao Shoaib 	msg->_flags &= (~fd->mask);
117*9525b14bSRao Shoaib 	msg->_flags |= (value << fd->shift);
118*9525b14bSRao Shoaib }
119*9525b14bSRao Shoaib 
120*9525b14bSRao Shoaib /* Add a question (or zone, if it's an update) to a "newmsg" object.
121*9525b14bSRao Shoaib  */
122*9525b14bSRao Shoaib int
123*9525b14bSRao Shoaib ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname,
124*9525b14bSRao Shoaib 	    ns_type qtype, ns_class qclass)
125*9525b14bSRao Shoaib {
126*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
127*9525b14bSRao Shoaib 	u_char *t;
128*9525b14bSRao Shoaib 	int n;
129*9525b14bSRao Shoaib 
130*9525b14bSRao Shoaib 	if (msg->_sect != ns_s_qd) {
131*9525b14bSRao Shoaib 		errno = ENODEV;
132*9525b14bSRao Shoaib 		return (-1);
133*9525b14bSRao Shoaib 	}
134*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg_ptr;
135*9525b14bSRao Shoaib 	if (msg->_rrnum == 0)
136*9525b14bSRao Shoaib 		msg->_sections[ns_s_qd] = t;
137*9525b14bSRao Shoaib 	n = ns_name_pack(qname, t, msg->_eom - t,
138*9525b14bSRao Shoaib 			 handle->dnptrs, handle->lastdnptr);
139*9525b14bSRao Shoaib 	if (n < 0)
140*9525b14bSRao Shoaib 		return (-1);
141*9525b14bSRao Shoaib 	t += n;
142*9525b14bSRao Shoaib 	if (t + QFIXEDSZ >= msg->_eom) {
143*9525b14bSRao Shoaib 		errno = EMSGSIZE;
144*9525b14bSRao Shoaib 		return (-1);
145*9525b14bSRao Shoaib 	}
146*9525b14bSRao Shoaib 	NS_PUT16(qtype, t);
147*9525b14bSRao Shoaib 	NS_PUT16(qclass, t);
148*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
149*9525b14bSRao Shoaib 	msg->_counts[ns_s_qd] = ++msg->_rrnum;
150*9525b14bSRao Shoaib 	return (0);
151*9525b14bSRao Shoaib }
152*9525b14bSRao Shoaib 
153*9525b14bSRao Shoaib /* Add an RR to a "newmsg" object.
154*9525b14bSRao Shoaib  */
155*9525b14bSRao Shoaib int
156*9525b14bSRao Shoaib ns_newmsg_rr(ns_newmsg *handle, ns_sect sect,
157*9525b14bSRao Shoaib 	     ns_nname_ct name, ns_type type,
158*9525b14bSRao Shoaib 	     ns_class rr_class, u_int32_t ttl,
159*9525b14bSRao Shoaib 	     u_int16_t rdlen, const u_char *rdata)
160*9525b14bSRao Shoaib {
161*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
162*9525b14bSRao Shoaib 	u_char *t;
163*9525b14bSRao Shoaib 	int n;
164*9525b14bSRao Shoaib 
165*9525b14bSRao Shoaib 	if (sect < msg->_sect) {
166*9525b14bSRao Shoaib 		errno = ENODEV;
167*9525b14bSRao Shoaib 		return (-1);
168*9525b14bSRao Shoaib 	}
169*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg_ptr;
170*9525b14bSRao Shoaib 	if (sect > msg->_sect) {
171*9525b14bSRao Shoaib 		msg->_sect = sect;
172*9525b14bSRao Shoaib 		msg->_sections[sect] = t;
173*9525b14bSRao Shoaib 		msg->_rrnum = 0;
174*9525b14bSRao Shoaib 	}
175*9525b14bSRao Shoaib 	n = ns_name_pack(name, t, msg->_eom - t,
176*9525b14bSRao Shoaib 			 handle->dnptrs, handle->lastdnptr);
177*9525b14bSRao Shoaib 	if (n < 0)
178*9525b14bSRao Shoaib 		return (-1);
179*9525b14bSRao Shoaib 	t += n;
180*9525b14bSRao Shoaib 	if (t + RRFIXEDSZ + rdlen >= msg->_eom) {
181*9525b14bSRao Shoaib 		errno = EMSGSIZE;
182*9525b14bSRao Shoaib 		return (-1);
183*9525b14bSRao Shoaib 	}
184*9525b14bSRao Shoaib 	NS_PUT16(type, t);
185*9525b14bSRao Shoaib 	NS_PUT16(rr_class, t);
186*9525b14bSRao Shoaib 	NS_PUT32(ttl, t);
187*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
188*9525b14bSRao Shoaib 	if (rdcpy(handle, type, rdata, rdlen) < 0)
189*9525b14bSRao Shoaib 		return (-1);
190*9525b14bSRao Shoaib 	msg->_counts[sect] = ++msg->_rrnum;
191*9525b14bSRao Shoaib 	return (0);
192*9525b14bSRao Shoaib }
193*9525b14bSRao Shoaib 
194*9525b14bSRao Shoaib /* Complete a "newmsg" object and return its size for use in write().
195*9525b14bSRao Shoaib  * (Note: the "newmsg" object is also made ready for ns_parserr() etc.)
196*9525b14bSRao Shoaib  */
197*9525b14bSRao Shoaib size_t
198*9525b14bSRao Shoaib ns_newmsg_done(ns_newmsg *handle) {
199*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
200*9525b14bSRao Shoaib 	ns_sect sect;
201*9525b14bSRao Shoaib 	u_char *t;
202*9525b14bSRao Shoaib 
203*9525b14bSRao Shoaib 	t = (u_char *) (unsigned long) msg->_msg;
204*9525b14bSRao Shoaib 	NS_PUT16(msg->_id, t);
205*9525b14bSRao Shoaib 	NS_PUT16(msg->_flags, t);
206*9525b14bSRao Shoaib 	for (sect = 0; sect < ns_s_max; sect++)
207*9525b14bSRao Shoaib 		NS_PUT16(msg->_counts[sect], t);
208*9525b14bSRao Shoaib 	msg->_eom = msg->_msg_ptr;
209*9525b14bSRao Shoaib 	msg->_sect = ns_s_max;
210*9525b14bSRao Shoaib 	msg->_rrnum = -1;
211*9525b14bSRao Shoaib 	msg->_msg_ptr = NULL;
212*9525b14bSRao Shoaib 	return (msg->_eom - msg->_msg);
213*9525b14bSRao Shoaib }
214*9525b14bSRao Shoaib 
215*9525b14bSRao Shoaib /* Private. */
216*9525b14bSRao Shoaib 
217*9525b14bSRao Shoaib /* Copy an RDATA, using compression pointers where RFC1035 permits.
218*9525b14bSRao Shoaib  */
219*9525b14bSRao Shoaib static int
220*9525b14bSRao Shoaib rdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) {
221*9525b14bSRao Shoaib 	ns_msg *msg = &handle->msg;
222*9525b14bSRao Shoaib 	u_char *p = (u_char *) (unsigned long) msg->_msg_ptr;
223*9525b14bSRao Shoaib 	u_char *t = p + NS_INT16SZ;
224*9525b14bSRao Shoaib 	u_char *s = t;
225*9525b14bSRao Shoaib 	int n;
226*9525b14bSRao Shoaib 
227*9525b14bSRao Shoaib 	switch (type) {
228*9525b14bSRao Shoaib 	case ns_t_soa:
229*9525b14bSRao Shoaib 		/* MNAME. */
230*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
231*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
232*9525b14bSRao Shoaib 		if (n < 0)
233*9525b14bSRao Shoaib 			return (-1);
234*9525b14bSRao Shoaib 		t += n;
235*9525b14bSRao Shoaib 		if (ns_name_skip(&rdata, msg->_eom) < 0)
236*9525b14bSRao Shoaib 			return (-1);
237*9525b14bSRao Shoaib 
238*9525b14bSRao Shoaib 		/* ANAME. */
239*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
240*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
241*9525b14bSRao Shoaib 		if (n < 0)
242*9525b14bSRao Shoaib 			return (-1);
243*9525b14bSRao Shoaib 		t += n;
244*9525b14bSRao Shoaib 		if (ns_name_skip(&rdata, msg->_eom) < 0)
245*9525b14bSRao Shoaib 			return (-1);
246*9525b14bSRao Shoaib 
247*9525b14bSRao Shoaib 		/* Serial, Refresh, Retry, Expiry, and Minimum. */
248*9525b14bSRao Shoaib 		if ((msg->_eom - t) < (NS_INT32SZ * 5)) {
249*9525b14bSRao Shoaib 			errno = EMSGSIZE;
250*9525b14bSRao Shoaib 			return (-1);
251*9525b14bSRao Shoaib 		}
252*9525b14bSRao Shoaib 		memcpy(t, rdata, NS_INT32SZ * 5);
253*9525b14bSRao Shoaib 		t += (NS_INT32SZ * 5);
254*9525b14bSRao Shoaib 		break;
255*9525b14bSRao Shoaib 	case ns_t_ptr:
256*9525b14bSRao Shoaib 	case ns_t_cname:
257*9525b14bSRao Shoaib 	case ns_t_ns:
258*9525b14bSRao Shoaib 		/* PTRDNAME, CNAME, or NSDNAME. */
259*9525b14bSRao Shoaib 		n = ns_name_pack(rdata, t, msg->_eom - t,
260*9525b14bSRao Shoaib 				 handle->dnptrs, handle->lastdnptr);
261*9525b14bSRao Shoaib 		if (n < 0)
262*9525b14bSRao Shoaib 			return (-1);
263*9525b14bSRao Shoaib 		t += n;
264*9525b14bSRao Shoaib 		break;
265*9525b14bSRao Shoaib 	default:
266*9525b14bSRao Shoaib 		memcpy(t, rdata, rdlen);
267*9525b14bSRao Shoaib 		t += rdlen;
268*9525b14bSRao Shoaib 	}
269*9525b14bSRao Shoaib 	NS_PUT16(t - s, p);
270*9525b14bSRao Shoaib 	msg->_msg_ptr = t;
271*9525b14bSRao Shoaib 	return (0);
272*9525b14bSRao Shoaib }
273*9525b14bSRao Shoaib 
274