2009-09-01 00:22:28 +00:00
|
|
|
/*
|
2017-05-30 23:45:32 +00:00
|
|
|
* Copyright (C) 2009, 2010, 2012-2017 Internet Systems Consortium, Inc. ("ISC")
|
2009-09-01 00:22:28 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2009-09-01 00:22:28 +00:00
|
|
|
*/
|
|
|
|
|
2010-12-09 00:54:34 +00:00
|
|
|
/* $Id: sample-update.c,v 1.10 2010/12/09 00:54:34 marka Exp $ */
|
2009-09-01 03:43:27 +00:00
|
|
|
|
|
|
|
#include <config.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2014-02-26 19:00:05 -08:00
|
|
|
#ifndef WIN32
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2014-02-26 19:00:05 -08:00
|
|
|
#include <netdb.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <unistd.h>
|
2014-02-26 19:00:05 -08:00
|
|
|
#endif
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <isc/buffer.h>
|
2014-02-26 19:00:05 -08:00
|
|
|
#include <isc/commandline.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/lex.h>
|
|
|
|
#include <isc/lib.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/parseint.h>
|
2015-05-23 14:21:51 +02:00
|
|
|
#include <isc/print.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/sockaddr.h>
|
2014-02-17 12:22:42 +11:00
|
|
|
#include <isc/string.h>
|
2009-09-01 00:22:28 +00:00
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/callbacks.h>
|
|
|
|
#include <dns/client.h>
|
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/lib.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataclass.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatastruct.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/result.h>
|
|
|
|
#include <dns/secalg.h>
|
|
|
|
#include <dns/tsec.h>
|
|
|
|
|
|
|
|
#include <dst/dst.h>
|
|
|
|
|
|
|
|
static dns_tsec_t *tsec = NULL;
|
|
|
|
static const dns_rdataclass_t default_rdataclass = dns_rdataclass_in;
|
|
|
|
static isc_bufferlist_t usedbuffers;
|
|
|
|
static ISC_LIST(dns_rdatalist_t) usedrdatalists;
|
|
|
|
|
2016-12-13 15:47:03 +11:00
|
|
|
static const char *port = "53";
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static void setup_tsec(char *keyfile, isc_mem_t *mctx);
|
|
|
|
static void update_addordelete(isc_mem_t *mctx, char *cmdline,
|
|
|
|
isc_boolean_t isdelete, dns_name_t *name);
|
|
|
|
static void evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name);
|
|
|
|
|
2009-09-29 15:06:07 +00:00
|
|
|
ISC_PLATFORM_NORETURN_PRE static void
|
|
|
|
usage(void) ISC_PLATFORM_NORETURN_POST;
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
static void
|
2009-09-29 15:06:07 +00:00
|
|
|
usage(void) {
|
2009-09-01 00:22:28 +00:00
|
|
|
fprintf(stderr, "sample-update "
|
2017-05-30 09:47:41 +10:00
|
|
|
"-s "
|
2009-09-01 00:22:28 +00:00
|
|
|
"[-a auth_server] "
|
|
|
|
"[-k keyfile] "
|
|
|
|
"[-p prerequisite] "
|
|
|
|
"[-r recursive_server] "
|
|
|
|
"[-z zonename] "
|
|
|
|
"(add|delete) \"name TTL RRtype RDATA\"\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2018-02-08 13:33:51 -08:00
|
|
|
#ifdef _WIN32
|
|
|
|
static void
|
|
|
|
InitSockets(void) {
|
|
|
|
WORD wVersionRequested;
|
|
|
|
WSADATA wsaData;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
wVersionRequested = MAKEWORD(2, 0);
|
|
|
|
|
|
|
|
err = WSAStartup(wVersionRequested, &wsaData);
|
|
|
|
if (err != 0) {
|
|
|
|
fprintf(stderr, "WSAStartup() failed: %d\n", err);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DestroySockets(void) {
|
|
|
|
WSACleanup();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define InitSockets() ((void)0)
|
|
|
|
#define DestroySockets() ((void)0)
|
|
|
|
#endif
|
|
|
|
|
2016-12-13 15:47:03 +11:00
|
|
|
static isc_boolean_t
|
|
|
|
addserver(const char *server, isc_sockaddrlist_t *list,
|
|
|
|
isc_sockaddr_t *sockaddr)
|
|
|
|
{
|
|
|
|
struct addrinfo hints, *res;
|
|
|
|
int gaierror;
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
hints.ai_protocol = IPPROTO_UDP;
|
|
|
|
#ifdef AI_NUMERICHOST
|
|
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
#endif
|
|
|
|
#ifdef AI_NUMERICSERV
|
|
|
|
hints.ai_flags |= AI_NUMERICSERV;
|
|
|
|
#endif
|
2018-02-08 13:33:51 -08:00
|
|
|
InitSockets();
|
2016-12-13 15:47:03 +11:00
|
|
|
gaierror = getaddrinfo(server, port, &hints, &res);
|
|
|
|
if (gaierror != 0) {
|
|
|
|
fprintf(stderr, "getaddrinfo(%s) failed: %s\n",
|
|
|
|
server, gai_strerror(gaierror));
|
2018-02-08 13:33:51 -08:00
|
|
|
DestroySockets();
|
2016-12-13 15:47:03 +11:00
|
|
|
return (ISC_FALSE);
|
|
|
|
}
|
|
|
|
INSIST(res->ai_addrlen <= sizeof(sockaddr->type));
|
|
|
|
memmove(&sockaddr->type, res->ai_addr, res->ai_addrlen);
|
|
|
|
sockaddr->length = (unsigned int)res->ai_addrlen;
|
|
|
|
ISC_LINK_INIT(sockaddr, link);
|
|
|
|
ISC_LIST_APPEND(*list, sockaddr, link);
|
2016-12-15 09:38:12 +11:00
|
|
|
freeaddrinfo(res);
|
2018-02-08 13:33:51 -08:00
|
|
|
DestroySockets();
|
2016-12-13 15:47:03 +11:00
|
|
|
return (ISC_TRUE);
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[]) {
|
|
|
|
int ch;
|
|
|
|
dns_client_t *client = NULL;
|
|
|
|
char *zonenamestr = NULL;
|
|
|
|
char *keyfilename = NULL;
|
|
|
|
char *prereqstr = NULL;
|
2016-12-13 15:47:03 +11:00
|
|
|
isc_sockaddr_t sa_auth[10], sa_recursive[10];
|
|
|
|
unsigned int nsa_auth = 0, nsa_recursive = 0;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_sockaddrlist_t rec_servers;
|
2017-05-30 09:47:41 +10:00
|
|
|
isc_sockaddrlist_t auth_servers, *auth_serversp = &auth_servers;
|
2009-09-01 00:22:28 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_boolean_t isdelete;
|
|
|
|
isc_buffer_t b, *buf;
|
|
|
|
dns_fixedname_t zname0, pname0, uname0;
|
2014-02-26 19:00:05 -08:00
|
|
|
unsigned int namelen;
|
2009-09-01 00:22:28 +00:00
|
|
|
dns_name_t *zname = NULL, *uname, *pname;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdatalist_t *rdatalist;
|
|
|
|
dns_rdata_t *rdata;
|
|
|
|
dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL;
|
|
|
|
isc_mem_t *umctx = NULL;
|
2017-09-27 10:27:09 +10:00
|
|
|
isc_boolean_t sendtwice = ISC_FALSE;
|
2009-09-01 00:22:28 +00:00
|
|
|
|
2016-12-13 15:47:03 +11:00
|
|
|
ISC_LIST_INIT(auth_servers);
|
|
|
|
ISC_LIST_INIT(rec_servers);
|
|
|
|
|
2017-09-27 10:27:09 +10:00
|
|
|
while ((ch = isc_commandline_parse(argc, argv,
|
|
|
|
"a:k:p:P:r:sz:")) != EOF)
|
|
|
|
{
|
2009-09-01 00:22:28 +00:00
|
|
|
switch (ch) {
|
|
|
|
case 'k':
|
2014-02-26 19:00:05 -08:00
|
|
|
keyfilename = isc_commandline_argument;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
case 'a':
|
2016-12-13 15:47:03 +11:00
|
|
|
if (nsa_auth < sizeof(sa_auth)/sizeof(*sa_auth) &&
|
|
|
|
addserver(isc_commandline_argument, &auth_servers,
|
|
|
|
&sa_auth[nsa_auth]))
|
|
|
|
nsa_auth++;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
case 'p':
|
2014-02-26 19:00:05 -08:00
|
|
|
prereqstr = isc_commandline_argument;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
2016-12-13 15:47:03 +11:00
|
|
|
case 'P':
|
|
|
|
port = isc_commandline_argument;
|
|
|
|
break;
|
2009-09-01 00:22:28 +00:00
|
|
|
case 'r':
|
2016-12-13 23:46:28 +00:00
|
|
|
if (nsa_recursive <
|
2016-12-13 15:47:03 +11:00
|
|
|
sizeof(sa_recursive)/sizeof(*sa_recursive) &&
|
|
|
|
addserver(isc_commandline_argument, &rec_servers,
|
|
|
|
&sa_recursive[nsa_recursive]))
|
|
|
|
nsa_recursive++;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
2017-05-30 09:47:41 +10:00
|
|
|
case 's':
|
|
|
|
sendtwice = ISC_TRUE;
|
|
|
|
break;
|
2009-09-01 00:22:28 +00:00
|
|
|
case 'z':
|
2014-02-26 19:00:05 -08:00
|
|
|
zonenamestr = isc_commandline_argument;
|
2009-09-01 00:22:28 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-26 19:00:05 -08:00
|
|
|
argc -= isc_commandline_index;
|
|
|
|
argv += isc_commandline_index;
|
2009-09-01 00:22:28 +00:00
|
|
|
if (argc < 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
/* command line argument validation */
|
|
|
|
if (strcmp(argv[0], "delete") == 0)
|
|
|
|
isdelete = ISC_TRUE;
|
|
|
|
else if (strcmp(argv[0], "add") == 0)
|
|
|
|
isdelete = ISC_FALSE;
|
|
|
|
else {
|
|
|
|
fprintf(stderr, "invalid update command: %s\n", argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2016-12-13 15:47:03 +11:00
|
|
|
if (ISC_LIST_HEAD(auth_servers) == NULL &&
|
|
|
|
ISC_LIST_HEAD(rec_servers) == NULL) {
|
|
|
|
fprintf(stderr, "authoritative or recursive servers "
|
2009-09-01 00:22:28 +00:00
|
|
|
"must be specified\n");
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialization */
|
|
|
|
ISC_LIST_INIT(usedbuffers);
|
|
|
|
ISC_LIST_INIT(usedrdatalists);
|
|
|
|
ISC_LIST_INIT(prereqlist);
|
|
|
|
isc_lib_register();
|
|
|
|
result = dns_lib_init();
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "dns_lib_init failed: %d\n", result);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
result = isc_mem_create(0, 0, &umctx);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to crate mctx\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_client_create(&client, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "dns_client_create failed: %d\n", result);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct zone name */
|
|
|
|
zname = NULL;
|
|
|
|
if (zonenamestr != NULL) {
|
|
|
|
namelen = strlen(zonenamestr);
|
|
|
|
isc_buffer_init(&b, zonenamestr, namelen);
|
|
|
|
isc_buffer_add(&b, namelen);
|
|
|
|
dns_fixedname_init(&zname0);
|
|
|
|
zname = dns_fixedname_name(&zname0);
|
|
|
|
result = dns_name_fromtext(zname, &b, dns_rootname, 0, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
fprintf(stderr, "failed to convert zone name: %d\n",
|
|
|
|
result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct prerequisite name (if given) */
|
|
|
|
if (prereqstr != NULL) {
|
|
|
|
dns_fixedname_init(&pname0);
|
|
|
|
pname = dns_fixedname_name(&pname0);
|
|
|
|
evaluate_prereq(umctx, prereqstr, pname);
|
|
|
|
ISC_LIST_APPEND(prereqlist, pname, link);
|
|
|
|
prereqlistp = &prereqlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Construct update name */
|
|
|
|
ISC_LIST_INIT(updatelist);
|
|
|
|
dns_fixedname_init(&uname0);
|
|
|
|
uname = dns_fixedname_name(&uname0);
|
|
|
|
update_addordelete(umctx, argv[1], isdelete, uname);
|
|
|
|
ISC_LIST_APPEND(updatelist, uname, link);
|
|
|
|
|
|
|
|
/* Set up TSIG/SIG(0) key (if given) */
|
|
|
|
if (keyfilename != NULL)
|
|
|
|
setup_tsec(keyfilename, umctx);
|
|
|
|
|
2017-05-30 09:47:41 +10:00
|
|
|
if (ISC_LIST_HEAD(auth_servers) == NULL)
|
|
|
|
auth_serversp = NULL;
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/* Perform update */
|
|
|
|
result = dns_client_update(client,
|
|
|
|
default_rdataclass, /* XXX: fixed */
|
|
|
|
zname, prereqlistp, &updatelist,
|
2017-05-30 09:47:41 +10:00
|
|
|
auth_serversp, tsec, 0);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"update failed: %s\n", dns_result_totext(result));
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "update succeeded\n");
|
|
|
|
|
2017-05-30 09:47:41 +10:00
|
|
|
if (sendtwice) {
|
|
|
|
/* Perform 2nd update */
|
|
|
|
result = dns_client_update(client,
|
|
|
|
default_rdataclass, /* XXX: fixed */
|
|
|
|
zname, prereqlistp, &updatelist,
|
|
|
|
auth_serversp, tsec, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "2nd update failed: %s\n",
|
|
|
|
dns_result_totext(result));
|
|
|
|
} else
|
|
|
|
fprintf(stderr, "2nd update succeeded\n");
|
|
|
|
}
|
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
/* Cleanup */
|
|
|
|
while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) {
|
|
|
|
while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(pname->list, rdataset, link);
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
isc_mem_put(umctx, rdataset, sizeof(*rdataset));
|
|
|
|
}
|
|
|
|
ISC_LIST_UNLINK(prereqlist, pname, link);
|
|
|
|
}
|
|
|
|
while ((uname = ISC_LIST_HEAD(updatelist)) != NULL) {
|
|
|
|
while ((rdataset = ISC_LIST_HEAD(uname->list)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(uname->list, rdataset, link);
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
isc_mem_put(umctx, rdataset, sizeof(*rdataset));
|
|
|
|
}
|
|
|
|
ISC_LIST_UNLINK(updatelist, uname, link);
|
|
|
|
}
|
|
|
|
while ((rdatalist = ISC_LIST_HEAD(usedrdatalists)) != NULL) {
|
|
|
|
while ((rdata = ISC_LIST_HEAD(rdatalist->rdata)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
|
|
|
|
isc_mem_put(umctx, rdata, sizeof(*rdata));
|
|
|
|
}
|
|
|
|
ISC_LIST_UNLINK(usedrdatalists, rdatalist, link);
|
|
|
|
isc_mem_put(umctx, rdatalist, sizeof(*rdatalist));
|
|
|
|
}
|
|
|
|
while ((buf = ISC_LIST_HEAD(usedbuffers)) != NULL) {
|
|
|
|
ISC_LIST_UNLINK(usedbuffers, buf, link);
|
|
|
|
isc_buffer_free(&buf);
|
|
|
|
}
|
|
|
|
if (tsec != NULL)
|
|
|
|
dns_tsec_destroy(&tsec);
|
|
|
|
isc_mem_destroy(&umctx);
|
|
|
|
dns_client_destroy(&client);
|
|
|
|
dns_lib_shutdown();
|
|
|
|
|
2013-04-12 14:06:41 +10:00
|
|
|
return (0);
|
2009-09-01 00:22:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Subroutines borrowed from nsupdate.c
|
|
|
|
*/
|
|
|
|
#define MAXWIRE (64 * 1024)
|
|
|
|
#define TTL_MAX 2147483647U /* Maximum signed 32 bit integer. */
|
|
|
|
|
|
|
|
static char *
|
|
|
|
nsu_strsep(char **stringp, const char *delim) {
|
|
|
|
char *string = *stringp;
|
|
|
|
char *s;
|
|
|
|
const char *d;
|
|
|
|
char sc, dc;
|
|
|
|
|
|
|
|
if (string == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
for (; *string != '\0'; string++) {
|
|
|
|
sc = *string;
|
|
|
|
for (d = delim; (dc = *d) != '\0'; d++) {
|
|
|
|
if (sc == dc)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dc == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (s = string; *s != '\0'; s++) {
|
|
|
|
sc = *s;
|
|
|
|
for (d = delim; (dc = *d) != '\0'; d++) {
|
|
|
|
if (sc == dc) {
|
|
|
|
*s++ = '\0';
|
|
|
|
*stringp = s;
|
|
|
|
return (string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*stringp = NULL;
|
|
|
|
return (string);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fatal(const char *format, ...) {
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
vfprintf(stderr, format, args);
|
|
|
|
va_end(args);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
check_result(isc_result_t result, const char *msg) {
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
fatal("%s: %s", msg, isc_result_totext(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
parse_name(char **cmdlinep, dns_name_t *name) {
|
|
|
|
isc_result_t result;
|
|
|
|
char *word;
|
|
|
|
isc_buffer_t source;
|
|
|
|
|
|
|
|
word = nsu_strsep(cmdlinep, " \t\r\n");
|
2012-10-02 23:44:03 -07:00
|
|
|
if (word == NULL || *word == 0) {
|
2009-09-01 00:22:28 +00:00
|
|
|
fprintf(stderr, "could not read owner name\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_init(&source, word, strlen(word));
|
|
|
|
isc_buffer_add(&source, strlen(word));
|
|
|
|
result = dns_name_fromtext(name, &source, dns_rootname, 0, NULL);
|
|
|
|
check_result(result, "dns_name_fromtext");
|
|
|
|
isc_buffer_invalidate(&source);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
parse_rdata(isc_mem_t *mctx, char **cmdlinep, dns_rdataclass_t rdataclass,
|
|
|
|
dns_rdatatype_t rdatatype, dns_rdata_t *rdata)
|
|
|
|
{
|
|
|
|
char *cmdline = *cmdlinep;
|
|
|
|
isc_buffer_t source, *buf = NULL, *newbuf = NULL;
|
|
|
|
isc_region_t r;
|
|
|
|
isc_lex_t *lex = NULL;
|
|
|
|
dns_rdatacallbacks_t callbacks;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
while (cmdline != NULL && *cmdline != 0 &&
|
|
|
|
isspace((unsigned char)*cmdline))
|
|
|
|
cmdline++;
|
|
|
|
|
|
|
|
if (cmdline != NULL && *cmdline != 0) {
|
|
|
|
dns_rdatacallbacks_init(&callbacks);
|
|
|
|
result = isc_lex_create(mctx, strlen(cmdline), &lex);
|
|
|
|
check_result(result, "isc_lex_create");
|
|
|
|
isc_buffer_init(&source, cmdline, strlen(cmdline));
|
|
|
|
isc_buffer_add(&source, strlen(cmdline));
|
|
|
|
result = isc_lex_openbuffer(lex, &source);
|
|
|
|
check_result(result, "isc_lex_openbuffer");
|
|
|
|
result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
|
|
|
|
check_result(result, "isc_buffer_allocate");
|
|
|
|
result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
|
|
|
|
dns_rootname, 0, mctx, buf,
|
|
|
|
&callbacks);
|
|
|
|
isc_lex_destroy(&lex);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
isc_buffer_usedregion(buf, &r);
|
|
|
|
result = isc_buffer_allocate(mctx, &newbuf, r.length);
|
|
|
|
check_result(result, "isc_buffer_allocate");
|
|
|
|
isc_buffer_putmem(newbuf, r.base, r.length);
|
|
|
|
isc_buffer_usedregion(newbuf, &r);
|
|
|
|
dns_rdata_reset(rdata);
|
|
|
|
dns_rdata_fromregion(rdata, rdataclass, rdatatype, &r);
|
|
|
|
isc_buffer_free(&buf);
|
|
|
|
ISC_LIST_APPEND(usedbuffers, newbuf, link);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "invalid rdata format: %s\n",
|
|
|
|
isc_result_totext(result));
|
|
|
|
isc_buffer_free(&buf);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rdata->flags = DNS_RDATA_UPDATE;
|
|
|
|
}
|
|
|
|
*cmdlinep = cmdline;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_addordelete(isc_mem_t *mctx, char *cmdline, isc_boolean_t isdelete,
|
|
|
|
dns_name_t *name)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
isc_uint32_t ttl;
|
|
|
|
char *word;
|
|
|
|
dns_rdataclass_t rdataclass;
|
|
|
|
dns_rdatatype_t rdatatype;
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
isc_textregion_t region;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the owner name.
|
|
|
|
*/
|
|
|
|
parse_name(&cmdline, name);
|
|
|
|
|
|
|
|
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
|
|
|
if (rdata == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdata failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdata_init(rdata);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is an add, read the TTL and verify that it's in range.
|
|
|
|
* If it's a delete, ignore a TTL if present (for compatibility).
|
|
|
|
*/
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
if (!isdelete) {
|
|
|
|
fprintf(stderr, "could not read owner ttl\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ttl = 0;
|
|
|
|
rdataclass = dns_rdataclass_any;
|
|
|
|
rdatatype = dns_rdatatype_any;
|
|
|
|
rdata->flags = DNS_RDATA_UPDATE;
|
|
|
|
goto doneparsing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = isc_parse_uint32(&ttl, word, 10);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
if (isdelete) {
|
|
|
|
ttl = 0;
|
|
|
|
goto parseclass;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "ttl '%s': %s\n", word,
|
|
|
|
isc_result_totext(result));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isdelete)
|
|
|
|
ttl = 0;
|
|
|
|
else if (ttl > TTL_MAX) {
|
|
|
|
fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
|
|
|
|
word, TTL_MAX);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the class or type.
|
|
|
|
*/
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
parseclass:
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
if (isdelete) {
|
|
|
|
rdataclass = dns_rdataclass_any;
|
|
|
|
rdatatype = dns_rdatatype_any;
|
|
|
|
rdata->flags = DNS_RDATA_UPDATE;
|
|
|
|
goto doneparsing;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "could not read class or type\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
region.base = word;
|
|
|
|
region.length = strlen(word);
|
|
|
|
result = dns_rdataclass_fromtext(&rdataclass, ®ion);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* Now read the type.
|
|
|
|
*/
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
if (isdelete) {
|
|
|
|
rdataclass = dns_rdataclass_any;
|
|
|
|
rdatatype = dns_rdatatype_any;
|
|
|
|
rdata->flags = DNS_RDATA_UPDATE;
|
|
|
|
goto doneparsing;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "could not read type\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
region.base = word;
|
|
|
|
region.length = strlen(word);
|
|
|
|
result = dns_rdatatype_fromtext(&rdatatype, ®ion);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "'%s' is not a valid type: %s\n",
|
|
|
|
word, isc_result_totext(result));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rdataclass = default_rdataclass;
|
|
|
|
result = dns_rdatatype_fromtext(&rdatatype, ®ion);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "'%s' is not a valid class or type: "
|
|
|
|
"%s\n", word, isc_result_totext(result));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata);
|
|
|
|
|
|
|
|
if (isdelete) {
|
|
|
|
if ((rdata->flags & DNS_RDATA_UPDATE) != 0)
|
|
|
|
rdataclass = dns_rdataclass_any;
|
|
|
|
else
|
|
|
|
rdataclass = dns_rdataclass_none;
|
|
|
|
} else {
|
|
|
|
if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
|
|
|
|
fprintf(stderr, "could not read rdata\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
doneparsing:
|
|
|
|
|
|
|
|
rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
|
|
|
|
if (rdatalist == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdatalist failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdatalist_init(rdatalist);
|
|
|
|
rdatalist->type = rdatatype;
|
|
|
|
rdatalist->rdclass = rdataclass;
|
|
|
|
rdatalist->covers = rdatatype;
|
|
|
|
rdatalist->ttl = (dns_ttl_t)ttl;
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
ISC_LIST_APPEND(usedrdatalists, rdatalist, link);
|
|
|
|
|
|
|
|
rdataset = isc_mem_get(mctx, sizeof(*rdataset));
|
|
|
|
if (rdataset == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdataset failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_rdataset_setownercase(rdataset, name);
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_INIT(name->list);
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
make_prereq(isc_mem_t *mctx, char *cmdline, isc_boolean_t ispositive,
|
|
|
|
isc_boolean_t isrrset, dns_name_t *name)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
char *word;
|
|
|
|
isc_textregion_t region;
|
|
|
|
dns_rdataset_t *rdataset = NULL;
|
|
|
|
dns_rdatalist_t *rdatalist = NULL;
|
|
|
|
dns_rdataclass_t rdataclass;
|
|
|
|
dns_rdatatype_t rdatatype;
|
|
|
|
dns_rdata_t *rdata = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the owner name
|
|
|
|
*/
|
|
|
|
parse_name(&cmdline, name);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is an rrset prereq, read the class or type.
|
|
|
|
*/
|
|
|
|
if (isrrset) {
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
fprintf(stderr, "could not read class or type\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
region.base = word;
|
|
|
|
region.length = strlen(word);
|
|
|
|
result = dns_rdataclass_fromtext(&rdataclass, ®ion);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* Now read the type.
|
|
|
|
*/
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
fprintf(stderr, "could not read type\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
region.base = word;
|
|
|
|
region.length = strlen(word);
|
|
|
|
result = dns_rdatatype_fromtext(&rdatatype, ®ion);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "invalid type: %s\n", word);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rdataclass = default_rdataclass;
|
|
|
|
result = dns_rdatatype_fromtext(&rdatatype, ®ion);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "invalid type: %s\n", word);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
rdatatype = dns_rdatatype_any;
|
|
|
|
|
|
|
|
rdata = isc_mem_get(mctx, sizeof(*rdata));
|
|
|
|
if (rdata == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdata failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdata_init(rdata);
|
|
|
|
|
|
|
|
if (isrrset && ispositive)
|
|
|
|
parse_rdata(mctx, &cmdline, rdataclass, rdatatype, rdata);
|
|
|
|
else
|
|
|
|
rdata->flags = DNS_RDATA_UPDATE;
|
|
|
|
|
|
|
|
rdatalist = isc_mem_get(mctx, sizeof(*rdatalist));
|
|
|
|
if (rdatalist == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdatalist failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdatalist_init(rdatalist);
|
|
|
|
rdatalist->type = rdatatype;
|
|
|
|
if (ispositive) {
|
|
|
|
if (isrrset && rdata->data != NULL)
|
|
|
|
rdatalist->rdclass = rdataclass;
|
|
|
|
else
|
|
|
|
rdatalist->rdclass = dns_rdataclass_any;
|
|
|
|
} else
|
|
|
|
rdatalist->rdclass = dns_rdataclass_none;
|
|
|
|
rdata->rdclass = rdatalist->rdclass;
|
|
|
|
rdata->type = rdatatype;
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
ISC_LIST_APPEND(usedrdatalists, rdatalist, link);
|
|
|
|
|
|
|
|
rdataset = isc_mem_get(mctx, sizeof(*rdataset));
|
|
|
|
if (rdataset == NULL) {
|
|
|
|
fprintf(stderr, "memory allocation for rdataset failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_rdataset_setownercase(rdataset, name);
|
2009-09-01 00:22:28 +00:00
|
|
|
ISC_LIST_INIT(name->list);
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
evaluate_prereq(isc_mem_t *mctx, char *cmdline, dns_name_t *name) {
|
|
|
|
char *word;
|
|
|
|
isc_boolean_t ispositive, isrrset;
|
|
|
|
|
|
|
|
word = nsu_strsep(&cmdline, " \t\r\n");
|
|
|
|
if (word == NULL || *word == 0) {
|
|
|
|
fprintf(stderr, "could not read operation code\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (strcasecmp(word, "nxdomain") == 0) {
|
|
|
|
ispositive = ISC_FALSE;
|
|
|
|
isrrset = ISC_FALSE;
|
|
|
|
} else if (strcasecmp(word, "yxdomain") == 0) {
|
|
|
|
ispositive = ISC_TRUE;
|
|
|
|
isrrset = ISC_FALSE;
|
|
|
|
} else if (strcasecmp(word, "nxrrset") == 0) {
|
|
|
|
ispositive = ISC_FALSE;
|
|
|
|
isrrset = ISC_TRUE;
|
|
|
|
} else if (strcasecmp(word, "yxrrset") == 0) {
|
|
|
|
ispositive = ISC_TRUE;
|
|
|
|
isrrset = ISC_TRUE;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "incorrect operation code: %s\n", word);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-09-02 23:48:03 +00:00
|
|
|
|
2009-09-01 00:22:28 +00:00
|
|
|
make_prereq(mctx, cmdline, ispositive, isrrset, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_tsec(char *keyfile, isc_mem_t *mctx) {
|
|
|
|
dst_key_t *dstkey = NULL;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_tsectype_t tsectype;
|
|
|
|
|
|
|
|
result = dst_key_fromnamedfile(keyfile, NULL,
|
|
|
|
DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
|
|
|
|
&dstkey);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "could not read key from %s: %s\n",
|
|
|
|
keyfile, isc_result_totext(result));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dst_key_alg(dstkey) == DST_ALG_HMACMD5)
|
|
|
|
tsectype = dns_tsectype_tsig;
|
|
|
|
else
|
|
|
|
tsectype = dns_tsectype_sig0;
|
|
|
|
|
2010-12-09 00:54:34 +00:00
|
|
|
result = dns_tsec_create(mctx, tsectype, dstkey, &tsec);
|
|
|
|
dst_key_free(&dstkey);
|
2009-09-01 00:22:28 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
fprintf(stderr, "could not create tsec: %s\n",
|
|
|
|
isc_result_totext(result));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|