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 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 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 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 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 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 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 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 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