1224090Sdougb/* 2262706Serwin * Copyright (C) 2009, 2010, 2012-2014 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id: sample-update.c,v 1.10 2010/12/09 00:54:34 marka Exp $ */ 18224090Sdougb 19224090Sdougb#include <config.h> 20224090Sdougb 21224090Sdougb#include <sys/types.h> 22224090Sdougb#include <sys/socket.h> 23224090Sdougb 24224090Sdougb#include <netinet/in.h> 25224090Sdougb 26224090Sdougb#include <arpa/inet.h> 27224090Sdougb 28224090Sdougb#include <unistd.h> 29224090Sdougb#include <ctype.h> 30224090Sdougb#include <stdio.h> 31224090Sdougb#include <stdlib.h> 32224090Sdougb#include <string.h> 33224090Sdougb#include <netdb.h> 34224090Sdougb 35224090Sdougb#include <isc/buffer.h> 36224090Sdougb#include <isc/lex.h> 37224090Sdougb#include <isc/lib.h> 38224090Sdougb#include <isc/mem.h> 39224090Sdougb#include <isc/parseint.h> 40224090Sdougb#include <isc/sockaddr.h> 41224090Sdougb#include <isc/util.h> 42224090Sdougb 43224090Sdougb#include <dns/callbacks.h> 44224090Sdougb#include <dns/client.h> 45224090Sdougb#include <dns/fixedname.h> 46224090Sdougb#include <dns/lib.h> 47224090Sdougb#include <dns/name.h> 48224090Sdougb#include <dns/rdata.h> 49224090Sdougb#include <dns/rdataclass.h> 50224090Sdougb#include <dns/rdatalist.h> 51224090Sdougb#include <dns/rdataset.h> 52224090Sdougb#include <dns/rdatastruct.h> 53224090Sdougb#include <dns/rdatatype.h> 54224090Sdougb#include <dns/result.h> 55224090Sdougb#include <dns/secalg.h> 56224090Sdougb#include <dns/tsec.h> 57224090Sdougb 58224090Sdougb#include <dst/dst.h> 59224090Sdougb 60224090Sdougbstatic dns_tsec_t *tsec = NULL; 61224090Sdougbstatic const dns_rdataclass_t default_rdataclass = dns_rdataclass_in; 62224090Sdougbstatic isc_bufferlist_t usedbuffers; 63224090Sdougbstatic ISC_LIST(dns_rdatalist_t) usedrdatalists; 64224090Sdougb 65224090Sdougbstatic void setup_tsec(char *keyfile, isc_mem_t *mctx); 66224090Sdougbstatic void update_addordelete(isc_mem_t *mctx, char *cmdline, 67224090Sdougb isc_boolean_t isdelete, dns_name_t *name); 68224090Sdougbstatic void evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name); 69224090Sdougb 70224090SdougbISC_PLATFORM_NORETURN_PRE static void 71224090Sdougbusage(void) ISC_PLATFORM_NORETURN_POST; 72224090Sdougb 73224090Sdougbstatic void 74224090Sdougbusage(void) { 75224090Sdougb fprintf(stderr, "sample-update " 76224090Sdougb "[-a auth_server] " 77224090Sdougb "[-k keyfile] " 78224090Sdougb "[-p prerequisite] " 79224090Sdougb "[-r recursive_server] " 80224090Sdougb "[-z zonename] " 81224090Sdougb "(add|delete) \"name TTL RRtype RDATA\"\n"); 82224090Sdougb exit(1); 83224090Sdougb} 84224090Sdougb 85224090Sdougbint 86224090Sdougbmain(int argc, char *argv[]) { 87224090Sdougb int ch; 88224090Sdougb struct addrinfo hints, *res; 89224090Sdougb int gai_error; 90224090Sdougb dns_client_t *client = NULL; 91224090Sdougb char *zonenamestr = NULL; 92224090Sdougb char *keyfilename = NULL; 93224090Sdougb char *prereqstr = NULL; 94224090Sdougb isc_sockaddrlist_t auth_servers; 95224090Sdougb char *auth_server = NULL; 96224090Sdougb char *recursive_server = NULL; 97224090Sdougb isc_sockaddr_t sa_auth, sa_recursive; 98224090Sdougb isc_sockaddrlist_t rec_servers; 99224090Sdougb isc_result_t result; 100224090Sdougb isc_boolean_t isdelete; 101224090Sdougb isc_buffer_t b, *buf; 102224090Sdougb dns_fixedname_t zname0, pname0, uname0; 103224090Sdougb size_t namelen; 104224090Sdougb dns_name_t *zname = NULL, *uname, *pname; 105224090Sdougb dns_rdataset_t *rdataset; 106224090Sdougb dns_rdatalist_t *rdatalist; 107224090Sdougb dns_rdata_t *rdata; 108224090Sdougb dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL; 109224090Sdougb isc_mem_t *umctx = NULL; 110224090Sdougb 111224090Sdougb while ((ch = getopt(argc, argv, "a:k:p:r:z:")) != -1) { 112224090Sdougb switch (ch) { 113224090Sdougb case 'k': 114224090Sdougb keyfilename = optarg; 115224090Sdougb break; 116224090Sdougb case 'a': 117224090Sdougb auth_server = optarg; 118224090Sdougb break; 119224090Sdougb case 'p': 120224090Sdougb prereqstr = optarg; 121224090Sdougb break; 122224090Sdougb case 'r': 123224090Sdougb recursive_server = optarg; 124224090Sdougb break; 125224090Sdougb case 'z': 126224090Sdougb zonenamestr = optarg; 127224090Sdougb break; 128224090Sdougb default: 129224090Sdougb usage(); 130224090Sdougb } 131224090Sdougb } 132224090Sdougb 133224090Sdougb argc -= optind; 134224090Sdougb argv += optind; 135224090Sdougb if (argc < 2) 136224090Sdougb usage(); 137224090Sdougb 138224090Sdougb /* command line argument validation */ 139224090Sdougb if (strcmp(argv[0], "delete") == 0) 140224090Sdougb isdelete = ISC_TRUE; 141224090Sdougb else if (strcmp(argv[0], "add") == 0) 142224090Sdougb isdelete = ISC_FALSE; 143224090Sdougb else { 144224090Sdougb fprintf(stderr, "invalid update command: %s\n", argv[0]); 145224090Sdougb exit(1); 146224090Sdougb } 147224090Sdougb 148224090Sdougb if (auth_server == NULL && recursive_server == NULL) { 149224090Sdougb fprintf(stderr, "authoritative or recursive server " 150224090Sdougb "must be specified\n"); 151224090Sdougb usage(); 152224090Sdougb } 153224090Sdougb 154224090Sdougb /* Initialization */ 155224090Sdougb ISC_LIST_INIT(usedbuffers); 156224090Sdougb ISC_LIST_INIT(usedrdatalists); 157224090Sdougb ISC_LIST_INIT(prereqlist); 158224090Sdougb ISC_LIST_INIT(auth_servers); 159224090Sdougb isc_lib_register(); 160224090Sdougb result = dns_lib_init(); 161224090Sdougb if (result != ISC_R_SUCCESS) { 162224090Sdougb fprintf(stderr, "dns_lib_init failed: %d\n", result); 163224090Sdougb exit(1); 164224090Sdougb } 165224090Sdougb result = isc_mem_create(0, 0, &umctx); 166224090Sdougb if (result != ISC_R_SUCCESS) { 167224090Sdougb fprintf(stderr, "failed to crate mctx\n"); 168224090Sdougb exit(1); 169224090Sdougb } 170224090Sdougb 171224090Sdougb result = dns_client_create(&client, 0); 172224090Sdougb if (result != ISC_R_SUCCESS) { 173224090Sdougb fprintf(stderr, "dns_client_create failed: %d\n", result); 174224090Sdougb exit(1); 175224090Sdougb } 176224090Sdougb 177224090Sdougb /* Set the authoritative server */ 178224090Sdougb if (auth_server != NULL) { 179224090Sdougb memset(&hints, 0, sizeof(hints)); 180224090Sdougb hints.ai_family = AF_UNSPEC; 181224090Sdougb hints.ai_socktype = SOCK_DGRAM; 182224090Sdougb hints.ai_protocol = IPPROTO_UDP; 183224090Sdougb hints.ai_flags = AI_NUMERICHOST; 184224090Sdougb gai_error = getaddrinfo(auth_server, "53", &hints, &res); 185224090Sdougb if (gai_error != 0) { 186224090Sdougb fprintf(stderr, "getaddrinfo failed: %s\n", 187224090Sdougb gai_strerror(gai_error)); 188224090Sdougb exit(1); 189224090Sdougb } 190224090Sdougb INSIST(res->ai_addrlen <= sizeof(sa_auth.type)); 191262706Serwin memmove(&sa_auth.type, res->ai_addr, res->ai_addrlen); 192224090Sdougb freeaddrinfo(res); 193224090Sdougb sa_auth.length = res->ai_addrlen; 194224090Sdougb ISC_LINK_INIT(&sa_auth, link); 195224090Sdougb 196224090Sdougb ISC_LIST_APPEND(auth_servers, &sa_auth, link); 197224090Sdougb } 198224090Sdougb 199224090Sdougb /* Set the recursive server */ 200224090Sdougb if (recursive_server != NULL) { 201224090Sdougb memset(&hints, 0, sizeof(hints)); 202224090Sdougb hints.ai_family = AF_UNSPEC; 203224090Sdougb hints.ai_socktype = SOCK_DGRAM; 204224090Sdougb hints.ai_protocol = IPPROTO_UDP; 205224090Sdougb hints.ai_flags = AI_NUMERICHOST; 206224090Sdougb gai_error = getaddrinfo(recursive_server, "53", &hints, &res); 207224090Sdougb if (gai_error != 0) { 208224090Sdougb fprintf(stderr, "getaddrinfo failed: %s\n", 209224090Sdougb gai_strerror(gai_error)); 210224090Sdougb exit(1); 211224090Sdougb } 212224090Sdougb INSIST(res->ai_addrlen <= sizeof(sa_recursive.type)); 213262706Serwin memmove(&sa_recursive.type, res->ai_addr, res->ai_addrlen); 214224090Sdougb freeaddrinfo(res); 215224090Sdougb sa_recursive.length = res->ai_addrlen; 216224090Sdougb ISC_LINK_INIT(&sa_recursive, link); 217224090Sdougb ISC_LIST_INIT(rec_servers); 218224090Sdougb ISC_LIST_APPEND(rec_servers, &sa_recursive, link); 219224090Sdougb result = dns_client_setservers(client, dns_rdataclass_in, 220224090Sdougb NULL, &rec_servers); 221224090Sdougb if (result != ISC_R_SUCCESS) { 222224090Sdougb fprintf(stderr, "set server failed: %d\n", result); 223224090Sdougb exit(1); 224224090Sdougb } 225224090Sdougb } 226224090Sdougb 227224090Sdougb /* Construct zone name */ 228224090Sdougb zname = NULL; 229224090Sdougb if (zonenamestr != NULL) { 230224090Sdougb namelen = strlen(zonenamestr); 231224090Sdougb isc_buffer_init(&b, zonenamestr, namelen); 232224090Sdougb isc_buffer_add(&b, namelen); 233224090Sdougb dns_fixedname_init(&zname0); 234224090Sdougb zname = dns_fixedname_name(&zname0); 235224090Sdougb result = dns_name_fromtext(zname, &b, dns_rootname, 0, NULL); 236224090Sdougb if (result != ISC_R_SUCCESS) 237224090Sdougb fprintf(stderr, "failed to convert zone name: %d\n", 238224090Sdougb result); 239224090Sdougb } 240224090Sdougb 241224090Sdougb /* Construct prerequisite name (if given) */ 242224090Sdougb if (prereqstr != NULL) { 243224090Sdougb dns_fixedname_init(&pname0); 244224090Sdougb pname = dns_fixedname_name(&pname0); 245224090Sdougb evaluate_prereq(umctx, prereqstr, pname); 246224090Sdougb ISC_LIST_APPEND(prereqlist, pname, link); 247224090Sdougb prereqlistp = &prereqlist; 248224090Sdougb } 249224090Sdougb 250224090Sdougb /* Construct update name */ 251224090Sdougb ISC_LIST_INIT(updatelist); 252224090Sdougb dns_fixedname_init(&uname0); 253224090Sdougb uname = dns_fixedname_name(&uname0); 254224090Sdougb update_addordelete(umctx, argv[1], isdelete, uname); 255224090Sdougb ISC_LIST_APPEND(updatelist, uname, link); 256224090Sdougb 257224090Sdougb /* Set up TSIG/SIG(0) key (if given) */ 258224090Sdougb if (keyfilename != NULL) 259224090Sdougb setup_tsec(keyfilename, umctx); 260224090Sdougb 261224090Sdougb /* Perform update */ 262224090Sdougb result = dns_client_update(client, 263224090Sdougb default_rdataclass, /* XXX: fixed */ 264224090Sdougb zname, prereqlistp, &updatelist, 265224090Sdougb (auth_server == NULL) ? NULL : 266224090Sdougb &auth_servers, tsec, 0); 267224090Sdougb if (result != ISC_R_SUCCESS) { 268224090Sdougb fprintf(stderr, 269224090Sdougb "update failed: %s\n", dns_result_totext(result)); 270224090Sdougb } else 271224090Sdougb fprintf(stderr, "update succeeded\n"); 272224090Sdougb 273224090Sdougb /* Cleanup */ 274224090Sdougb while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) { 275224090Sdougb while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) { 276224090Sdougb ISC_LIST_UNLINK(pname->list, rdataset, link); 277224090Sdougb dns_rdataset_disassociate(rdataset); 278224090Sdougb isc_mem_put(umctx, rdataset, sizeof(*rdataset)); 279224090Sdougb } 280224090Sdougb ISC_LIST_UNLINK(prereqlist, pname, link); 281224090Sdougb } 282224090Sdougb while ((uname = ISC_LIST_HEAD(updatelist)) != NULL) { 283224090Sdougb while ((rdataset = ISC_LIST_HEAD(uname->list)) != NULL) { 284224090Sdougb ISC_LIST_UNLINK(uname->list, rdataset, link); 285224090Sdougb dns_rdataset_disassociate(rdataset); 286224090Sdougb isc_mem_put(umctx, rdataset, sizeof(*rdataset)); 287224090Sdougb } 288224090Sdougb ISC_LIST_UNLINK(updatelist, uname, link); 289224090Sdougb } 290224090Sdougb while ((rdatalist = ISC_LIST_HEAD(usedrdatalists)) != NULL) { 291224090Sdougb while ((rdata = ISC_LIST_HEAD(rdatalist->rdata)) != NULL) { 292224090Sdougb ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); 293224090Sdougb isc_mem_put(umctx, rdata, sizeof(*rdata)); 294224090Sdougb } 295224090Sdougb ISC_LIST_UNLINK(usedrdatalists, rdatalist, link); 296224090Sdougb isc_mem_put(umctx, rdatalist, sizeof(*rdatalist)); 297224090Sdougb } 298224090Sdougb while ((buf = ISC_LIST_HEAD(usedbuffers)) != NULL) { 299224090Sdougb ISC_LIST_UNLINK(usedbuffers, buf, link); 300224090Sdougb isc_buffer_free(&buf); 301224090Sdougb } 302224090Sdougb if (tsec != NULL) 303224090Sdougb dns_tsec_destroy(&tsec); 304224090Sdougb isc_mem_destroy(&umctx); 305224090Sdougb dns_client_destroy(&client); 306224090Sdougb dns_lib_shutdown(); 307224090Sdougb 308254402Serwin return (0); 309224090Sdougb} 310224090Sdougb 311224090Sdougb/* 312224090Sdougb * Subroutines borrowed from nsupdate.c 313224090Sdougb */ 314224090Sdougb#define MAXWIRE (64 * 1024) 315224090Sdougb#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */ 316224090Sdougb 317224090Sdougbstatic char * 318224090Sdougbnsu_strsep(char **stringp, const char *delim) { 319224090Sdougb char *string = *stringp; 320224090Sdougb char *s; 321224090Sdougb const char *d; 322224090Sdougb char sc, dc; 323224090Sdougb 324224090Sdougb if (string == NULL) 325224090Sdougb return (NULL); 326224090Sdougb 327224090Sdougb for (; *string != '\0'; string++) { 328224090Sdougb sc = *string; 329224090Sdougb for (d = delim; (dc = *d) != '\0'; d++) { 330224090Sdougb if (sc == dc) 331224090Sdougb break; 332224090Sdougb } 333224090Sdougb if (dc == 0) 334224090Sdougb break; 335224090Sdougb } 336224090Sdougb 337224090Sdougb for (s = string; *s != '\0'; s++) { 338224090Sdougb sc = *s; 339224090Sdougb for (d = delim; (dc = *d) != '\0'; d++) { 340224090Sdougb if (sc == dc) { 341224090Sdougb *s++ = '\0'; 342224090Sdougb *stringp = s; 343224090Sdougb return (string); 344224090Sdougb } 345224090Sdougb } 346224090Sdougb } 347224090Sdougb *stringp = NULL; 348224090Sdougb return (string); 349224090Sdougb} 350224090Sdougb 351224090Sdougbstatic void 352224090Sdougbfatal(const char *format, ...) { 353224090Sdougb va_list args; 354224090Sdougb 355224090Sdougb va_start(args, format); 356224090Sdougb vfprintf(stderr, format, args); 357224090Sdougb va_end(args); 358224090Sdougb fprintf(stderr, "\n"); 359224090Sdougb exit(1); 360224090Sdougb} 361224090Sdougb 362224090Sdougbstatic inline void 363224090Sdougbcheck_result(isc_result_t result, const char *msg) { 364224090Sdougb if (result != ISC_R_SUCCESS) 365224090Sdougb fatal("%s: %s", msg, isc_result_totext(result)); 366224090Sdougb} 367224090Sdougb 368224090Sdougbstatic void 369224090Sdougbparse_name(char **cmdlinep, dns_name_t *name) { 370224090Sdougb isc_result_t result; 371224090Sdougb char *word; 372224090Sdougb isc_buffer_t source; 373224090Sdougb 374224090Sdougb word = nsu_strsep(cmdlinep, " \t\r\n"); 375254402Serwin if (word == NULL || *word == 0) { 376224090Sdougb fprintf(stderr, "could not read owner name\n"); 377224090Sdougb exit(1); 378224090Sdougb } 379224090Sdougb 380224090Sdougb isc_buffer_init(&source, word, strlen(word)); 381224090Sdougb isc_buffer_add(&source, strlen(word)); 382224090Sdougb result = dns_name_fromtext(name, &source, dns_rootname, 0, NULL); 383224090Sdougb check_result(result, "dns_name_fromtext"); 384224090Sdougb isc_buffer_invalidate(&source); 385224090Sdougb} 386224090Sdougb 387224090Sdougbstatic void 388224090Sdougbparse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass, 389224090Sdougb dns_rdatatype_t rdatatype, dns_rdata_t *rdata) 390224090Sdougb{ 391224090Sdougb char *cmdline = *cmdlinep; 392224090Sdougb isc_buffer_t source, *buf = NULL, *newbuf = NULL; 393224090Sdougb isc_region_t r; 394224090Sdougb isc_lex_t *lex = NULL; 395224090Sdougb dns_rdatacallbacks_t callbacks; 396224090Sdougb isc_result_t result; 397224090Sdougb 398224090Sdougb while (cmdline != NULL && *cmdline != 0 && 399224090Sdougb isspace((unsigned char)*cmdline)) 400224090Sdougb cmdline++; 401224090Sdougb 402224090Sdougb if (cmdline != NULL && *cmdline != 0) { 403224090Sdougb dns_rdatacallbacks_init(&callbacks); 404224090Sdougb result = isc_lex_create(mctx, strlen(cmdline), &lex); 405224090Sdougb check_result(result, "isc_lex_create"); 406224090Sdougb isc_buffer_init(&source, cmdline, strlen(cmdline)); 407224090Sdougb isc_buffer_add(&source, strlen(cmdline)); 408224090Sdougb result = isc_lex_openbuffer(lex, &source); 409224090Sdougb check_result(result, "isc_lex_openbuffer"); 410224090Sdougb result = isc_buffer_allocate(mctx, &buf, MAXWIRE); 411224090Sdougb check_result(result, "isc_buffer_allocate"); 412224090Sdougb result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex, 413224090Sdougb dns_rootname, 0, mctx, buf, 414224090Sdougb &callbacks); 415224090Sdougb isc_lex_destroy(&lex); 416224090Sdougb if (result == ISC_R_SUCCESS) { 417224090Sdougb isc_buffer_usedregion(buf, &r); 418224090Sdougb result = isc_buffer_allocate(mctx, &newbuf, r.length); 419224090Sdougb check_result(result, "isc_buffer_allocate"); 420224090Sdougb isc_buffer_putmem(newbuf, r.base, r.length); 421224090Sdougb isc_buffer_usedregion(newbuf, &r); 422224090Sdougb dns_rdata_reset(rdata); 423224090Sdougb dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r); 424224090Sdougb isc_buffer_free(&buf); 425224090Sdougb ISC_LIST_APPEND(usedbuffers, newbuf, link); 426224090Sdougb } else { 427224090Sdougb fprintf(stderr, "invalid rdata format: %s\n", 428224090Sdougb isc_result_totext(result)); 429224090Sdougb isc_buffer_free(&buf); 430224090Sdougb exit(1); 431224090Sdougb } 432224090Sdougb } else { 433224090Sdougb rdata->flags = DNS_RDATA_UPDATE; 434224090Sdougb } 435224090Sdougb *cmdlinep = cmdline; 436224090Sdougb} 437224090Sdougb 438224090Sdougbstatic void 439224090Sdougbupdate_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete, 440224090Sdougb dns_name_t *name) 441224090Sdougb{ 442224090Sdougb isc_result_t result; 443224090Sdougb isc_uint32_t ttl; 444224090Sdougb char *word; 445224090Sdougb dns_rdataclass_t rdataclass; 446224090Sdougb dns_rdatatype_t rdatatype; 447224090Sdougb dns_rdata_t *rdata = NULL; 448224090Sdougb dns_rdatalist_t *rdatalist = NULL; 449224090Sdougb dns_rdataset_t *rdataset = NULL; 450224090Sdougb isc_textregion_t region; 451224090Sdougb 452224090Sdougb /* 453224090Sdougb * Read the owner name. 454224090Sdougb */ 455224090Sdougb parse_name(&cmdline, name); 456224090Sdougb 457224090Sdougb rdata = isc_mem_get(mctx, sizeof(*rdata)); 458224090Sdougb if (rdata == NULL) { 459224090Sdougb fprintf(stderr, "memory allocation for rdata failed\n"); 460224090Sdougb exit(1); 461224090Sdougb } 462224090Sdougb dns_rdata_init(rdata); 463224090Sdougb 464224090Sdougb /* 465224090Sdougb * If this is an add, read the TTL and verify that it's in range. 466224090Sdougb * If it's a delete, ignore a TTL if present (for compatibility). 467224090Sdougb */ 468224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 469224090Sdougb if (word == NULL || *word == 0) { 470224090Sdougb if (!isdelete) { 471224090Sdougb fprintf(stderr, "could not read owner ttl\n"); 472224090Sdougb exit(1); 473224090Sdougb } 474224090Sdougb else { 475224090Sdougb ttl = 0; 476224090Sdougb rdataclass = dns_rdataclass_any; 477224090Sdougb rdatatype = dns_rdatatype_any; 478224090Sdougb rdata->flags = DNS_RDATA_UPDATE; 479224090Sdougb goto doneparsing; 480224090Sdougb } 481224090Sdougb } 482224090Sdougb result = isc_parse_uint32(&ttl, word, 10); 483224090Sdougb if (result != ISC_R_SUCCESS) { 484224090Sdougb if (isdelete) { 485224090Sdougb ttl = 0; 486224090Sdougb goto parseclass; 487224090Sdougb } else { 488224090Sdougb fprintf(stderr, "ttl '%s': %s\n", word, 489224090Sdougb isc_result_totext(result)); 490224090Sdougb exit(1); 491224090Sdougb } 492224090Sdougb } 493224090Sdougb 494224090Sdougb if (isdelete) 495224090Sdougb ttl = 0; 496224090Sdougb else if (ttl > TTL_MAX) { 497224090Sdougb fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n", 498224090Sdougb word, TTL_MAX); 499224090Sdougb exit(1); 500224090Sdougb } 501224090Sdougb 502224090Sdougb /* 503224090Sdougb * Read the class or type. 504224090Sdougb */ 505224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 506224090Sdougb parseclass: 507224090Sdougb if (word == NULL || *word == 0) { 508224090Sdougb if (isdelete) { 509224090Sdougb rdataclass = dns_rdataclass_any; 510224090Sdougb rdatatype = dns_rdatatype_any; 511224090Sdougb rdata->flags = DNS_RDATA_UPDATE; 512224090Sdougb goto doneparsing; 513224090Sdougb } else { 514224090Sdougb fprintf(stderr, "could not read class or type\n"); 515224090Sdougb exit(1); 516224090Sdougb } 517224090Sdougb } 518224090Sdougb region.base = word; 519224090Sdougb region.length = strlen(word); 520224090Sdougb result = dns_rdataclass_fromtext(&rdataclass, ®ion); 521224090Sdougb if (result == ISC_R_SUCCESS) { 522224090Sdougb /* 523224090Sdougb * Now read the type. 524224090Sdougb */ 525224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 526224090Sdougb if (word == NULL || *word == 0) { 527224090Sdougb if (isdelete) { 528224090Sdougb rdataclass = dns_rdataclass_any; 529224090Sdougb rdatatype = dns_rdatatype_any; 530224090Sdougb rdata->flags = DNS_RDATA_UPDATE; 531224090Sdougb goto doneparsing; 532224090Sdougb } else { 533224090Sdougb fprintf(stderr, "could not read type\n"); 534224090Sdougb exit(1); 535224090Sdougb } 536224090Sdougb } 537224090Sdougb region.base = word; 538224090Sdougb region.length = strlen(word); 539224090Sdougb result = dns_rdatatype_fromtext(&rdatatype, ®ion); 540224090Sdougb if (result != ISC_R_SUCCESS) { 541224090Sdougb fprintf(stderr, "'%s' is not a valid type: %s\n", 542224090Sdougb word, isc_result_totext(result)); 543224090Sdougb exit(1); 544224090Sdougb } 545224090Sdougb } else { 546224090Sdougb rdataclass = default_rdataclass; 547224090Sdougb result = dns_rdatatype_fromtext(&rdatatype, ®ion); 548224090Sdougb if (result != ISC_R_SUCCESS) { 549224090Sdougb fprintf(stderr, "'%s' is not a valid class or type: " 550224090Sdougb "%s\n", word, isc_result_totext(result)); 551224090Sdougb exit(1); 552224090Sdougb } 553224090Sdougb } 554224090Sdougb 555224090Sdougb parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata); 556224090Sdougb 557224090Sdougb if (isdelete) { 558224090Sdougb if ((rdata->flags & DNS_RDATA_UPDATE) != 0) 559224090Sdougb rdataclass = dns_rdataclass_any; 560224090Sdougb else 561224090Sdougb rdataclass = dns_rdataclass_none; 562224090Sdougb } else { 563224090Sdougb if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 564224090Sdougb fprintf(stderr, "could not read rdata\n"); 565224090Sdougb exit(1); 566224090Sdougb } 567224090Sdougb } 568224090Sdougb 569224090Sdougb doneparsing: 570224090Sdougb 571224090Sdougb rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); 572224090Sdougb if (rdatalist == NULL) { 573224090Sdougb fprintf(stderr, "memory allocation for rdatalist failed\n"); 574224090Sdougb exit(1); 575224090Sdougb } 576224090Sdougb dns_rdatalist_init(rdatalist); 577224090Sdougb rdatalist->type = rdatatype; 578224090Sdougb rdatalist->rdclass = rdataclass; 579224090Sdougb rdatalist->covers = rdatatype; 580224090Sdougb rdatalist->ttl = (dns_ttl_t)ttl; 581224090Sdougb ISC_LIST_INIT(rdatalist->rdata); 582224090Sdougb ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 583224090Sdougb ISC_LIST_APPEND(usedrdatalists, rdatalist, link); 584224090Sdougb 585224090Sdougb rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 586224090Sdougb if (rdataset == NULL) { 587224090Sdougb fprintf(stderr, "memory allocation for rdataset failed\n"); 588224090Sdougb exit(1); 589224090Sdougb } 590224090Sdougb dns_rdataset_init(rdataset); 591224090Sdougb dns_rdatalist_tordataset(rdatalist, rdataset); 592224090Sdougb ISC_LIST_INIT(name->list); 593224090Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 594224090Sdougb} 595224090Sdougb 596224090Sdougbstatic void 597224090Sdougbmake_prereq(isc_mem_t *mctx, char *cmdline, isc_boolean_t ispositive, 598224090Sdougb isc_boolean_t isrrset, dns_name_t *name) 599224090Sdougb{ 600224090Sdougb isc_result_t result; 601224090Sdougb char *word; 602224090Sdougb isc_textregion_t region; 603224090Sdougb dns_rdataset_t *rdataset = NULL; 604224090Sdougb dns_rdatalist_t *rdatalist = NULL; 605224090Sdougb dns_rdataclass_t rdataclass; 606224090Sdougb dns_rdatatype_t rdatatype; 607224090Sdougb dns_rdata_t *rdata = NULL; 608224090Sdougb 609224090Sdougb /* 610224090Sdougb * Read the owner name 611224090Sdougb */ 612224090Sdougb parse_name(&cmdline, name); 613224090Sdougb 614224090Sdougb /* 615224090Sdougb * If this is an rrset prereq, read the class or type. 616224090Sdougb */ 617224090Sdougb if (isrrset) { 618224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 619224090Sdougb if (word == NULL || *word == 0) { 620224090Sdougb fprintf(stderr, "could not read class or type\n"); 621224090Sdougb exit(1); 622224090Sdougb } 623224090Sdougb region.base = word; 624224090Sdougb region.length = strlen(word); 625224090Sdougb result = dns_rdataclass_fromtext(&rdataclass, ®ion); 626224090Sdougb if (result == ISC_R_SUCCESS) { 627224090Sdougb /* 628224090Sdougb * Now read the type. 629224090Sdougb */ 630224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 631224090Sdougb if (word == NULL || *word == 0) { 632224090Sdougb fprintf(stderr, "could not read type\n"); 633224090Sdougb exit(1); 634224090Sdougb } 635224090Sdougb region.base = word; 636224090Sdougb region.length = strlen(word); 637224090Sdougb result = dns_rdatatype_fromtext(&rdatatype, ®ion); 638224090Sdougb if (result != ISC_R_SUCCESS) { 639224090Sdougb fprintf(stderr, "invalid type: %s\n", word); 640224090Sdougb exit(1); 641224090Sdougb } 642224090Sdougb } else { 643224090Sdougb rdataclass = default_rdataclass; 644224090Sdougb result = dns_rdatatype_fromtext(&rdatatype, ®ion); 645224090Sdougb if (result != ISC_R_SUCCESS) { 646224090Sdougb fprintf(stderr, "invalid type: %s\n", word); 647224090Sdougb exit(1); 648224090Sdougb } 649224090Sdougb } 650224090Sdougb } else 651224090Sdougb rdatatype = dns_rdatatype_any; 652224090Sdougb 653224090Sdougb rdata = isc_mem_get(mctx, sizeof(*rdata)); 654224090Sdougb if (rdata == NULL) { 655224090Sdougb fprintf(stderr, "memory allocation for rdata failed\n"); 656224090Sdougb exit(1); 657224090Sdougb } 658224090Sdougb dns_rdata_init(rdata); 659224090Sdougb 660224090Sdougb if (isrrset && ispositive) 661224090Sdougb parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata); 662224090Sdougb else 663224090Sdougb rdata->flags = DNS_RDATA_UPDATE; 664224090Sdougb 665224090Sdougb rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); 666224090Sdougb if (rdatalist == NULL) { 667224090Sdougb fprintf(stderr, "memory allocation for rdatalist failed\n"); 668224090Sdougb exit(1); 669224090Sdougb } 670224090Sdougb dns_rdatalist_init(rdatalist); 671224090Sdougb rdatalist->type = rdatatype; 672224090Sdougb if (ispositive) { 673224090Sdougb if (isrrset && rdata->data != NULL) 674224090Sdougb rdatalist->rdclass = rdataclass; 675224090Sdougb else 676224090Sdougb rdatalist->rdclass = dns_rdataclass_any; 677224090Sdougb } else 678224090Sdougb rdatalist->rdclass = dns_rdataclass_none; 679224090Sdougb rdatalist->covers = 0; 680224090Sdougb rdatalist->ttl = 0; 681224090Sdougb rdata->rdclass = rdatalist->rdclass; 682224090Sdougb rdata->type = rdatatype; 683224090Sdougb ISC_LIST_INIT(rdatalist->rdata); 684224090Sdougb ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 685224090Sdougb ISC_LIST_APPEND(usedrdatalists, rdatalist, link); 686224090Sdougb 687224090Sdougb rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 688224090Sdougb if (rdataset == NULL) { 689224090Sdougb fprintf(stderr, "memory allocation for rdataset failed\n"); 690224090Sdougb exit(1); 691224090Sdougb } 692224090Sdougb dns_rdataset_init(rdataset); 693224090Sdougb dns_rdatalist_tordataset(rdatalist, rdataset); 694224090Sdougb ISC_LIST_INIT(name->list); 695224090Sdougb ISC_LIST_APPEND(name->list, rdataset, link); 696224090Sdougb} 697224090Sdougb 698224090Sdougbstatic void 699224090Sdougbevaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name) { 700224090Sdougb char *word; 701224090Sdougb isc_boolean_t ispositive, isrrset; 702224090Sdougb 703224090Sdougb word = nsu_strsep(&cmdline, " \t\r\n"); 704224090Sdougb if (word == NULL || *word == 0) { 705224090Sdougb fprintf(stderr, "could not read operation code\n"); 706224090Sdougb exit(1); 707224090Sdougb } 708224090Sdougb if (strcasecmp(word, "nxdomain") == 0) { 709224090Sdougb ispositive = ISC_FALSE; 710224090Sdougb isrrset = ISC_FALSE; 711224090Sdougb } else if (strcasecmp(word, "yxdomain") == 0) { 712224090Sdougb ispositive = ISC_TRUE; 713224090Sdougb isrrset = ISC_FALSE; 714224090Sdougb } else if (strcasecmp(word, "nxrrset") == 0) { 715224090Sdougb ispositive = ISC_FALSE; 716224090Sdougb isrrset = ISC_TRUE; 717224090Sdougb } else if (strcasecmp(word, "yxrrset") == 0) { 718224090Sdougb ispositive = ISC_TRUE; 719224090Sdougb isrrset = ISC_TRUE; 720224090Sdougb } else { 721224090Sdougb fprintf(stderr, "incorrect operation code: %s\n", word); 722224090Sdougb exit(1); 723224090Sdougb } 724224090Sdougb 725224090Sdougb make_prereq(mctx, cmdline, ispositive, isrrset, name); 726224090Sdougb} 727224090Sdougb 728224090Sdougbstatic void 729224090Sdougbsetup_tsec(char *keyfile, isc_mem_t *mctx) { 730224090Sdougb dst_key_t *dstkey = NULL; 731224090Sdougb isc_result_t result; 732224090Sdougb dns_tsectype_t tsectype; 733224090Sdougb 734224090Sdougb result = dst_key_fromnamedfile(keyfile, NULL, 735224090Sdougb DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx, 736224090Sdougb &dstkey); 737224090Sdougb if (result != ISC_R_SUCCESS) { 738224090Sdougb fprintf(stderr, "could not read key from %s: %s\n", 739224090Sdougb keyfile, isc_result_totext(result)); 740224090Sdougb exit(1); 741224090Sdougb } 742224090Sdougb 743224090Sdougb if (dst_key_alg(dstkey) == DST_ALG_HMACMD5) 744224090Sdougb tsectype = dns_tsectype_tsig; 745224090Sdougb else 746224090Sdougb tsectype = dns_tsectype_sig0; 747224090Sdougb 748224090Sdougb result = dns_tsec_create(mctx, tsectype, dstkey, &tsec); 749224090Sdougb dst_key_free(&dstkey); 750224090Sdougb if (result != ISC_R_SUCCESS) { 751224090Sdougb fprintf(stderr, "could not create tsec: %s\n", 752224090Sdougb isc_result_totext(result)); 753224090Sdougb exit(1); 754224090Sdougb } 755224090Sdougb} 756