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
ns_newmsg_init(u_char * buffer,size_t bufsiz,ns_newmsg * handle)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
ns_newmsg_copy(ns_newmsg * handle,ns_msg * msg)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
ns_newmsg_id(ns_newmsg * handle,u_int16_t id)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
ns_newmsg_flag(ns_newmsg * handle,ns_flag flag,u_int value)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
ns_newmsg_q(ns_newmsg * handle,ns_nname_ct qname,ns_type qtype,ns_class qclass)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
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)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
ns_newmsg_done(ns_newmsg * handle)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
rdcpy(ns_newmsg * handle,ns_type type,const u_char * rdata,size_t rdlen)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