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