bind9/bin/nsupdate/nsupdate.c
Michael Sawyer d4024b720c All prereq and update messages correctly generated now (hopefully)
Need to imprt\ove user interface and fix known problem where prereq
cannot include value dependent rrset exist tests (2.4.2)
2000-06-19 22:09:46 +00:00

1144 lines
31 KiB
C

/*
* Copyright (C) 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/* $Id: nsupdate.c,v 1.5 2000/06/19 22:09:46 mws Exp $ */
#include <config.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <isc/app.h>
#include <isc/mutex.h>
#include <isc/condition.h>
#include <isc/mem.h>
#include <isc/socket.h>
#include <isc/sockaddr.h>
#include <isc/buffer.h>
#include <isc/region.h>
#include <isc/task.h>
#include <isc/util.h>
#include <isc/string.h>
#include <isc/lex.h>
#include <isc/timer.h>
#include <dns/dispatch.h>
#include <dns/request.h>
#include <dns/message.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
#include <dns/rdatalist.h>
#include <dns/rdatatype.h>
#include <dns/callbacks.h>
#include <dns/rdatastruct.h>
#include <dns/events.h>
#include <dns/name.h>
#define MXNAME 256
#define MAXCMD 256
#define NAMEBUF 512
#define NAMEHINT 64
#define PACKETSIZE 2048
#define MSGTEXT 4069
#define FIND_TIMEOUT 5
#define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
#define RESOLV_CONF "/etc/resolv.conf"
extern isc_boolean_t isc_mem_debugging;
isc_boolean_t busy= ISC_FALSE, debugging = ISC_TRUE, ddebugging = ISC_FALSE,
have_ipv6 = ISC_FALSE, valid_zonename = ISC_FALSE;
isc_mutex_t lock;
isc_condition_t cond;
isc_taskmgr_t *taskmgr = NULL;
isc_task_t *global_task = NULL;
isc_mem_t *mctx = NULL;
dns_dispatchmgr_t *dispatchmgr = NULL;
dns_requestmgr_t *requestmgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
isc_timermgr_t *timermgr = NULL;
dns_dispatch_t *dispatchv4 = NULL;
dns_message_t *updatemsg = NULL, *findmsg = NULL;
dns_name_t domainname;
isc_buffer_t domainname_buf;
char domainname_store[NAMEBUF];
dns_name_t zonename, actualzone, master;
int exitcode = 0;
char server[MXNAME];
char nameservername[3][MXNAME];
int nameservers;
int ns_inuse = 0;
int ndots = 1;
char domain[MXNAME];
#define STATUS_MORE 0
#define STATUS_SEND 1
#define STATUS_QUIT 2
#define STATUS_FAIL 3
#define STATUS_SYNTAX 4
static void
fatal(const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
if (exitcode == 0)
exitcode = 8;
exit(exitcode);
}
static void
debug(const char *format, ...) {
va_list args;
if (debugging) {
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
}
}
static void
ddebug(const char *format, ...) {
va_list args;
if (ddebugging) {
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
}
}
static void
check_result(isc_result_t result, const char *msg) {
if (result != ISC_R_SUCCESS) {
exitcode = 1;
fatal("%s: %s", msg, isc_result_totext(result));
}
}
static void
load_resolv_conf() {
FILE *fp;
char rcinput[MXNAME];
char *ptr;
ddebug ("load_resolv_conf()");
fp = fopen (RESOLV_CONF, "r");
if (fp != NULL) {
while (fgets(rcinput, MXNAME, fp) != 0) {
ptr = strtok (rcinput, " \t\r\n");
if (ptr != NULL) {
if (strcasecmp(ptr, "nameserver") == 0) {
ddebug ("Got a nameserver line");
ptr = strtok (NULL, " \t\r\n");
if (ptr != NULL) {
if (nameservers < 3) {
strncpy(nameservername
[nameservers],
ptr,MXNAME);
nameservers++;
}
}
} else if (strcasecmp(ptr, "options") == 0) {
ptr = strtok(NULL, " \t\r\n");
if (ptr != NULL) {
if (strncasecmp(ptr, "ndots:",
6) == 0) {
ndots = atoi(&ptr[6]);
ddebug ("ndots is "
"%d.",
ndots);
}
}
/* XXXMWS Searchlist not supported! */
} else if ((strcasecmp(ptr, "domain") == 0) &&
(domain[0] == 0 )){
while ((ptr = strtok(NULL, " \t\r\n"))
!= NULL) {
strncpy(domain, ptr, MXNAME);
}
}
}
}
fclose (fp);
}
}
static void
reset_system() {
isc_result_t result;
ddebug ("reset_system()");
/* If the update message is still around, destroy it */
if (updatemsg != NULL)
dns_message_destroy(&updatemsg);
if (findmsg != NULL)
dns_message_destroy(&findmsg);
result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
&updatemsg);
check_result (result, "dns_message_create");
updatemsg->opcode = dns_opcode_update;
valid_zonename = ISC_FALSE;
if (VALID_NAME(&zonename))
dns_name_free(&zonename, mctx);
if (VALID_NAME(&actualzone))
dns_name_free(&actualzone, mctx);
if (VALID_NAME(&master))
dns_name_free(&master, mctx);
}
static void
setup_system(){
isc_result_t result;
isc_sockaddr_t bind_any;
ddebug("setup_system()");
/*
* Warning: This is not particularly good randomness. We'll
* just use random() now for getting id values, but doing so
* does NOT insure that id's can't be guessed.
*/
srandom (getpid() + (int)&setup_system);
isc_mem_debugging = ISC_FALSE;
load_resolv_conf();
result = isc_app_start();
check_result(result, "isc_app_start");
result = isc_net_probeipv4();
check_result(result, "isc_net_probeipv4");
/* XXXMWS There isn't any actual V6 support in the code yet */
result = isc_net_probeipv6();
if (result == ISC_R_SUCCESS)
have_ipv6=ISC_TRUE;
result = isc_mem_create(0, 0, &mctx);
check_result(result, "isc_mem_create");
result = isc_taskmgr_create (mctx, 1, 0, &taskmgr);
check_result(result, "isc_taskmgr_create");
result = isc_task_create (taskmgr, 0, &global_task);
check_result(result, "isc_task_create");
result = dns_dispatchmgr_create(mctx, &dispatchmgr);
check_result(result, "dns_dispatchmgr_create");
result = isc_socketmgr_create(mctx, &socketmgr);
check_result(result, "dns_socketmgr_create");
result = isc_timermgr_create(mctx, &timermgr);
check_result(result, "dns_timermgr_create");
isc_sockaddr_any(&bind_any);
result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
&bind_any, PACKETSIZE, 4, 2, 3, 5,
DNS_DISPATCHATTR_UDP |
DNS_DISPATCHATTR_IPV4 |
DNS_DISPATCHATTR_MAKEQUERY, 0,
&dispatchv4);
check_result(result, "dns_dispatch_getudp");
result = dns_requestmgr_create(mctx, timermgr,
socketmgr, taskmgr, dispatchmgr,
dispatchv4, NULL, &requestmgr);
check_result(result, "dns_requestmgr_create");
#if 0
if (domain[0] != 0) {
dns_name_init(&domainname, NULL);
isc_buffer_init(&domainname_buf, domainname_store, NAMEBUF);
dns_name_setbuffer(&domainname, &domainname_buf);
isc_buffer_init(&buf, domain, strlen(domain));
isc_buffer_add(&buf, strlen(domain));
result = dns_name_fromtext(&domainname, &buf, dns_rootname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
}
else {
#endif
dns_name_init(&domainname, NULL);
dns_name_clone(dns_rootname, &domainname);
#if 0
}
#endif
}
static void
parse_args() {
}
static void
check_and_add_zone(dns_name_t *namein) {
ddebug ("check_and_add_zone()");
if (valid_zonename)
return;
dns_name_init(&zonename, NULL);
dns_name_dup(namein, mctx, &zonename);
valid_zonename = ISC_TRUE;
}
static isc_uint16_t
make_rrset_prereq(dns_rdataclass_t rdclass) {
isc_result_t result;
char *nameptr, *typeptr;
dns_name_t *name = NULL;
isc_buffer_t *buf = NULL;
isc_buffer_t source;
isc_textregion_t typeregion;
dns_rdataset_t *rdataset = NULL;
dns_rdatalist_t *rdatalist = NULL;
dns_rdatatype_t rdatatype;
dns_rdata_t *rdata = NULL;
ddebug ("make_rrset_prereq()");
nameptr = strtok(NULL, " \t\r\n");
if (nameptr == NULL) {
puts ("failed to read owner name");
return STATUS_SYNTAX;
}
typeptr = strtok(NULL, " \t\r\n");
if (typeptr == NULL) {
puts ("failed to read owner type");
return STATUS_SYNTAX;
}
result = dns_message_gettempname(updatemsg, &name);
check_result(result, "dns_message_gettempname");
result = isc_buffer_allocate(mctx, &buf, NAMEBUF);
check_result(result, "isc_buffer_allocate");
dns_name_init(name, NULL);
dns_name_setbuffer(name, buf);
dns_message_takebuffer(updatemsg, &buf);
isc_buffer_init(&source, nameptr, strlen(nameptr));
isc_buffer_add(&source, strlen(nameptr));
result = dns_name_fromtext(name, &source, &domainname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
check_and_add_zone(name);
typeregion.base = typeptr;
typeregion.length = strlen(typeptr);
result = dns_rdatatype_fromtext(&rdatatype, &typeregion);
check_result (result, "dns_rdatatype_fromtext");
result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
check_result(result, "dns_message_gettemprdatalist");
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdatalist_init(rdatalist);
rdatalist->type = rdatatype;
rdatalist->rdclass = rdclass;
rdatalist->covers = 0;
rdatalist->ttl = 0;
result = dns_message_gettemprdata(updatemsg, &rdata);
check_result(result, "dns_message_gettemprdata");
rdata->data = NULL;
rdata->length = 0;
rdata->rdclass = rdclass;
rdata->type = rdatatype;
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
dns_rdatalist_tordataset(rdatalist, rdataset);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
return STATUS_MORE;
}
static isc_uint16_t
make_domain_prereq(dns_rdataclass_t rdclass) {
isc_result_t result;
char *ptr;
dns_name_t *name;
isc_buffer_t *buf;
isc_buffer_t source;
dns_rdataset_t *rdataset = NULL;
dns_rdatalist_t *rdatalist = NULL;
dns_rdata_t *rdata = NULL;
ddebug ("make_domain_prereq()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read owner name");
return STATUS_SYNTAX;
}
result = dns_message_gettempname(updatemsg, &name);
check_result(result, "dns_message_gettempname");
result = isc_buffer_allocate(mctx, &buf, NAMEBUF);
check_result(result, "isc_buffer_allocate");
dns_name_init(name, NULL);
dns_name_setbuffer(name, buf);
dns_message_takebuffer(updatemsg, &buf);
isc_buffer_init(&source, ptr, strlen(ptr));
isc_buffer_add(&source, strlen(ptr));
result = dns_name_fromtext(name, &source, &domainname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
check_and_add_zone(name);
result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
check_result(result, "dns_message_gettemprdatalist");
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdatalist_init(rdatalist);
rdatalist->type = dns_rdatatype_any;
rdatalist->rdclass = rdclass;
rdatalist->covers = 0;
rdatalist->ttl = 0;
result = dns_message_gettemprdata(updatemsg, &rdata);
check_result(result, "dns_message_gettemprdata");
rdata->data = NULL;
rdata->length = 0;
rdata->rdclass = rdclass;
rdata->type = dns_rdatatype_any;
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
dns_rdatalist_tordataset(rdatalist, rdataset);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_PREREQUISITE);
return STATUS_MORE;
}
static isc_uint16_t
evaluate_prereq() {
char *ptr;
ddebug ("evaluate_prereq()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read operation code");
return STATUS_SYNTAX;
}
if (strcasecmp(ptr,"nxdomain") == 0)
return(make_domain_prereq(dns_rdataclass_none));
if (strcasecmp(ptr,"yxdomain") == 0)
return(make_domain_prereq(dns_rdataclass_any));
if (strcasecmp(ptr,"nxrrset") == 0)
return(make_rrset_prereq(dns_rdataclass_none));
if (strcasecmp(ptr,"yxrrset") == 0)
return(make_rrset_prereq(dns_rdataclass_any));
printf ("incorrect operation code: %s\n",ptr);
return(STATUS_SYNTAX);
}
static isc_uint16_t
evaluate_server() {
char *ptr;
ddebug ("evaluate_server()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read server name");
return STATUS_SYNTAX;
}
strncpy(server, ptr, MXNAME);
return STATUS_MORE;
}
static isc_uint16_t
update_add() {
isc_result_t result;
isc_lex_t *lex = NULL;
isc_buffer_t *buf = NULL;
isc_buffer_t *namebuf = NULL;
isc_buffer_t source;
dns_name_t *name = NULL;
isc_uint16_t ttl;
char *ptr, *type, *data;
dns_rdatatype_t rdatatype;
dns_rdatacallbacks_t callbacks;
dns_rdata_t *rdata;
dns_rdatalist_t *rdatalist = NULL;
dns_rdataset_t *rdataset = NULL;
isc_textregion_t region;
ddebug ("update_add()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read owner name");
return STATUS_SYNTAX;
}
result = dns_message_gettempname(updatemsg, &name);
check_result(result, "dns_message_gettempname");
result = isc_buffer_allocate(mctx, &namebuf, NAMEBUF);
check_result(result, "isc_buffer_allocate");
dns_name_init(name, NULL);
dns_name_setbuffer(name, namebuf);
dns_message_takebuffer(updatemsg, &namebuf);
isc_buffer_init(&source, ptr, strlen(ptr));
isc_buffer_add(&source, strlen(ptr));
result = dns_name_fromtext(name, &source, &domainname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
check_and_add_zone(name);
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read owner ttl");
dns_message_puttempname(updatemsg, &name);
return STATUS_SYNTAX;
}
ttl = atoi(ptr);
type = strtok(NULL, " \t\r\n");
if (type == NULL) {
puts ("failed to read owner type");
dns_message_puttempname(updatemsg, &name);
return STATUS_SYNTAX;
}
data = strtok(NULL, " \t\r\n");
if (data == NULL) {
puts ("failed to read owner data");
dns_message_puttempname(updatemsg, &name);
return STATUS_SYNTAX;
}
result = isc_lex_create(mctx, NAMEHINT, &lex);
check_result(result, "isc_lex_create");
region.base = type;
region.length = strlen(type);
result = dns_rdatatype_fromtext(&rdatatype, &region);
check_result(result, "dns_rdatatype_fromtext");
isc_buffer_invalidate(&source);
isc_buffer_init(&source, data, strlen(data));
isc_buffer_add(&source, strlen(data));
result = isc_lex_openbuffer(lex, &source);
check_result(result, "isc_lex_openbuffer");
result = isc_buffer_allocate(mctx, &buf, MXNAME);
check_result(result, "isc_buffer_allocate");
result = dns_message_gettemprdata(updatemsg, &rdata);
check_result(result, "dns_message_gettemprdata");
dns_rdatacallbacks_init_stdio(&callbacks);
result = dns_rdata_fromtext(rdata, dns_rdataclass_in, rdatatype,
lex, &domainname, ISC_FALSE, buf,
&callbacks);
check_result(result, "dns_rdata_fromtext");
isc_lex_destroy(&lex);
check_and_add_zone(name);
result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
check_result(result, "dns_message_gettemprdatalist");
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdatalist_init(rdatalist);
rdatalist->type = rdatatype;
rdatalist->rdclass = dns_rdataclass_in;
rdatalist->covers = rdatatype;
rdatalist->ttl = ttl;
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
dns_rdatalist_tordataset(rdatalist, rdataset);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
dns_message_takebuffer(updatemsg, &buf);
#if 0
isc_buffer_free(&buf);
#endif
return STATUS_MORE;
}
/* XXXMWS add and delete share so much code, they should be collapsed. */
static isc_uint16_t
update_delete() {
isc_result_t result;
isc_lex_t *lex = NULL;
isc_buffer_t *namebuf = NULL;
isc_buffer_t *buf = NULL;
isc_buffer_t source;
dns_name_t *name = NULL;
char *ptr, *typeptr, *dataptr = NULL;
dns_rdatatype_t rdatatype;
dns_rdatacallbacks_t callbacks;
dns_rdata_t *rdata = NULL;
dns_rdatalist_t *rdatalist = NULL;
dns_rdataset_t *rdataset = NULL;
isc_textregion_t typeregion;
ddebug ("update_delete()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read owner name");
return STATUS_SYNTAX;
}
result = dns_message_gettempname(updatemsg, &name);
check_result(result, "dns_message_gettempname");
result = isc_buffer_allocate(mctx, &namebuf, NAMEBUF);
check_result(result, "isc_buffer_allocate");
dns_name_init(name, NULL);
dns_name_setbuffer(name, namebuf);
dns_message_takebuffer(updatemsg, &namebuf);
isc_buffer_init(&source, ptr, strlen(ptr));
isc_buffer_add(&source, strlen(ptr));
result = dns_name_fromtext(name, &source, &domainname,
ISC_FALSE, NULL);
check_result(result, "dns_name_fromtext");
check_and_add_zone(name);
typeptr = strtok(NULL, " \t\r\n");
if (typeptr != NULL) {
dataptr = strtok(NULL, " \t\r\n");
}
if (typeptr != NULL) {
typeregion.base = typeptr;
typeregion.length = strlen(typeptr);
result = dns_rdatatype_fromtext(&rdatatype, &typeregion);
check_result(result, "dns_rdatatype_fromtext");
isc_buffer_invalidate(&source);
}
else {
rdatatype = dns_rdatatype_any;
}
if (dataptr != NULL) {
result = isc_lex_create(mctx, NAMEHINT, &lex);
check_result(result, "isc_lex_create");
isc_buffer_init(&source, dataptr, strlen(dataptr));
isc_buffer_add(&source, strlen(dataptr));
result = isc_lex_openbuffer(lex, &source);
check_result(result, "isc_lex_openbuffer");
result = isc_buffer_allocate(mctx, &buf, MXNAME);
check_result(result, "isc_buffer_allocate");
result = dns_message_gettemprdata(updatemsg, &rdata);
check_result(result, "dns_message_gettemprdata");
dns_rdatacallbacks_init_stdio(&callbacks);
result = dns_rdata_fromtext(rdata, dns_rdataclass_in,
rdatatype, lex, &domainname,
ISC_FALSE, buf, &callbacks);
check_result(result, "dns_rdata_fromtext");
isc_lex_destroy(&lex);
result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
check_result(result, "dns_message_gettemprdatalist");
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdatalist_init(rdatalist);
rdatalist->type = rdatatype;
rdatalist->rdclass = dns_rdataclass_none;
rdatalist->covers = 0;
rdatalist->ttl = 0;
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
dns_rdatalist_tordataset(rdatalist, rdataset);
isc_buffer_free(&buf);
}
else {
#if 0
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdataset_makequestion(rdataset, dns_rdataclass_any,
rdatatype);
#endif
result = dns_message_gettemprdatalist(updatemsg, &rdatalist);
check_result(result, "dns_message_gettemprdatalist");
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdatalist_init(rdatalist);
rdatalist->type = rdatatype;
rdatalist->rdclass = dns_rdataclass_any;
rdatalist->covers = 0;
rdatalist->ttl = 0;
result = dns_message_gettemprdata(updatemsg, &rdata);
check_result(result, "dns_message_gettemprdata");
rdata->data = NULL;
rdata->length = 0;
rdata->rdclass = dns_rdataclass_any;
rdata->type = rdatatype;
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
dns_rdatalist_tordataset(rdatalist, rdataset);
}
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_UPDATE);
return STATUS_MORE;
}
static isc_uint16_t
evaluate_update() {
char *ptr;
ddebug ("evaluate_update()");
ptr = strtok(NULL, " \t\r\n");
if (ptr == NULL) {
puts ("failed to read operation code");
return STATUS_SYNTAX;
}
if (strcasecmp(ptr,"delete") == 0)
return(update_delete());
if (strcasecmp(ptr,"add") == 0)
return(update_add());
printf ("incorrect operation code: %s\n",ptr);
return(STATUS_SYNTAX);
}
static void
show_message() {
isc_result_t result;
char store[MSGTEXT];
isc_buffer_t buf;
ddebug ("show_message()");
isc_buffer_init(&buf, store, MSGTEXT);
result = dns_message_totext(updatemsg, 0, &buf);
check_result(result, "dns_message_totext");
printf ("Outgoing update query:\n%.*s",
(int)isc_buffer_usedlength(&buf),
(char*)isc_buffer_base(&buf));
}
static isc_uint16_t
get_next_command() {
char cmdline[MAXCMD];
char *ptr;
ddebug ("get_next_command()");
fputs ("> ", stderr);
fgets (cmdline, MAXCMD, stdin);
ptr = strtok(cmdline, " \t\r\n");
if (ptr == NULL) {
if (!feof(stdin))
return(STATUS_SEND);
else
return(STATUS_QUIT);
}
if (strcasecmp(ptr,"quit") == 0)
return(STATUS_QUIT);
if (strcasecmp(ptr,"prereq") == 0)
return(evaluate_prereq());
if (strcasecmp(ptr,"update") == 0)
return(evaluate_update());
if (strcasecmp(ptr,"server") == 0)
return(evaluate_server());
if (strcasecmp(ptr,"send") == 0)
return(STATUS_SEND);
if (strcasecmp(ptr,"show") == 0) {
show_message();
return(STATUS_MORE);
}
printf ("incorrect section name: %s\n",ptr);
return(STATUS_SYNTAX);
}
static isc_boolean_t
user_interaction() {
isc_uint16_t result = STATUS_MORE;
ddebug ("user_interaction()");
while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) {
result = get_next_command();
}
if (result == STATUS_SEND)
return ISC_TRUE;
if (result == STATUS_FAIL)
exitcode = 1;
return ISC_FALSE;
}
static void
get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
struct in_addr in4;
struct in6_addr in6;
struct hostent *he;
ddebug("get_address()");
if (have_ipv6 && inet_pton(AF_INET6, host, &in6) == 1)
isc_sockaddr_fromin6(sockaddr, &in6, port);
else if (inet_pton(AF_INET, host, &in4) == 1)
isc_sockaddr_fromin(sockaddr, &in4, port);
else {
he = gethostbyname(host);
if (he == NULL)
fatal("Couldn't look up your server host %s. errno=%d",
host, h_errno);
INSIST(he->h_addrtype == AF_INET);
isc_sockaddr_fromin(sockaddr,
(struct in_addr *)(he->h_addr_list[0]),
port);
}
}
static void
update_completed(isc_task_t *task, isc_event_t *event) {
dns_requestevent_t *reqev = NULL;
isc_result_t result;
isc_buffer_t buf;
dns_message_t *rcvmsg = NULL;
char bufstore[MSGTEXT];
UNUSED (task);
ddebug ("updated_completed()");
REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
reqev = (dns_requestevent_t *)event;
if (reqev->result != ISC_R_SUCCESS) {
printf ("; Communication with server failed: %d-%s\n",
reqev->result, isc_result_totext(reqev->result));
goto done;
}
result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
check_result(result, "dns_message_create");
result = dns_request_getresponse(reqev->request, rcvmsg, ISC_TRUE);
check_result(result, "dns_request_getresponse");
if (debug) {
isc_buffer_init(&buf, bufstore, MSGTEXT);
result = dns_message_totext(rcvmsg, 0, &buf);
check_result(result, "dns_message_totext");
printf ("\nReply from update query:\n%.*s\n",
(int)isc_buffer_usedlength(&buf),
(char*)isc_buffer_base(&buf));
}
dns_message_destroy(&rcvmsg);
done:
dns_request_destroy(&reqev->request);
isc_event_free(&event);
isc_mutex_lock(&lock);
busy = ISC_FALSE;
isc_condition_signal(&cond);
isc_mutex_unlock(&lock);
}
static void
send_update() {
isc_result_t result;
isc_sockaddr_t sockaddr;
dns_request_t *request = NULL;
char servername[MXNAME];
isc_buffer_t buf;
dns_name_t *name = NULL;
dns_rdataset_t *rdataset = NULL;
ddebug ("send_update()");
result = dns_message_gettempname(updatemsg, &name);
check_result(result, "dns_message_gettempname");
dns_name_init(name, NULL);
dns_name_clone(&actualzone, name);
result = dns_message_gettemprdataset(updatemsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdataset_makequestion(rdataset, dns_rdataclass_in,
dns_rdatatype_soa);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
isc_buffer_init(&buf, servername, MXNAME);
result = dns_name_totext(&master, ISC_TRUE, &buf);
check_result(result, "dns_name_totext");
servername[isc_buffer_usedlength(&buf)] = 0;
get_address(servername, 53, &sockaddr);
result = dns_request_create(requestmgr, updatemsg, &sockaddr,
0, NULL,
FIND_TIMEOUT, global_task,
update_completed, NULL, &request);
check_result(result, "dns_request_create");
}
static void
find_completed(isc_task_t *task, isc_event_t *event) {
dns_requestevent_t *reqev = NULL;
isc_sockaddr_t sockaddr;
dns_request_t *request = NULL;
isc_result_t result;
dns_message_t *rcvmsg = NULL;
dns_section_t section;
dns_name_t *name = NULL;
dns_rdataset_t *rdataset = NULL;
dns_rdata_soa_t soa;
dns_rdata_t rdata;
isc_buffer_t buf;
char bufstore[MSGTEXT];
UNUSED(task);
ddebug ("find_completed()");
REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
reqev = (dns_requestevent_t *)event;
if (reqev->result != ISC_R_SUCCESS) {
printf ("; Communication with %s failed: %d-%s\n",
nameservername[ns_inuse], reqev->result,
isc_result_totext(reqev->result));
ns_inuse++;
if (ns_inuse >= nameservers) {
fatal ("Couldn't talk to any default nameserver.");
}
get_address(nameservername[ns_inuse], 53, &sockaddr);
#if 1
ddebug("Destroying %lx[%lx]", &reqev->request,
reqev->request);
dns_request_destroy(&reqev->request);
#endif
isc_event_free(&event);
result = dns_request_create(requestmgr, findmsg, &sockaddr,
0, NULL,
FIND_TIMEOUT, global_task,
find_completed, NULL, &request);
check_result(result, "dns_result_create");
return;
}
ddebug ("About to create rcvmsg");
result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
check_result(result, "dns_message_create");
result = dns_request_getresponse(reqev->request, rcvmsg, ISC_TRUE);
check_result(result, "dns_request_getresponse");
section = DNS_SECTION_ANSWER;
if (debugging) {
isc_buffer_init(&buf, bufstore, MSGTEXT);
result = dns_message_totext(rcvmsg, 0, &buf);
check_result(result, "dns_message_totext");
printf ("Reply from SOA query:\n%.*s\n", (int)isc_buffer_usedlength(&buf),
(char*)isc_buffer_base(&buf));
}
/* XXXMWS Really shouldn't use firstname here */
section = DNS_SECTION_ANSWER;
result = dns_message_firstname(rcvmsg, section);
if (result != ISC_R_SUCCESS) {
section = DNS_SECTION_AUTHORITY;
result = dns_message_firstname(rcvmsg, section);
check_result(result, "dns_message_firstname");
}
dns_message_currentname(rcvmsg, section, &name);
dns_name_init(&actualzone, NULL);
result = dns_name_dup(name, mctx, &actualzone);
/* Name is just a reference, so this is safe. */
name = NULL;
if (debugging) {
isc_buffer_clear(&buf);
result = dns_name_totext(&actualzone, ISC_FALSE, &buf);
check_result(result, "dns_name_totext");
printf ("Found zone name: %.*s\n",
(int)isc_buffer_usedlength(&buf),
(char*)isc_buffer_base(&buf));
}
ddebug("Finding name");
result = dns_message_findname(rcvmsg, section, &actualzone,
dns_rdatatype_soa, 0,
&name, &rdataset);
check_result(result, "Couldn't find SOA in reply");
result = dns_rdataset_first(rdataset);
check_result(result, "dns_rdataset_first");
dns_rdataset_current(rdataset, &rdata);
ddebug("tostruct");
result = dns_rdata_tostruct(&rdata, &soa, mctx);
check_result(result, "dns_rdata_tostruct");
dns_name_init(&master, NULL);
ddebug("Duping master");
result = dns_name_dup(&soa.origin, mctx, &master);
check_result(result, "dns_name_dup");
if (debugging) {
isc_buffer_clear(&buf);
result = dns_name_totext(&master, ISC_FALSE, &buf);
check_result(result, "dns_name_totext");
printf ("The master is: %.*s\n",
(int)isc_buffer_usedlength(&buf),
(char*)isc_buffer_base(&buf));
}
dns_rdata_freestruct(&soa);
dns_message_destroy(&rcvmsg);
dns_request_destroy(&reqev->request);
isc_event_free(&event);
ddebug ("Out of find_completed");
send_update();
}
static void
start_update() {
isc_result_t result;
dns_rdataset_t *rdataset = NULL;
dns_name_t *name = NULL;
isc_sockaddr_t sockaddr;
dns_request_t *request = NULL;
ddebug ("start_update()");
result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
&findmsg);
check_result(result, "dns_message_create");
findmsg->flags |= DNS_MESSAGEFLAG_RD;
result = dns_message_gettempname(findmsg, &name);
check_result(result, "dns_message_gettempname");
result = dns_message_gettemprdataset(findmsg, &rdataset);
check_result(result, "dns_message_gettemprdataset");
dns_rdataset_makequestion(rdataset, dns_rdataclass_in,
dns_rdatatype_soa);
dns_name_init(name, NULL);
if (!valid_zonename) {
fatal ("don't have a valid zone yet.");
}
dns_name_clone(&zonename, name);
ISC_LIST_INIT(name->list);
ISC_LIST_APPEND(name->list, rdataset, link);
dns_message_addname(findmsg, name, DNS_SECTION_QUESTION);
ns_inuse = 0;
get_address(nameservername[0], 53, &sockaddr);
result = dns_request_create(requestmgr, findmsg, &sockaddr,
0, NULL,
FIND_TIMEOUT, global_task,
find_completed, NULL, &request);
check_result(result, "dns_request_create");
}
static void
free_lists() {
ddebug ("free_lists()");
if (updatemsg != NULL)
dns_message_destroy(&updatemsg);
if (findmsg != NULL)
dns_message_destroy(&findmsg);
if (VALID_NAME(&actualzone)) {
ddebug("Freeing actualzone");
dns_name_free(&actualzone, mctx);
}
if (VALID_NAME(&zonename)) {
ddebug("Freeing zonename");
dns_name_free(&zonename, mctx);
}
ddebug("Invalidating domainname");
dns_name_invalidate(&domainname);
ddebug("Shutting down request manager");
dns_requestmgr_shutdown(requestmgr);
dns_requestmgr_detach(&requestmgr);
ddebug("Freeing the dispatcher");
dns_dispatch_detach(&dispatchv4);
ddebug("Shutting down dispatch manager");
dns_dispatchmgr_destroy(&dispatchmgr);
ddebug("Shutting down socket manager");
isc_socketmgr_destroy(&socketmgr);
ddebug("Shutting down timer manager");
isc_timermgr_destroy(&timermgr);
ddebug("Ending task");
isc_task_detach(&global_task);
ddebug("Shutting down task manager");
isc_taskmgr_destroy(&taskmgr);
ddebug("Destroying memory context");
if (isc_mem_debugging)
isc_mem_stats(mctx, stderr);
isc_mem_destroy(&mctx);
exit(0);
}
int
main(int argc, char **argv) {
isc_result_t result;
setup_system();
result = isc_mutex_init(&lock);
check_result(result, "isc_mutex_init");
result = isc_condition_init(&cond);
check_result(result, "isc_condition_init");
result = isc_mutex_trylock(&lock);
check_result(result, "isc_mutex_trylock");
parse_args(argc, argv);
while (ISC_TRUE) {
reset_system();
if (!user_interaction())
break;
busy = ISC_TRUE;
start_update();
while (busy) {
result = isc_condition_wait(&cond, &lock);
check_result(result, "isc_condition_wait");
}
}
puts ("");
ddebug ("Fell through app_run");
free_lists(0);
isc_mutex_destroy(&lock);
isc_condition_destroy(&cond);
return (0);
}