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