/*
* 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.
+ *
+ * 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.8.2.12 2000/10/19 17:13:22 gson Exp $ */
+/* $Id: nsupdate.c,v 1.8.2.13 2000/10/20 18:32:20 gson Exp $ */
#include <config.h>
#include <isc/app.h>
#include <isc/base64.h>
#include <isc/buffer.h>
-#include <isc/condition.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
+#include <isc/event.h>
#include <isc/lex.h>
#include <isc/mem.h>
-#include <isc/mutex.h>
#include <isc/region.h>
#include <isc/sockaddr.h>
#include <isc/socket.h>
#include <dns/callbacks.h>
#include <dns/dispatch.h>
#include <dns/events.h>
+#include <dns/fixedname.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <lwres/lwres.h>
#include <lwres/net.h>
-#define MXNAME 256
-#define MAXPNAME 1025
-#define MAXCMD 1024
+#define MAXCMD (4 * 1024)
+#define INITDATA (32 * 1024)
+#define MAXDATA (64 * 1024)
#define NAMEBUF 512
#define WORDLEN 512
-#define PACKETSIZE 2048
-#define MSGTEXT 4096
+#define PACKETSIZE ((64 * 1024) - 1)
+#define INITTEXT (2 * 1024)
+#define MAXTEXT (128 * 1024)
#define FIND_TIMEOUT 5
#define TTL_MAX 2147483647 /* Maximum signed 32 bit integer. */
#define DNSDEFAULTPORT 53
+#define MAXNAME 1024
#define RESOLV_CONF "/etc/resolv.conf"
-static isc_boolean_t busy = ISC_FALSE;
static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE;
static isc_boolean_t have_ipv6 = ISC_FALSE;
static isc_boolean_t is_dst_up = ISC_FALSE;
static isc_boolean_t usevc = ISC_FALSE;
-static isc_mutex_t lock;
-static isc_condition_t cond;
static isc_taskmgr_t *taskmgr = NULL;
static isc_task_t *global_task = NULL;
+static isc_event_t *global_event = NULL;
static isc_mem_t *mctx = NULL;
static dns_dispatchmgr_t *dispatchmgr = NULL;
static dns_requestmgr_t *requestmgr = NULL;
static dns_fixedname_t fuserzone;
static dns_name_t *userzone = NULL;
static dns_tsigkey_t *key = NULL;
-static dns_tsig_keyring_t *keyring = NULL;
static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf;
static isc_sockaddr_t *servers;
fatal(const char *format, ...) {
va_list args;
- va_start(args, format);
+ va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
va_list args;
if (debugging) {
- va_start(args, format);
+ va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
va_list args;
if (ddebugging) {
- va_start(args, format);
+ va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
dns_fixedname_t fkeyname;
dns_name_t *keyname;
- result = dns_tsigkeyring_create(mctx, &keyring);
- check_result(result, "dns_tsigkeyringcreate");
-
dns_fixedname_init(&fkeyname);
keyname = dns_fixedname_name(&fkeyname);
if (keystr != NULL) {
isc_buffer_t keynamesrc;
char *secretstr;
- isc_buffer_t secretsrc;
- isc_lex_t *lex = NULL;
char *s;
debug("Creating key...");
if (secret == NULL)
fatal("out of memory");
- isc_buffer_init(&secretsrc, secretstr, strlen(secretstr));
- isc_buffer_add(&secretsrc, strlen(secretstr));
-
isc_buffer_init(&secretbuf, secret, secretlen);
-
- result = isc_lex_create(mctx, strlen(secretstr), &lex);
- check_result(result, "isc_lex_create");
- result = isc_lex_openbuffer(lex, &secretsrc);
- check_result(result, "isc_lex_openbuffer");
- result = isc_base64_tobuffer(lex, &secretbuf, -1);
+ result = isc_base64_decodestring(mctx, secretstr, &secretbuf);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "Couldn't create key from %s: %s\n",
keystr, isc_result_totext(result));
- isc_lex_close(lex);
- isc_lex_destroy(&lex);
goto failure;
}
+
secretlen = isc_buffer_usedlength(&secretbuf);
debug("close");
- isc_lex_close(lex);
- isc_lex_destroy(&lex);
} else {
dst_key_t *dstkey = NULL;
dst_key_free(&dstkey);
}
-
+
debug("keycreate");
result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name,
secret, secretlen, ISC_TRUE, NULL, 0, 0,
- mctx, keyring, &key);
+ mctx, NULL, &key);
if (result != ISC_R_SUCCESS) {
char *str;
if (keystr != NULL)
if (secret != NULL)
isc_mem_free(mctx, secret);
- dns_tsigkeyring_destroy(&keyring);
}
static void
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.
- *
- * XXX Shouldn't random() be called somewhere if this is here?
- */
- srandom(getpid() + (int)&setup_system);
-
dns_result_register();
result = isc_net_probeipv4();
case 'M': /* was -dm */
debugging = ISC_TRUE;
ddebugging = ISC_TRUE;
- isc_mem_debugging = ISC_TRUE;
+ isc_mem_debugging = 1;
break;
case 'y':
keystr = isc_commandline_argument;
dns_rdatacallbacks_t callbacks;
isc_result_t result;
dns_name_t *rn;
+ int bufsz = INITDATA;
while (*cmdline != 0 && isspace((unsigned char)*cmdline))
cmdline++;
if (*cmdline != 0) {
- result = isc_lex_create(mctx, WORDLEN, &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, MXNAME);
- check_result(result, "isc_buffer_allocate");
- dns_rdatacallbacks_init_stdio(&callbacks);
+ dns_rdatacallbacks_init(&callbacks);
if (userzone != NULL)
rn = userzone;
else
rn = origin;
- result = dns_rdata_fromtext(*rdatap, rdataclass, rdatatype,
- lex, rn, ISC_FALSE, buf,
- &callbacks);
+ do {
+ 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");
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ if (bufsz > MAXDATA) {
+ fprintf(stderr, "couldn't allocate enough "
+ "space for the rdata\n");
+ exit(1);
+ }
+ result = isc_buffer_allocate(mctx, &buf, bufsz);
+ check_result(result, "isc_buffer_allocate");
+ result = dns_rdata_fromtext(*rdatap, rdataclass,
+ rdatatype,
+ lex, rn, ISC_FALSE, buf,
+ &callbacks);
+ bufsz *= 2;
+ isc_lex_destroy(&lex);
+ } while (result == ISC_R_NOSPACE);
+ check_result(result, "dns_rdata_fromtext");
dns_message_takebuffer(msg, &buf);
- isc_lex_destroy(&lex);
if (result != ISC_R_SUCCESS)
return (STATUS_MORE);
}
ISC_LIST_INIT(rdatalist->rdata);
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
dns_rdataset_init(rdataset);
- dns_rdatalist_tordataset(rdatalist, 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);
}
static void
-show_message(void) {
+show_message(dns_message_t *msg) {
isc_result_t result;
- char store[MSGTEXT];
- isc_buffer_t buf;
+ isc_buffer_t *buf = NULL;
+ int bufsz;
ddebug("show_message()");
- isc_buffer_init(&buf, store, MSGTEXT);
- result = dns_message_totext(updatemsg, 0, &buf);
+ bufsz = INITTEXT;
+ do {
+ if (bufsz > MAXTEXT) {
+ fprintf(stderr, "couldn't allocate large enough "
+ "buffer to display message\n");
+ exit(1);
+ }
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ result = isc_buffer_allocate(mctx, &buf, bufsz);
+ check_result(result, "isc_buffer_allocate");
+ result = dns_message_totext(msg, 0, buf);
+ bufsz *= 2;
+ } while (result == ISC_R_NOSPACE);
if (result != ISC_R_SUCCESS) {
- fprintf(stderr, "Failed to concert message to text format.\n");
+ fprintf(stderr, "Failed to convert message to text format.\n");
+ isc_buffer_free(&buf);
return;
}
printf("Outgoing update query:\n%.*s",
- (int)isc_buffer_usedlength(&buf),
- (char*)isc_buffer_base(&buf));
+ (int)isc_buffer_usedlength(buf),
+ (char*)isc_buffer_base(buf));
+ isc_buffer_free(&buf);
}
-
+
static isc_uint16_t
get_next_command(void) {
ddebug("get_next_command()");
fprintf(stdout, "> ");
- fgets (cmdlinebuf, MAXCMD, stdin);
- cmdline = cmdlinebuf;
+ cmdline = fgets(cmdlinebuf, MAXCMD, stdin);
+ if (cmdline == NULL)
+ return (STATUS_QUIT);
word = nsu_strsep(&cmdline, " \t\r\n");
if (feof(stdin))
if (strcasecmp(word, "send") == 0)
return (STATUS_SEND);
if (strcasecmp(word, "show") == 0) {
- show_message();
+ show_message(updatemsg);
return (STATUS_MORE);
}
fprintf(stderr, "incorrect section name: %s\n", word);
}
static void
-done_update(isc_boolean_t acquirelock) {
- if (acquirelock)
- LOCK(&lock);
- busy = ISC_FALSE;
- SIGNAL(&cond);
- if (acquirelock)
- UNLOCK(&lock);
+done_update(void) {
+ isc_event_t *event = global_event;
+ isc_task_send(global_task, &event);
}
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()");
result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
check_result(result, "dns_message_create");
- result = dns_request_getresponse(reqev->request, rcvmsg, ISC_TRUE);
+ result = dns_request_getresponse(reqev->request, rcvmsg,
+ ISC_TRUE);
check_result(result, "dns_request_getresponse");
if (debugging) {
- isc_buffer_init(&buf, bufstore, MSGTEXT);
- result = dns_message_totext(rcvmsg, 0, &buf);
+ isc_buffer_t *buf = NULL;
+ int bufsz;
+
+ bufsz = INITTEXT;
+ do {
+ if (bufsz > MAXTEXT) {
+ fprintf (stderr, "couldn't allocate large "
+ "enough buffer to display message\n");
+ exit(1);
+ }
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ result = isc_buffer_allocate(mctx, &buf, bufsz);
+ check_result(result, "isc_buffer_allocate");
+ result = dns_message_totext(rcvmsg, 0, buf);
+ bufsz *= 2;
+ } while (result == ISC_R_NOSPACE);
check_result(result, "dns_message_totext");
fprintf(stderr, "\nReply from update query:\n%.*s\n",
- (int)isc_buffer_usedlength(&buf),
- (char*)isc_buffer_base(&buf));
+ (int)isc_buffer_usedlength(buf),
+ (char*)isc_buffer_base(buf));
+ isc_buffer_free(&buf);
}
dns_message_destroy(&rcvmsg);
done:
dns_request_destroy(&reqev->request);
isc_event_free(&event);
- done_update(ISC_TRUE);
+ done_update();
}
static void
if (eresult != ISC_R_SUCCESS) {
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
+
isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
fprintf(stderr, "; Communication with %s failed: %s\n",
addrbuf, isc_result_totext(eresult));
ddebug("About to create rcvmsg");
result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
check_result(result, "dns_message_create");
- result = dns_request_getresponse(request, rcvmsg, ISC_TRUE);
+ result = dns_request_getresponse(request, rcvmsg,
+ ISC_TRUE);
check_result(result, "dns_request_getresponse");
section = DNS_SECTION_ANSWER;
if (debugging) {
- isc_buffer_t buf;
- char bufstore[MSGTEXT];
-
- isc_buffer_init(&buf, bufstore, MSGTEXT);
- result = dns_message_totext(rcvmsg, 0, &buf);
+ isc_buffer_t *buf = NULL;
+ int bufsz;
+ bufsz = INITTEXT;
+ do {
+ if (buf != NULL)
+ isc_buffer_free(&buf);
+ if (bufsz > MAXTEXT) {
+ fprintf(stderr, "couldn't allocate enough "
+ "space for debugging message\n");
+ exit(1);
+ }
+ result = isc_buffer_allocate(mctx, &buf, bufsz);
+ check_result(result, "isc_buffer_allocate");
+ result = dns_message_totext(rcvmsg, 0, buf);
+ } while (result == ISC_R_NOSPACE);
check_result(result, "dns_message_totext");
fprintf(stderr, "Reply from SOA query:\n%.*s\n",
- (int)isc_buffer_usedlength(&buf),
- (char*)isc_buffer_base(&buf));
+ (int)isc_buffer_usedlength(buf),
+ (char*)isc_buffer_base(buf));
+ isc_buffer_free(&buf);
}
if (rcvmsg->rcode != dns_rcode_noerror &&
}
if (debugging) {
- char namestr[MAXPNAME];
+ char namestr[MAXNAME];
dns_name_format(name, namestr, sizeof(namestr));
fprintf(stderr, "Found zone name: %s\n", namestr);
}
zonename = name;
if (debugging) {
- char namestr[MAXPNAME];
+ char namestr[MAXNAME];
dns_name_format(&master, namestr, sizeof(namestr));
fprintf(stderr, "The master is: %s\n", namestr);
}
if (userserver != NULL)
serveraddr = userserver;
else {
- char serverstr[MXNAME];
+ char serverstr[MAXNAME+1];
isc_buffer_t buf;
isc_buffer_init(&buf, serverstr, sizeof(serverstr));
result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE);
if (result != ISC_R_SUCCESS) {
- done_update(ISC_FALSE);
+ done_update();
return;
}
if (key != NULL) {
debug("Freeing key");
- dns_tsigkey_setdeleted(key);
dns_tsigkey_detach(&key);
}
- if (keyring != NULL) {
- debug("Freeing keyring %lx", keyring);
- dns_tsigkeyring_destroy(&keyring);
- }
-
if (updatemsg != NULL)
dns_message_destroy(&updatemsg);
lwres_context_destroy(&lwctx);
isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
-
+
ddebug("Shutting down request manager");
dns_requestmgr_shutdown(requestmgr);
dns_requestmgr_detach(&requestmgr);
ddebug("Ending task");
isc_task_detach(&global_task);
+ ddebug("Destroying event task");
+ if (global_event != NULL)
+ isc_event_free(&global_event);
+
ddebug("Shutting down task manager");
isc_taskmgr_destroy(&taskmgr);
isc_mem_destroy(&mctx);
}
+static void
+getinput(isc_task_t *task, isc_event_t *event) {
+ isc_boolean_t more;
+
+ UNUSED(task);
+
+ if (global_event == NULL)
+ global_event = event;
+
+ reset_system();
+ more = user_interaction();
+ if (!more) {
+ isc_app_shutdown();
+ return;
+ }
+ start_update();
+ return;
+}
+
int
main(int argc, char **argv) {
isc_result_t result;
+ isc_app_start();
+
parse_args(argc, argv);
setup_system();
- result = isc_mutex_init(&lock);
- check_result(result, "isc_mutex_init");
- result = isc_condition_init(&cond);
- check_result(result, "isc_condition_init");
- LOCK(&lock);
-
- while (ISC_TRUE) {
- reset_system();
- if (!user_interaction())
- break;
- busy = ISC_TRUE;
- start_update();
- while (busy)
- WAIT(&cond, &lock);
- }
+
+ result = isc_app_onrun(mctx, global_task, getinput, NULL);
+ check_result(result, "isc_app_onrun");
+
+ (void)isc_app_run();
fprintf(stdout, "\n");
- isc_mutex_destroy(&lock);
- isc_condition_destroy(&cond);
cleanup();
+ isc_app_finish();
+
return (0);
}