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