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