res_mkupdate.c revision 158782
1158782Sume/* 2158782Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3158782Sume * Copyright (c) 1996-1999 by Internet Software Consortium. 4158782Sume * 5158782Sume * Permission to use, copy, modify, and distribute this software for any 6158782Sume * purpose with or without fee is hereby granted, provided that the above 7158782Sume * copyright notice and this permission notice appear in all copies. 8158782Sume * 9158782Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10158782Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11158782Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12158782Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13158782Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14158782Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15158782Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16158782Sume */ 17158782Sume 18158782Sume/* 19158782Sume * Based on the Dynamic DNS reference implementation by Viraj Bais 20158782Sume * <viraj_bais@ccm.fm.intel.com> 21158782Sume */ 22158782Sume 23158782Sume#if !defined(lint) && !defined(SABER) 24158782Sumestatic const char rcsid[] = "$Id: res_mkupdate.c,v 1.1.2.1.4.5 2005/10/14 05:43:47 marka Exp $"; 25158782Sume#endif /* not lint */ 26158782Sume 27158782Sume#include "port_before.h" 28158782Sume 29158782Sume#include <sys/types.h> 30158782Sume#include <sys/param.h> 31158782Sume 32158782Sume#include <netinet/in.h> 33158782Sume#include <arpa/nameser.h> 34158782Sume#include <arpa/inet.h> 35158782Sume 36158782Sume#include <errno.h> 37158782Sume#include <limits.h> 38158782Sume#include <netdb.h> 39158782Sume#include <resolv.h> 40158782Sume#include <res_update.h> 41158782Sume#include <stdio.h> 42158782Sume#include <stdlib.h> 43158782Sume#include <string.h> 44158782Sume#include <unistd.h> 45158782Sume#include <ctype.h> 46158782Sume 47158782Sume#include "port_after.h" 48158782Sume 49158782Sume/* Options. Leave them on. */ 50158782Sume#define DEBUG 51158782Sume#define MAXPORT 1024 52158782Sume 53158782Sumestatic int getnum_str(u_char **, u_char *); 54158782Sumestatic int gethexnum_str(u_char **, u_char *); 55158782Sumestatic int getword_str(char *, int, u_char **, u_char *); 56158782Sumestatic int getstr_str(char *, int, u_char **, u_char *); 57158782Sume 58158782Sume#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2); 59158782Sume 60158782Sume/* Forward. */ 61158782Sume 62158782Sumeint res_protocolnumber(const char *); 63158782Sumeint res_servicenumber(const char *); 64158782Sume 65158782Sume/* 66158782Sume * Form update packets. 67158782Sume * Returns the size of the resulting packet if no error 68158782Sume * On error, 69158782Sume * returns -1 if error in reading a word/number in rdata 70158782Sume * portion for update packets 71158782Sume * -2 if length of buffer passed is insufficient 72158782Sume * -3 if zone section is not the first section in 73158782Sume * the linked list, or section order has a problem 74158782Sume * -4 on a number overflow 75158782Sume * -5 unknown operation or no records 76158782Sume */ 77158782Sumeint 78158782Sumeres_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { 79158782Sume ns_updrec *rrecp_start = rrecp_in; 80158782Sume HEADER *hp; 81158782Sume u_char *cp, *sp2, *startp, *endp; 82158782Sume int n, i, soanum, multiline; 83158782Sume ns_updrec *rrecp; 84158782Sume struct in_addr ina; 85158782Sume struct in6_addr in6a; 86158782Sume char buf2[MAXDNAME]; 87158782Sume u_char buf3[MAXDNAME]; 88158782Sume int section, numrrs = 0, counts[ns_s_max]; 89158782Sume u_int16_t rtype, rclass; 90158782Sume u_int32_t n1, rttl; 91158782Sume u_char *dnptrs[20], **dpp, **lastdnptr; 92158782Sume int siglen, keylen, certlen; 93158782Sume 94158782Sume /* 95158782Sume * Initialize header fields. 96158782Sume */ 97158782Sume if ((buf == NULL) || (buflen < HFIXEDSZ)) 98158782Sume return (-1); 99158782Sume memset(buf, 0, HFIXEDSZ); 100158782Sume hp = (HEADER *) buf; 101158782Sume hp->id = htons(++statp->id); 102158782Sume hp->opcode = ns_o_update; 103158782Sume hp->rcode = NOERROR; 104158782Sume cp = buf + HFIXEDSZ; 105158782Sume buflen -= HFIXEDSZ; 106158782Sume dpp = dnptrs; 107158782Sume *dpp++ = buf; 108158782Sume *dpp++ = NULL; 109158782Sume lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; 110158782Sume 111158782Sume if (rrecp_start == NULL) 112158782Sume return (-5); 113158782Sume else if (rrecp_start->r_section != S_ZONE) 114158782Sume return (-3); 115158782Sume 116158782Sume memset(counts, 0, sizeof counts); 117158782Sume for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { 118158782Sume numrrs++; 119158782Sume section = rrecp->r_section; 120158782Sume if (section < 0 || section >= ns_s_max) 121158782Sume return (-1); 122158782Sume counts[section]++; 123158782Sume for (i = section + 1; i < ns_s_max; i++) 124158782Sume if (counts[i]) 125158782Sume return (-3); 126158782Sume rtype = rrecp->r_type; 127158782Sume rclass = rrecp->r_class; 128158782Sume rttl = rrecp->r_ttl; 129158782Sume /* overload class and type */ 130158782Sume if (section == S_PREREQ) { 131158782Sume rttl = 0; 132158782Sume switch (rrecp->r_opcode) { 133158782Sume case YXDOMAIN: 134158782Sume rclass = C_ANY; 135158782Sume rtype = T_ANY; 136158782Sume rrecp->r_size = 0; 137158782Sume break; 138158782Sume case NXDOMAIN: 139158782Sume rclass = C_NONE; 140158782Sume rtype = T_ANY; 141158782Sume rrecp->r_size = 0; 142158782Sume break; 143158782Sume case NXRRSET: 144158782Sume rclass = C_NONE; 145158782Sume rrecp->r_size = 0; 146158782Sume break; 147158782Sume case YXRRSET: 148158782Sume if (rrecp->r_size == 0) 149158782Sume rclass = C_ANY; 150158782Sume break; 151158782Sume default: 152158782Sume fprintf(stderr, 153158782Sume "res_mkupdate: incorrect opcode: %d\n", 154158782Sume rrecp->r_opcode); 155158782Sume fflush(stderr); 156158782Sume return (-1); 157158782Sume } 158158782Sume } else if (section == S_UPDATE) { 159158782Sume switch (rrecp->r_opcode) { 160158782Sume case DELETE: 161158782Sume rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; 162158782Sume break; 163158782Sume case ADD: 164158782Sume break; 165158782Sume default: 166158782Sume fprintf(stderr, 167158782Sume "res_mkupdate: incorrect opcode: %d\n", 168158782Sume rrecp->r_opcode); 169158782Sume fflush(stderr); 170158782Sume return (-1); 171158782Sume } 172158782Sume } 173158782Sume 174158782Sume /* 175158782Sume * XXX appending default domain to owner name is omitted, 176158782Sume * fqdn must be provided 177158782Sume */ 178158782Sume if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, 179158782Sume lastdnptr)) < 0) 180158782Sume return (-1); 181158782Sume cp += n; 182158782Sume ShrinkBuffer(n + 2*INT16SZ); 183158782Sume PUTSHORT(rtype, cp); 184158782Sume PUTSHORT(rclass, cp); 185158782Sume if (section == S_ZONE) { 186158782Sume if (numrrs != 1 || rrecp->r_type != T_SOA) 187158782Sume return (-3); 188158782Sume continue; 189158782Sume } 190158782Sume ShrinkBuffer(INT32SZ + INT16SZ); 191158782Sume PUTLONG(rttl, cp); 192158782Sume sp2 = cp; /* save pointer to length byte */ 193158782Sume cp += INT16SZ; 194158782Sume if (rrecp->r_size == 0) { 195158782Sume if (section == S_UPDATE && rclass != C_ANY) 196158782Sume return (-1); 197158782Sume else { 198158782Sume PUTSHORT(0, sp2); 199158782Sume continue; 200158782Sume } 201158782Sume } 202158782Sume startp = rrecp->r_data; 203158782Sume endp = startp + rrecp->r_size - 1; 204158782Sume /* XXX this should be done centrally. */ 205158782Sume switch (rrecp->r_type) { 206158782Sume case T_A: 207158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 208158782Sume return (-1); 209158782Sume if (!inet_aton(buf2, &ina)) 210158782Sume return (-1); 211158782Sume n1 = ntohl(ina.s_addr); 212158782Sume ShrinkBuffer(INT32SZ); 213158782Sume PUTLONG(n1, cp); 214158782Sume break; 215158782Sume case T_CNAME: 216158782Sume case T_MB: 217158782Sume case T_MG: 218158782Sume case T_MR: 219158782Sume case T_NS: 220158782Sume case T_PTR: 221158782Sume case ns_t_dname: 222158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 223158782Sume return (-1); 224158782Sume n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 225158782Sume if (n < 0) 226158782Sume return (-1); 227158782Sume cp += n; 228158782Sume ShrinkBuffer(n); 229158782Sume break; 230158782Sume case T_MINFO: 231158782Sume case T_SOA: 232158782Sume case T_RP: 233158782Sume for (i = 0; i < 2; i++) { 234158782Sume if (!getword_str(buf2, sizeof buf2, &startp, 235158782Sume endp)) 236158782Sume return (-1); 237158782Sume n = dn_comp(buf2, cp, buflen, 238158782Sume dnptrs, lastdnptr); 239158782Sume if (n < 0) 240158782Sume return (-1); 241158782Sume cp += n; 242158782Sume ShrinkBuffer(n); 243158782Sume } 244158782Sume if (rrecp->r_type == T_SOA) { 245158782Sume ShrinkBuffer(5 * INT32SZ); 246158782Sume while (isspace(*startp) || !*startp) 247158782Sume startp++; 248158782Sume if (*startp == '(') { 249158782Sume multiline = 1; 250158782Sume startp++; 251158782Sume } else 252158782Sume multiline = 0; 253158782Sume /* serial, refresh, retry, expire, minimum */ 254158782Sume for (i = 0; i < 5; i++) { 255158782Sume soanum = getnum_str(&startp, endp); 256158782Sume if (soanum < 0) 257158782Sume return (-1); 258158782Sume PUTLONG(soanum, cp); 259158782Sume } 260158782Sume if (multiline) { 261158782Sume while (isspace(*startp) || !*startp) 262158782Sume startp++; 263158782Sume if (*startp != ')') 264158782Sume return (-1); 265158782Sume } 266158782Sume } 267158782Sume break; 268158782Sume case T_MX: 269158782Sume case T_AFSDB: 270158782Sume case T_RT: 271158782Sume n = getnum_str(&startp, endp); 272158782Sume if (n < 0) 273158782Sume return (-1); 274158782Sume ShrinkBuffer(INT16SZ); 275158782Sume PUTSHORT(n, cp); 276158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 277158782Sume return (-1); 278158782Sume n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 279158782Sume if (n < 0) 280158782Sume return (-1); 281158782Sume cp += n; 282158782Sume ShrinkBuffer(n); 283158782Sume break; 284158782Sume case T_SRV: 285158782Sume n = getnum_str(&startp, endp); 286158782Sume if (n < 0) 287158782Sume return (-1); 288158782Sume ShrinkBuffer(INT16SZ); 289158782Sume PUTSHORT(n, cp); 290158782Sume 291158782Sume n = getnum_str(&startp, endp); 292158782Sume if (n < 0) 293158782Sume return (-1); 294158782Sume ShrinkBuffer(INT16SZ); 295158782Sume PUTSHORT(n, cp); 296158782Sume 297158782Sume n = getnum_str(&startp, endp); 298158782Sume if (n < 0) 299158782Sume return (-1); 300158782Sume ShrinkBuffer(INT16SZ); 301158782Sume PUTSHORT(n, cp); 302158782Sume 303158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 304158782Sume return (-1); 305158782Sume n = dn_comp(buf2, cp, buflen, NULL, NULL); 306158782Sume if (n < 0) 307158782Sume return (-1); 308158782Sume cp += n; 309158782Sume ShrinkBuffer(n); 310158782Sume break; 311158782Sume case T_PX: 312158782Sume n = getnum_str(&startp, endp); 313158782Sume if (n < 0) 314158782Sume return (-1); 315158782Sume PUTSHORT(n, cp); 316158782Sume ShrinkBuffer(INT16SZ); 317158782Sume for (i = 0; i < 2; i++) { 318158782Sume if (!getword_str(buf2, sizeof buf2, &startp, 319158782Sume endp)) 320158782Sume return (-1); 321158782Sume n = dn_comp(buf2, cp, buflen, dnptrs, 322158782Sume lastdnptr); 323158782Sume if (n < 0) 324158782Sume return (-1); 325158782Sume cp += n; 326158782Sume ShrinkBuffer(n); 327158782Sume } 328158782Sume break; 329158782Sume case T_WKS: { 330158782Sume char bm[MAXPORT/8]; 331158782Sume unsigned int maxbm = 0; 332158782Sume 333158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 334158782Sume return (-1); 335158782Sume if (!inet_aton(buf2, &ina)) 336158782Sume return (-1); 337158782Sume n1 = ntohl(ina.s_addr); 338158782Sume ShrinkBuffer(INT32SZ); 339158782Sume PUTLONG(n1, cp); 340158782Sume 341158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 342158782Sume return (-1); 343158782Sume if ((i = res_protocolnumber(buf2)) < 0) 344158782Sume return (-1); 345158782Sume ShrinkBuffer(1); 346158782Sume *cp++ = i & 0xff; 347158782Sume 348158782Sume for (i = 0; i < MAXPORT/8 ; i++) 349158782Sume bm[i] = 0; 350158782Sume 351158782Sume while (getword_str(buf2, sizeof buf2, &startp, endp)) { 352158782Sume if ((n = res_servicenumber(buf2)) <= 0) 353158782Sume return (-1); 354158782Sume 355158782Sume if (n < MAXPORT) { 356158782Sume bm[n/8] |= (0x80>>(n%8)); 357158782Sume if ((unsigned)n > maxbm) 358158782Sume maxbm = n; 359158782Sume } else 360158782Sume return (-1); 361158782Sume } 362158782Sume maxbm = maxbm/8 + 1; 363158782Sume ShrinkBuffer(maxbm); 364158782Sume memcpy(cp, bm, maxbm); 365158782Sume cp += maxbm; 366158782Sume break; 367158782Sume } 368158782Sume case T_HINFO: 369158782Sume for (i = 0; i < 2; i++) { 370158782Sume if ((n = getstr_str(buf2, sizeof buf2, 371158782Sume &startp, endp)) < 0) 372158782Sume return (-1); 373158782Sume if (n > 255) 374158782Sume return (-1); 375158782Sume ShrinkBuffer(n+1); 376158782Sume *cp++ = n; 377158782Sume memcpy(cp, buf2, n); 378158782Sume cp += n; 379158782Sume } 380158782Sume break; 381158782Sume case T_TXT: 382158782Sume for (;;) { 383158782Sume if ((n = getstr_str(buf2, sizeof buf2, 384158782Sume &startp, endp)) < 0) { 385158782Sume if (cp != (sp2 + INT16SZ)) 386158782Sume break; 387158782Sume return (-1); 388158782Sume } 389158782Sume if (n > 255) 390158782Sume return (-1); 391158782Sume ShrinkBuffer(n+1); 392158782Sume *cp++ = n; 393158782Sume memcpy(cp, buf2, n); 394158782Sume cp += n; 395158782Sume } 396158782Sume break; 397158782Sume case T_X25: 398158782Sume /* RFC 1183 */ 399158782Sume if ((n = getstr_str(buf2, sizeof buf2, &startp, 400158782Sume endp)) < 0) 401158782Sume return (-1); 402158782Sume if (n > 255) 403158782Sume return (-1); 404158782Sume ShrinkBuffer(n+1); 405158782Sume *cp++ = n; 406158782Sume memcpy(cp, buf2, n); 407158782Sume cp += n; 408158782Sume break; 409158782Sume case T_ISDN: 410158782Sume /* RFC 1183 */ 411158782Sume if ((n = getstr_str(buf2, sizeof buf2, &startp, 412158782Sume endp)) < 0) 413158782Sume return (-1); 414158782Sume if ((n > 255) || (n == 0)) 415158782Sume return (-1); 416158782Sume ShrinkBuffer(n+1); 417158782Sume *cp++ = n; 418158782Sume memcpy(cp, buf2, n); 419158782Sume cp += n; 420158782Sume if ((n = getstr_str(buf2, sizeof buf2, &startp, 421158782Sume endp)) < 0) 422158782Sume n = 0; 423158782Sume if (n > 255) 424158782Sume return (-1); 425158782Sume ShrinkBuffer(n+1); 426158782Sume *cp++ = n; 427158782Sume memcpy(cp, buf2, n); 428158782Sume cp += n; 429158782Sume break; 430158782Sume case T_NSAP: 431158782Sume if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { 432158782Sume ShrinkBuffer(n); 433158782Sume memcpy(cp, buf2, n); 434158782Sume cp += n; 435158782Sume } else { 436158782Sume return (-1); 437158782Sume } 438158782Sume break; 439158782Sume case T_LOC: 440158782Sume if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { 441158782Sume ShrinkBuffer(n); 442158782Sume memcpy(cp, buf2, n); 443158782Sume cp += n; 444158782Sume } else 445158782Sume return (-1); 446158782Sume break; 447158782Sume case ns_t_sig: 448158782Sume { 449158782Sume int sig_type, success, dateerror; 450158782Sume u_int32_t exptime, timesigned; 451158782Sume 452158782Sume /* type */ 453158782Sume if ((n = getword_str(buf2, sizeof buf2, 454158782Sume &startp, endp)) < 0) 455158782Sume return (-1); 456158782Sume sig_type = sym_ston(__p_type_syms, buf2, &success); 457158782Sume if (!success || sig_type == ns_t_any) 458158782Sume return (-1); 459158782Sume ShrinkBuffer(INT16SZ); 460158782Sume PUTSHORT(sig_type, cp); 461158782Sume /* alg */ 462158782Sume n = getnum_str(&startp, endp); 463158782Sume if (n < 0) 464158782Sume return (-1); 465158782Sume ShrinkBuffer(1); 466158782Sume *cp++ = n; 467158782Sume /* labels */ 468158782Sume n = getnum_str(&startp, endp); 469158782Sume if (n <= 0 || n > 255) 470158782Sume return (-1); 471158782Sume ShrinkBuffer(1); 472158782Sume *cp++ = n; 473158782Sume /* ottl & expire */ 474158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 475158782Sume return (-1); 476158782Sume exptime = ns_datetosecs(buf2, &dateerror); 477158782Sume if (!dateerror) { 478158782Sume ShrinkBuffer(INT32SZ); 479158782Sume PUTLONG(rttl, cp); 480158782Sume } 481158782Sume else { 482158782Sume char *ulendp; 483158782Sume u_int32_t ottl; 484158782Sume 485158782Sume errno = 0; 486158782Sume ottl = strtoul(buf2, &ulendp, 10); 487158782Sume if (errno != 0 || 488158782Sume (ulendp != NULL && *ulendp != '\0')) 489158782Sume return (-1); 490158782Sume ShrinkBuffer(INT32SZ); 491158782Sume PUTLONG(ottl, cp); 492158782Sume if (!getword_str(buf2, sizeof buf2, &startp, 493158782Sume endp)) 494158782Sume return (-1); 495158782Sume exptime = ns_datetosecs(buf2, &dateerror); 496158782Sume if (dateerror) 497158782Sume return (-1); 498158782Sume } 499158782Sume /* expire */ 500158782Sume ShrinkBuffer(INT32SZ); 501158782Sume PUTLONG(exptime, cp); 502158782Sume /* timesigned */ 503158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 504158782Sume return (-1); 505158782Sume timesigned = ns_datetosecs(buf2, &dateerror); 506158782Sume if (!dateerror) { 507158782Sume ShrinkBuffer(INT32SZ); 508158782Sume PUTLONG(timesigned, cp); 509158782Sume } 510158782Sume else 511158782Sume return (-1); 512158782Sume /* footprint */ 513158782Sume n = getnum_str(&startp, endp); 514158782Sume if (n < 0) 515158782Sume return (-1); 516158782Sume ShrinkBuffer(INT16SZ); 517158782Sume PUTSHORT(n, cp); 518158782Sume /* signer name */ 519158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 520158782Sume return (-1); 521158782Sume n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); 522158782Sume if (n < 0) 523158782Sume return (-1); 524158782Sume cp += n; 525158782Sume ShrinkBuffer(n); 526158782Sume /* sig */ 527158782Sume if ((n = getword_str(buf2, sizeof buf2, 528158782Sume &startp, endp)) < 0) 529158782Sume return (-1); 530158782Sume siglen = b64_pton(buf2, buf3, sizeof(buf3)); 531158782Sume if (siglen < 0) 532158782Sume return (-1); 533158782Sume ShrinkBuffer(siglen); 534158782Sume memcpy(cp, buf3, siglen); 535158782Sume cp += siglen; 536158782Sume break; 537158782Sume } 538158782Sume case ns_t_key: 539158782Sume /* flags */ 540158782Sume n = gethexnum_str(&startp, endp); 541158782Sume if (n < 0) 542158782Sume return (-1); 543158782Sume ShrinkBuffer(INT16SZ); 544158782Sume PUTSHORT(n, cp); 545158782Sume /* proto */ 546158782Sume n = getnum_str(&startp, endp); 547158782Sume if (n < 0) 548158782Sume return (-1); 549158782Sume ShrinkBuffer(1); 550158782Sume *cp++ = n; 551158782Sume /* alg */ 552158782Sume n = getnum_str(&startp, endp); 553158782Sume if (n < 0) 554158782Sume return (-1); 555158782Sume ShrinkBuffer(1); 556158782Sume *cp++ = n; 557158782Sume /* key */ 558158782Sume if ((n = getword_str(buf2, sizeof buf2, 559158782Sume &startp, endp)) < 0) 560158782Sume return (-1); 561158782Sume keylen = b64_pton(buf2, buf3, sizeof(buf3)); 562158782Sume if (keylen < 0) 563158782Sume return (-1); 564158782Sume ShrinkBuffer(keylen); 565158782Sume memcpy(cp, buf3, keylen); 566158782Sume cp += keylen; 567158782Sume break; 568158782Sume case ns_t_nxt: 569158782Sume { 570158782Sume int success, nxt_type; 571158782Sume u_char data[32]; 572158782Sume int maxtype; 573158782Sume 574158782Sume /* next name */ 575158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 576158782Sume return (-1); 577158782Sume n = dn_comp(buf2, cp, buflen, NULL, NULL); 578158782Sume if (n < 0) 579158782Sume return (-1); 580158782Sume cp += n; 581158782Sume ShrinkBuffer(n); 582158782Sume maxtype = 0; 583158782Sume memset(data, 0, sizeof data); 584158782Sume for (;;) { 585158782Sume if (!getword_str(buf2, sizeof buf2, &startp, 586158782Sume endp)) 587158782Sume break; 588158782Sume nxt_type = sym_ston(__p_type_syms, buf2, 589158782Sume &success); 590158782Sume if (!success || !ns_t_rr_p(nxt_type)) 591158782Sume return (-1); 592158782Sume NS_NXT_BIT_SET(nxt_type, data); 593158782Sume if (nxt_type > maxtype) 594158782Sume maxtype = nxt_type; 595158782Sume } 596158782Sume n = maxtype/NS_NXT_BITS+1; 597158782Sume ShrinkBuffer(n); 598158782Sume memcpy(cp, data, n); 599158782Sume cp += n; 600158782Sume break; 601158782Sume } 602158782Sume case ns_t_cert: 603158782Sume /* type */ 604158782Sume n = getnum_str(&startp, endp); 605158782Sume if (n < 0) 606158782Sume return (-1); 607158782Sume ShrinkBuffer(INT16SZ); 608158782Sume PUTSHORT(n, cp); 609158782Sume /* key tag */ 610158782Sume n = getnum_str(&startp, endp); 611158782Sume if (n < 0) 612158782Sume return (-1); 613158782Sume ShrinkBuffer(INT16SZ); 614158782Sume PUTSHORT(n, cp); 615158782Sume /* alg */ 616158782Sume n = getnum_str(&startp, endp); 617158782Sume if (n < 0) 618158782Sume return (-1); 619158782Sume ShrinkBuffer(1); 620158782Sume *cp++ = n; 621158782Sume /* cert */ 622158782Sume if ((n = getword_str(buf2, sizeof buf2, 623158782Sume &startp, endp)) < 0) 624158782Sume return (-1); 625158782Sume certlen = b64_pton(buf2, buf3, sizeof(buf3)); 626158782Sume if (certlen < 0) 627158782Sume return (-1); 628158782Sume ShrinkBuffer(certlen); 629158782Sume memcpy(cp, buf3, certlen); 630158782Sume cp += certlen; 631158782Sume break; 632158782Sume case ns_t_aaaa: 633158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 634158782Sume return (-1); 635158782Sume if (inet_pton(AF_INET6, buf2, &in6a) <= 0) 636158782Sume return (-1); 637158782Sume ShrinkBuffer(NS_IN6ADDRSZ); 638158782Sume memcpy(cp, &in6a, NS_IN6ADDRSZ); 639158782Sume cp += NS_IN6ADDRSZ; 640158782Sume break; 641158782Sume case ns_t_naptr: 642158782Sume /* Order Preference Flags Service Replacement Regexp */ 643158782Sume /* Order */ 644158782Sume n = getnum_str(&startp, endp); 645158782Sume if (n < 0 || n > 65535) 646158782Sume return (-1); 647158782Sume ShrinkBuffer(INT16SZ); 648158782Sume PUTSHORT(n, cp); 649158782Sume /* Preference */ 650158782Sume n = getnum_str(&startp, endp); 651158782Sume if (n < 0 || n > 65535) 652158782Sume return (-1); 653158782Sume ShrinkBuffer(INT16SZ); 654158782Sume PUTSHORT(n, cp); 655158782Sume /* Flags */ 656158782Sume if ((n = getstr_str(buf2, sizeof buf2, 657158782Sume &startp, endp)) < 0) { 658158782Sume return (-1); 659158782Sume } 660158782Sume if (n > 255) 661158782Sume return (-1); 662158782Sume ShrinkBuffer(n+1); 663158782Sume *cp++ = n; 664158782Sume memcpy(cp, buf2, n); 665158782Sume cp += n; 666158782Sume /* Service Classes */ 667158782Sume if ((n = getstr_str(buf2, sizeof buf2, 668158782Sume &startp, endp)) < 0) { 669158782Sume return (-1); 670158782Sume } 671158782Sume if (n > 255) 672158782Sume return (-1); 673158782Sume ShrinkBuffer(n+1); 674158782Sume *cp++ = n; 675158782Sume memcpy(cp, buf2, n); 676158782Sume cp += n; 677158782Sume /* Pattern */ 678158782Sume if ((n = getstr_str(buf2, sizeof buf2, 679158782Sume &startp, endp)) < 0) { 680158782Sume return (-1); 681158782Sume } 682158782Sume if (n > 255) 683158782Sume return (-1); 684158782Sume ShrinkBuffer(n+1); 685158782Sume *cp++ = n; 686158782Sume memcpy(cp, buf2, n); 687158782Sume cp += n; 688158782Sume /* Replacement */ 689158782Sume if (!getword_str(buf2, sizeof buf2, &startp, endp)) 690158782Sume return (-1); 691158782Sume n = dn_comp(buf2, cp, buflen, NULL, NULL); 692158782Sume if (n < 0) 693158782Sume return (-1); 694158782Sume cp += n; 695158782Sume ShrinkBuffer(n); 696158782Sume break; 697158782Sume default: 698158782Sume return (-1); 699158782Sume } /*switch*/ 700158782Sume n = (u_int16_t)((cp - sp2) - INT16SZ); 701158782Sume PUTSHORT(n, sp2); 702158782Sume } /*for*/ 703158782Sume 704158782Sume hp->qdcount = htons(counts[0]); 705158782Sume hp->ancount = htons(counts[1]); 706158782Sume hp->nscount = htons(counts[2]); 707158782Sume hp->arcount = htons(counts[3]); 708158782Sume return (cp - buf); 709158782Sume} 710158782Sume 711158782Sume/* 712158782Sume * Get a whitespace delimited word from a string (not file) 713158782Sume * into buf. modify the start pointer to point after the 714158782Sume * word in the string. 715158782Sume */ 716158782Sumestatic int 717158782Sumegetword_str(char *buf, int size, u_char **startpp, u_char *endp) { 718158782Sume char *cp; 719158782Sume int c; 720158782Sume 721158782Sume for (cp = buf; *startpp <= endp; ) { 722158782Sume c = **startpp; 723158782Sume if (isspace(c) || c == '\0') { 724158782Sume if (cp != buf) /* trailing whitespace */ 725158782Sume break; 726158782Sume else { /* leading whitespace */ 727158782Sume (*startpp)++; 728158782Sume continue; 729158782Sume } 730158782Sume } 731158782Sume (*startpp)++; 732158782Sume if (cp >= buf+size-1) 733158782Sume break; 734158782Sume *cp++ = (u_char)c; 735158782Sume } 736158782Sume *cp = '\0'; 737158782Sume return (cp != buf); 738158782Sume} 739158782Sume 740158782Sume/* 741158782Sume * get a white spae delimited string from memory. Process quoted strings 742158782Sume * and \DDD escapes. Return length or -1 on error. Returned string may 743158782Sume * contain nulls. 744158782Sume */ 745158782Sumestatic char digits[] = "0123456789"; 746158782Sumestatic int 747158782Sumegetstr_str(char *buf, int size, u_char **startpp, u_char *endp) { 748158782Sume char *cp; 749158782Sume int c, c1 = 0; 750158782Sume int inquote = 0; 751158782Sume int seen_quote = 0; 752158782Sume int escape = 0; 753158782Sume int dig = 0; 754158782Sume 755158782Sume for (cp = buf; *startpp <= endp; ) { 756158782Sume if ((c = **startpp) == '\0') 757158782Sume break; 758158782Sume /* leading white space */ 759158782Sume if ((cp == buf) && !seen_quote && isspace(c)) { 760158782Sume (*startpp)++; 761158782Sume continue; 762158782Sume } 763158782Sume 764158782Sume switch (c) { 765158782Sume case '\\': 766158782Sume if (!escape) { 767158782Sume escape = 1; 768158782Sume dig = 0; 769158782Sume c1 = 0; 770158782Sume (*startpp)++; 771158782Sume continue; 772158782Sume } 773158782Sume goto do_escape; 774158782Sume case '"': 775158782Sume if (!escape) { 776158782Sume inquote = !inquote; 777158782Sume seen_quote = 1; 778158782Sume (*startpp)++; 779158782Sume continue; 780158782Sume } 781158782Sume /* fall through */ 782158782Sume default: 783158782Sume do_escape: 784158782Sume if (escape) { 785158782Sume switch (c) { 786158782Sume case '0': 787158782Sume case '1': 788158782Sume case '2': 789158782Sume case '3': 790158782Sume case '4': 791158782Sume case '5': 792158782Sume case '6': 793158782Sume case '7': 794158782Sume case '8': 795158782Sume case '9': 796158782Sume c1 = c1 * 10 + 797158782Sume (strchr(digits, c) - digits); 798158782Sume 799158782Sume if (++dig == 3) { 800158782Sume c = c1 &0xff; 801158782Sume break; 802158782Sume } 803158782Sume (*startpp)++; 804158782Sume continue; 805158782Sume } 806158782Sume escape = 0; 807158782Sume } else if (!inquote && isspace(c)) 808158782Sume goto done; 809158782Sume if (cp >= buf+size-1) 810158782Sume goto done; 811158782Sume *cp++ = (u_char)c; 812158782Sume (*startpp)++; 813158782Sume } 814158782Sume } 815158782Sume done: 816158782Sume *cp = '\0'; 817158782Sume return ((cp == buf)? (seen_quote? 0: -1): (cp - buf)); 818158782Sume} 819158782Sume/* 820158782Sume * Get a whitespace delimited base 16 number from a string (not file) into buf 821158782Sume * update the start pointer to point after the number in the string. 822158782Sume */ 823158782Sumestatic int 824158782Sumegethexnum_str(u_char **startpp, u_char *endp) { 825158782Sume int c, n; 826158782Sume int seendigit = 0; 827158782Sume int m = 0; 828158782Sume 829158782Sume if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0) 830158782Sume return getnum_str(startpp, endp); 831158782Sume (*startpp)+=2; 832158782Sume for (n = 0; *startpp <= endp; ) { 833158782Sume c = **startpp; 834158782Sume if (isspace(c) || c == '\0') { 835158782Sume if (seendigit) /* trailing whitespace */ 836158782Sume break; 837158782Sume else { /* leading whitespace */ 838158782Sume (*startpp)++; 839158782Sume continue; 840158782Sume } 841158782Sume } 842158782Sume if (c == ';') { 843158782Sume while ((*startpp <= endp) && 844158782Sume ((c = **startpp) != '\n')) 845158782Sume (*startpp)++; 846158782Sume if (seendigit) 847158782Sume break; 848158782Sume continue; 849158782Sume } 850158782Sume if (!isxdigit(c)) { 851158782Sume if (c == ')' && seendigit) { 852158782Sume (*startpp)--; 853158782Sume break; 854158782Sume } 855158782Sume return (-1); 856158782Sume } 857158782Sume (*startpp)++; 858158782Sume if (isdigit(c)) 859158782Sume n = n * 16 + (c - '0'); 860158782Sume else 861158782Sume n = n * 16 + (tolower(c) - 'a' + 10); 862158782Sume seendigit = 1; 863158782Sume } 864158782Sume return (n + m); 865158782Sume} 866158782Sume 867158782Sume/* 868158782Sume * Get a whitespace delimited base 10 number from a string (not file) into buf 869158782Sume * update the start pointer to point after the number in the string. 870158782Sume */ 871158782Sumestatic int 872158782Sumegetnum_str(u_char **startpp, u_char *endp) { 873158782Sume int c, n; 874158782Sume int seendigit = 0; 875158782Sume int m = 0; 876158782Sume 877158782Sume for (n = 0; *startpp <= endp; ) { 878158782Sume c = **startpp; 879158782Sume if (isspace(c) || c == '\0') { 880158782Sume if (seendigit) /* trailing whitespace */ 881158782Sume break; 882158782Sume else { /* leading whitespace */ 883158782Sume (*startpp)++; 884158782Sume continue; 885158782Sume } 886158782Sume } 887158782Sume if (c == ';') { 888158782Sume while ((*startpp <= endp) && 889158782Sume ((c = **startpp) != '\n')) 890158782Sume (*startpp)++; 891158782Sume if (seendigit) 892158782Sume break; 893158782Sume continue; 894158782Sume } 895158782Sume if (!isdigit(c)) { 896158782Sume if (c == ')' && seendigit) { 897158782Sume (*startpp)--; 898158782Sume break; 899158782Sume } 900158782Sume return (-1); 901158782Sume } 902158782Sume (*startpp)++; 903158782Sume n = n * 10 + (c - '0'); 904158782Sume seendigit = 1; 905158782Sume } 906158782Sume return (n + m); 907158782Sume} 908158782Sume 909158782Sume/* 910158782Sume * Allocate a resource record buffer & save rr info. 911158782Sume */ 912158782Sumens_updrec * 913158782Sumeres_mkupdrec(int section, const char *dname, 914158782Sume u_int class, u_int type, u_long ttl) { 915158782Sume ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec)); 916158782Sume 917158782Sume if (!rrecp || !(rrecp->r_dname = strdup(dname))) { 918158782Sume if (rrecp) 919158782Sume free((char *)rrecp); 920158782Sume return (NULL); 921158782Sume } 922158782Sume INIT_LINK(rrecp, r_link); 923158782Sume INIT_LINK(rrecp, r_glink); 924158782Sume rrecp->r_class = (ns_class)class; 925158782Sume rrecp->r_type = (ns_type)type; 926158782Sume rrecp->r_ttl = ttl; 927158782Sume rrecp->r_section = (ns_sect)section; 928158782Sume return (rrecp); 929158782Sume} 930158782Sume 931158782Sume/* 932158782Sume * Free a resource record buffer created by res_mkupdrec. 933158782Sume */ 934158782Sumevoid 935158782Sumeres_freeupdrec(ns_updrec *rrecp) { 936158782Sume /* Note: freeing r_dp is the caller's responsibility. */ 937158782Sume if (rrecp->r_dname != NULL) 938158782Sume free(rrecp->r_dname); 939158782Sume free(rrecp); 940158782Sume} 941158782Sume 942158782Sumestruct valuelist { 943158782Sume struct valuelist * next; 944158782Sume struct valuelist * prev; 945158782Sume char * name; 946158782Sume char * proto; 947158782Sume int port; 948158782Sume}; 949158782Sumestatic struct valuelist *servicelist, *protolist; 950158782Sume 951158782Sumestatic void 952158782Sumeres_buildservicelist() { 953158782Sume struct servent *sp; 954158782Sume struct valuelist *slp; 955158782Sume 956158782Sume#ifdef MAYBE_HESIOD 957158782Sume setservent(0); 958158782Sume#else 959158782Sume setservent(1); 960158782Sume#endif 961158782Sume while ((sp = getservent()) != NULL) { 962158782Sume slp = (struct valuelist *)malloc(sizeof(struct valuelist)); 963158782Sume if (!slp) 964158782Sume break; 965158782Sume slp->name = strdup(sp->s_name); 966158782Sume slp->proto = strdup(sp->s_proto); 967158782Sume if ((slp->name == NULL) || (slp->proto == NULL)) { 968158782Sume if (slp->name) free(slp->name); 969158782Sume if (slp->proto) free(slp->proto); 970158782Sume free(slp); 971158782Sume break; 972158782Sume } 973158782Sume slp->port = ntohs((u_int16_t)sp->s_port); /* host byt order */ 974158782Sume slp->next = servicelist; 975158782Sume slp->prev = NULL; 976158782Sume if (servicelist) 977158782Sume servicelist->prev = slp; 978158782Sume servicelist = slp; 979158782Sume } 980158782Sume endservent(); 981158782Sume} 982158782Sume 983158782Sumevoid 984158782Sumeres_destroyservicelist() { 985158782Sume struct valuelist *slp, *slp_next; 986158782Sume 987158782Sume for (slp = servicelist; slp != NULL; slp = slp_next) { 988158782Sume slp_next = slp->next; 989158782Sume free(slp->name); 990158782Sume free(slp->proto); 991158782Sume free(slp); 992158782Sume } 993158782Sume servicelist = (struct valuelist *)0; 994158782Sume} 995158782Sume 996158782Sumevoid 997158782Sumeres_buildprotolist(void) { 998158782Sume struct protoent *pp; 999158782Sume struct valuelist *slp; 1000158782Sume 1001158782Sume#ifdef MAYBE_HESIOD 1002158782Sume setprotoent(0); 1003158782Sume#else 1004158782Sume setprotoent(1); 1005158782Sume#endif 1006158782Sume while ((pp = getprotoent()) != NULL) { 1007158782Sume slp = (struct valuelist *)malloc(sizeof(struct valuelist)); 1008158782Sume if (!slp) 1009158782Sume break; 1010158782Sume slp->name = strdup(pp->p_name); 1011158782Sume if (slp->name == NULL) { 1012158782Sume free(slp); 1013158782Sume break; 1014158782Sume } 1015158782Sume slp->port = pp->p_proto; /* host byte order */ 1016158782Sume slp->next = protolist; 1017158782Sume slp->prev = NULL; 1018158782Sume if (protolist) 1019158782Sume protolist->prev = slp; 1020158782Sume protolist = slp; 1021158782Sume } 1022158782Sume endprotoent(); 1023158782Sume} 1024158782Sume 1025158782Sumevoid 1026158782Sumeres_destroyprotolist(void) { 1027158782Sume struct valuelist *plp, *plp_next; 1028158782Sume 1029158782Sume for (plp = protolist; plp != NULL; plp = plp_next) { 1030158782Sume plp_next = plp->next; 1031158782Sume free(plp->name); 1032158782Sume free(plp); 1033158782Sume } 1034158782Sume protolist = (struct valuelist *)0; 1035158782Sume} 1036158782Sume 1037158782Sumestatic int 1038158782Sumefindservice(const char *s, struct valuelist **list) { 1039158782Sume struct valuelist *lp = *list; 1040158782Sume int n; 1041158782Sume 1042158782Sume for (; lp != NULL; lp = lp->next) 1043158782Sume if (strcasecmp(lp->name, s) == 0) { 1044158782Sume if (lp != *list) { 1045158782Sume lp->prev->next = lp->next; 1046158782Sume if (lp->next) 1047158782Sume lp->next->prev = lp->prev; 1048158782Sume (*list)->prev = lp; 1049158782Sume lp->next = *list; 1050158782Sume *list = lp; 1051158782Sume } 1052158782Sume return (lp->port); /* host byte order */ 1053158782Sume } 1054158782Sume if (sscanf(s, "%d", &n) != 1 || n <= 0) 1055158782Sume n = -1; 1056158782Sume return (n); 1057158782Sume} 1058158782Sume 1059158782Sume/* 1060158782Sume * Convert service name or (ascii) number to int. 1061158782Sume */ 1062158782Sumeint 1063158782Sumeres_servicenumber(const char *p) { 1064158782Sume if (servicelist == (struct valuelist *)0) 1065158782Sume res_buildservicelist(); 1066158782Sume return (findservice(p, &servicelist)); 1067158782Sume} 1068158782Sume 1069158782Sume/* 1070158782Sume * Convert protocol name or (ascii) number to int. 1071158782Sume */ 1072158782Sumeint 1073158782Sumeres_protocolnumber(const char *p) { 1074158782Sume if (protolist == (struct valuelist *)0) 1075158782Sume res_buildprotolist(); 1076158782Sume return (findservice(p, &protolist)); 1077158782Sume} 1078158782Sume 1079158782Sumestatic struct servent * 1080158782Sumecgetservbyport(u_int16_t port, const char *proto) { /* Host byte order. */ 1081158782Sume struct valuelist **list = &servicelist; 1082158782Sume struct valuelist *lp = *list; 1083158782Sume static struct servent serv; 1084158782Sume 1085158782Sume port = ntohs(port); 1086158782Sume for (; lp != NULL; lp = lp->next) { 1087158782Sume if (port != (u_int16_t)lp->port) /* Host byte order. */ 1088158782Sume continue; 1089158782Sume if (strcasecmp(lp->proto, proto) == 0) { 1090158782Sume if (lp != *list) { 1091158782Sume lp->prev->next = lp->next; 1092158782Sume if (lp->next) 1093158782Sume lp->next->prev = lp->prev; 1094158782Sume (*list)->prev = lp; 1095158782Sume lp->next = *list; 1096158782Sume *list = lp; 1097158782Sume } 1098158782Sume serv.s_name = lp->name; 1099158782Sume serv.s_port = htons((u_int16_t)lp->port); 1100158782Sume serv.s_proto = lp->proto; 1101158782Sume return (&serv); 1102158782Sume } 1103158782Sume } 1104158782Sume return (0); 1105158782Sume} 1106158782Sume 1107158782Sumestatic struct protoent * 1108158782Sumecgetprotobynumber(int proto) { /* Host byte order. */ 1109158782Sume struct valuelist **list = &protolist; 1110158782Sume struct valuelist *lp = *list; 1111158782Sume static struct protoent prot; 1112158782Sume 1113158782Sume for (; lp != NULL; lp = lp->next) 1114158782Sume if (lp->port == proto) { /* Host byte order. */ 1115158782Sume if (lp != *list) { 1116158782Sume lp->prev->next = lp->next; 1117158782Sume if (lp->next) 1118158782Sume lp->next->prev = lp->prev; 1119158782Sume (*list)->prev = lp; 1120158782Sume lp->next = *list; 1121158782Sume *list = lp; 1122158782Sume } 1123158782Sume prot.p_name = lp->name; 1124158782Sume prot.p_proto = lp->port; /* Host byte order. */ 1125158782Sume return (&prot); 1126158782Sume } 1127158782Sume return (0); 1128158782Sume} 1129158782Sume 1130158782Sumeconst char * 1131158782Sumeres_protocolname(int num) { 1132158782Sume static char number[8]; 1133158782Sume struct protoent *pp; 1134158782Sume 1135158782Sume if (protolist == (struct valuelist *)0) 1136158782Sume res_buildprotolist(); 1137158782Sume pp = cgetprotobynumber(num); 1138158782Sume if (pp == 0) { 1139158782Sume (void) sprintf(number, "%d", num); 1140158782Sume return (number); 1141158782Sume } 1142158782Sume return (pp->p_name); 1143158782Sume} 1144158782Sume 1145158782Sumeconst char * 1146158782Sumeres_servicename(u_int16_t port, const char *proto) { /* Host byte order. */ 1147158782Sume static char number[8]; 1148158782Sume struct servent *ss; 1149158782Sume 1150158782Sume if (servicelist == (struct valuelist *)0) 1151158782Sume res_buildservicelist(); 1152158782Sume ss = cgetservbyport(htons(port), proto); 1153158782Sume if (ss == 0) { 1154158782Sume (void) sprintf(number, "%d", port); 1155158782Sume return (number); 1156158782Sume } 1157158782Sume return (ss->s_name); 1158158782Sume} 1159