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