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