diff options
Diffstat (limited to 'usr.sbin/bind/bin/nsupdate')
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/Makefile.in | 78 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/nsupdate.8 | 341 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/nsupdate.c | 1869 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/nsupdate.docbook | 556 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/nsupdate.html | 959 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsp | 103 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsw | 29 | ||||
-rw-r--r-- | usr.sbin/bind/bin/nsupdate/win32/nsupdate.mak | 203 |
8 files changed, 4138 insertions, 0 deletions
diff --git a/usr.sbin/bind/bin/nsupdate/Makefile.in b/usr.sbin/bind/bin/nsupdate/Makefile.in new file mode 100644 index 00000000000..417211c1d3d --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/Makefile.in @@ -0,0 +1,78 @@ +# Copyright (C) 2000, 2001 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. + +# $ISC: Makefile.in,v 1.15 2001/06/01 00:45:01 bwelling Exp $ + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +@BIND9_INCLUDES@ + +CINCLUDES = ${LWRES_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} + +CDEFINES = +CWARNINGS = + +LWRESLIBS = ../../lib/lwres/liblwres.@A@ +DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_OPENSSL_LIBS@ @DNS_GSSAPI_LIBS@ +ISCLIBS = ../../lib/isc/libisc.@A@ + +LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ + +DEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${LWRESLIBS} ${DNSLIBS} ${ISCLIBS} @LIBS@ + +SUBDIRS = + +TARGETS = nsupdate + +OBJS = nsupdate.@O@ + +UOBJS = + +SRCS = nsupdate.c + +MANPAGES = nsupdate.8 + +HTMLPAGES = nsupdate.html + +MANOBJS = ${MANPAGES} ${HTMLPAGES} + +@BIND9_MAKE_RULES@ + +nsupdate: nsupdate.@O@ ${UOBJS} ${DEPLIBS} + ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ nsupdate.@O@ ${UOBJS} ${LIBS} + +doc man:: ${MANOBJS} + +docclean manclean maintainer-clean:: + rm -f ${MANOBJS} + +clean distclean:: + rm -f ${TARGETS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 + +install:: nsupdate installdirs + ${LIBTOOL} ${INSTALL_PROGRAM} nsupdate ${DESTDIR}${bindir} + ${INSTALL_DATA} ${srcdir}/nsupdate.8 ${DESTDIR}${mandir}/man8 diff --git a/usr.sbin/bind/bin/nsupdate/nsupdate.8 b/usr.sbin/bind/bin/nsupdate/nsupdate.8 new file mode 100644 index 00000000000..9d469db25bc --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/nsupdate.8 @@ -0,0 +1,341 @@ +.\" +.\" Copyright (C) 2000, 2001 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. +.\" +.TH "NSUPDATE" "8" "Jun 30, 2000" "BIND9" "" +.SH NAME +nsupdate \- Dynamic DNS update utility +.SH SYNOPSIS +.sp +\fBnsupdate\fR [ \fB-d\fR ] [ \fB [ -y \fIkeyname:secret\fB ] [ -k \fIkeyfile\fB ] \fR ] [ \fB-v\fR ] [ \fBfilename\fR ] +.SH "DESCRIPTION" +.PP +\fBnsupdate\fR +is used to submit Dynamic DNS Update requests as defined in RFC2136 +to a name server. +This allows resource records to be added or removed from a zone +without manually editing the zone file. +A single update request can contain requests to add or remove more than one +resource record. +.PP +Zones that are under dynamic control via +\fBnsupdate\fR +or a DHCP server should not be edited by hand. +Manual edits could +conflict with dynamic updates and cause data to be lost. +.PP +The resource records that are dynamically added or removed with +\fBnsupdate\fR +have to be in the same zone. +Requests are sent to the zone's master server. +This is identified by the MNAME field of the zone's SOA record. +.PP +The +\fB-d\fR +option makes +\fBnsupdate\fR +operate in debug mode. +This provides tracing information about the update requests that are +made and the replies received from the name server. +.PP +Transaction signatures can be used to authenticate the Dynamic DNS +updates. +These use the TSIG resource record type described in RFC2845. +The signatures rely on a shared secret that should only be known to +\fBnsupdate\fR +and the name server. +Currently, the only supported encryption algorithm for TSIG is +HMAC-MD5, which is defined in RFC 2104. +Once other algorithms are defined for TSIG, applications will need to +ensure they select the appropriate algorithm as well as the key when +authenticating each other. +For instance suitable +\fBkey\fR +and +\fBserver\fR +statements would be added to +\fI/etc/named.conf\fR +so that the name server can associate the appropriate secret key +and algorithm with the IP address of the +client application that will be using TSIG authentication. +\fBnsupdate\fR +does not read +\fI/etc/named.conf\fR. +.PP +\fBnsupdate\fR +uses the +\fB-y\fR +or +\fB-k\fR +option to provide the shared secret needed to generate a TSIG record +for authenticating Dynamic DNS update requests. +These options are mutually exclusive. +With the +\fB-k\fR +option, +\fBnsupdate\fR +reads the shared secret from the file +\fIkeyfile\fR, +whose name is of the form +\fIK{name}.+157.+{random}.private\fR. +For historical +reasons, the file +\fIK{name}.+157.+{random}.key\fR +must also be present. When the +\fB-y\fR +option is used, a signature is generated from +\fIkeyname:secret.\fR +\fIkeyname\fR +is the name of the key, +and +\fIsecret\fR +is the base64 encoded shared secret. +Use of the +\fB-y\fR +option is discouraged because the shared secret is supplied as a command +line argument in clear text. +This may be visible in the output from +\fBps\fR(1) +or in a history file maintained by the user's shell. +.PP +By default +\fBnsupdate\fR +uses UDP to send update requests to the name server. +The +\fB-v\fR +option makes +\fBnsupdate\fR +use a TCP connection. +This may be preferable when a batch of update requests is made. +.SH "INPUT FORMAT" +.PP +\fBnsupdate\fR +reads input from +\fIfilename\fR +or standard input. +Each command is supplied on exactly one line of input. +Some commands are for administrative purposes. +The others are either update instructions or prerequisite checks on the +contents of the zone. +These checks set conditions that some name or set of +resource records (RRset) either exists or is absent from the zone. +These conditions must be met if the entire update request is to succeed. +Updates will be rejected if the tests for the prerequisite conditions fail. +.PP +Every update request consists of zero or more prerequisites +and zero or more updates. +This allows a suitably authenticated update request to proceed if some +specified resource records are present or missing from the zone. +A blank input line (or the \fBsend\fR command) causes the +accumulated commands to be sent as one Dynamic DNS update request to the +name server. +.PP +The command formats and their meaning are as follows: +.TP +\fBserver servername [ port ]\fR +Sends all dynamic update requests to the name server +\fIservername\fR. +When no server statement is provided, +\fBnsupdate\fR +will send updates to the master server of the correct zone. +The MNAME field of that zone's SOA record will identify the master +server for that zone. +\fIport\fR +is the port number on +\fIservername\fR +where the dynamic update requests get sent. +If no port number is specified, the default DNS port number of 53 is +used. +.TP +\fBlocal address [ port ]\fR +Sends all dynamic update requests using the local +\fIaddress\fR. +When no local statement is provided, +\fBnsupdate\fR +will send updates using an address and port choosen by the system. +\fIport\fR +can additionally be used to make requests come from a specific port. +If no port number is specified, the system will assign one. +.TP +\fBzone zonename\fR +Specifies that all updates are to be made to the zone +\fIzonename\fR. +If no +\fIzone\fR +statement is provided, +\fBnsupdate\fR +will attempt determine the correct zone to update based on the rest of the input. +.TP +\fBkey name secret\fR +Specifies that all updates are to be TSIG signed using the +\fIkeyname\fR \fIkeysecret\fR pair. +The \fBkey\fR command +overrides any key specified on the command line via +\fB-y\fR or \fB-k\fR. +.TP +\fBprereq nxdomain domain-name\fR +Requires that no resource record of any type exists with name +\fIdomain-name\fR. +.TP +\fBprereq yxdomain domain-name\fR +Requires that +\fIdomain-name\fR +exists (has as at least one resource record, of any type). +.TP +\fBprereq nxrrset domain-name [ class ] type\fR +Requires that no resource record exists of the specified +\fItype\fR, +\fIclass\fR +and +\fIdomain-name\fR. +If +\fIclass\fR +is omitted, IN (internet) is assumed. +.TP +\fBprereq yxrrset domain-name [ class ] type\fR +This requires that a resource record of the specified +\fItype\fR, +\fIclass\fR +and +\fIdomain-name\fR +must exist. +If +\fIclass\fR +is omitted, IN (internet) is assumed. +.TP +\fBprereq yxrrset domain-name [ class ] type data\fI...\fB\fR +The +\fIdata\fR +from each set of prerequisites of this form +sharing a common +\fItype\fR, +\fIclass\fR, +and +\fIdomain-name\fR +are combined to form a set of RRs. This set of RRs must +exactly match the set of RRs existing in the zone at the +given +\fItype\fR, +\fIclass\fR, +and +\fIdomain-name\fR. +The +\fIdata\fR +are written in the standard text representation of the resource record's +RDATA. +.TP +\fBupdate delete domain-name [ ttl ] [ class ] [ type [ data\fI...\fB ] ]\fR +Deletes any resource records named +\fIdomain-name\fR. +If +\fItype\fR +and +\fIdata\fR +is provided, only matching resource records will be removed. +The internet class is assumed if +\fIclass\fR +is not supplied. The +\fIttl\fR +is ignored, and is only allowed for compatibility. +.TP +\fBupdate add domain-name ttl [ class ] type data\fI...\fB\fR +Adds a new resource record with the specified +\fIttl\fR, +\fIclass\fR +and +\fIdata\fR. +.TP +\fBshow\fR +Displays the current message, containing all of the prerequisites and +updates specified since the last send. +.TP +\fBsend\fR +Sends the current message. This is equivalent to entering a blank line. +.PP +Lines beginning with a semicolon are comments, and are ignored. +.SH "EXAMPLES" +.PP +The examples below show how +\fBnsupdate\fR +could be used to insert and delete resource records from the +\fBexample.com\fR +zone. +Notice that the input in each example contains a trailing blank line so that +a group of commands are sent as one dynamic update request to the +master name server for +\fBexample.com\fR. +.sp +.nf +# nsupdate +> update delete oldhost.example.com A +> update add newhost.example.com 86400 A 172.16.1.1 +> +.sp +.fi +.PP +Any A records for +\fBoldhost.example.com\fR +are deleted. +and an A record for +\fBnewhost.example.com\fR +it IP address 172.16.1.1 is added. +The newly-added record has a 1 day TTL (86400 seconds) +.sp +.nf +# nsupdate +> prereq nxdomain nickname.example.com +> update add nickname.example.com 86400 CNAME somehost.example.com +> +.sp +.fi +.PP +The prerequisite condition gets the name server to check that there +are no resource records of any type for +\fBnickname.example.com\fR. +If there are, the update request fails. +If this name does not exist, a CNAME for it is added. +This ensures that when the CNAME is added, it cannot conflict with the +long-standing rule in RFC1034 that a name must not exist as any other +record type if it exists as a CNAME. +(The rule has been updated for DNSSEC in RFC2535 to allow CNAMEs to have +SIG, KEY and NXT records.) +.SH "FILES" +.TP +\fB/etc/resolv.conf\fR +used to identify default name server +.TP +\fBK{name}.+157.+{random}.key\fR +base-64 encoding of HMAC-MD5 key created by +\fBdnssec-keygen\fR(8). +.TP +\fBK{name}.+157.+{random}.private\fR +base-64 encoding of HMAC-MD5 key created by +\fBdnssec-keygen\fR(8). +.SH "SEE ALSO" +.PP +\fBRFC2136\fR, +\fBRFC3007\fR, +\fBRFC2104\fR, +\fBRFC2845\fR, +\fBRFC1034\fR, +\fBRFC2535\fR, +\fBnamed\fR(8), +\fBdnssec-keygen\fR(8). +.SH "BUGS" +.PP +The TSIG key is redundantly stored in two separate files. +This is a consequence of nsupdate using the DST library +for its cryptographic operations, and may change in future +releases. diff --git a/usr.sbin/bind/bin/nsupdate/nsupdate.c b/usr.sbin/bind/bin/nsupdate/nsupdate.c new file mode 100644 index 00000000000..0ba3bf8f646 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/nsupdate.c @@ -0,0 +1,1869 @@ +/* + * Copyright (C) 2000-2002 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. + */ + +/* $ISC: nsupdate.c,v 1.103.2.11 2002/08/06 04:23:20 marka Exp $ */ + +#include <config.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <unistd.h> + +#include <isc/app.h> +#include <isc/base64.h> +#include <isc/buffer.h> +#include <isc/commandline.h> +#include <isc/entropy.h> +#include <isc/event.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/region.h> +#include <isc/sockaddr.h> +#include <isc/socket.h> +#include <isc/stdio.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/types.h> +#include <isc/util.h> + +#include <dns/callbacks.h> +#include <dns/dispatch.h> +#include <dns/events.h> +#include <dns/fixedname.h> +#include <dns/masterdump.h> +#include <dns/message.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/request.h> +#include <dns/result.h> +#include <dns/tsig.h> + +#include <dst/dst.h> + +#include <lwres/lwres.h> +#include <lwres/net.h> + +#ifdef HAVE_ADDRINFO +#ifdef HAVE_GETADDRINFO +#ifdef HAVE_GAISTRERROR +#define USE_GETADDRINFO +#endif +#endif +#endif + +#ifndef USE_GETADDRINFO +#ifndef ISC_PLATFORM_NONSTDHERRNO +extern int h_errno; +#endif +#endif + +#define MAXCMD (4 * 1024) +#define MAXWIRE (64 * 1024) +#define NAMEBUF 512 +#define WORDLEN 512 +#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 + +#ifndef RESOLV_CONF +#define RESOLV_CONF "/etc/resolv.conf" +#endif + +static isc_boolean_t debugging = ISC_FALSE, ddebugging = ISC_FALSE; +static isc_boolean_t memdebugging = ISC_FALSE; +static isc_boolean_t have_ipv4 = 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_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 isc_socketmgr_t *socketmgr = NULL; +static isc_timermgr_t *timermgr = NULL; +static dns_dispatch_t *dispatchv4 = NULL; +static dns_dispatch_t *dispatchv6 = NULL; +static dns_message_t *updatemsg = NULL; +static dns_fixedname_t resolvdomain; /* from resolv.conf's domain line */ +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 lwres_context_t *lwctx = NULL; +static lwres_conf_t *lwconf; +static isc_sockaddr_t *servers; +static int ns_inuse = 0; +static int ns_total = 0; +static isc_sockaddr_t *userserver = NULL; +static isc_sockaddr_t *localaddr = NULL; +static char *keystr = NULL, *keyfile = NULL; +static isc_entropy_t *entp = NULL; +static isc_boolean_t shuttingdown = ISC_FALSE; +static FILE *input; +static isc_boolean_t interactive = ISC_TRUE; +static isc_boolean_t seenerror = ISC_FALSE; +static const dns_master_style_t *style; +static int requests = 0; + +typedef struct nsu_requestinfo { + dns_message_t *msg; + isc_sockaddr_t *addr; +} nsu_requestinfo_t; + +static void +sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request); +static void +fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +static void +ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); + +#define STATUS_MORE (isc_uint16_t)0 +#define STATUS_SEND (isc_uint16_t)1 +#define STATUS_QUIT (isc_uint16_t)2 +#define STATUS_SYNTAX (isc_uint16_t)3 + +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 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 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 * +mem_alloc(void *arg, size_t size) { + return (isc_mem_get(arg, size)); +} + +static void +mem_free(void *arg, void *mem, size_t size) { + isc_mem_put(arg, mem, size); +} + +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 unsigned int +count_dots(char *s, isc_boolean_t *last_was_dot) { + int i = 0; + *last_was_dot = ISC_FALSE; + while (*s != 0) { + if (*s++ == '.') { + i++; + *last_was_dot = ISC_TRUE; + } else + *last_was_dot = ISC_FALSE; + } + return (i); +} + +static void +reset_system(void) { + isc_result_t result; + + ddebug("reset_system()"); + /* If the update message is still around, destroy it */ + if (updatemsg != NULL) + dns_message_reset(updatemsg, DNS_MESSAGE_INTENTRENDER); + else { + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &updatemsg); + check_result(result, "dns_message_create"); + } + updatemsg->opcode = dns_opcode_update; +} + +static void +setup_keystr(void) { + unsigned char *secret = NULL; + int secretlen; + isc_buffer_t secretbuf; + isc_result_t result; + isc_buffer_t keynamesrc; + char *secretstr; + char *s; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + + debug("Creating key..."); + + s = strchr(keystr, ':'); + if (s == NULL || s == keystr || *s == 0) + fatal("key option must specify keyname:secret"); + secretstr = s + 1; + + isc_buffer_init(&keynamesrc, keystr, s - keystr); + isc_buffer_add(&keynamesrc, s - keystr); + + debug("namefromtext"); + result = dns_name_fromtext(keyname, &keynamesrc, dns_rootname, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext"); + + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(mctx, secretlen); + if (secret == NULL) + fatal("out of memory"); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + keystr, isc_result_totext(result)); + goto failure; + } + + secretlen = isc_buffer_usedlength(&secretbuf); + + debug("keycreate"); + result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, + secret, secretlen, ISC_TRUE, NULL, + 0, 0, mctx, NULL, &key); + if (result != ISC_R_SUCCESS) + fprintf(stderr, "could not create key from %s: %s\n", + keystr, dns_result_totext(result)); + failure: + if (secret != NULL) + isc_mem_free(mctx, secret); +} + +static void +setup_keyfile(void) { + dst_key_t *dstkey = NULL; + isc_result_t result; + + debug("Creating key..."); + + result = dst_key_fromnamedfile(keyfile, DST_TYPE_PRIVATE, mctx, + &dstkey); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not read key from %s: %s\n", + keyfile, isc_result_totext(result)); + return; + } + result = dns_tsigkey_createfromkey(dst_key_name(dstkey), + dns_tsig_hmacmd5_name, + dstkey, ISC_FALSE, NULL, + 0, 0, mctx, NULL, &key); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + keyfile, isc_result_totext(result)); + dst_key_free(&dstkey); + return; + } +} + +static void +doshutdown(void) { + isc_task_detach(&global_task); + + if (userserver != NULL) + isc_mem_put(mctx, userserver, sizeof(isc_sockaddr_t)); + + if (localaddr != NULL) + isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); + + if (key != NULL) { + ddebug("Freeing key"); + dns_tsigkey_detach(&key); + } + + if (updatemsg != NULL) + dns_message_destroy(&updatemsg); + + if (is_dst_up) { + ddebug("Destroy DST lib"); + dst_lib_destroy(); + is_dst_up = ISC_FALSE; + } + + if (entp != NULL) { + ddebug("Detach from entropy"); + isc_entropy_detach(&entp); + } + + lwres_conf_clear(lwctx); + lwres_context_destroy(&lwctx); + + isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); + + ddebug("Destroying request manager"); + dns_requestmgr_detach(&requestmgr); + + ddebug("Freeing the dispatchers"); + if (have_ipv4) + dns_dispatch_detach(&dispatchv4); + if (have_ipv6) + dns_dispatch_detach(&dispatchv6); + + ddebug("Shutting down dispatch manager"); + dns_dispatchmgr_destroy(&dispatchmgr); + +} + +static void +maybeshutdown(void) { + ddebug("Shutting down request manager"); + dns_requestmgr_shutdown(requestmgr); + + if (requests != 0) + return; + + doshutdown(); +} + +static void +shutdown_program(isc_task_t *task, isc_event_t *event) { + REQUIRE(task == global_task); + UNUSED(task); + + ddebug("shutdown_program()"); + isc_event_free(&event); + + shuttingdown = ISC_TRUE; + maybeshutdown(); +} + +static void +setup_system(void) { + isc_result_t result; + isc_sockaddr_t bind_any, bind_any6; + isc_buffer_t buf; + lwres_result_t lwresult; + unsigned int attrs, attrmask; + int i; + + ddebug("setup_system()"); + + dns_result_register(); + + result = isc_net_probeipv4(); + if (result == ISC_R_SUCCESS) + have_ipv4 = ISC_TRUE; + + result = isc_net_probeipv6(); + if (result == ISC_R_SUCCESS) + have_ipv6 = ISC_TRUE; + + if (!have_ipv4 && !have_ipv6) + fatal("could not find either IPv4 or IPv6"); + + result = isc_mem_create(0, 0, &mctx); + check_result(result, "isc_mem_create"); + + lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1); + if (lwresult != LWRES_R_SUCCESS) + fatal("lwres_context_create failed"); + + (void)lwres_conf_parse(lwctx, RESOLV_CONF); + lwconf = lwres_conf_get(lwctx); + + ns_total = lwconf->nsnext; + if (ns_total <= 0) { + /* No name servers in resolv.conf; default to loopback. */ + struct in_addr localhost; + ns_total = 1; + servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); + if (servers == NULL) + fatal("out of memory"); + localhost.s_addr = htonl(INADDR_LOOPBACK); + isc_sockaddr_fromin(&servers[0], &localhost, DNSDEFAULTPORT); + } else { + servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); + if (servers == NULL) + fatal("out of memory"); + for (i = 0; i < ns_total; i++) { + if (lwconf->nameservers[i].family == LWRES_ADDRTYPE_V4) { + struct in_addr in4; + memcpy(&in4, lwconf->nameservers[i].address, 4); + isc_sockaddr_fromin(&servers[i], &in4, DNSDEFAULTPORT); + } else { + struct in6_addr in6; + memcpy(&in6, lwconf->nameservers[i].address, 16); + isc_sockaddr_fromin6(&servers[i], &in6, + DNSDEFAULTPORT); + } + } + } + + result = isc_entropy_create(mctx, &entp); + check_result(result, "isc_entropy_create"); + + result = dns_dispatchmgr_create(mctx, entp, &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"); + + 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 = isc_task_onshutdown(global_task, shutdown_program, NULL); + check_result(result, "isc_task_onshutdown"); + + result = dst_lib_init(mctx, entp, 0); + check_result(result, "dst_lib_init"); + is_dst_up = ISC_TRUE; + + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; + attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + + if (have_ipv6) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV6; + isc_sockaddr_any6(&bind_any6); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any6, PACKETSIZE, + 4, 2, 3, 5, + attrs, attrmask, &dispatchv6); + check_result(result, "dns_dispatch_getudp (v6)"); + } + + if (have_ipv4) { + attrs = DNS_DISPATCHATTR_UDP; + attrs |= DNS_DISPATCHATTR_MAKEQUERY; + attrs |= DNS_DISPATCHATTR_IPV4; + isc_sockaddr_any(&bind_any); + result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + &bind_any, PACKETSIZE, + 4, 2, 3, 5, + attrs, attrmask, &dispatchv4); + check_result(result, "dns_dispatch_getudp (v4)"); + } + + result = dns_requestmgr_create(mctx, timermgr, + socketmgr, taskmgr, dispatchmgr, + dispatchv4, dispatchv6, &requestmgr); + check_result(result, "dns_requestmgr_create"); + + if (lwconf->domainname != NULL) { + dns_fixedname_init(&resolvdomain); + isc_buffer_init(&buf, lwconf->domainname, + strlen(lwconf->domainname)); + isc_buffer_add(&buf, strlen(lwconf->domainname)); + result = dns_name_fromtext(dns_fixedname_name(&resolvdomain), + &buf, dns_rootname, ISC_FALSE, + NULL); + check_result(result, "dns_name_fromtext"); + origin = dns_fixedname_name(&resolvdomain); + } + else + origin = dns_rootname; + + if (keystr != NULL) + setup_keystr(); + else if (keyfile != NULL) + setup_keyfile(); +} + +static void +get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) { + struct in_addr in4; + struct in6_addr in6; +#ifdef USE_GETADDRINFO + struct addrinfo *res = NULL, hints; + int result; +#else + struct hostent *he; +#endif + + ddebug("get_address()"); + + /* + * Assume we have v4 if we don't have v6, since setup_libs + * fatal()'s out if we don't have either. + */ + 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 { +#ifdef USE_GETADDRINFO + memset(&hints, 0, sizeof(hints)); + if (!have_ipv6) + hints.ai_family = PF_INET; + else if (!have_ipv4) + hints.ai_family = PF_INET6; + else + hints.ai_family = PF_UNSPEC; + debug ("before getaddrinfo()"); + isc_app_block(); + result = getaddrinfo(host, NULL, &hints, &res); + isc_app_unblock(); + if (result != 0) { + fatal("couldn't find server '%s': %s", + host, gai_strerror(result)); + } + memcpy(&sockaddr->type.sa,res->ai_addr, res->ai_addrlen); + sockaddr->length = res->ai_addrlen; + isc_sockaddr_setport(sockaddr, port); + freeaddrinfo(res); +#else + debug ("before gethostbyname()"); + isc_app_block(); + he = gethostbyname(host); + isc_app_unblock(); + if (he == NULL) + fatal("couldn't find server '%s' (h_errno=%d)", + host, h_errno); + INSIST(he->h_addrtype == AF_INET); + isc_sockaddr_fromin(sockaddr, + (struct in_addr *)(he->h_addr_list[0]), + port); +#endif + } +} + +static void +parse_args(int argc, char **argv) { + int ch; + isc_result_t result; + + debug("parse_args"); + while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:")) != -1) { + switch (ch) { + case 'd': + debugging = ISC_TRUE; + break; + case 'D': /* was -dd */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + break; + case 'M': /* was -dm */ + debugging = ISC_TRUE; + ddebugging = ISC_TRUE; + memdebugging = ISC_TRUE; + isc_mem_debugging = ISC_MEM_DEBUGTRACE | + ISC_MEM_DEBUGRECORD; + break; + case 'y': + keystr = isc_commandline_argument; + break; + case 'v': + usevc = ISC_TRUE; + break; + case 'k': + keyfile = isc_commandline_argument; + break; + default: + fprintf(stderr, "%s: invalid argument -%c\n", + argv[0], ch); + fprintf(stderr, "usage: nsupdate [-d] " + "[-y keyname:secret | -k keyfile] [-v] " + "[filename]\n"); + exit(1); + } + } + if (keyfile != NULL && keystr != NULL) { + fprintf(stderr, "%s: cannot specify both -k and -y\n", + argv[0]); + exit(1); + } + + if (argv[isc_commandline_index] != NULL) { + if (strcmp(argv[isc_commandline_index], "-") == 0) { + input = stdin; + } else { + result = isc_stdio_open(argv[isc_commandline_index], + "r", &input); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not open '%s': %s\n", + argv[isc_commandline_index], + isc_result_totext(result)); + exit(1); + } + } + interactive = ISC_FALSE; + } +} + +static isc_uint16_t +parse_name(char **cmdlinep, dns_message_t *msg, dns_name_t **namep) { + isc_result_t result; + char *word; + isc_buffer_t *namebuf = NULL; + isc_buffer_t source; + unsigned int dots; + isc_boolean_t last; + dns_name_t *rn; + + word = nsu_strsep(cmdlinep, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read owner name\n"); + return (STATUS_SYNTAX); + } + + result = dns_message_gettempname(msg, namep); + check_result(result, "dns_message_gettempname"); + result = isc_buffer_allocate(mctx, &namebuf, NAMEBUF); + check_result(result, "isc_buffer_allocate"); + dns_name_init(*namep, NULL); + dns_name_setbuffer(*namep, namebuf); + dns_message_takebuffer(msg, &namebuf); + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + dots = count_dots(word, &last); + if (dots > lwconf->ndots || last) + rn = dns_rootname; + else if (userzone != NULL) + rn = userzone; + else + rn = origin; + result = dns_name_fromtext(*namep, &source, rn, + ISC_FALSE, NULL); + check_result(result, "dns_name_fromtext"); + isc_buffer_invalidate(&source); + return (STATUS_MORE); +} + +static isc_uint16_t +parse_rdata(char **cmdlinep, dns_rdataclass_t rdataclass, + dns_rdatatype_t rdatatype, dns_message_t *msg, + 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; + dns_name_t *rn; + + while (*cmdline != 0 && isspace((unsigned char)*cmdline)) + cmdline++; + + if (*cmdline != 0) { + dns_rdatacallbacks_init(&callbacks); + if (userzone != NULL) + rn = userzone; + else + rn = origin; + 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, + rn, ISC_FALSE, 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_fromregion(rdata, rdataclass, rdatatype, &r); + isc_buffer_free(&buf); + dns_message_takebuffer(msg, &newbuf); + } else { + fprintf(stderr, "invalid rdata format: %s\n", + isc_result_totext(result)); + isc_buffer_free(&buf); + return (STATUS_SYNTAX); + } + } else { + rdata->flags = DNS_RDATA_UPDATE; + } + *cmdlinep = cmdline; + return (STATUS_MORE); +} + +static isc_uint16_t +make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { + isc_result_t result; + char *word; + dns_name_t *name = NULL; + 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; + isc_uint16_t retval; + + ddebug("make_prereq()"); + + /* + * Read the owner name + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) + return (retval); + + /* + * If this is an rrset prereq, read the class or type. + */ + if (isrrset) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read class or type\n"); + goto failure; + } + 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 == 0) { + fprintf(stderr, "could not read type\n"); + goto failure; + } + 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); + goto failure; + } + } else { + rdataclass = dns_rdataclass_in; + result = dns_rdatatype_fromtext(&rdatatype, ®ion); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "invalid type: %s\n", word); + goto failure; + } + } + } else + rdatatype = dns_rdatatype_any; + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + rdata->data = NULL; + rdata->length = 0; + + if (isrrset && ispositive) { + retval = parse_rdata(&cmdline, rdataclass, rdatatype, + updatemsg, rdata); + if (retval != STATUS_MORE) + goto failure; + } else + rdata->flags = DNS_RDATA_UPDATE; + + 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; + if (ispositive) { + if (isrrset && rdata->data != NULL) + rdatalist->rdclass = rdataclass; + else + rdatalist->rdclass = dns_rdataclass_any; + } else + rdatalist->rdclass = dns_rdataclass_none; + rdatalist->covers = 0; + rdatalist->ttl = 0; + rdata->rdclass = rdatalist->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); + + failure: + if (name != NULL) + dns_message_puttempname(updatemsg, &name); + return (STATUS_SYNTAX); +} + +static isc_uint16_t +evaluate_prereq(char *cmdline) { + char *word; + isc_boolean_t ispositive, isrrset; + + ddebug("evaluate_prereq()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + 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); + return (STATUS_SYNTAX); + } + return (make_prereq(cmdline, ispositive, isrrset)); +} + +static isc_uint16_t +evaluate_server(char *cmdline) { + char *word, *server; + long port; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + server = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) + port = DNSDEFAULTPORT; + else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, "port '%s' is out of range " + "(1 to 65535)\n", word); + return (STATUS_SYNTAX); + } + } + + if (userserver == NULL) { + userserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); + if (userserver == NULL) + fatal("out of memory"); + } + + get_address(server, (in_port_t)port, userserver); + + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_local(char *cmdline) { + char *word, *local; + long port; + struct in_addr in4; + struct in6_addr in6; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read server name\n"); + return (STATUS_SYNTAX); + } + local = word; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) + port = 0; + else { + char *endp; + port = strtol(word, &endp, 10); + if (*endp != 0) { + fprintf(stderr, "port '%s' is not numeric\n", word); + return (STATUS_SYNTAX); + } else if (port < 1 || port > 65535) { + fprintf(stderr, "port '%s' is out of range " + "(1 to 65535)\n", word); + return (STATUS_SYNTAX); + } + } + + if (localaddr == NULL) { + localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); + if (localaddr == NULL) + fatal("out of memory"); + } + + if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) + isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); + else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) + isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); + else { + fprintf(stderr, "invalid address %s", local); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_key(char *cmdline) { + char *namestr; + char *secretstr; + isc_buffer_t b; + isc_result_t result; + dns_fixedname_t fkeyname; + dns_name_t *keyname; + int secretlen; + unsigned char *secret = NULL; + isc_buffer_t secretbuf; + + namestr = nsu_strsep(&cmdline, " \t\r\n"); + if (*namestr == 0) { + fprintf(stderr, "could not read key name\n"); + return (STATUS_SYNTAX); + } + + dns_fixedname_init(&fkeyname); + keyname = dns_fixedname_name(&fkeyname); + + isc_buffer_init(&b, namestr, strlen(namestr)); + isc_buffer_add(&b, strlen(namestr)); + result = dns_name_fromtext(keyname, &b, dns_rootname, ISC_FALSE, NULL); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not parse key name\n"); + return (STATUS_SYNTAX); + } + + secretstr = nsu_strsep(&cmdline, "\r\n"); + if (*secretstr == 0) { + fprintf(stderr, "could not read key secret\n"); + return (STATUS_SYNTAX); + } + secretlen = strlen(secretstr) * 3 / 4; + secret = isc_mem_allocate(mctx, secretlen); + if (secret == NULL) + fatal("out of memory"); + + isc_buffer_init(&secretbuf, secret, secretlen); + result = isc_base64_decodestring(secretstr, &secretbuf); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s: %s\n", + secretstr, isc_result_totext(result)); + isc_mem_free(mctx, secret); + return (STATUS_SYNTAX); + } + secretlen = isc_buffer_usedlength(&secretbuf); + + if (key != NULL) + dns_tsigkey_detach(&key); + result = dns_tsigkey_create(keyname, dns_tsig_hmacmd5_name, + secret, secretlen, ISC_TRUE, NULL, 0, 0, + mctx, NULL, &key); + isc_mem_free(mctx, secret); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not create key from %s %s: %s\n", + namestr, secretstr, dns_result_totext(result)); + return (STATUS_SYNTAX); + } + return (STATUS_MORE); +} + +static isc_uint16_t +evaluate_zone(char *cmdline) { + char *word; + isc_buffer_t b; + isc_result_t result; + + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read zone name\n"); + return (STATUS_SYNTAX); + } + + dns_fixedname_init(&fuserzone); + userzone = dns_fixedname_name(&fuserzone); + isc_buffer_init(&b, word, strlen(word)); + isc_buffer_add(&b, strlen(word)); + result = dns_name_fromtext(userzone, &b, dns_rootname, ISC_FALSE, + NULL); + if (result != ISC_R_SUCCESS) { + userzone = NULL; /* Lest it point to an invalid name */ + fprintf(stderr, "could not parse zone name\n"); + return (STATUS_SYNTAX); + } + + return (STATUS_MORE); +} + +static isc_uint16_t +update_addordelete(char *cmdline, isc_boolean_t isdelete) { + isc_result_t result; + dns_name_t *name = NULL; + unsigned long 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; + char *endp; + isc_uint16_t retval; + + ddebug("update_addordelete()"); + + /* + * Read the owner name. + */ + retval = parse_name(&cmdline, updatemsg, &name); + if (retval != STATUS_MORE) + return (retval); + + result = dns_message_gettemprdata(updatemsg, &rdata); + check_result(result, "dns_message_gettemprdata"); + + rdata->rdclass = 0; + rdata->type = 0; + rdata->data = NULL; + rdata->length = 0; + + /* + * 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 == 0) { + if (!isdelete) { + fprintf(stderr, "could not read owner ttl\n"); + goto failure; + } + else { + ttl = 0; + rdataclass = dns_rdataclass_any; + rdatatype = dns_rdatatype_any; + rdata->flags = DNS_RDATA_UPDATE; + goto doneparsing; + } + } + ttl = strtoul(word, &endp, 10); + if (!isdigit((unsigned char)*word) || *endp != '\0') { + if (isdelete) { + ttl = 0; + goto parseclass; + } else { + fprintf(stderr, "ttl '%s' is not legal\n", word); + goto failure; + } + } + + if (isdelete) + ttl = 0; + else if (ttl > TTL_MAX) { + fprintf(stderr, "ttl '%s' is out of range (0 to %d)\n", + word, TTL_MAX); + goto failure; + } + + /* + * Read the class or type. + */ + word = nsu_strsep(&cmdline, " \t\r\n"); + parseclass: + if (*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"); + goto failure; + } + } + 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 == 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"); + goto failure; + } + } + 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)); + goto failure; + } + } else { + rdataclass = dns_rdataclass_in; + 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)); + goto failure; + } + } + + retval = parse_rdata(&cmdline, rdataclass, rdatatype, updatemsg, + rdata); + if (retval != STATUS_MORE) + goto failure; + + 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"); + goto failure; + } + } + + doneparsing: + + 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 = rdataclass; + rdatalist->covers = rdatatype; + rdatalist->ttl = (dns_ttl_t)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); + return (STATUS_MORE); + + failure: + if (name != NULL) + dns_message_puttempname(updatemsg, &name); + if (rdata != NULL) + dns_message_puttemprdata(updatemsg, &rdata); + return (STATUS_SYNTAX); +} + +static isc_uint16_t +evaluate_update(char *cmdline) { + char *word; + isc_boolean_t isdelete; + + ddebug("evaluate_update()"); + word = nsu_strsep(&cmdline, " \t\r\n"); + if (*word == 0) { + fprintf(stderr, "could not read operation code\n"); + return (STATUS_SYNTAX); + } + if (strcasecmp(word, "delete") == 0) + isdelete = ISC_TRUE; + else if (strcasecmp(word, "add") == 0) + isdelete = ISC_FALSE; + else { + fprintf(stderr, "incorrect operation code: %s\n", word); + return (STATUS_SYNTAX); + } + return (update_addordelete(cmdline, isdelete)); +} + +static void +show_message(dns_message_t *msg) { + isc_result_t result; + isc_buffer_t *buf = NULL; + int bufsz; + + ddebug("show_message()"); + bufsz = INITTEXT; + do { + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not 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, style, 0, buf); + bufsz *= 2; + } while (result == ISC_R_NOSPACE); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "could not 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)); + isc_buffer_free(&buf); +} + + +static isc_uint16_t +get_next_command(void) { + char cmdlinebuf[MAXCMD]; + char *cmdline; + char *word; + + ddebug("get_next_command()"); + if (interactive) + fprintf(stdout, "> "); + isc_app_block(); + cmdline = fgets(cmdlinebuf, MAXCMD, input); + isc_app_unblock(); + if (cmdline == NULL) + return (STATUS_QUIT); + word = nsu_strsep(&cmdline, " \t\r\n"); + + if (feof(input)) + return (STATUS_QUIT); + if (*word == 0) + return (STATUS_SEND); + if (word[0] == ';') + return (STATUS_MORE); + if (strcasecmp(word, "quit") == 0) + return (STATUS_QUIT); + if (strcasecmp(word, "prereq") == 0) + return (evaluate_prereq(cmdline)); + if (strcasecmp(word, "update") == 0) + return (evaluate_update(cmdline)); + if (strcasecmp(word, "server") == 0) + return (evaluate_server(cmdline)); + if (strcasecmp(word, "local") == 0) + return (evaluate_local(cmdline)); + if (strcasecmp(word, "zone") == 0) + return (evaluate_zone(cmdline)); + if (strcasecmp(word, "send") == 0) + return (STATUS_SEND); + if (strcasecmp(word, "show") == 0) { + show_message(updatemsg); + return (STATUS_MORE); + } + if (strcasecmp(word, "key") == 0) + return (evaluate_key(cmdline)); + fprintf(stderr, "incorrect section name: %s\n", word); + return (STATUS_SYNTAX); +} + +static isc_boolean_t +user_interaction(void) { + 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); + return (ISC_FALSE); + +} + +static void +done_update(void) { + isc_event_t *event = global_event; + ddebug("done_update()"); + 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; + dns_message_t *rcvmsg = NULL; + dns_request_t *request; + + UNUSED(task); + + ddebug("update_completed()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + + if (shuttingdown) { + dns_request_destroy(&request); + isc_event_free(&event); + maybeshutdown(); + return; + } + + if (reqev->result != ISC_R_SUCCESS) { + fprintf(stderr, "; Communication with server failed: %s\n", + isc_result_totext(reqev->result)); + seenerror = ISC_TRUE; + goto done; + } + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg); + check_result(result, "dns_message_create"); + result = dns_request_getresponse(request, rcvmsg, + DNS_MESSAGEPARSE_PRESERVEORDER); + switch (result) { + case ISC_R_SUCCESS: + break; + case DNS_R_CLOCKSKEW: + case DNS_R_EXPECTEDTSIG: + case DNS_R_TSIGERRORSET: + case DNS_R_TSIGVERIFYFAILURE: + case DNS_R_UNEXPECTEDTSIG: + fprintf(stderr, "; TSIG error with server: %s\n", + isc_result_totext(result)); + seenerror = ISC_TRUE; + break; + default: + check_result(result, "dns_request_getresponse"); + } + + if (rcvmsg->rcode != dns_rcode_noerror) + seenerror = ISC_TRUE; + if (debugging) { + isc_buffer_t *buf = NULL; + int bufsz; + + bufsz = INITTEXT; + do { + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not 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, style, 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)); + isc_buffer_free(&buf); + } + dns_message_destroy(&rcvmsg); + done: + dns_request_destroy(&request); + isc_event_free(&event); + done_update(); +} + +static void +send_update(dns_name_t *zonename, isc_sockaddr_t *master, + isc_sockaddr_t *srcaddr) +{ + isc_result_t result; + dns_request_t *request = NULL; + dns_name_t *name = NULL; + dns_rdataset_t *rdataset = NULL; + unsigned int options = 0; + + ddebug("send_update()"); + + result = dns_message_gettempname(updatemsg, &name); + check_result(result, "dns_message_gettempname"); + dns_name_init(name, NULL); + dns_name_clone(zonename, 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); + + if (usevc) + options |= DNS_REQUESTOPT_TCP; + result = dns_request_createvia(requestmgr, updatemsg, srcaddr, + master, options, key, + FIND_TIMEOUT, global_task, + update_completed, NULL, &request); + check_result(result, "dns_request_createvia"); + requests++; +} + +static void +recvsoa(isc_task_t *task, isc_event_t *event) { + dns_requestevent_t *reqev = NULL; + dns_request_t *request = NULL; + isc_result_t result, eresult; + dns_message_t *rcvmsg = NULL; + dns_section_t section; + dns_name_t *name = NULL; + dns_rdataset_t *soaset = NULL; + dns_rdata_soa_t soa; + dns_rdata_t soarr = DNS_RDATA_INIT; + int pass = 0; + dns_name_t master; + isc_sockaddr_t *serveraddr, tempaddr; + dns_name_t *zonename; + nsu_requestinfo_t *reqinfo; + dns_message_t *soaquery = NULL; + isc_sockaddr_t *addr; + isc_boolean_t seencname = ISC_FALSE; + + UNUSED(task); + + ddebug("recvsoa()"); + + requests--; + + REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); + reqev = (dns_requestevent_t *)event; + request = reqev->request; + eresult = reqev->result; + reqinfo = reqev->ev_arg; + soaquery = reqinfo->msg; + addr = reqinfo->addr; + + if (shuttingdown) { + dns_request_destroy(&request); + dns_message_destroy(&soaquery); + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + maybeshutdown(); + return; + } + + 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)); + if (userserver != NULL) + fatal("could not talk to specified name server"); + else if (++ns_inuse >= lwconf->nsnext) + fatal("could not talk to any default name server"); + ddebug("Destroying request [%p]", request); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + isc_event_free(&event); + return; + } + isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); + + isc_event_free(&event); + reqev = NULL; + + 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, + DNS_MESSAGEPARSE_PRESERVEORDER); + check_result(result, "dns_request_getresponse"); + section = DNS_SECTION_ANSWER; + if (debugging) { + isc_buffer_t *buf = NULL; + int bufsz; + bufsz = INITTEXT; + do { + if (buf != NULL) + isc_buffer_free(&buf); + if (bufsz > MAXTEXT) { + fprintf(stderr, "could not 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, style, 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)); + isc_buffer_free(&buf); + } + + if (rcvmsg->rcode != dns_rcode_noerror && + rcvmsg->rcode != dns_rcode_nxdomain) + fatal("response to SOA query was unsuccessful"); + + lookforsoa: + if (pass == 0) + section = DNS_SECTION_ANSWER; + else if (pass == 1) + section = DNS_SECTION_AUTHORITY; + else + fatal("response to SOA query didn't contain an SOA"); + + + result = dns_message_firstname(rcvmsg, section); + if (result != ISC_R_SUCCESS) { + pass++; + goto lookforsoa; + } + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(rcvmsg, section, &name); + soaset = NULL; + result = dns_message_findtype(name, dns_rdatatype_soa, 0, + &soaset); + if (result == ISC_R_SUCCESS) + break; + if (section == DNS_SECTION_ANSWER) { + dns_rdataset_t *tset = NULL; + if (dns_message_findtype(name, dns_rdatatype_cname, 0, + &tset) == ISC_R_SUCCESS + || + dns_message_findtype(name, dns_rdatatype_dname, 0, + &tset) == ISC_R_SUCCESS + ) + { + seencname = ISC_TRUE; + break; + } + } + + result = dns_message_nextname(rcvmsg, section); + } + + if (soaset == NULL && !seencname) { + pass++; + goto lookforsoa; + } + + if (seencname) { + dns_name_t tname; + unsigned int nlabels; + + result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); + INSIST(result == ISC_R_SUCCESS); + name = NULL; + dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); + nlabels = dns_name_countlabels(name); + if (nlabels == 1) + fatal("could not find enclosing zone"); + dns_name_init(&tname, NULL); + dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); + dns_name_clone(&tname, name); + dns_request_destroy(&request); + dns_message_renderreset(soaquery); + if (userserver != NULL) + sendrequest(localaddr, userserver, soaquery, &request); + else + sendrequest(localaddr, &servers[ns_inuse], soaquery, + &request); + goto out; + } + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + fprintf(stderr, "Found zone name: %s\n", namestr); + } + + result = dns_rdataset_first(soaset); + check_result(result, "dns_rdataset_first"); + + dns_rdata_init(&soarr); + dns_rdataset_current(soaset, &soarr); + result = dns_rdata_tostruct(&soarr, &soa, NULL); + check_result(result, "dns_rdata_tostruct"); + + dns_name_init(&master, NULL); + dns_name_clone(&soa.origin, &master); + + if (userzone != NULL) + zonename = userzone; + else + zonename = name; + + if (debugging) { + char namestr[DNS_NAME_FORMATSIZE]; + dns_name_format(&master, namestr, sizeof(namestr)); + fprintf(stderr, "The master is: %s\n", namestr); + } + + if (userserver != NULL) + serveraddr = userserver; + else { + char serverstr[DNS_NAME_MAXTEXT+1]; + isc_buffer_t buf; + + isc_buffer_init(&buf, serverstr, sizeof(serverstr)); + result = dns_name_totext(&master, ISC_TRUE, &buf); + check_result(result, "dns_name_totext"); + serverstr[isc_buffer_usedlength(&buf)] = 0; + get_address(serverstr, DNSDEFAULTPORT, &tempaddr); + serveraddr = &tempaddr; + } + + send_update(zonename, serveraddr, localaddr); + + dns_message_destroy(&soaquery); + dns_request_destroy(&request); + + out: + dns_rdata_freestruct(&soa); + dns_message_destroy(&rcvmsg); + ddebug("Out of recvsoa"); +} + +static void +sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + dns_message_t *msg, dns_request_t **request) +{ + isc_result_t result; + nsu_requestinfo_t *reqinfo; + + reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); + if (reqinfo == NULL) + fatal("out of memory"); + reqinfo->msg = msg; + reqinfo->addr = destaddr; + result = dns_request_createvia(requestmgr, msg, srcaddr, destaddr, + 0, NULL, FIND_TIMEOUT, global_task, + recvsoa, reqinfo, request); + check_result(result, "dns_request_createvia"); + requests++; +} + +static void +start_update(void) { + isc_result_t result; + dns_rdataset_t *rdataset = NULL; + dns_name_t *name = NULL; + dns_request_t *request = NULL; + dns_message_t *soaquery = NULL; + dns_name_t *firstname; + + ddebug("start_update()"); + + result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE); + if (result != ISC_R_SUCCESS) { + done_update(); + return; + } + + if (userzone != NULL && userserver != NULL) { + send_update(userzone, userserver, localaddr); + return; + } + + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, + &soaquery); + check_result(result, "dns_message_create"); + + soaquery->flags |= DNS_MESSAGEFLAG_RD; + + result = dns_message_gettempname(soaquery, &name); + check_result(result, "dns_message_gettempname"); + + result = dns_message_gettemprdataset(soaquery, &rdataset); + check_result(result, "dns_message_gettemprdataset"); + + dns_rdataset_makequestion(rdataset, dns_rdataclass_in, + dns_rdatatype_soa); + + firstname = NULL; + dns_message_currentname(updatemsg, DNS_SECTION_UPDATE, &firstname); + dns_name_init(name, NULL); + dns_name_clone(firstname, name); + + ISC_LIST_INIT(name->list); + ISC_LIST_APPEND(name->list, rdataset, link); + dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); + + if (userserver != NULL) + sendrequest(localaddr, userserver, soaquery, &request); + else { + ns_inuse = 0; + sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); + } +} + +static void +cleanup(void) { + ddebug("cleanup()"); + + ddebug("Shutting down task manager"); + isc_taskmgr_destroy(&taskmgr); + + ddebug("Destroying event"); + isc_event_free(&global_event); + + ddebug("Shutting down socket manager"); + isc_socketmgr_destroy(&socketmgr); + + ddebug("Shutting down timer manager"); + isc_timermgr_destroy(&timermgr); + + ddebug("Destroying memory context"); + if (memdebugging) + isc_mem_stats(mctx, stderr); + isc_mem_destroy(&mctx); +} + +static void +getinput(isc_task_t *task, isc_event_t *event) { + isc_boolean_t more; + + UNUSED(task); + + if (shuttingdown) { + maybeshutdown(); + return; + } + + 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; + style = &dns_master_style_debug; + + input = stdin; + + isc_app_start(); + + parse_args(argc, argv); + + setup_system(); + + result = isc_app_onrun(mctx, global_task, getinput, NULL); + check_result(result, "isc_app_onrun"); + + (void)isc_app_run(); + + cleanup(); + + isc_app_finish(); + + if (seenerror) + return (2); + else + return (0); +} diff --git a/usr.sbin/bind/bin/nsupdate/nsupdate.docbook b/usr.sbin/bind/bin/nsupdate/nsupdate.docbook new file mode 100644 index 00000000000..03d1086c1b7 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/nsupdate.docbook @@ -0,0 +1,556 @@ +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> +<!-- + - Copyright (C) 2001 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. +--> + +<!-- $ISC: nsupdate.docbook,v 1.8.2.1 2001/11/27 18:57:40 gson Exp $ --> + +<refentry> +<refentryinfo> +<date>Jun 30, 2000</date> +</refentryinfo> +<refmeta> +<refentrytitle>nsupdate</refentrytitle> +<manvolnum>8</manvolnum> +<refmiscinfo>BIND9</refmiscinfo> +</refmeta> +<refnamediv> +<refname>nsupdate</refname> +<refpurpose>Dynamic DNS update utility</refpurpose> +</refnamediv> +<refsynopsisdiv> +<cmdsynopsis> +<command>nsupdate</command> +<arg><option>-d</option></arg> +<group> + <arg><option>-y <replaceable class="parameter">keyname:secret</replaceable></option></arg> + <arg><option>-k <replaceable class="parameter">keyfile</replaceable></option></arg> +</group> +<arg><option>-v</option></arg> +<arg>filename</arg> +</cmdsynopsis> +</refsynopsisdiv> + +<refsect1> +<title>DESCRIPTION</title> +<para> +<command>nsupdate</command> +is used to submit Dynamic DNS Update requests as defined in RFC2136 +to a name server. +This allows resource records to be added or removed from a zone +without manually editing the zone file. +A single update request can contain requests to add or remove more than one +resource record. +</para> +<para> +Zones that are under dynamic control via +<command>nsupdate</command> +or a DHCP server should not be edited by hand. +Manual edits could +conflict with dynamic updates and cause data to be lost. +</para> +<para> +The resource records that are dynamically added or removed with +<command>nsupdate</command> +have to be in the same zone. +Requests are sent to the zone's master server. +This is identified by the MNAME field of the zone's SOA record. +</para> +<para> +The +<option>-d</option> +option makes +<command>nsupdate</command> +operate in debug mode. +This provides tracing information about the update requests that are +made and the replies received from the name server. +</para> +<para> +Transaction signatures can be used to authenticate the Dynamic DNS +updates. +These use the TSIG resource record type described in RFC2845. +The signatures rely on a shared secret that should only be known to +<command>nsupdate</command> +and the name server. +Currently, the only supported encryption algorithm for TSIG is +HMAC-MD5, which is defined in RFC 2104. +Once other algorithms are defined for TSIG, applications will need to +ensure they select the appropriate algorithm as well as the key when +authenticating each other. +For instance suitable +<type>key</type> +and +<type>server</type> +statements would be added to +<filename>/etc/named.conf</filename> +so that the name server can associate the appropriate secret key +and algorithm with the IP address of the +client application that will be using TSIG authentication. +<command>nsupdate</command> +does not read +<filename>/etc/named.conf</filename>. +</para> +<para> +<command>nsupdate</command> +uses the +<option>-y</option> +or +<option>-k</option> +option to provide the shared secret needed to generate a TSIG record +for authenticating Dynamic DNS update requests. +These options are mutually exclusive. +With the +<option>-k</option> +option, +<command>nsupdate</command> +reads the shared secret from the file +<parameter>keyfile</parameter>, +whose name is of the form +<filename>K{name}.+157.+{random}.private</filename>. +For historical +reasons, the file +<filename>K{name}.+157.+{random}.key</filename> +must also be present. When the +<option>-y</option> +option is used, a signature is generated from +<parameter>keyname:secret.</parameter> +<parameter>keyname</parameter> +is the name of the key, +and +<parameter>secret</parameter> +is the base64 encoded shared secret. +Use of the +<option>-y</option> +option is discouraged because the shared secret is supplied as a command +line argument in clear text. +This may be visible in the output from +<citerefentry> +<refentrytitle>ps</refentrytitle><manvolnum>1 +</manvolnum> +</citerefentry> +or in a history file maintained by the user's shell. +</para> +<para> +By default +<command>nsupdate</command> +uses UDP to send update requests to the name server. +The +<option>-v</option> +option makes +<command>nsupdate</command> +use a TCP connection. +This may be preferable when a batch of update requests is made. +</para> +</refsect1> + +<refsect1> +<title>INPUT FORMAT</title> +<para> +<command>nsupdate</command> +reads input from +<parameter>filename</parameter> +or standard input. +Each command is supplied on exactly one line of input. +Some commands are for administrative purposes. +The others are either update instructions or prerequisite checks on the +contents of the zone. +These checks set conditions that some name or set of +resource records (RRset) either exists or is absent from the zone. +These conditions must be met if the entire update request is to succeed. +Updates will be rejected if the tests for the prerequisite conditions fail. +</para> +<para> +Every update request consists of zero or more prerequisites +and zero or more updates. +This allows a suitably authenticated update request to proceed if some +specified resource records are present or missing from the zone. +A blank input line (or the <command>send</command> command) causes the +accumulated commands to be sent as one Dynamic DNS update request to the +name server. +</para> +<para> +The command formats and their meaning are as follows: +<variablelist> +<varlistentry><term> +<cmdsynopsis> +<command>server</command> +<arg choice="req">servername</arg> +<arg choice="opt">port</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Sends all dynamic update requests to the name server +<parameter>servername</parameter>. +When no server statement is provided, +<command>nsupdate</command> +will send updates to the master server of the correct zone. +The MNAME field of that zone's SOA record will identify the master +server for that zone. +<parameter>port</parameter> +is the port number on +<parameter>servername</parameter> +where the dynamic update requests get sent. +If no port number is specified, the default DNS port number of 53 is +used. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>local</command> +<arg choice="req">address</arg> +<arg choice="opt">port</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Sends all dynamic update requests using the local +<parameter>address</parameter>. + +When no local statement is provided, +<command>nsupdate</command> +will send updates using an address and port choosen by the system. +<parameter>port</parameter> +can additionally be used to make requests come from a specific port. +If no port number is specified, the system will assign one. + +<varlistentry><term> +<cmdsynopsis> +<command>zone</command> +<arg choice="req">zonename</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Specifies that all updates are to be made to the zone +<parameter>zonename</parameter>. +If no +<parameter>zone</parameter> +statement is provided, +<command>nsupdate</command> +will attempt determine the correct zone to update based on the rest of the input. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>key</command> +<arg choice="req">name</arg> +<arg choice="req">secret</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Specifies that all updates are to be TSIG signed using the +<parameter>keyname</parameter> <parameter>keysecret</parameter> pair. +The <command>key</command> command +overrides any key specified on the command line via +<option>-y</option> or <option>-k</option>. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>prereq nxdomain</command> +<arg choice="req">domain-name</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Requires that no resource record of any type exists with name +<parameter>domain-name</parameter>. +</para> + + +<varlistentry><term> +<cmdsynopsis> +<command>prereq yxdomain</command> +<arg choice="req">domain-name</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Requires that +<parameter>domain-name</parameter> +exists (has as at least one resource record, of any type). +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>prereq nxrrset</command> +<arg choice="req">domain-name</arg> +<arg choice="opt">class</arg> +<arg choice="req">type</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Requires that no resource record exists of the specified +<parameter>type</parameter>, +<parameter>class</parameter> +and +<parameter>domain-name</parameter>. +If +<parameter>class</parameter> +is omitted, IN (internet) is assumed. + + +<varlistentry><term> +<cmdsynopsis> +<command>prereq yxrrset</command> +<arg choice="req">domain-name</arg> +<arg choice="opt">class</arg> +<arg choice="req">type</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +This requires that a resource record of the specified +<parameter>type</parameter>, +<parameter>class</parameter> +and +<parameter>domain-name</parameter> +must exist. +If +<parameter>class</parameter> +is omitted, IN (internet) is assumed. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>prereq yxrrset</command> +<arg choice="req">domain-name</arg> +<arg choice="opt">class</arg> +<arg choice="req">type</arg> +<arg choice="req" rep="repeat">data</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +The +<parameter>data</parameter> +from each set of prerequisites of this form +sharing a common +<parameter>type</parameter>, +<parameter>class</parameter>, +and +<parameter>domain-name</parameter> +are combined to form a set of RRs. This set of RRs must +exactly match the set of RRs existing in the zone at the +given +<parameter>type</parameter>, +<parameter>class</parameter>, +and +<parameter>domain-name</parameter>. +The +<parameter>data</parameter> +are written in the standard text representation of the resource record's +RDATA. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>update delete</command> +<arg choice="req">domain-name</arg> +<arg choice="opt">ttl</arg> +<arg choice="opt">class</arg> +<arg choice="opt">type <arg choice="opt" rep="repeat">data</arg></arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Deletes any resource records named +<parameter>domain-name</parameter>. +If +<parameter>type</parameter> +and +<parameter>data</parameter> +is provided, only matching resource records will be removed. +The internet class is assumed if +<parameter>class</parameter> +is not supplied. The +<parameter>ttl</parameter> +is ignored, and is only allowed for compatibility. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>update add</command> +<arg choice="req">domain-name</arg> +<arg choice="req">ttl</arg> +<arg choice="opt">class</arg> +<arg choice="req">type</arg> +<arg choice="req" rep="repeat">data</arg> +</cmdsynopsis> +</term> +<listitem> +<para> +Adds a new resource record with the specified +<parameter>ttl</parameter>, +<parameter>class</parameter> +and +<parameter>data</parameter>. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>show</command> +</cmdsynopsis> +</term> +<listitem> +<para> +Displays the current message, containing all of the prerequisites and +updates specified since the last send. +</para> + +<varlistentry><term> +<cmdsynopsis> +<command>send</command> +</cmdsynopsis> +</term> +<listitem> +<para> +Sends the current message. This is equivalent to entering a blank line. +</para> +</listitem> +</variablelist> + +<para> +Lines beginning with a semicolon are comments, and are ignored. +</para> + +</refsect1> + +<refsect1> +<title>EXAMPLES</title> +<para> +The examples below show how +<command>nsupdate</command> +could be used to insert and delete resource records from the +<type>example.com</type> +zone. +Notice that the input in each example contains a trailing blank line so that +a group of commands are sent as one dynamic update request to the +master name server for +<type>example.com</type>. + +<programlisting> +# nsupdate +> update delete oldhost.example.com A +> update add newhost.example.com 86400 A 172.16.1.1 +> +</programlisting> +</para> +<para> +Any A records for +<type>oldhost.example.com</type> +are deleted. +and an A record for +<type>newhost.example.com</type> +it IP address 172.16.1.1 is added. +The newly-added record has a 1 day TTL (86400 seconds) +<programlisting> +# nsupdate +> prereq nxdomain nickname.example.com +> update add nickname.example.com 86400 CNAME somehost.example.com +> +</programlisting> +</para> +<para> +The prerequisite condition gets the name server to check that there +are no resource records of any type for +<type>nickname.example.com</type>. + +If there are, the update request fails. +If this name does not exist, a CNAME for it is added. +This ensures that when the CNAME is added, it cannot conflict with the +long-standing rule in RFC1034 that a name must not exist as any other +record type if it exists as a CNAME. +(The rule has been updated for DNSSEC in RFC2535 to allow CNAMEs to have +SIG, KEY and NXT records.) +</para> +</refsect1> + +<refsect1> +<title>FILES</title> + +<variablelist> +<varlistentry><term><constant>/etc/resolv.conf</constant></term> +<listitem> +<para> +used to identify default name server +</para> +</listitem> + +<varlistentry><term><constant>K{name}.+157.+{random}.key</constant></term> +<listitem> +<para> +base-64 encoding of HMAC-MD5 key created by +<citerefentry> +<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum> +</citerefentry>. +</para> +</listitem> + +<varlistentry><term><constant>K{name}.+157.+{random}.private</constant></term> +<listitem> +<para> +base-64 encoding of HMAC-MD5 key created by +<citerefentry> +<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum> +</citerefentry>. +</para> +</listitem> +</variablelist> +</refsect1> + +<refsect1> +<title>SEE ALSO</title> +<para> +<citerefentry> +<refentrytitle>RFC2136</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>RFC3007</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>RFC2104</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>RFC2845</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>RFC1034</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>RFC2535</refentrytitle> +</citerefentry>, +<citerefentry> +<refentrytitle>named</refentrytitle><manvolnum>8</manvolnum> +</citerefentry>, +<citerefentry> +<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum> +</citerefentry>. + +</refsect1> +<refsect1> +<title>BUGS</title> +<para> +The TSIG key is redundantly stored in two separate files. +This is a consequence of nsupdate using the DST library +for its cryptographic operations, and may change in future +releases. +</para> +</refsect1> +</refentry> diff --git a/usr.sbin/bind/bin/nsupdate/nsupdate.html b/usr.sbin/bind/bin/nsupdate/nsupdate.html new file mode 100644 index 00000000000..b8e63dcaea9 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/nsupdate.html @@ -0,0 +1,959 @@ +<!-- + - Copyright (C) 2000, 2001 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. +--> +<HTML +><HEAD +><TITLE +>nsupdate</TITLE +><META +NAME="GENERATOR" +CONTENT="Modular DocBook HTML Stylesheet Version 1.61 +"></HEAD +><BODY +CLASS="REFENTRY" +BGCOLOR="#FFFFFF" +TEXT="#000000" +LINK="#0000FF" +VLINK="#840084" +ALINK="#0000FF" +><H1 +><A +NAME="AEN1" +>nsupdate</A +></H1 +><DIV +CLASS="REFNAMEDIV" +><A +NAME="AEN8" +></A +><H2 +>Name</H2 +>nsupdate -- Dynamic DNS update utility</DIV +><DIV +CLASS="REFSYNOPSISDIV" +><A +NAME="AEN11" +></A +><H2 +>Synopsis</H2 +><P +><B +CLASS="COMMAND" +>nsupdate</B +> [<TT +CLASS="OPTION" +>-d</TT +>] [<TT +CLASS="OPTION" +>-y <TT +CLASS="REPLACEABLE" +><I +>keyname:secret</I +></TT +></TT +> | <TT +CLASS="OPTION" +>-k <TT +CLASS="REPLACEABLE" +><I +>keyfile</I +></TT +></TT +>] [<TT +CLASS="OPTION" +>-v</TT +>] [filename]</P +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN26" +></A +><H2 +>DESCRIPTION</H2 +><P +><B +CLASS="COMMAND" +>nsupdate</B +> +is used to submit Dynamic DNS Update requests as defined in RFC2136 +to a name server. +This allows resource records to be added or removed from a zone +without manually editing the zone file. +A single update request can contain requests to add or remove more than one +resource record.</P +><P +>Zones that are under dynamic control via +<B +CLASS="COMMAND" +>nsupdate</B +> +or a DHCP server should not be edited by hand. +Manual edits could +conflict with dynamic updates and cause data to be lost.</P +><P +>The resource records that are dynamically added or removed with +<B +CLASS="COMMAND" +>nsupdate</B +> +have to be in the same zone. +Requests are sent to the zone's master server. +This is identified by the MNAME field of the zone's SOA record.</P +><P +>The +<TT +CLASS="OPTION" +>-d</TT +> +option makes +<B +CLASS="COMMAND" +>nsupdate</B +> +operate in debug mode. +This provides tracing information about the update requests that are +made and the replies received from the name server.</P +><P +>Transaction signatures can be used to authenticate the Dynamic DNS +updates. +These use the TSIG resource record type described in RFC2845. +The signatures rely on a shared secret that should only be known to +<B +CLASS="COMMAND" +>nsupdate</B +> +and the name server. +Currently, the only supported encryption algorithm for TSIG is +HMAC-MD5, which is defined in RFC 2104. +Once other algorithms are defined for TSIG, applications will need to +ensure they select the appropriate algorithm as well as the key when +authenticating each other. +For instance suitable +<SPAN +CLASS="TYPE" +>key</SPAN +> +and +<SPAN +CLASS="TYPE" +>server</SPAN +> +statements would be added to +<TT +CLASS="FILENAME" +>/etc/named.conf</TT +> +so that the name server can associate the appropriate secret key +and algorithm with the IP address of the +client application that will be using TSIG authentication. +<B +CLASS="COMMAND" +>nsupdate</B +> +does not read +<TT +CLASS="FILENAME" +>/etc/named.conf</TT +>.</P +><P +><B +CLASS="COMMAND" +>nsupdate</B +> +uses the +<TT +CLASS="OPTION" +>-y</TT +> +or +<TT +CLASS="OPTION" +>-k</TT +> +option to provide the shared secret needed to generate a TSIG record +for authenticating Dynamic DNS update requests. +These options are mutually exclusive. +With the +<TT +CLASS="OPTION" +>-k</TT +> +option, +<B +CLASS="COMMAND" +>nsupdate</B +> +reads the shared secret from the file +<TT +CLASS="PARAMETER" +><I +>keyfile</I +></TT +>, +whose name is of the form +<TT +CLASS="FILENAME" +>K{name}.+157.+{random}.private</TT +>. +For historical +reasons, the file +<TT +CLASS="FILENAME" +>K{name}.+157.+{random}.key</TT +> +must also be present. When the +<TT +CLASS="OPTION" +>-y</TT +> +option is used, a signature is generated from +<TT +CLASS="PARAMETER" +><I +>keyname:secret.</I +></TT +> +<TT +CLASS="PARAMETER" +><I +>keyname</I +></TT +> +is the name of the key, +and +<TT +CLASS="PARAMETER" +><I +>secret</I +></TT +> +is the base64 encoded shared secret. +Use of the +<TT +CLASS="OPTION" +>-y</TT +> +option is discouraged because the shared secret is supplied as a command +line argument in clear text. +This may be visible in the output from +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>ps</SPAN +>(1)</SPAN +> +or in a history file maintained by the user's shell.</P +><P +>By default +<B +CLASS="COMMAND" +>nsupdate</B +> +uses UDP to send update requests to the name server. +The +<TT +CLASS="OPTION" +>-v</TT +> +option makes +<B +CLASS="COMMAND" +>nsupdate</B +> +use a TCP connection. +This may be preferable when a batch of update requests is made.</P +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN65" +></A +><H2 +>INPUT FORMAT</H2 +><P +><B +CLASS="COMMAND" +>nsupdate</B +> +reads input from +<TT +CLASS="PARAMETER" +><I +>filename</I +></TT +> +or standard input. +Each command is supplied on exactly one line of input. +Some commands are for administrative purposes. +The others are either update instructions or prerequisite checks on the +contents of the zone. +These checks set conditions that some name or set of +resource records (RRset) either exists or is absent from the zone. +These conditions must be met if the entire update request is to succeed. +Updates will be rejected if the tests for the prerequisite conditions fail.</P +><P +>Every update request consists of zero or more prerequisites +and zero or more updates. +This allows a suitably authenticated update request to proceed if some +specified resource records are present or missing from the zone. +A blank input line (or the <B +CLASS="COMMAND" +>send</B +> command) causes the +accumulated commands to be sent as one Dynamic DNS update request to the +name server.</P +><P +>The command formats and their meaning are as follows: +<P +></P +><DIV +CLASS="VARIABLELIST" +><DL +><DT +><P +><B +CLASS="COMMAND" +>server</B +> {servername} [port]</P +></DT +><DD +><P +>Sends all dynamic update requests to the name server +<TT +CLASS="PARAMETER" +><I +>servername</I +></TT +>. +When no server statement is provided, +<B +CLASS="COMMAND" +>nsupdate</B +> +will send updates to the master server of the correct zone. +The MNAME field of that zone's SOA record will identify the master +server for that zone. +<TT +CLASS="PARAMETER" +><I +>port</I +></TT +> +is the port number on +<TT +CLASS="PARAMETER" +><I +>servername</I +></TT +> +where the dynamic update requests get sent. +If no port number is specified, the default DNS port number of 53 is +used.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>local</B +> {address} [port]</P +></DT +><DD +><P +>Sends all dynamic update requests using the local +<TT +CLASS="PARAMETER" +><I +>address</I +></TT +>. + +When no local statement is provided, +<B +CLASS="COMMAND" +>nsupdate</B +> +will send updates using an address and port choosen by the system. +<TT +CLASS="PARAMETER" +><I +>port</I +></TT +> +can additionally be used to make requests come from a specific port. +If no port number is specified, the system will assign one. </P +></DD +><DT +><P +><B +CLASS="COMMAND" +>zone</B +> {zonename}</P +></DT +><DD +><P +>Specifies that all updates are to be made to the zone +<TT +CLASS="PARAMETER" +><I +>zonename</I +></TT +>. +If no +<TT +CLASS="PARAMETER" +><I +>zone</I +></TT +> +statement is provided, +<B +CLASS="COMMAND" +>nsupdate</B +> +will attempt determine the correct zone to update based on the rest of the input.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>key</B +> {name} {secret}</P +></DT +><DD +><P +>Specifies that all updates are to be TSIG signed using the +<TT +CLASS="PARAMETER" +><I +>keyname</I +></TT +> <TT +CLASS="PARAMETER" +><I +>keysecret</I +></TT +> pair. +The <B +CLASS="COMMAND" +>key</B +> command +overrides any key specified on the command line via +<TT +CLASS="OPTION" +>-y</TT +> or <TT +CLASS="OPTION" +>-k</TT +>.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>prereq nxdomain</B +> {domain-name}</P +></DT +><DD +><P +>Requires that no resource record of any type exists with name +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +>.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>prereq yxdomain</B +> {domain-name}</P +></DT +><DD +><P +>Requires that +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +> +exists (has as at least one resource record, of any type).</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>prereq nxrrset</B +> {domain-name} [class] {type}</P +></DT +><DD +><P +>Requires that no resource record exists of the specified +<TT +CLASS="PARAMETER" +><I +>type</I +></TT +>, +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +and +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +>. +If +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +is omitted, IN (internet) is assumed. + </P +></DD +><DT +><P +><B +CLASS="COMMAND" +>prereq yxrrset</B +> {domain-name} [class] {type}</P +></DT +><DD +><P +>This requires that a resource record of the specified +<TT +CLASS="PARAMETER" +><I +>type</I +></TT +>, +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +and +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +> +must exist. +If +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +is omitted, IN (internet) is assumed.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>prereq yxrrset</B +> {domain-name} [class] {type} {data...}</P +></DT +><DD +><P +>The +<TT +CLASS="PARAMETER" +><I +>data</I +></TT +> +from each set of prerequisites of this form +sharing a common +<TT +CLASS="PARAMETER" +><I +>type</I +></TT +>, +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +>, +and +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +> +are combined to form a set of RRs. This set of RRs must +exactly match the set of RRs existing in the zone at the +given +<TT +CLASS="PARAMETER" +><I +>type</I +></TT +>, +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +>, +and +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +>. +The +<TT +CLASS="PARAMETER" +><I +>data</I +></TT +> +are written in the standard text representation of the resource record's +RDATA.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>update delete</B +> {domain-name} [ttl] [class] [type [data...]]</P +></DT +><DD +><P +>Deletes any resource records named +<TT +CLASS="PARAMETER" +><I +>domain-name</I +></TT +>. +If +<TT +CLASS="PARAMETER" +><I +>type</I +></TT +> +and +<TT +CLASS="PARAMETER" +><I +>data</I +></TT +> +is provided, only matching resource records will be removed. +The internet class is assumed if +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +is not supplied. The +<TT +CLASS="PARAMETER" +><I +>ttl</I +></TT +> +is ignored, and is only allowed for compatibility.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>update add</B +> {domain-name} {ttl} [class] {type} {data...}</P +></DT +><DD +><P +>Adds a new resource record with the specified +<TT +CLASS="PARAMETER" +><I +>ttl</I +></TT +>, +<TT +CLASS="PARAMETER" +><I +>class</I +></TT +> +and +<TT +CLASS="PARAMETER" +><I +>data</I +></TT +>.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>show</B +> </P +></DT +><DD +><P +>Displays the current message, containing all of the prerequisites and +updates specified since the last send.</P +></DD +><DT +><P +><B +CLASS="COMMAND" +>send</B +> </P +></DT +><DD +><P +>Sends the current message. This is equivalent to entering a blank line.</P +></DD +></DL +></DIV +> </P +><P +>Lines beginning with a semicolon are comments, and are ignored.</P +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN223" +></A +><H2 +>EXAMPLES</H2 +><P +>The examples below show how +<B +CLASS="COMMAND" +>nsupdate</B +> +could be used to insert and delete resource records from the +<SPAN +CLASS="TYPE" +>example.com</SPAN +> +zone. +Notice that the input in each example contains a trailing blank line so that +a group of commands are sent as one dynamic update request to the +master name server for +<SPAN +CLASS="TYPE" +>example.com</SPAN +>. + +<PRE +CLASS="PROGRAMLISTING" +># nsupdate +> update delete oldhost.example.com A +> update add newhost.example.com 86400 A 172.16.1.1 +></PRE +></P +><P +>Any A records for +<SPAN +CLASS="TYPE" +>oldhost.example.com</SPAN +> +are deleted. +and an A record for +<SPAN +CLASS="TYPE" +>newhost.example.com</SPAN +> +it IP address 172.16.1.1 is added. +The newly-added record has a 1 day TTL (86400 seconds) +<PRE +CLASS="PROGRAMLISTING" +># nsupdate +> prereq nxdomain nickname.example.com +> update add nickname.example.com 86400 CNAME somehost.example.com +></PRE +></P +><P +>The prerequisite condition gets the name server to check that there +are no resource records of any type for +<SPAN +CLASS="TYPE" +>nickname.example.com</SPAN +>. + +If there are, the update request fails. +If this name does not exist, a CNAME for it is added. +This ensures that when the CNAME is added, it cannot conflict with the +long-standing rule in RFC1034 that a name must not exist as any other +record type if it exists as a CNAME. +(The rule has been updated for DNSSEC in RFC2535 to allow CNAMEs to have +SIG, KEY and NXT records.)</P +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN236" +></A +><H2 +>FILES</H2 +><P +></P +><DIV +CLASS="VARIABLELIST" +><DL +><DT +><TT +CLASS="CONSTANT" +>/etc/resolv.conf</TT +></DT +><DD +><P +>used to identify default name server</P +></DD +><DT +><TT +CLASS="CONSTANT" +>K{name}.+157.+{random}.key</TT +></DT +><DD +><P +>base-64 encoding of HMAC-MD5 key created by +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>dnssec-keygen</SPAN +>(8)</SPAN +>.</P +></DD +><DT +><TT +CLASS="CONSTANT" +>K{name}.+157.+{random}.private</TT +></DT +><DD +><P +>base-64 encoding of HMAC-MD5 key created by +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>dnssec-keygen</SPAN +>(8)</SPAN +>.</P +></DD +></DL +></DIV +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN260" +></A +><H2 +>SEE ALSO</H2 +><P +><SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC2136</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC3007</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC2104</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC2845</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC1034</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>RFC2535</SPAN +></SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>named</SPAN +>(8)</SPAN +>, +<SPAN +CLASS="CITEREFENTRY" +><SPAN +CLASS="REFENTRYTITLE" +>dnssec-keygen</SPAN +>(8)</SPAN +>. </P +></DIV +><DIV +CLASS="REFSECT1" +><A +NAME="AEN281" +></A +><H2 +>BUGS</H2 +><P +>The TSIG key is redundantly stored in two separate files. +This is a consequence of nsupdate using the DST library +for its cryptographic operations, and may change in future +releases.</P +></DIV +></BODY +></HTML +>
\ No newline at end of file diff --git a/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsp b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsp new file mode 100644 index 00000000000..fc16c0189d5 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsp @@ -0,0 +1,103 @@ +# Microsoft Developer Studio Project File - Name="nsupdate" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=nsupdate - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "nsupdate.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "nsupdate.mak" CFG="nsupdate - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "nsupdate - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "nsupdate - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "nsupdate - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/dns/sec/dst/include" /D "WIN32" /D "__STDC__" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 ../../../lib/isc/win32/Release/libisc.lib ../../../lib/dns/win32/Release/libdns.lib ../../../lib/lwres/win32/Release/liblwres.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /out:"../../../Build/Release/nsupdate.exe" + +!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/dns/sec/dst/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c +# SUBTRACT CPP /X /u /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ../../../lib/isc/win32/Debug/libisc.lib ../../../lib/dns/win32/Debug/libdns.lib ../../../lib/lwres/win32/Debug/liblwres.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../../Build/Debug/nsupdate.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "nsupdate - Win32 Release" +# Name "nsupdate - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\nsupdate.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsw b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsw new file mode 100644 index 00000000000..e3b777225a0 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "nsupdate"=".\nsupdate.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/usr.sbin/bind/bin/nsupdate/win32/nsupdate.mak b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.mak new file mode 100644 index 00000000000..176fa548fc9 --- /dev/null +++ b/usr.sbin/bind/bin/nsupdate/win32/nsupdate.mak @@ -0,0 +1,203 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on nsupdate.dsp +!IF "$(CFG)" == "" +CFG=nsupdate - Win32 Debug +!MESSAGE No configuration specified. Defaulting to nsupdate - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "nsupdate - Win32 Release" && "$(CFG)" != "nsupdate - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "nsupdate.mak" CFG="nsupdate - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "nsupdate - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "nsupdate - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +!IF "$(CFG)" == "nsupdate - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "..\..\..\Build\Release\nsupdate.exe" + + +CLEAN : + -@erase "$(INTDIR)\nsupdate.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "..\..\..\Build\Release\nsupdate.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/dns/sec/dst/include" /D "WIN32" /D "__STDC__" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\nsupdate.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\nsupdate.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=../../../lib/isc/win32/Release/libisc.lib ../../../lib/dns/win32/Release/libdns.lib ../../../lib/lwres/win32/Release/liblwres.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\nsupdate.pdb" /machine:I386 /out:"../../../Build/Release/nsupdate.exe" +LINK32_OBJS= \ + "$(INTDIR)\nsupdate.obj" + +"..\..\..\Build\Release\nsupdate.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "..\..\..\Build\Debug\nsupdate.exe" "$(OUTDIR)\nsupdate.bsc" + + +CLEAN : + -@erase "$(INTDIR)\nsupdate.obj" + -@erase "$(INTDIR)\nsupdate.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(OUTDIR)\nsupdate.bsc" + -@erase "$(OUTDIR)\nsupdate.pdb" + -@erase "..\..\..\Build\Debug\nsupdate.exe" + -@erase "..\..\..\Build\Debug\nsupdate.ilk" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/dns/sec/dst/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +RSC=rc.exe +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\nsupdate.bsc" +BSC32_SBRS= \ + "$(INTDIR)\nsupdate.sbr" + +"$(OUTDIR)\nsupdate.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=../../../lib/isc/win32/Debug/libisc.lib ../../../lib/dns/win32/Debug/libdns.lib ../../../lib/lwres/win32/Debug/liblwres.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\nsupdate.pdb" /debug /machine:I386 /out:"../../../Build/Debug/nsupdate.exe" /pdbtype:sept +LINK32_OBJS= \ + "$(INTDIR)\nsupdate.obj" + +"..\..\..\Build\Debug\nsupdate.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("nsupdate.dep") +!INCLUDE "nsupdate.dep" +!ELSE +!MESSAGE Warning: cannot find "nsupdate.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "nsupdate - Win32 Release" || "$(CFG)" == "nsupdate - Win32 Debug" +SOURCE=..\nsupdate.c + +!IF "$(CFG)" == "nsupdate - Win32 Release" + + +"$(INTDIR)\nsupdate.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug" + + +"$(INTDIR)\nsupdate.obj" "$(INTDIR)\nsupdate.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + + +!ENDIF + |