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