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