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