diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index e546bda034..e3026ab389 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -1,21 +1,21 @@ /* * 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 @@ -33,12 +33,11 @@ extern int h_errno; #include #include #include -#include #include #include +#include #include #include -#include #include #include #include @@ -51,6 +50,7 @@ extern int h_errno; #include #include #include +#include #include #include #include @@ -68,29 +68,29 @@ extern int h_errno; #include #include -#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; @@ -104,7 +104,6 @@ static dns_name_t *origin; /* Points to one of above, or dns_rootname */ 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; @@ -132,7 +131,7 @@ static void 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"); @@ -144,7 +143,7 @@ debug(const char *format, ...) { va_list args; if (debugging) { - va_start(args, format); + va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr, "\n"); @@ -156,7 +155,7 @@ ddebug(const char *format, ...) { va_list args; if (ddebugging) { - va_start(args, format); + va_start(args, format); vfprintf(stderr, format, args); va_end(args); fprintf(stderr, "\n"); @@ -252,17 +251,12 @@ setup_key(void) { 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..."); @@ -285,27 +279,16 @@ setup_key(void) { 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; @@ -333,11 +316,11 @@ setup_key(void) { 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) @@ -354,7 +337,6 @@ setup_key(void) { if (secret != NULL) isc_mem_free(mctx, secret); - dns_tsigkeyring_destroy(&keyring); } static void @@ -368,15 +350,6 @@ setup_system(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(); @@ -545,7 +518,7 @@ parse_args(int argc, char **argv) { 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; @@ -621,31 +594,42 @@ parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, 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); } @@ -743,7 +727,7 @@ make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { 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); @@ -1014,23 +998,37 @@ evaluate_update(char *cmdline) { } 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) { @@ -1040,8 +1038,9 @@ 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)) @@ -1061,7 +1060,7 @@ get_next_command(void) { 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); @@ -1082,23 +1081,17 @@ user_interaction(void) { } 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()"); @@ -1112,21 +1105,38 @@ update_completed(isc_task_t *task, isc_event_t *event) { 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 @@ -1195,7 +1205,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) { 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)); @@ -1216,19 +1226,31 @@ recvsoa(isc_task_t *task, isc_event_t *event) { 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 && @@ -1266,7 +1288,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) { } if (debugging) { - char namestr[MAXPNAME]; + char namestr[MAXNAME]; dns_name_format(name, namestr, sizeof(namestr)); fprintf(stderr, "Found zone name: %s\n", namestr); } @@ -1288,7 +1310,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) { 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); } @@ -1296,7 +1318,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) { if (userserver != NULL) serveraddr = userserver; else { - char serverstr[MXNAME]; + char serverstr[MAXNAME+1]; isc_buffer_t buf; isc_buffer_init(&buf, serverstr, sizeof(serverstr)); @@ -1351,7 +1373,7 @@ start_update(void) { result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE); if (result != ISC_R_SUCCESS) { - done_update(ISC_FALSE); + done_update(); return; } @@ -1396,15 +1418,9 @@ cleanup(void) { 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); @@ -1423,7 +1439,7 @@ cleanup(void) { 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); @@ -1439,6 +1455,10 @@ cleanup(void) { 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); @@ -1454,33 +1474,44 @@ cleanup(void) { 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); }