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