1 /** @file 2 Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR> 3 This program and the accompanying materials are licensed and made available 4 under the terms and conditions of the BSD License which accompanies this 5 distribution. The full text of the license may be found at 6 http://opensource.org/licenses/bsd-license.php. 7 8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 **/ 11 /* 12 * Copyright (c) 1996 by Internet Software Consortium. 13 * 14 * Permission to use, copy, modify, and distribute this software for any 15 * purpose with or without fee is hereby granted, provided that the above 16 * copyright notice and this permission notice appear in all copies. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 19 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 21 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 22 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 23 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 24 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 25 * SOFTWARE. 26 */ 27 28 /* 29 * Portions copyright (c) 1999, 2000 30 * Intel Corporation. 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * 47 * This product includes software developed by Intel Corporation and 48 * its contributors. 49 * 50 * 4. Neither the name of Intel Corporation or its contributors may be 51 * used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' 55 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE 58 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 64 * THE POSSIBILITY OF SUCH DAMAGE. 65 * 66 */ 67 68 /* 69 * Based on the Dynamic DNS reference implementation by Viraj Bais 70 * <viraj_bais (at) ccm.fm.intel.com> 71 */ 72 73 #include <sys/types.h> 74 #include <sys/param.h> 75 76 #include <netinet/in.h> 77 #include <arpa/nameser.h> 78 #include <arpa/inet.h> 79 80 #include <errno.h> 81 #include <limits.h> 82 #include <netdb.h> 83 #include <resolv.h> 84 #include <stdio.h> 85 #include <stdlib.h> 86 #include <string.h> 87 #include <unistd.h> 88 #include <ctype.h> 89 90 #include "res_config.h" 91 92 static int getnum_str(u_char **, u_char *); 93 static int getword_str(char *, int, u_char **, u_char *); 94 95 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); 96 97 /* 98 * Form update packets. 99 * Returns the size of the resulting packet if no error 100 * On error, 101 * returns -1 if error in reading a word/number in rdata 102 * portion for update packets 103 * -2 if length of buffer passed is insufficient 104 * -3 if zone section is not the first section in 105 * the linked list, or section order has a problem 106 * -4 on a number overflow 107 * -5 unknown operation or no records 108 */ 109 int 110 res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { 111 ns_updrec *rrecp_start = rrecp_in; 112 HEADER *hp; 113 u_char *cp, *sp2, *startp, *endp; 114 int n, i, soanum, multiline; 115 ns_updrec *rrecp; 116 struct in_addr ina; 117 char buf2[MAXDNAME]; 118 int section, numrrs = 0, counts[ns_s_max]; 119 u_int16_t rtype, rclass; 120 u_int32_t n1, rttl; 121 u_char *dnptrs[20], **dpp, **lastdnptr; 122 123 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 124 h_errno = NETDB_INTERNAL; 125 return (-1); 126 } 127 128 /* 129 * Initialize header fields. 130 */ 131 if ((buf == NULL) || (buflen < HFIXEDSZ)) 132 return (-1); 133 memset(buf, 0, HFIXEDSZ); 134 hp = (HEADER *) buf; 135 hp->id = htons(++_res.id); 136 hp->opcode = ns_o_update; 137 hp->rcode = NOERROR; 138 cp = buf + HFIXEDSZ; 139 buflen -= HFIXEDSZ; 140 dpp = dnptrs; 141 *dpp++ = buf; 142 *dpp++ = NULL; 143 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; 144 145 if (rrecp_start == NULL) 146 return (-5); 147 else if (rrecp_start->r_section != S_ZONE) 148 return (-3); 149 150 memset(counts, 0, sizeof counts); 151 for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) { 152 numrrs++; 153 section = rrecp->r_section; 154 if (section < 0 || section >= ns_s_max) 155 return (-1); 156 counts[section]++; 157 for (i = section + 1; i < ns_s_max; i++) 158 if (counts[i]) 159 return (-3); 160 rtype = rrecp->r_type; 161 rclass = rrecp->r_class; 162 rttl = rrecp->r_ttl; 163 /* overload class and type */ 164 if (section == S_PREREQ) { 165 rttl = 0; 166 switch (rrecp->r_opcode) { 167 case YXDOMAIN: 168 rclass = C_ANY; 169 rtype = T_ANY; 170 rrecp->r_size = 0; 171 break; 172 case NXDOMAIN: 173 rclass = C_NONE; 174 rtype = T_ANY; 175 rrecp->r_size = 0; 176 break; 177 case NXRRSET: 178 rclass = C_NONE; 179 rrecp->r_size = 0; 180 break; 181 case YXRRSET: 182 if (rrecp->r_size == 0) 183 rclass = C_ANY; 184 break; 185 default: 186 fprintf(stderr, 187 "res_mkupdate: incorrect opcode: %d\n", 188 rrecp->r_opcode); 189 fflush(stderr); 190 return (-1); 191 } 192 } else if (section == S_UPDATE) { 193 switch (rrecp->r_opcode) { 194 case DELETE: 195 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; 196 break; 197 case ADD: 198 break; 199 default: 200 fprintf(stderr, 201 "res_mkupdate: incorrect opcode: %d\n", 202 rrecp->r_opcode); 203 fflush(stderr); 204 return (-1); 205 } 206 } 207 208 /* 209 * XXX appending default domain to owner name is omitted, 210 * fqdn must be provided 211 */ 212 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, 213 lastdnptr)) < 0) 214 return (-1); 215 cp += n; 216 ShrinkBuffer(n + 2*INT16SZ); 217 PUTSHORT(rtype, cp); 218 PUTSHORT(rclass, cp); 219 if (section == S_ZONE) { 220 if (numrrs != 1 || rrecp->r_type != T_SOA) 221 return (-3); 222 continue; 223 } 224 ShrinkBuffer(INT32SZ + INT16SZ); 225 PUTLONG(rttl, cp); 226 sp2 = cp; /* save pointer to length byte */ 227 cp += INT16SZ; 228 if (rrecp->r_size == 0) { 229 if (section == S_UPDATE && rclass != C_ANY) 230 return (-1); 231 else { 232 PUTSHORT(0, sp2); 233 continue; 234 } 235 } 236 startp = rrecp->r_data; 237 endp = startp + rrecp->r_size - 1; 238 /* XXX this should be done centrally. */ 239 switch (rrecp->r_type) { 240 case T_A: 241 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 242 return (-1); 243 if (!inet_aton(buf2, &ina)) 244 return (-1); 245 n1 = ntohl(ina.s_addr); 246 ShrinkBuffer(INT32SZ); 247 PUTLONG(n1, cp); 248 break; 249 case T_CNAME: 250 case T_MB: 251 case T_MG: 252 case T_MR: 253 case T_NS: 254 case T_PTR: 255 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 256 return (-1); 257 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 258 if (n < 0) 259 return (-1); 260 cp += n; 261 ShrinkBuffer(n); 262 break; 263 case T_MINFO: 264 case T_SOA: 265 case T_RP: 266 for (i = 0; i < 2; i++) { 267 if (!getword_str(buf2, sizeof buf2, &startp, 268 endp)) 269 return (-1); 270 n = dn_comp(buf2, cp, buflen, 271 dnptrs, lastdnptr); 272 if (n < 0) 273 return (-1); 274 cp += n; 275 ShrinkBuffer(n); 276 } 277 if (rrecp->r_type == T_SOA) { 278 ShrinkBuffer(5 * INT32SZ); 279 while (isspace(*startp) || !*startp) 280 startp++; 281 if (*startp == '(') { 282 multiline = 1; 283 startp++; 284 } else 285 multiline = 0; 286 /* serial, refresh, retry, expire, minimum */ 287 for (i = 0; i < 5; i++) { 288 soanum = getnum_str(&startp, endp); 289 if (soanum < 0) 290 return (-1); 291 PUTLONG(soanum, cp); 292 } 293 if (multiline) { 294 while (isspace(*startp) || !*startp) 295 startp++; 296 if (*startp != ')') 297 return (-1); 298 } 299 } 300 break; 301 case T_MX: 302 case T_AFSDB: 303 case T_RT: 304 n = getnum_str(&startp, endp); 305 if (n < 0) 306 return (-1); 307 PUTSHORT(n, cp); 308 ShrinkBuffer(INT16SZ); 309 if (!getword_str(buf2, sizeof buf2, &startp, endp)) 310 return (-1); 311 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 312 if (n < 0) 313 return (-1); 314 cp += n; 315 ShrinkBuffer(n); 316 break; 317 case T_PX: 318 n = getnum_str(&startp, endp); 319 if (n < 0) 320 return (-1); 321 PUTSHORT(n, cp); 322 ShrinkBuffer(INT16SZ); 323 for (i = 0; i < 2; i++) { 324 if (!getword_str(buf2, sizeof buf2, &startp, 325 endp)) 326 return (-1); 327 n = dn_comp(buf2, cp, buflen, dnptrs, 328 lastdnptr); 329 if (n < 0) 330 return (-1); 331 cp += n; 332 ShrinkBuffer(n); 333 } 334 break; 335 case T_WKS: 336 case T_HINFO: 337 case T_TXT: 338 case T_X25: 339 case T_ISDN: 340 case T_NSAP: 341 case T_LOC: 342 /* XXX - more fine tuning needed here */ 343 ShrinkBuffer(rrecp->r_size); 344 memcpy(cp, rrecp->r_data, rrecp->r_size); 345 cp += rrecp->r_size; 346 break; 347 default: 348 return (-1); 349 } /*switch*/ 350 n = (u_int16_t)((cp - sp2) - INT16SZ); 351 PUTSHORT(n, sp2); 352 } /*for*/ 353 354 hp->qdcount = htons(counts[0]); 355 hp->ancount = htons(counts[1]); 356 hp->nscount = htons(counts[2]); 357 hp->arcount = htons(counts[3]); 358 return ((int)(cp - buf)); 359 } 360 361 /* 362 * Get a whitespace delimited word from a string (not file) 363 * into buf. modify the start pointer to point after the 364 * word in the string. 365 */ 366 static int 367 getword_str(char *buf, int size, u_char **startpp, u_char *endp) { 368 char *cp; 369 int c; 370 371 for (cp = buf; *startpp <= endp; ) { 372 c = **startpp; 373 if (isspace(c) || c == '\0') { 374 if (cp != buf) /* trailing whitespace */ 375 break; 376 else { /* leading whitespace */ 377 (*startpp)++; 378 continue; 379 } 380 } 381 (*startpp)++; 382 if (cp >= buf+size-1) 383 break; 384 *cp++ = (u_char)c; 385 } 386 *cp = '\0'; 387 return (cp != buf); 388 } 389 390 /* 391 * Get a whitespace delimited number from a string (not file) into buf 392 * update the start pointer to point after the number in the string. 393 */ 394 static int 395 getnum_str(u_char **startpp, u_char *endp) { 396 int c; 397 int n; 398 int seendigit = 0; 399 int m = 0; 400 401 for (n = 0; *startpp <= endp; ) { 402 c = **startpp; 403 if (isspace(c) || c == '\0') { 404 if (seendigit) /* trailing whitespace */ 405 break; 406 else { /* leading whitespace */ 407 (*startpp)++; 408 continue; 409 } 410 } 411 if (c == ';') { 412 while ((*startpp <= endp) && 413 ((c = **startpp) != '\n')) 414 (*startpp)++; 415 if (seendigit) 416 break; 417 continue; 418 } 419 if (!isdigit(c)) { 420 if (c == ')' && seendigit) { 421 (*startpp)--; 422 break; 423 } 424 return (-1); 425 } 426 (*startpp)++; 427 n = n * 10 + (c - '0'); 428 seendigit = 1; 429 } 430 return (n + m); 431 } 432 433 /* 434 * Allocate a resource record buffer & save rr info. 435 */ 436 ns_updrec * 437 res_mkupdrec(int section, const char *dname, 438 u_int class, u_int type, u_long ttl) { 439 ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); 440 441 if (!rrecp || !(rrecp->r_dname = strdup(dname))) 442 return (NULL); 443 rrecp->r_class = (u_int16_t)class; 444 rrecp->r_type = (u_int16_t)type; 445 rrecp->r_ttl = (u_int32_t)ttl; 446 rrecp->r_section = (u_int8_t)section; 447 return (rrecp); 448 } 449 450 /* 451 * Free a resource record buffer created by res_mkupdrec. 452 */ 453 void 454 res_freeupdrec(ns_updrec *rrecp) { 455 /* Note: freeing r_dp is the caller's responsibility. */ 456 if (rrecp->r_dname != NULL) 457 free(rrecp->r_dname); 458 free(rrecp); 459 } 460