1/* $NetBSD$ */ 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 20static 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 29static int rdcpy(ns_newmsg *, ns_type, const u_char *, size_t); 30 31/* Initialize a "newmsg" object to empty. 32 */ 33int 34ns_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 */ 52int 53ns_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 */ 92void 93ns_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 */ 101void 102ns_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 */ 114int 115ns_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 */ 147int 148ns_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 */ 189size_t 190ns_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 */ 211static int 212rdcpy(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