summaryrefslogtreecommitdiffstats
path: root/bin/nsupdate
diff options
context:
space:
mode:
authorMartin Nagy <mnagy@redhat.com>2009-02-11 20:37:59 +0100
committerMartin Nagy <mnagy@redhat.com>2009-02-11 20:37:59 +0100
commitf50ae72ec3417cae55dd4e085991c01af9fdc5f1 (patch)
tree0e36c9a3320f6d068df93d3ff6d84b821d23db40 /bin/nsupdate
downloadbind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.tar.gz
bind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.tar.xz
bind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.zip
Initial commitstart
Diffstat (limited to 'bin/nsupdate')
-rw-r--r--bin/nsupdate/Makefile.in83
-rw-r--r--bin/nsupdate/nsupdate.1377
-rw-r--r--bin/nsupdate/nsupdate.c2724
-rw-r--r--bin/nsupdate/nsupdate.docbook701
-rw-r--r--bin/nsupdate/nsupdate.html530
-rw-r--r--bin/nsupdate/win32/nsupdate.dsp103
-rw-r--r--bin/nsupdate/win32/nsupdate.dsw29
-rw-r--r--bin/nsupdate/win32/nsupdate.mak373
8 files changed, 4920 insertions, 0 deletions
diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in
new file mode 100644
index 0000000..6d65697
--- /dev/null
+++ b/bin/nsupdate/Makefile.in
@@ -0,0 +1,83 @@
+# Copyright (C) 2004, 2006-2008 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000-2002 Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: Makefile.in,v 1.29 2008/08/29 23:47:22 tbox Exp $
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+top_srcdir = @top_srcdir@
+
+@BIND9_VERSION@
+
+@BIND9_MAKE_INCLUDES@
+
+CINCLUDES = ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \
+ ${ISC_INCLUDES} @DST_GSSAPI_INC@
+
+CDEFINES = @USE_GSSAPI@
+CWARNINGS =
+
+LWRESLIBS = ../../lib/lwres/liblwres.@A@
+DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
+BIND9LIBS = ../../lib/bind9/libbind9.@A@
+ISCLIBS = ../../lib/isc/libisc.@A@
+ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@
+
+LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@
+DNSDEPLIBS = ../../lib/dns/libdns.@A@
+BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@
+ISCDEPLIBS = ../../lib/isc/libisc.@A@
+ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@
+
+DEPLIBS = ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS}
+
+LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCLIBS} ${ISCCFGLIBS} @LIBS@
+
+SUBDIRS =
+
+TARGETS = nsupdate@EXEEXT@
+
+OBJS = nsupdate.@O@
+
+UOBJS =
+
+SRCS = nsupdate.c
+
+MANPAGES = nsupdate.1
+
+HTMLPAGES = nsupdate.html
+
+MANOBJS = ${MANPAGES} ${HTMLPAGES}
+
+@BIND9_MAKE_RULES@
+
+nsupdate@EXEEXT@: nsupdate.@O@ ${UOBJS} ${DEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -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}/man1
+
+install:: nsupdate@EXEEXT@ installdirs
+ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} nsupdate@EXEEXT@ ${DESTDIR}${bindir}
+ ${INSTALL_DATA} ${srcdir}/nsupdate.1 ${DESTDIR}${mandir}/man1
diff --git a/bin/nsupdate/nsupdate.1 b/bin/nsupdate/nsupdate.1
new file mode 100644
index 0000000..19f2889
--- /dev/null
+++ b/bin/nsupdate/nsupdate.1
@@ -0,0 +1,377 @@
+.\" Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
+.\" Copyright (C) 2000-2003 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 ISC DISCLAIMS ALL WARRANTIES WITH
+.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $Id: nsupdate.1,v 1.3 2008/09/25 04:45:04 tbox Exp $
+.\"
+.hy 0
+.ad l
+.\" Title: nsupdate
+.\" Author:
+.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
+.\" Date: Jun 30, 2000
+.\" Manual: BIND9
+.\" Source: BIND9
+.\"
+.TH "NSUPDATE" "1" "Jun 30, 2000" "BIND9" "BIND9"
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.SH "NAME"
+nsupdate \- Dynamic DNS update utility
+.SH "SYNOPSIS"
+.HP 9
+\fBnsupdate\fR [\fB\-d\fR] [\fB\-D\fR] [[\fB\-y\ \fR\fB\fI[hmac:]\fR\fIkeyname:secret\fR\fR] | [\fB\-k\ \fR\fB\fIkeyfile\fR\fR]] [\fB\-t\ \fR\fB\fItimeout\fR\fR] [\fB\-u\ \fR\fB\fIudptimeout\fR\fR] [\fB\-r\ \fR\fB\fIudpretries\fR\fR] [\fB\-R\ \fR\fB\fIrandomdev\fR\fR] [\fB\-v\fR] [filename]
+.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
+The
+\fB\-D\fR
+option makes
+\fBnsupdate\fR
+report additional debugging information to
+\fB\-d\fR.
+.PP
+Transaction signatures can be used to authenticate the Dynamic DNS updates. These use the TSIG resource record type described in RFC2845 or the SIG(0) record described in RFC3535 and RFC2931. TSIG relies 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. SIG(0) uses public key cryptography. To use a SIG(0) key, the public key must be stored in a KEY record in a zone served by the name server.
+\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, default type HMAC\-MD5. 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
+[\fIhmac:\fR]\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
+The
+\fB\-k\fR
+may also be used to specify a SIG(0) key used to authenticate Dynamic DNS update requests. In this case, the key specified is not an HMAC\-MD5 key.
+.PP
+By default
+\fBnsupdate\fR
+uses UDP to send update requests to the name server unless they are too large to fit in a UDP request in which case TCP will be used. The
+\fB\-v\fR
+option makes
+\fBnsupdate\fR
+use a TCP connection. This may be preferable when a batch of update requests is made.
+.PP
+The
+\fB\-t\fR
+option sets the maximum time an update request can take before it is aborted. The default is 300 seconds. Zero can be used to disable the timeout.
+.PP
+The
+\fB\-u\fR
+option sets the UDP retry interval. The default is 3 seconds. If zero, the interval will be computed from the timeout interval and number of UDP retries.
+.PP
+The
+\fB\-r\fR
+option sets the number of UDP retries. The default is 3. If zero, only one update request will be made.
+.PP
+The
+\fB\-R \fR\fB\fIrandomdev\fR\fR
+option specifies a source of randomness. If the operating system does not provide a
+\fI/dev/random\fR
+or equivalent device, the default source of randomness is keyboard input.
+\fIrandomdev\fR
+specifies the name of a character device or file containing random data to be used instead of the default. The special value
+\fIkeyboard\fR
+indicates that keyboard input should be used. This option may be specified multiple times.
+.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:
+.PP
+\fBserver\fR {servername} [port]
+.RS 4
+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.
+.RE
+.PP
+\fBlocal\fR {address} [port]
+.RS 4
+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 chosen 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.
+.RE
+.PP
+\fBzone\fR {zonename}
+.RS 4
+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.
+.RE
+.PP
+\fBclass\fR {classname}
+.RS 4
+Specify the default class. If no
+\fIclass\fR
+is specified, the default class is
+\fIIN\fR.
+.RE
+.PP
+\fBttl\fR {seconds}
+.RS 4
+Specify the default time to live for records to be added. The value
+\fInone\fR
+will clear the default ttl.
+.RE
+.PP
+\fBkey\fR {name} {secret}
+.RS 4
+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.
+.RE
+.PP
+\fBprereq nxdomain\fR {domain\-name}
+.RS 4
+Requires that no resource record of any type exists with name
+\fIdomain\-name\fR.
+.RE
+.PP
+\fBprereq yxdomain\fR {domain\-name}
+.RS 4
+Requires that
+\fIdomain\-name\fR
+exists (has as at least one resource record, of any type).
+.RE
+.PP
+\fBprereq nxrrset\fR {domain\-name} [class] {type}
+.RS 4
+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.
+.RE
+.PP
+\fBprereq yxrrset\fR {domain\-name} [class] {type}
+.RS 4
+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.
+.RE
+.PP
+\fBprereq yxrrset\fR {domain\-name} [class] {type} {data...}
+.RS 4
+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.
+.RE
+.PP
+\fBupdate delete\fR {domain\-name} [ttl] [class] [type\ [data...]]
+.RS 4
+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.
+.RE
+.PP
+\fBupdate add\fR {domain\-name} {ttl} [class] {type} {data...}
+.RS 4
+Adds a new resource record with the specified
+\fIttl\fR,
+\fIclass\fR
+and
+\fIdata\fR.
+.RE
+.PP
+\fBshow\fR
+.RS 4
+Displays the current message, containing all of the prerequisites and updates specified since the last send.
+.RE
+.PP
+\fBsend\fR
+.RS 4
+Sends the current message. This is equivalent to entering a blank line.
+.RE
+.PP
+\fBanswer\fR
+.RS 4
+Displays the answer.
+.RE
+.PP
+\fBdebug\fR
+.RS 4
+Turn on debugging.
+.RE
+.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
+.RS 4
+.nf
+# nsupdate
+> update delete oldhost.example.com A
+> update add newhost.example.com 86400 A 172.16.1.1
+> send
+.fi
+.RE
+.sp
+.PP
+Any A records for
+\fBoldhost.example.com\fR
+are deleted. And an A record for
+\fBnewhost.example.com\fR
+with IP address 172.16.1.1 is added. The newly\-added record has a 1 day TTL (86400 seconds).
+.sp
+.RS 4
+.nf
+# nsupdate
+> prereq nxdomain nickname.example.com
+> update add nickname.example.com 86400 CNAME somehost.example.com
+> send
+.fi
+.RE
+.sp
+.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 RRSIG, DNSKEY and NSEC records.)
+.SH "FILES"
+.PP
+\fB/etc/resolv.conf\fR
+.RS 4
+used to identify default name server
+.RE
+.PP
+\fBK{name}.+157.+{random}.key\fR
+.RS 4
+base\-64 encoding of HMAC\-MD5 key created by
+\fBdnssec\-keygen\fR(8).
+.RE
+.PP
+\fBK{name}.+157.+{random}.private\fR
+.RS 4
+base\-64 encoding of HMAC\-MD5 key created by
+\fBdnssec\-keygen\fR(8).
+.RE
+.SH "SEE ALSO"
+.PP
+\fBRFC2136\fR(),
+\fBRFC3007\fR(),
+\fBRFC2104\fR(),
+\fBRFC2845\fR(),
+\fBRFC1034\fR(),
+\fBRFC2535\fR(),
+\fBRFC2931\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.
+.SH "COPYRIGHT"
+Copyright \(co 2004\-2008 Internet Systems Consortium, Inc. ("ISC")
+.br
+Copyright \(co 2000\-2003 Internet Software Consortium.
+.br
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
new file mode 100644
index 0000000..0987638
--- /dev/null
+++ b/bin/nsupdate/nsupdate.c
@@ -0,0 +1,2724 @@
+/*
+ * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: nsupdate.c,v 1.163 2008/09/25 04:02:38 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.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/hash.h>
+#include <isc/lex.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/parseint.h>
+#include <isc/random.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/dnssec.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/log.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rcode.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/tkey.h>
+#include <dns/tsig.h>
+
+#include <dst/dst.h>
+
+#include <lwres/lwres.h>
+#include <lwres/net.h>
+
+#ifdef GSSAPI
+#include <dst/gssapi.h>
+#endif
+#include <bind9/getaddresses.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 PACKETSIZE ((64 * 1024) - 1)
+#define INITTEXT (2 * 1024)
+#define MAXTEXT (128 * 1024)
+#define FIND_TIMEOUT 5
+#define TTL_MAX 2147483647U /* 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_boolean_t usegsstsig = ISC_FALSE;
+static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
+static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
+static isc_taskmgr_t *taskmgr = NULL;
+static isc_task_t *global_task = NULL;
+static isc_event_t *global_event = NULL;
+static isc_log_t *lctx = 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 fuserzone;
+static dns_name_t *userzone = NULL;
+static dns_name_t *zonename = NULL;
+static dns_name_t tmpzonename;
+static dns_name_t restart_master;
+static dns_tsig_keyring_t *gssring = NULL;
+static dns_tsigkey_t *tsigkey = NULL;
+static dst_key_t *sig0key;
+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 isc_sockaddr_t *serveraddr = NULL;
+static isc_sockaddr_t tempaddr;
+static char *keystr = NULL, *keyfile = NULL;
+static isc_entropy_t *entropy = 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;
+static unsigned int logdebuglevel = 0;
+static unsigned int timeout = 300;
+static unsigned int udp_timeout = 3;
+static unsigned int udp_retries = 3;
+static dns_rdataclass_t defaultclass = dns_rdataclass_in;
+static dns_rdataclass_t zoneclass = dns_rdataclass_none;
+static dns_message_t *answer = NULL;
+static isc_uint32_t default_ttl = 0;
+static isc_boolean_t default_ttl_set = ISC_FALSE;
+
+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);
+
+#ifdef GSSAPI
+static dns_fixedname_t fkname;
+static isc_sockaddr_t *kserver = NULL;
+static char servicename[DNS_NAME_FORMATSIZE];
+static dns_name_t *keyname;
+typedef struct nsu_gssinfo {
+ dns_message_t *msg;
+ isc_sockaddr_t *addr;
+ gss_ctx_id_t context;
+} nsu_gssinfo_t;
+
+static void
+start_gssrequest(dns_name_t *master);
+static void
+send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ dns_message_t *msg, dns_request_t **request,
+ gss_ctx_id_t context);
+static void
+recvgss(isc_task_t *task, isc_event_t *event);
+#endif /* GSSAPI */
+
+static void
+error(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
+
+typedef struct entropysource entropysource_t;
+
+struct entropysource {
+ isc_entropysource_t *source;
+ isc_mem_t *mctx;
+ ISC_LINK(entropysource_t) link;
+};
+
+static ISC_LIST(entropysource_t) sources;
+
+static void
+setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx)
+{
+ isc_result_t result;
+ isc_entropysource_t *source = NULL;
+ entropysource_t *elt;
+ int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE;
+
+ REQUIRE(ectx != NULL);
+
+ if (*ectx == NULL) {
+ result = isc_entropy_create(mctx, ectx);
+ if (result != ISC_R_SUCCESS)
+ fatal("could not create entropy object");
+ ISC_LIST_INIT(sources);
+ }
+
+ if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) {
+ usekeyboard = ISC_ENTROPY_KEYBOARDYES;
+ randomfile = NULL;
+ }
+
+ result = isc_entropy_usebestsource(*ectx, &source, randomfile,
+ usekeyboard);
+
+ if (result != ISC_R_SUCCESS)
+ fatal("could not initialize entropy source: %s",
+ isc_result_totext(result));
+
+ if (source != NULL) {
+ elt = isc_mem_get(mctx, sizeof(*elt));
+ if (elt == NULL)
+ fatal("out of memory");
+ elt->source = source;
+ elt->mctx = mctx;
+ ISC_LINK_INIT(elt, link);
+ ISC_LIST_APPEND(sources, elt, link);
+ }
+}
+
+static void
+cleanup_entropy(isc_entropy_t **ectx) {
+ entropysource_t *source;
+ while (!ISC_LIST_EMPTY(sources)) {
+ source = ISC_LIST_HEAD(sources);
+ ISC_LIST_UNLINK(sources, source, link);
+ isc_entropy_destroysource(&source->source);
+ isc_mem_put(source->mctx, source, sizeof(*source));
+ }
+ isc_entropy_detach(ectx);
+}
+
+
+static dns_rdataclass_t
+getzoneclass(void) {
+ if (zoneclass == dns_rdataclass_none)
+ zoneclass = defaultclass;
+ return (zoneclass);
+}
+
+static isc_boolean_t
+setzoneclass(dns_rdataclass_t rdclass) {
+ if (zoneclass == dns_rdataclass_none ||
+ rdclass == dns_rdataclass_none)
+ zoneclass = rdclass;
+ if (zoneclass != rdclass)
+ return (ISC_FALSE);
+ return (ISC_TRUE);
+}
+
+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
+error(const char *format, ...) {
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+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 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;
+ if (usegsstsig) {
+ if (tsigkey != NULL)
+ dns_tsigkey_detach(&tsigkey);
+ if (gssring != NULL)
+ dns_tsigkeyring_destroy(&gssring);
+ tried_other_gsstsig = ISC_FALSE;
+ }
+}
+
+static isc_uint16_t
+parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
+ isc_uint16_t digestbits = 0;
+ isc_result_t result;
+ char buf[20];
+
+ REQUIRE(hmac != NULL && *hmac == NULL);
+ REQUIRE(hmacstr != NULL);
+
+ if (len >= sizeof(buf))
+ fatal("unknown key type '%.*s'", (int)(len), hmacstr);
+
+ strncpy(buf, hmacstr, len);
+ buf[len] = 0;
+
+ if (strcasecmp(buf, "hmac-md5") == 0) {
+ *hmac = DNS_TSIG_HMACMD5_NAME;
+ } else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
+ *hmac = DNS_TSIG_HMACMD5_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[9], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 128)
+ fatal("digest-bits out of range [0..128]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else if (strcasecmp(buf, "hmac-sha1") == 0) {
+ *hmac = DNS_TSIG_HMACSHA1_NAME;
+ } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
+ *hmac = DNS_TSIG_HMACSHA1_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[10], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 160)
+ fatal("digest-bits out of range [0..160]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else if (strcasecmp(buf, "hmac-sha224") == 0) {
+ *hmac = DNS_TSIG_HMACSHA224_NAME;
+ } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
+ *hmac = DNS_TSIG_HMACSHA224_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[12], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 224)
+ fatal("digest-bits out of range [0..224]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else if (strcasecmp(buf, "hmac-sha256") == 0) {
+ *hmac = DNS_TSIG_HMACSHA256_NAME;
+ } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
+ *hmac = DNS_TSIG_HMACSHA256_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[12], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 256)
+ fatal("digest-bits out of range [0..256]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else if (strcasecmp(buf, "hmac-sha384") == 0) {
+ *hmac = DNS_TSIG_HMACSHA384_NAME;
+ } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
+ *hmac = DNS_TSIG_HMACSHA384_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[12], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 384)
+ fatal("digest-bits out of range [0..384]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else if (strcasecmp(buf, "hmac-sha512") == 0) {
+ *hmac = DNS_TSIG_HMACSHA512_NAME;
+ } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
+ *hmac = DNS_TSIG_HMACSHA512_NAME;
+ result = isc_parse_uint16(&digestbits, &buf[12], 10);
+ if (result != ISC_R_SUCCESS || digestbits > 512)
+ fatal("digest-bits out of range [0..512]");
+ digestbits = (digestbits +7) & ~0x7U;
+ } else
+ fatal("unknown key type '%s'", buf);
+ return (digestbits);
+}
+
+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, *n;
+ dns_fixedname_t fkeyname;
+ dns_name_t *keyname;
+ char *name;
+ dns_name_t *hmacname = NULL;
+ isc_uint16_t digestbits = 0;
+
+ dns_fixedname_init(&fkeyname);
+ keyname = dns_fixedname_name(&fkeyname);
+
+ debug("Creating key...");
+
+ s = strchr(keystr, ':');
+ if (s == NULL || s == keystr || s[1] == 0)
+ fatal("key option must specify [hmac:]keyname:secret");
+ secretstr = s + 1;
+ n = strchr(secretstr, ':');
+ if (n != NULL) {
+ if (n == secretstr || n[1] == 0)
+ fatal("key option must specify [hmac:]keyname:secret");
+ name = secretstr;
+ secretstr = n + 1;
+ digestbits = parse_hmac(&hmacname, keystr, s - keystr);
+ } else {
+ hmacname = DNS_TSIG_HMACMD5_NAME;
+ name = keystr;
+ n = s;
+ }
+
+ isc_buffer_init(&keynamesrc, name, n - name);
+ isc_buffer_add(&keynamesrc, n - name);
+
+ 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, hmacname, secret, secretlen,
+ ISC_TRUE, NULL, 0, 0, mctx, NULL, &tsigkey);
+ if (result != ISC_R_SUCCESS)
+ fprintf(stderr, "could not create key from %s: %s\n",
+ keystr, dns_result_totext(result));
+ else
+ dst_key_setbits(tsigkey->key, digestbits);
+ failure:
+ if (secret != NULL)
+ isc_mem_free(mctx, secret);
+}
+
+static void
+setup_keyfile(void) {
+ dst_key_t *dstkey = NULL;
+ isc_result_t result;
+ dns_name_t *hmacname = NULL;
+
+ debug("Creating key...");
+
+ result = dst_key_fromnamedfile(keyfile,
+ DST_TYPE_PRIVATE | DST_TYPE_KEY, mctx,
+ &dstkey);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "could not read key from %s: %s\n",
+ keyfile, isc_result_totext(result));
+ return;
+ }
+ switch (dst_key_alg(dstkey)) {
+ case DST_ALG_HMACMD5:
+ hmacname = DNS_TSIG_HMACMD5_NAME;
+ break;
+ case DST_ALG_HMACSHA1:
+ hmacname = DNS_TSIG_HMACSHA1_NAME;
+ break;
+ case DST_ALG_HMACSHA224:
+ hmacname = DNS_TSIG_HMACSHA224_NAME;
+ break;
+ case DST_ALG_HMACSHA256:
+ hmacname = DNS_TSIG_HMACSHA256_NAME;
+ break;
+ case DST_ALG_HMACSHA384:
+ hmacname = DNS_TSIG_HMACSHA384_NAME;
+ break;
+ case DST_ALG_HMACSHA512:
+ hmacname = DNS_TSIG_HMACSHA512_NAME;
+ break;
+ }
+ if (hmacname != NULL) {
+ result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
+ hmacname, dstkey, ISC_FALSE,
+ NULL, 0, 0, mctx, NULL,
+ &tsigkey);
+ 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;
+ }
+ } else
+ sig0key = dstkey;
+}
+
+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 (tsigkey != NULL) {
+ ddebug("Freeing TSIG key");
+ dns_tsigkey_detach(&tsigkey);
+ }
+
+ if (sig0key != NULL) {
+ ddebug("Freeing SIG(0) key");
+ dst_key_free(&sig0key);
+ }
+
+ if (updatemsg != NULL)
+ dns_message_destroy(&updatemsg);
+
+ if (is_dst_up) {
+ ddebug("Destroy DST lib");
+ dst_lib_destroy();
+ is_dst_up = ISC_FALSE;
+ }
+
+ cleanup_entropy(&entropy);
+
+ 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;
+ lwres_result_t lwresult;
+ unsigned int attrs, attrmask;
+ int i;
+ isc_logconfig_t *logconfig = NULL;
+
+ 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_log_create(mctx, &lctx, &logconfig);
+ check_result(result, "isc_log_create");
+
+ isc_log_setcontext(lctx);
+ dns_log_init(lctx);
+ dns_log_setcontext(lctx);
+
+ result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
+ check_result(result, "isc_log_usechannel");
+
+ isc_log_setdebuglevel(lctx, logdebuglevel);
+
+ 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);
+ }
+ }
+ }
+
+ setup_entropy(mctx, NULL, &entropy);
+
+ result = isc_hash_create(mctx, entropy, DNS_NAME_MAXWIRE);
+ check_result(result, "isc_hash_create");
+ isc_hash_init();
+
+ result = dns_dispatchmgr_create(mctx, entropy, &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, entropy, 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 (keystr != NULL)
+ setup_keystr();
+ else if (keyfile != NULL)
+ setup_keyfile();
+}
+
+static void
+get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
+ int count;
+ isc_result_t result;
+
+ isc_app_block();
+ result = bind9_getaddresses(host, port, sockaddr, 1, &count);
+ isc_app_unblock();
+ if (result != ISC_R_SUCCESS)
+ fatal("couldn't get address for '%s': %s",
+ host, isc_result_totext(result));
+ INSIST(count == 1);
+}
+
+#define PARSE_ARGS_FMT "dDMl:y:govk:rR::t:u:"
+
+static void
+pre_parse_args(int argc, char **argv) {
+ int ch;
+
+ while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
+ switch (ch) {
+ case 'M': /* was -dm */
+ debugging = ISC_TRUE;
+ ddebugging = ISC_TRUE;
+ memdebugging = ISC_TRUE;
+ isc_mem_debugging = ISC_MEM_DEBUGTRACE |
+ ISC_MEM_DEBUGRECORD;
+ break;
+
+ case '?':
+ if (isc_commandline_option != '?')
+ fprintf(stderr, "%s: invalid argument -%c\n",
+ argv[0], isc_commandline_option);
+ fprintf(stderr, "usage: nsupdate [-d] "
+ "[-g | -o | -y keyname:secret | -k keyfile] "
+ "[-v] [filename]\n");
+ exit(1);
+
+ default:
+ break;
+ }
+ }
+ isc_commandline_reset = ISC_TRUE;
+ isc_commandline_index = 1;
+}
+
+static void
+parse_args(int argc, char **argv, isc_mem_t *mctx, isc_entropy_t **ectx) {
+ int ch;
+ isc_uint32_t i;
+ isc_result_t result;
+
+ debug("parse_args");
+ while ((ch = isc_commandline_parse(argc, argv, PARSE_ARGS_FMT)) != -1) {
+ switch (ch) {
+ case 'd':
+ debugging = ISC_TRUE;
+ break;
+ case 'D': /* was -dd */
+ debugging = ISC_TRUE;
+ ddebugging = ISC_TRUE;
+ break;
+ case 'M':
+ break;
+ case 'l':
+ result = isc_parse_uint32(&i, isc_commandline_argument,
+ 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad library debug value "
+ "'%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ logdebuglevel = i;
+ break;
+ case 'y':
+ keystr = isc_commandline_argument;
+ break;
+ case 'v':
+ usevc = ISC_TRUE;
+ break;
+ case 'k':
+ keyfile = isc_commandline_argument;
+ break;
+ case 'g':
+ usegsstsig = ISC_TRUE;
+ use_win2k_gsstsig = ISC_FALSE;
+ break;
+ case 'o':
+ usegsstsig = ISC_TRUE;
+ use_win2k_gsstsig = ISC_TRUE;
+ break;
+ case 't':
+ result = isc_parse_uint32(&timeout,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad timeout '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ if (timeout == 0)
+ timeout = UINT_MAX;
+ break;
+ case 'u':
+ result = isc_parse_uint32(&udp_timeout,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad udp timeout '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ if (udp_timeout == 0)
+ udp_timeout = UINT_MAX;
+ break;
+ case 'r':
+ result = isc_parse_uint32(&udp_retries,
+ isc_commandline_argument, 10);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "bad udp retries '%s'\n", isc_commandline_argument);
+ exit(1);
+ }
+ break;
+
+ case 'R':
+ setup_entropy(mctx, isc_commandline_argument, ectx);
+ break;
+
+ default:
+ fprintf(stderr, "%s: unhandled option: %c\n",
+ argv[0], isc_commandline_option);
+ exit(1);
+ }
+ }
+ if (keyfile != NULL && keystr != NULL) {
+ fprintf(stderr, "%s: cannot specify both -k and -y\n",
+ argv[0]);
+ exit(1);
+ }
+
+#ifdef GSSAPI
+ if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
+ fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
+ argv[0]);
+ exit(1);
+ }
+#else
+ if (usegsstsig) {
+ fprintf(stderr, "%s: cannot specify -g or -o, " \
+ "program not linked with GSS API Library\n",
+ argv[0]);
+ exit(1);
+ }
+#endif
+
+ 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;
+
+ 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, DNS_NAME_MAXWIRE);
+ 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));
+ result = dns_name_fromtext(*namep, &source, dns_rootname,
+ 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;
+
+ while (*cmdline != 0 && isspace((unsigned char)*cmdline))
+ cmdline++;
+
+ if (*cmdline != 0) {
+ dns_rdatacallbacks_init(&callbacks);
+ result = isc_lex_create(mctx, strlen(cmdline), &lex);
+ check_result(result, "isc_lex_create");
+ isc_buffer_init(&source, cmdline, strlen(cmdline));
+ isc_buffer_add(&source, strlen(cmdline));
+ result = isc_lex_openbuffer(lex, &source);
+ check_result(result, "isc_lex_openbuffer");
+ result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
+ check_result(result, "isc_buffer_allocate");
+ result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
+ dns_rootname, 0, mctx, buf,
+ &callbacks);
+ isc_lex_destroy(&lex);
+ if (result == ISC_R_SUCCESS) {
+ isc_buffer_usedregion(buf, &r);
+ result = isc_buffer_allocate(mctx, &newbuf, r.length);
+ check_result(result, "isc_buffer_allocate");
+ isc_buffer_putmem(newbuf, r.base, r.length);
+ isc_buffer_usedregion(newbuf, &r);
+ dns_rdata_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, &region);
+ if (result == ISC_R_SUCCESS) {
+ if (!setzoneclass(rdataclass)) {
+ fprintf(stderr, "class mismatch: %s\n", word);
+ goto failure;
+ }
+ /*
+ * 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, &region);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "invalid type: %s\n", word);
+ goto failure;
+ }
+ } else {
+ rdataclass = getzoneclass();
+ result = dns_rdatatype_fromtext(&rdatatype, &region);
+ 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");
+
+ dns_rdata_init(rdata);
+
+ 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;
+ dns_name_t *hmacname = NULL;
+ isc_uint16_t digestbits = 0;
+ char *n;
+
+ 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);
+
+ n = strchr(namestr, ':');
+ if (n != NULL) {
+ digestbits = parse_hmac(&hmacname, namestr, n - namestr);
+ namestr = n + 1;
+ } else
+ hmacname = DNS_TSIG_HMACMD5_NAME;
+
+ 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 (tsigkey != NULL)
+ dns_tsigkey_detach(&tsigkey);
+ result = dns_tsigkey_create(keyname, hmacname, secret, secretlen,
+ ISC_TRUE, NULL, 0, 0, mctx, NULL,
+ &tsigkey);
+ 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);
+ }
+ dst_key_setbits(tsigkey->key, digestbits);
+ 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
+evaluate_ttl(char *cmdline) {
+ char *word;
+ isc_result_t result;
+ isc_uint32_t ttl;
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 0) {
+ fprintf(stderr, "could not ttl\n");
+ return (STATUS_SYNTAX);
+ }
+
+ if (!strcasecmp(word, "none")) {
+ default_ttl = 0;
+ default_ttl_set = ISC_FALSE;
+ return (STATUS_MORE);
+ }
+
+ result = isc_parse_uint32(&ttl, word, 10);
+ if (result != ISC_R_SUCCESS)
+ return (STATUS_SYNTAX);
+
+ if (ttl > TTL_MAX) {
+ fprintf(stderr, "ttl '%s' is out of range (0 to %u)\n",
+ word, TTL_MAX);
+ return (STATUS_SYNTAX);
+ }
+ default_ttl = ttl;
+ default_ttl_set = ISC_TRUE;
+
+ return (STATUS_MORE);
+}
+
+static isc_uint16_t
+evaluate_class(char *cmdline) {
+ char *word;
+ isc_textregion_t r;
+ isc_result_t result;
+ dns_rdataclass_t rdclass;
+
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 0) {
+ fprintf(stderr, "could not read class name\n");
+ return (STATUS_SYNTAX);
+ }
+
+ r.base = word;
+ r.length = strlen(word);
+ result = dns_rdataclass_fromtext(&rdclass, &r);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "could not parse class name: %s\n", word);
+ return (STATUS_SYNTAX);
+ }
+ switch (rdclass) {
+ case dns_rdataclass_none:
+ case dns_rdataclass_any:
+ case dns_rdataclass_reserved0:
+ fprintf(stderr, "bad default class: %s\n", word);
+ return (STATUS_SYNTAX);
+ default:
+ defaultclass = rdclass;
+ }
+
+ return (STATUS_MORE);
+}
+
+static isc_uint16_t
+update_addordelete(char *cmdline, isc_boolean_t isdelete) {
+ isc_result_t result;
+ dns_name_t *name = NULL;
+ isc_uint32_t ttl;
+ char *word;
+ dns_rdataclass_t rdataclass;
+ dns_rdatatype_t rdatatype;
+ dns_rdata_t *rdata = NULL;
+ dns_rdatalist_t *rdatalist = NULL;
+ dns_rdataset_t *rdataset = NULL;
+ isc_textregion_t region;
+ 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");
+
+ dns_rdata_init(rdata);
+
+ /*
+ * If this is an add, read the TTL and verify that it's in range.
+ * If it's a delete, ignore a TTL if present (for compatibility).
+ */
+ word = nsu_strsep(&cmdline, " \t\r\n");
+ if (*word == 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;
+ }
+ }
+ result = isc_parse_uint32(&ttl, word, 10);
+ if (result != ISC_R_SUCCESS) {
+ if (isdelete) {
+ ttl = 0;
+ goto parseclass;
+ } else if (default_ttl_set) {
+ ttl = default_ttl;
+ goto parseclass;
+ } else {
+ fprintf(stderr, "ttl '%s': %s\n", word,
+ isc_result_totext(result));
+ goto failure;
+ }
+ }
+
+ if (isdelete)
+ ttl = 0;
+ else if (ttl > TTL_MAX) {
+ fprintf(stderr, "ttl '%s' is out of range (0 to %u)\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, &region);
+ if (result == ISC_R_SUCCESS) {
+ if (!setzoneclass(rdataclass)) {
+ fprintf(stderr, "class mismatch: %s\n", word);
+ goto failure;
+ }
+ /*
+ * 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, &region);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "'%s' is not a valid type: %s\n",
+ word, isc_result_totext(result));
+ goto failure;
+ }
+ } else {
+ rdataclass = getzoneclass();
+ result = dns_rdatatype_fromtext(&rdatatype, &region);
+ 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);
+ 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
+setzone(dns_name_t *zonename) {
+ isc_result_t result;
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset = NULL;
+
+ result = dns_message_firstname(updatemsg, DNS_SECTION_ZONE);
+ if (result == ISC_R_SUCCESS) {
+ dns_message_currentname(updatemsg, DNS_SECTION_ZONE, &name);
+ dns_message_removename(updatemsg, name, DNS_SECTION_ZONE);
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_HEAD(name->list)) {
+ ISC_LIST_UNLINK(name->list, rdataset, link);
+ dns_rdataset_disassociate(rdataset);
+ dns_message_puttemprdataset(updatemsg, &rdataset);
+ }
+ dns_message_puttempname(updatemsg, &name);
+ }
+
+ if (zonename != NULL) {
+ 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, getzoneclass(),
+ dns_rdatatype_soa);
+ ISC_LIST_INIT(name->list);
+ ISC_LIST_APPEND(name->list, rdataset, link);
+ dns_message_addname(updatemsg, name, DNS_SECTION_ZONE);
+ }
+}
+
+static void
+show_message(FILE *stream, dns_message_t *msg, const char *description) {
+ isc_result_t result;
+ isc_buffer_t *buf = NULL;
+ int bufsz;
+
+ ddebug("show_message()");
+
+ setzone(userzone);
+
+ 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;
+ }
+ fprintf(stream, "%s\n%.*s", description,
+ (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, "> ");
+ fflush(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, "class") == 0)
+ return (evaluate_class(cmdline));
+ if (strcasecmp(word, "send") == 0)
+ return (STATUS_SEND);
+ if (strcasecmp(word, "debug") == 0) {
+ if (debugging)
+ ddebugging = ISC_TRUE;
+ else
+ debugging = ISC_TRUE;
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "ttl") == 0)
+ return (evaluate_ttl(cmdline));
+ if (strcasecmp(word, "show") == 0) {
+ show_message(stdout, updatemsg, "Outgoing update query:");
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "answer") == 0) {
+ if (answer != NULL)
+ show_message(stdout, answer, "Answer:");
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "key") == 0) {
+ usegsstsig = ISC_FALSE;
+ return (evaluate_key(cmdline));
+ }
+ if (strcasecmp(word, "gsstsig") == 0) {
+#ifdef GSSAPI
+ usegsstsig = ISC_TRUE;
+ use_win2k_gsstsig = ISC_FALSE;
+#else
+ fprintf(stderr, "gsstsig not supported\n");
+#endif
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "oldgsstsig") == 0) {
+#ifdef GSSAPI
+ usegsstsig = ISC_TRUE;
+ use_win2k_gsstsig = ISC_TRUE;
+#else
+ fprintf(stderr, "gsstsig not supported\n");
+#endif
+ return (STATUS_MORE);
+ }
+ if (strcasecmp(word, "help") == 0) {
+ fprintf(stdout,
+"local address [port] (set local resolver)\n"
+"server address [port] (set master server for zone)\n"
+"send (send the update request)\n"
+"show (show the update request)\n"
+"answer (show the answer to the last request)\n"
+"quit (quit, any pending update is not sent\n"
+"help (display this message_\n"
+"key [hmac:]keyname secret (use TSIG to sign the request)\n"
+"gsstsig (use GSS_TSIG to sign the request)\n"
+"oldgsstsig (use Microsoft's GSS_TSIG to sign the request)\n"
+"zone name (set the zone to be updated)\n"
+"class CLASS (set the zone's DNS class, e.g. IN (default), CH)\n"
+"prereq nxdomain name (does this name not exist)\n"
+"prereq yxdomain name (does this name exist)\n"
+"prereq nxrrset .... (does this RRset exist)\n"
+"prereq yxrrset .... (does this RRset not exist)\n"
+"update add .... (add the given record to the zone)\n"
+"update delete .... (remove the given record(s) from the zone)\n");
+ return (STATUS_MORE);
+ }
+ 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 (!interactive && result == STATUS_SYNTAX)
+ fatal("syntax error");
+ }
+ 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
+check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_any_tsig_t tsig;
+
+ result = dns_rdataset_first(rdataset);
+ check_result(result, "dns_rdataset_first");
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &tsig, NULL);
+ check_result(result, "dns_rdata_tostruct");
+ if (tsig.error != 0) {
+ if (isc_buffer_remaininglength(b) < 1)
+ check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
+ isc__buffer_putstr(b, "(" /*)*/);
+ result = dns_tsigrcode_totext(tsig.error, b);
+ check_result(result, "dns_tsigrcode_totext");
+ if (isc_buffer_remaininglength(b) < 1)
+ check_result(ISC_R_NOSPACE, "isc_buffer_remaininglength");
+ isc__buffer_putstr(b, /*(*/ ")");
+ }
+}
+
+static void
+update_completed(isc_task_t *task, isc_event_t *event) {
+ dns_requestevent_t *reqev = NULL;
+ isc_result_t result;
+ 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, &answer);
+ check_result(result, "dns_message_create");
+ result = dns_request_getresponse(request, answer,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ if (answer->verify_attempted)
+ ddebug("tsig verification successful");
+ break;
+ case DNS_R_CLOCKSKEW:
+ case DNS_R_EXPECTEDTSIG:
+ case DNS_R_TSIGERRORSET:
+ case DNS_R_TSIGVERIFYFAILURE:
+ case DNS_R_UNEXPECTEDTSIG:
+ case ISC_R_FAILURE:
+#if 0
+ if (usegsstsig && answer->rcode == dns_rcode_noerror) {
+ /*
+ * For MS DNS that violates RFC 2845, section 4.2
+ */
+ break;
+ }
+#endif
+ fprintf(stderr, "; TSIG error with server: %s\n",
+ isc_result_totext(result));
+ seenerror = ISC_TRUE;
+ break;
+ default:
+ check_result(result, "dns_request_getresponse");
+ }
+
+ if (answer->rcode != dns_rcode_noerror) {
+ seenerror = ISC_TRUE;
+ if (!debugging) {
+ char buf[64];
+ isc_buffer_t b;
+ dns_rdataset_t *rds;
+
+ isc_buffer_init(&b, buf, sizeof(buf) - 1);
+ result = dns_rcode_totext(answer->rcode, &b);
+ check_result(result, "dns_rcode_totext");
+ rds = dns_message_gettsig(answer, NULL);
+ if (rds != NULL)
+ check_tsig_error(rds, &b);
+ fprintf(stderr, "update failed: %.*s\n",
+ (int)isc_buffer_usedlength(&b), buf);
+ }
+ }
+ if (debugging)
+ show_message(stderr, answer, "\nReply from update query:");
+
+ done:
+ dns_request_destroy(&request);
+ if (usegsstsig) {
+ dns_name_free(&tmpzonename, mctx);
+ dns_name_free(&restart_master, mctx);
+ }
+ 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;
+ unsigned int options = 0;
+
+ ddebug("send_update()");
+
+ setzone(zonename);
+
+ if (usevc)
+ options |= DNS_REQUESTOPT_TCP;
+ if (tsigkey == NULL && sig0key != NULL) {
+ result = dns_message_setsig0key(updatemsg, sig0key);
+ check_result(result, "dns_message_setsig0key");
+ }
+ if (debugging) {
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
+ fprintf(stderr, "Sending update to %s\n", addrbuf);
+ }
+
+ result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
+ master, options, tsigkey, timeout,
+ udp_timeout, udp_retries, global_task,
+ update_completed, NULL, &request);
+ check_result(result, "dns_request_createvia3");
+
+ if (debugging)
+ show_message(stdout, updatemsg, "Outgoing update query:");
+
+ 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;
+ nsu_requestinfo_t *reqinfo;
+ dns_message_t *soaquery = NULL;
+ isc_sockaddr_t *addr;
+ isc_boolean_t seencname = ISC_FALSE;
+ dns_name_t tname;
+ unsigned int nlabels;
+
+ 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);
+ dns_message_settsigkey(soaquery, NULL);
+ sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
+ isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
+ isc_event_free(&event);
+ setzoneclass(dns_rdataclass_none);
+ return;
+ }
+
+ isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
+ reqinfo = NULL;
+ 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);
+ if (result == DNS_R_TSIGERRORSET && userserver != NULL) {
+ dns_message_destroy(&rcvmsg);
+ ddebug("Destroying request [%p]", request);
+ dns_request_destroy(&request);
+ reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
+ if (reqinfo == NULL)
+ fatal("out of memory");
+ reqinfo->msg = soaquery;
+ reqinfo->addr = addr;
+ dns_message_renderreset(soaquery);
+ ddebug("retrying soa request without TSIG");
+ result = dns_request_createvia3(requestmgr, soaquery,
+ localaddr, addr, 0, NULL,
+ FIND_TIMEOUT * 20,
+ FIND_TIMEOUT, 3,
+ global_task, recvsoa, reqinfo,
+ &request);
+ check_result(result, "dns_request_createvia");
+ requests++;
+ return;
+ }
+ check_result(result, "dns_request_getresponse");
+ section = DNS_SECTION_ANSWER;
+ if (debugging)
+ show_message(stderr, rcvmsg, "Reply from SOA query:");
+
+ if (rcvmsg->rcode != dns_rcode_noerror &&
+ rcvmsg->rcode != dns_rcode_nxdomain)
+ fatal("response to SOA query was unsuccessful");
+
+ if (userzone != NULL && rcvmsg->rcode == dns_rcode_nxdomain) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(userzone, namebuf, sizeof(namebuf));
+ error("specified zone '%s' does not exist (NXDOMAIN)",
+ namebuf);
+ dns_message_destroy(&rcvmsg);
+ dns_request_destroy(&request);
+ dns_message_destroy(&soaquery);
+ ddebug("Out of recvsoa");
+ done_update();
+ return;
+ }
+
+ lookforsoa:
+ if (pass == 0)
+ section = DNS_SECTION_ANSWER;
+ else if (pass == 1)
+ section = DNS_SECTION_AUTHORITY;
+ else
+ goto droplabel;
+
+ 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)
+ goto droplabel;
+
+ 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;
+ }
+ dns_rdata_freestruct(&soa);
+
+#ifdef GSSAPI
+ if (usegsstsig) {
+ dns_name_init(&tmpzonename, NULL);
+ dns_name_dup(zonename, mctx, &tmpzonename);
+ dns_name_init(&restart_master, NULL);
+ dns_name_dup(&master, mctx, &restart_master);
+ start_gssrequest(&master);
+ } else {
+ send_update(zonename, serveraddr, localaddr);
+ setzoneclass(dns_rdataclass_none);
+ }
+#else
+ send_update(zonename, serveraddr, localaddr);
+ setzoneclass(dns_rdataclass_none);
+#endif
+
+ dns_message_destroy(&soaquery);
+ dns_request_destroy(&request);
+
+ out:
+ dns_message_destroy(&rcvmsg);
+ ddebug("Out of recvsoa");
+ return;
+
+ droplabel:
+ 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);
+ dns_message_settsigkey(soaquery, NULL);
+ if (userserver != NULL)
+ sendrequest(localaddr, userserver, soaquery, &request);
+ else
+ sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
+ goto out;
+}
+
+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_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
+ (userserver != NULL) ? tsigkey : NULL,
+ FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
+ global_task, recvsoa, reqinfo, request);
+ check_result(result, "dns_request_createvia");
+ requests++;
+}
+
+#ifdef GSSAPI
+static void
+start_gssrequest(dns_name_t *master)
+{
+ gss_ctx_id_t context;
+ isc_buffer_t buf;
+ isc_result_t result;
+ isc_uint32_t val = 0;
+ dns_message_t *rmsg;
+ dns_request_t *request = NULL;
+ dns_name_t *servname;
+ dns_fixedname_t fname;
+ char namestr[DNS_NAME_FORMATSIZE];
+ char keystr[DNS_NAME_FORMATSIZE];
+
+ debug("start_gssrequest");
+ usevc = ISC_TRUE;
+
+ if (gssring != NULL)
+ dns_tsigkeyring_destroy(&gssring);
+ gssring = NULL;
+ result = dns_tsigkeyring_create(mctx, &gssring);
+
+ if (result != ISC_R_SUCCESS)
+ fatal("dns_tsigkeyring_create failed: %s",
+ isc_result_totext(result));
+
+ dns_name_format(master, namestr, sizeof(namestr));
+ if (kserver == NULL) {
+ kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
+ if (kserver == NULL)
+ fatal("out of memory");
+ }
+ if (userserver == NULL)
+ get_address(namestr, DNSDEFAULTPORT, kserver);
+ else
+ (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
+
+ dns_fixedname_init(&fname);
+ servname = dns_fixedname_name(&fname);
+
+ result = isc_string_printf(servicename, sizeof(servicename),
+ "DNS/%s", namestr);
+ if (result != ISC_R_SUCCESS)
+ fatal("isc_string_printf(servicename) failed: %s",
+ isc_result_totext(result));
+ isc_buffer_init(&buf, servicename, strlen(servicename));
+ isc_buffer_add(&buf, strlen(servicename));
+ result = dns_name_fromtext(servname, &buf, dns_rootname,
+ ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ fatal("dns_name_fromtext(servname) failed: %s",
+ isc_result_totext(result));
+
+ dns_fixedname_init(&fkname);
+ keyname = dns_fixedname_name(&fkname);
+
+ isc_random_get(&val);
+ result = isc_string_printf(keystr, sizeof(keystr), "%u.sig-%s",
+ val, namestr);
+ if (result != ISC_R_SUCCESS)
+ fatal("isc_string_printf(keystr) failed: %s",
+ isc_result_totext(result));
+ isc_buffer_init(&buf, keystr, strlen(keystr));
+ isc_buffer_add(&buf, strlen(keystr));
+
+ result = dns_name_fromtext(keyname, &buf, dns_rootname,
+ ISC_FALSE, NULL);
+ if (result != ISC_R_SUCCESS)
+ fatal("dns_name_fromtext(keyname) failed: %s",
+ isc_result_totext(result));
+
+ /* Windows doesn't recognize name compression in the key name. */
+ keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
+
+ rmsg = NULL;
+ result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
+ if (result != ISC_R_SUCCESS)
+ fatal("dns_message_create failed: %s",
+ isc_result_totext(result));
+
+ /* Build first request. */
+
+ context = GSS_C_NO_CONTEXT;
+ result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
+ &context, use_win2k_gsstsig);
+ if (result == ISC_R_FAILURE)
+ fatal("Check your Kerberos ticket, it may have expired.");
+ if (result != ISC_R_SUCCESS)
+ fatal("dns_tkey_buildgssquery failed: %s",
+ isc_result_totext(result));
+
+ send_gssrequest(localaddr, kserver, rmsg, &request, context);
+}
+
+static void
+send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ dns_message_t *msg, dns_request_t **request,
+ gss_ctx_id_t context)
+{
+ isc_result_t result;
+ nsu_gssinfo_t *reqinfo;
+ unsigned int options = 0;
+
+ debug("send_gssrequest");
+ reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
+ if (reqinfo == NULL)
+ fatal("out of memory");
+ reqinfo->msg = msg;
+ reqinfo->addr = destaddr;
+ reqinfo->context = context;
+
+ options |= DNS_REQUESTOPT_TCP;
+ result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
+ options, tsigkey, FIND_TIMEOUT * 20,
+ FIND_TIMEOUT, 3, global_task, recvgss,
+ reqinfo, request);
+ check_result(result, "dns_request_createvia3");
+ if (debugging)
+ show_message(stdout, msg, "Outgoing update query:");
+ requests++;
+}
+
+static void
+recvgss(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;
+ nsu_gssinfo_t *reqinfo;
+ dns_message_t *tsigquery = NULL;
+ isc_sockaddr_t *addr;
+ gss_ctx_id_t context;
+ isc_buffer_t buf;
+ dns_name_t *servname;
+ dns_fixedname_t fname;
+
+ UNUSED(task);
+
+ ddebug("recvgss()");
+
+ requests--;
+
+ REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
+ reqev = (dns_requestevent_t *)event;
+ request = reqev->request;
+ eresult = reqev->result;
+ reqinfo = reqev->ev_arg;
+ tsigquery = reqinfo->msg;
+ context = reqinfo->context;
+ addr = reqinfo->addr;
+
+ if (shuttingdown) {
+ dns_request_destroy(&request);
+ dns_message_destroy(&tsigquery);
+ isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_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(tsigquery);
+ sendrequest(localaddr, &servers[ns_inuse], tsigquery,
+ &request);
+ isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
+ isc_event_free(&event);
+ return;
+ }
+ isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
+
+ isc_event_free(&event);
+ reqev = NULL;
+
+ ddebug("recvgss creating 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");
+
+ if (debugging)
+ show_message(stderr, rcvmsg,
+ "recvmsg reply from GSS-TSIG query");
+
+ if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
+ ddebug("recvgss trying %s GSS-TSIG",
+ use_win2k_gsstsig ? "Standard" : "Win2k");
+ if (use_win2k_gsstsig)
+ use_win2k_gsstsig = ISC_FALSE;
+ else
+ use_win2k_gsstsig = ISC_TRUE;
+ tried_other_gsstsig = ISC_TRUE;
+ start_gssrequest(&restart_master);
+ goto done;
+ }
+
+ if (rcvmsg->rcode != dns_rcode_noerror &&
+ rcvmsg->rcode != dns_rcode_nxdomain)
+ fatal("response to GSS-TSIG query was unsuccessful");
+
+
+ dns_fixedname_init(&fname);
+ servname = dns_fixedname_name(&fname);
+ isc_buffer_init(&buf, servicename, strlen(servicename));
+ isc_buffer_add(&buf, strlen(servicename));
+ result = dns_name_fromtext(servname, &buf, dns_rootname,
+ ISC_FALSE, NULL);
+ check_result(result, "dns_name_fromtext");
+
+ tsigkey = NULL;
+ result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
+ &context, &tsigkey, gssring,
+ use_win2k_gsstsig);
+ switch (result) {
+
+ case DNS_R_CONTINUE:
+ send_gssrequest(localaddr, kserver, tsigquery, &request,
+ context);
+ break;
+
+ case ISC_R_SUCCESS:
+ /*
+ * XXXSRA Waaay too much fun here. There's no good
+ * reason why we need a TSIG here (the people who put
+ * it into the spec admitted at the time that it was
+ * not a security issue), and Windows clients don't
+ * seem to work if named complies with the spec and
+ * includes the gratuitous TSIG. So we're in the
+ * bizzare situation of having to choose between
+ * complying with a useless requirement in the spec
+ * and interoperating. This is nuts. If we can
+ * confirm this behavior, we should ask the WG to
+ * consider removing the requirement for the
+ * gratuitous TSIG here. For the moment, we ignore
+ * the TSIG -- this too is a spec violation, but it's
+ * the least insane thing to do.
+ */
+#if 0
+ /*
+ * Verify the signature.
+ */
+ rcvmsg->state = DNS_SECTION_ANY;
+ dns_message_setquerytsig(rcvmsg, NULL);
+ result = dns_message_settsigkey(rcvmsg, tsigkey);
+ check_result(result, "dns_message_settsigkey");
+ result = dns_message_checksig(rcvmsg, NULL);
+ ddebug("tsig verification: %s", dns_result_totext(result));
+ check_result(result, "dns_message_checksig");
+#endif /* 0 */
+
+ send_update(&tmpzonename, serveraddr, localaddr);
+ setzoneclass(dns_rdataclass_none);
+ break;
+
+ default:
+ fatal("dns_tkey_negotiategss: %s", isc_result_totext(result));
+ }
+
+ done:
+ dns_request_destroy(&request);
+ dns_message_destroy(&tsigquery);
+
+ dns_message_destroy(&rcvmsg);
+ ddebug("Out of recvgss");
+}
+#endif
+
+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;
+ dns_section_t section = DNS_SECTION_UPDATE;
+
+ ddebug("start_update()");
+
+ if (answer != NULL)
+ dns_message_destroy(&answer);
+
+ if (userzone != NULL && userserver != NULL && ! usegsstsig) {
+ send_update(userzone, userserver, localaddr);
+ setzoneclass(dns_rdataclass_none);
+ return;
+ }
+
+ result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
+ &soaquery);
+ check_result(result, "dns_message_create");
+
+ if (userserver == NULL)
+ 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, getzoneclass(), dns_rdatatype_soa);
+
+ if (userzone != NULL) {
+ dns_name_init(name, NULL);
+ dns_name_clone(userzone, name);
+ } else {
+ result = dns_message_firstname(updatemsg, section);
+ if (result == ISC_R_NOMORE) {
+ section = DNS_SECTION_PREREQUISITE;
+ result = dns_message_firstname(updatemsg, section);
+ }
+ if (result != ISC_R_SUCCESS) {
+ dns_message_puttempname(soaquery, &name);
+ dns_rdataset_disassociate(rdataset);
+ dns_message_puttemprdataset(soaquery, &rdataset);
+ dns_message_destroy(&soaquery);
+ done_update();
+ return;
+ }
+ firstname = NULL;
+ dns_message_currentname(updatemsg, section, &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()");
+
+ if (answer != NULL)
+ dns_message_destroy(&answer);
+
+#ifdef GSSAPI
+ if (tsigkey != NULL) {
+ ddebug("detach tsigkey x%p", tsigkey);
+ dns_tsigkey_detach(&tsigkey);
+ }
+ if (gssring != NULL) {
+ ddebug("Destroying GSS-TSIG keyring");
+ dns_tsigkeyring_destroy(&gssring);
+ }
+ if (kserver != NULL) {
+ isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
+ kserver = NULL;
+ }
+#endif
+
+ 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 hash context");
+ isc_hash_destroy();
+
+ ddebug("Destroying name state");
+ dns_name_destroy();
+
+ ddebug("Removing log context");
+ isc_log_destroy(&lctx);
+
+ 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;
+
+ interactive = ISC_TF(isatty(0));
+
+ isc_app_start();
+
+ pre_parse_args(argc, argv);
+
+ result = isc_mem_create(0, 0, &mctx);
+ check_result(result, "isc_mem_create");
+
+ parse_args(argc, argv, mctx, &entropy);
+
+ 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/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook
new file mode 100644
index 0000000..9787758
--- /dev/null
+++ b/bin/nsupdate/nsupdate.docbook
@@ -0,0 +1,701 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+ [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000-2003 Internet Software Consortium.
+ -
+ - Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id: nsupdate.docbook,v 1.34 2008/09/25 02:20:27 marka Exp $ -->
+<refentry id="man.nsupdate">
+ <refentryinfo>
+ <date>Jun 30, 2000</date>
+ </refentryinfo>
+ <refmeta>
+ <refentrytitle><application>nsupdate</application></refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>BIND9</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname><application>nsupdate</application></refname>
+ <refpurpose>Dynamic DNS update utility</refpurpose>
+ </refnamediv>
+
+ <docinfo>
+ <copyright>
+ <year>2004</year>
+ <year>2005</year>
+ <year>2006</year>
+ <year>2007</year>
+ <year>2008</year>
+ <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+ </copyright>
+ <copyright>
+ <year>2000</year>
+ <year>2001</year>
+ <year>2002</year>
+ <year>2003</year>
+ <holder>Internet Software Consortium.</holder>
+ </copyright>
+ </docinfo>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>nsupdate</command>
+ <arg><option>-d</option></arg>
+ <arg><option>-D</option></arg>
+ <group>
+ <arg><option>-y <replaceable class="parameter"><optional>hmac:</optional>keyname:secret</replaceable></option></arg>
+ <arg><option>-k <replaceable class="parameter">keyfile</replaceable></option></arg>
+ </group>
+ <arg><option>-t <replaceable class="parameter">timeout</replaceable></option></arg>
+ <arg><option>-u <replaceable class="parameter">udptimeout</replaceable></option></arg>
+ <arg><option>-r <replaceable class="parameter">udpretries</replaceable></option></arg>
+ <arg><option>-R <replaceable class="parameter">randomdev</replaceable></option></arg>
+ <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>
+ The <option>-D</option> option makes <command>nsupdate</command>
+ report additional debugging information to <option>-d</option>.
+ </para>
+ <para>
+ Transaction signatures can be used to authenticate the Dynamic DNS
+ updates.
+ These use the TSIG resource record type described in RFC2845 or the
+ SIG(0) record described in RFC3535 and RFC2931.
+ TSIG relies 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.
+ SIG(0) uses public key cryptography. To use a SIG(0) key, the public
+ key must be stored in a KEY record in a zone served by the name server.
+ <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, default type
+ HMAC-MD5. 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
+ <optional><parameter>hmac:</parameter></optional><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>
+ The <option>-k</option> may also be used to specify a SIG(0) key used
+ to authenticate Dynamic DNS update requests. In this case, the key
+ specified is not an HMAC-MD5 key.
+ </para>
+ <para>
+ By default
+ <command>nsupdate</command>
+ uses UDP to send update requests to the name server unless they are too
+ large to fit in a UDP request in which case TCP will be used.
+ 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>
+ <para>
+ The <option>-t</option> option sets the maximum time an update request
+ can
+ take before it is aborted. The default is 300 seconds. Zero can be
+ used
+ to disable the timeout.
+ </para>
+ <para>
+ The <option>-u</option> option sets the UDP retry interval. The default
+ is
+ 3 seconds. If zero, the interval will be computed from the timeout
+ interval
+ and number of UDP retries.
+ </para>
+ <para>
+ The <option>-r</option> option sets the number of UDP retries. The
+ default is
+ 3. If zero, only one update request will be made.
+ </para>
+ <para>
+ The <option>-R <replaceable
+ class="parameter">randomdev</replaceable></option> option
+ specifies a source of randomness. If the operating system
+ does not provide a <filename>/dev/random</filename> or
+ equivalent device, the default source of randomness is keyboard
+ input. <filename>randomdev</filename> specifies the name of
+ a character device or file containing random data to be used
+ instead of the default. The special value
+ <filename>keyboard</filename> indicates that keyboard input
+ should be used. This option may be specified multiple times.
+ </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>
+ <command>server</command>
+ <arg choice="req">servername</arg>
+ <arg choice="opt">port</arg>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>local</command>
+ <arg choice="req">address</arg>
+ <arg choice="opt">port</arg>
+ </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 chosen 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>zone</command>
+ <arg choice="req">zonename</arg>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>class</command>
+ <arg choice="req">classname</arg>
+ </term>
+ <listitem>
+ <para>
+ Specify the default class.
+ If no <parameter>class</parameter> is specified, the
+ default class is
+ <parameter>IN</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>ttl</command>
+ <arg choice="req">seconds</arg>
+ </term>
+ <listitem>
+ <para>
+ Specify the default time to live for records to be added.
+ The value <parameter>none</parameter> will clear the default
+ ttl.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>key</command>
+ <arg choice="req">name</arg>
+ <arg choice="req">secret</arg>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>prereq nxdomain</command>
+ <arg choice="req">domain-name</arg>
+ </term>
+ <listitem>
+ <para>
+ Requires that no resource record of any type exists with name
+ <parameter>domain-name</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>
+ <command>prereq yxdomain</command>
+ <arg choice="req">domain-name</arg>
+ </term>
+ <listitem>
+ <para>
+ Requires that
+ <parameter>domain-name</parameter>
+ exists (has as at least one resource record, of any type).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>prereq nxrrset</command>
+ <arg choice="req">domain-name</arg>
+ <arg choice="opt">class</arg>
+ <arg choice="req">type</arg>
+ </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.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>
+ <command>prereq yxrrset</command>
+ <arg choice="req">domain-name</arg>
+ <arg choice="opt">class</arg>
+ <arg choice="req">type</arg>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <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>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <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>
+ </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>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <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>
+ </term>
+ <listitem>
+ <para>
+ Adds a new resource record with the specified
+ <parameter>ttl</parameter>,
+ <parameter>class</parameter>
+ and
+ <parameter>data</parameter>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>show</command>
+ </term>
+ <listitem>
+ <para>
+ Displays the current message, containing all of the
+ prerequisites and
+ updates specified since the last send.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>send</command>
+ </term>
+ <listitem>
+ <para>
+ Sends the current message. This is equivalent to entering a
+ blank line.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>answer</command>
+ </term>
+ <listitem>
+ <para>
+ Displays the answer.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <command>debug</command>
+ </term>
+ <listitem>
+ <para>
+ Turn on debugging.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+
+ <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
+&gt; update delete oldhost.example.com A
+&gt; update add newhost.example.com 86400 A 172.16.1.1
+&gt; send
+</programlisting>
+ </para>
+ <para>
+ Any A records for
+ <type>oldhost.example.com</type>
+ are deleted.
+ And an A record for
+ <type>newhost.example.com</type>
+ with IP address 172.16.1.1 is added.
+ The newly-added record has a 1 day TTL (86400 seconds).
+ <programlisting>
+# nsupdate
+&gt; prereq nxdomain nickname.example.com
+&gt; update add nickname.example.com 86400 CNAME somehost.example.com
+&gt; send
+</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
+ RRSIG, DNSKEY and NSEC 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>
+
+ <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>
+
+ <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>
+ </varlistentry>
+
+ </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>RFC2931</refentrytitle>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>named</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry>
+ <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>.
+ </para>
+
+ </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><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->
diff --git a/bin/nsupdate/nsupdate.html b/bin/nsupdate/nsupdate.html
new file mode 100644
index 0000000..9d29806
--- /dev/null
+++ b/bin/nsupdate/nsupdate.html
@@ -0,0 +1,530 @@
+<!--
+ - Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2000-2003 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 ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+<!-- $Id: nsupdate.html,v 1.40 2008/09/25 04:45:04 tbox Exp $ -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>nsupdate</title>
+<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+<a name="man.nsupdate"></a><div class="titlepage"></div>
+<div class="refnamediv">
+<h2>Name</h2>
+<p><span class="application">nsupdate</span> &#8212; Dynamic DNS update utility</p>
+</div>
+<div class="refsynopsisdiv">
+<h2>Synopsis</h2>
+<div class="cmdsynopsis"><p><code class="command">nsupdate</code> [<code class="option">-d</code>] [<code class="option">-D</code>] [[<code class="option">-y <em class="replaceable"><code>[<span class="optional">hmac:</span>]keyname:secret</code></em></code>] | [<code class="option">-k <em class="replaceable"><code>keyfile</code></em></code>]] [<code class="option">-t <em class="replaceable"><code>timeout</code></em></code>] [<code class="option">-u <em class="replaceable"><code>udptimeout</code></em></code>] [<code class="option">-r <em class="replaceable"><code>udpretries</code></em></code>] [<code class="option">-R <em class="replaceable"><code>randomdev</code></em></code>] [<code class="option">-v</code>] [filename]</p></div>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543437"></a><h2>DESCRIPTION</h2>
+<p><span><strong class="command">nsupdate</strong></span>
+ 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
+ <span><strong class="command">nsupdate</strong></span>
+ 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
+ <span><strong class="command">nsupdate</strong></span>
+ 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
+ <code class="option">-d</code>
+ option makes
+ <span><strong class="command">nsupdate</strong></span>
+ 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>
+ The <code class="option">-D</code> option makes <span><strong class="command">nsupdate</strong></span>
+ report additional debugging information to <code class="option">-d</code>.
+ </p>
+<p>
+ Transaction signatures can be used to authenticate the Dynamic DNS
+ updates.
+ These use the TSIG resource record type described in RFC2845 or the
+ SIG(0) record described in RFC3535 and RFC2931.
+ TSIG relies on a shared secret that should only be known to
+ <span><strong class="command">nsupdate</strong></span> 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
+ <code class="filename">/etc/named.conf</code>
+ 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.
+ SIG(0) uses public key cryptography. To use a SIG(0) key, the public
+ key must be stored in a KEY record in a zone served by the name server.
+ <span><strong class="command">nsupdate</strong></span>
+ does not read
+ <code class="filename">/etc/named.conf</code>.
+ </p>
+<p><span><strong class="command">nsupdate</strong></span>
+ uses the <code class="option">-y</code> or <code class="option">-k</code> option
+ to provide the shared secret needed to generate a TSIG record
+ for authenticating Dynamic DNS update requests, default type
+ HMAC-MD5. These options are mutually exclusive. With the
+ <code class="option">-k</code> option, <span><strong class="command">nsupdate</strong></span> reads
+ the shared secret from the file <em class="parameter"><code>keyfile</code></em>,
+ whose name is of the form
+ <code class="filename">K{name}.+157.+{random}.private</code>. For
+ historical reasons, the file
+ <code class="filename">K{name}.+157.+{random}.key</code> must also be
+ present. When the <code class="option">-y</code> option is used, a
+ signature is generated from
+ [<span class="optional"><em class="parameter"><code>hmac:</code></em></span>]<em class="parameter"><code>keyname:secret.</code></em>
+ <em class="parameter"><code>keyname</code></em> is the name of the key, and
+ <em class="parameter"><code>secret</code></em> is the base64 encoded shared
+ secret. Use of the <code class="option">-y</code> 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>
+ The <code class="option">-k</code> may also be used to specify a SIG(0) key used
+ to authenticate Dynamic DNS update requests. In this case, the key
+ specified is not an HMAC-MD5 key.
+ </p>
+<p>
+ By default
+ <span><strong class="command">nsupdate</strong></span>
+ uses UDP to send update requests to the name server unless they are too
+ large to fit in a UDP request in which case TCP will be used.
+ The
+ <code class="option">-v</code>
+ option makes
+ <span><strong class="command">nsupdate</strong></span>
+ use a TCP connection.
+ This may be preferable when a batch of update requests is made.
+ </p>
+<p>
+ The <code class="option">-t</code> option sets the maximum time an update request
+ can
+ take before it is aborted. The default is 300 seconds. Zero can be
+ used
+ to disable the timeout.
+ </p>
+<p>
+ The <code class="option">-u</code> option sets the UDP retry interval. The default
+ is
+ 3 seconds. If zero, the interval will be computed from the timeout
+ interval
+ and number of UDP retries.
+ </p>
+<p>
+ The <code class="option">-r</code> option sets the number of UDP retries. The
+ default is
+ 3. If zero, only one update request will be made.
+ </p>
+<p>
+ The <code class="option">-R <em class="replaceable"><code>randomdev</code></em></code> option
+ specifies a source of randomness. If the operating system
+ does not provide a <code class="filename">/dev/random</code> or
+ equivalent device, the default source of randomness is keyboard
+ input. <code class="filename">randomdev</code> specifies the name of
+ a character device or file containing random data to be used
+ instead of the default. The special value
+ <code class="filename">keyboard</code> indicates that keyboard input
+ should be used. This option may be specified multiple times.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2543700"></a><h2>INPUT FORMAT</h2>
+<p><span><strong class="command">nsupdate</strong></span>
+ reads input from
+ <em class="parameter"><code>filename</code></em>
+ 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 <span><strong class="command">send</strong></span> 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>
+<div class="variablelist"><dl>
+<dt><span class="term">
+ <span><strong class="command">server</strong></span>
+ {servername}
+ [port]
+ </span></dt>
+<dd><p>
+ Sends all dynamic update requests to the name server
+ <em class="parameter"><code>servername</code></em>.
+ When no server statement is provided,
+ <span><strong class="command">nsupdate</strong></span>
+ 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.
+ <em class="parameter"><code>port</code></em>
+ is the port number on
+ <em class="parameter"><code>servername</code></em>
+ 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><span class="term">
+ <span><strong class="command">local</strong></span>
+ {address}
+ [port]
+ </span></dt>
+<dd><p>
+ Sends all dynamic update requests using the local
+ <em class="parameter"><code>address</code></em>.
+
+ When no local statement is provided,
+ <span><strong class="command">nsupdate</strong></span>
+ will send updates using an address and port chosen by the
+ system.
+ <em class="parameter"><code>port</code></em>
+ 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><span class="term">
+ <span><strong class="command">zone</strong></span>
+ {zonename}
+ </span></dt>
+<dd><p>
+ Specifies that all updates are to be made to the zone
+ <em class="parameter"><code>zonename</code></em>.
+ If no
+ <em class="parameter"><code>zone</code></em>
+ statement is provided,
+ <span><strong class="command">nsupdate</strong></span>
+ will attempt determine the correct zone to update based on the
+ rest of the input.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">class</strong></span>
+ {classname}
+ </span></dt>
+<dd><p>
+ Specify the default class.
+ If no <em class="parameter"><code>class</code></em> is specified, the
+ default class is
+ <em class="parameter"><code>IN</code></em>.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">ttl</strong></span>
+ {seconds}
+ </span></dt>
+<dd><p>
+ Specify the default time to live for records to be added.
+ The value <em class="parameter"><code>none</code></em> will clear the default
+ ttl.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">key</strong></span>
+ {name}
+ {secret}
+ </span></dt>
+<dd><p>
+ Specifies that all updates are to be TSIG-signed using the
+ <em class="parameter"><code>keyname</code></em> <em class="parameter"><code>keysecret</code></em> pair.
+ The <span><strong class="command">key</strong></span> command
+ overrides any key specified on the command line via
+ <code class="option">-y</code> or <code class="option">-k</code>.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">prereq nxdomain</strong></span>
+ {domain-name}
+ </span></dt>
+<dd><p>
+ Requires that no resource record of any type exists with name
+ <em class="parameter"><code>domain-name</code></em>.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">prereq yxdomain</strong></span>
+ {domain-name}
+ </span></dt>
+<dd><p>
+ Requires that
+ <em class="parameter"><code>domain-name</code></em>
+ exists (has as at least one resource record, of any type).
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">prereq nxrrset</strong></span>
+ {domain-name}
+ [class]
+ {type}
+ </span></dt>
+<dd><p>
+ Requires that no resource record exists of the specified
+ <em class="parameter"><code>type</code></em>,
+ <em class="parameter"><code>class</code></em>
+ and
+ <em class="parameter"><code>domain-name</code></em>.
+ If
+ <em class="parameter"><code>class</code></em>
+ is omitted, IN (internet) is assumed.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">prereq yxrrset</strong></span>
+ {domain-name}
+ [class]
+ {type}
+ </span></dt>
+<dd><p>
+ This requires that a resource record of the specified
+ <em class="parameter"><code>type</code></em>,
+ <em class="parameter"><code>class</code></em>
+ and
+ <em class="parameter"><code>domain-name</code></em>
+ must exist.
+ If
+ <em class="parameter"><code>class</code></em>
+ is omitted, IN (internet) is assumed.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">prereq yxrrset</strong></span>
+ {domain-name}
+ [class]
+ {type}
+ {data...}
+ </span></dt>
+<dd><p>
+ The
+ <em class="parameter"><code>data</code></em>
+ from each set of prerequisites of this form
+ sharing a common
+ <em class="parameter"><code>type</code></em>,
+ <em class="parameter"><code>class</code></em>,
+ and
+ <em class="parameter"><code>domain-name</code></em>
+ 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
+ <em class="parameter"><code>type</code></em>,
+ <em class="parameter"><code>class</code></em>,
+ and
+ <em class="parameter"><code>domain-name</code></em>.
+ The
+ <em class="parameter"><code>data</code></em>
+ are written in the standard text representation of the resource
+ record's
+ RDATA.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">update delete</strong></span>
+ {domain-name}
+ [ttl]
+ [class]
+ [type [data...]]
+ </span></dt>
+<dd><p>
+ Deletes any resource records named
+ <em class="parameter"><code>domain-name</code></em>.
+ If
+ <em class="parameter"><code>type</code></em>
+ and
+ <em class="parameter"><code>data</code></em>
+ is provided, only matching resource records will be removed.
+ The internet class is assumed if
+ <em class="parameter"><code>class</code></em>
+ is not supplied. The
+ <em class="parameter"><code>ttl</code></em>
+ is ignored, and is only allowed for compatibility.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">update add</strong></span>
+ {domain-name}
+ {ttl}
+ [class]
+ {type}
+ {data...}
+ </span></dt>
+<dd><p>
+ Adds a new resource record with the specified
+ <em class="parameter"><code>ttl</code></em>,
+ <em class="parameter"><code>class</code></em>
+ and
+ <em class="parameter"><code>data</code></em>.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">show</strong></span>
+ </span></dt>
+<dd><p>
+ Displays the current message, containing all of the
+ prerequisites and
+ updates specified since the last send.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">send</strong></span>
+ </span></dt>
+<dd><p>
+ Sends the current message. This is equivalent to entering a
+ blank line.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">answer</strong></span>
+ </span></dt>
+<dd><p>
+ Displays the answer.
+ </p></dd>
+<dt><span class="term">
+ <span><strong class="command">debug</strong></span>
+ </span></dt>
+<dd><p>
+ Turn on debugging.
+ </p></dd>
+</dl></div>
+<p>
+ </p>
+<p>
+ Lines beginning with a semicolon are comments and are ignored.
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2544540"></a><h2>EXAMPLES</h2>
+<p>
+ The examples below show how
+ <span><strong class="command">nsupdate</strong></span>
+ 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>.
+
+ </p>
+<pre class="programlisting">
+# nsupdate
+&gt; update delete oldhost.example.com A
+&gt; update add newhost.example.com 86400 A 172.16.1.1
+&gt; send
+</pre>
+<p>
+ </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>
+ with IP address 172.16.1.1 is added.
+ The newly-added record has a 1 day TTL (86400 seconds).
+ </p>
+<pre class="programlisting">
+# nsupdate
+&gt; prereq nxdomain nickname.example.com
+&gt; update add nickname.example.com 86400 CNAME somehost.example.com
+&gt; send
+</pre>
+<p>
+ </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
+ RRSIG, DNSKEY and NSEC records.)
+ </p>
+</div>
+<div class="refsect1" lang="en">
+<a name="id2544584"></a><h2>FILES</h2>
+<div class="variablelist"><dl>
+<dt><span class="term"><code class="constant">/etc/resolv.conf</code></span></dt>
+<dd><p>
+ used to identify default name server
+ </p></dd>
+<dt><span class="term"><code class="constant">K{name}.+157.+{random}.key</code></span></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><span class="term"><code class="constant">K{name}.+157.+{random}.private</code></span></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" lang="en">
+<a name="id2542128"></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">RFC2931</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" lang="en">
+<a name="id2544929"></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>
+</div></body>
+</html>
diff --git a/bin/nsupdate/win32/nsupdate.dsp b/bin/nsupdate/win32/nsupdate.dsp
new file mode 100644
index 0000000..028ed55
--- /dev/null
+++ b/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 /MD /W3 /GX /O2 /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/bind9/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 ../../../lib/bind9/win32/Release/libbind9.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 /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/bind9/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 ../../../lib/bind9/win32/Debug/libbind9.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/bin/nsupdate/win32/nsupdate.dsw b/bin/nsupdate/win32/nsupdate.dsw
new file mode 100644
index 0000000..5f0ac36
--- /dev/null
+++ b/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/bin/nsupdate/win32/nsupdate.mak b/bin/nsupdate/win32/nsupdate.mak
new file mode 100644
index 0000000..1e41c29
--- /dev/null
+++ b/bin/nsupdate/win32/nsupdate.mak
@@ -0,0 +1,373 @@
+# 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
+
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "nsupdate - Win32 Release"
+_VC_MANIFEST_INC=0
+_VC_MANIFEST_BASENAME=__VC80
+!ELSE
+_VC_MANIFEST_INC=1
+_VC_MANIFEST_BASENAME=__VC80.Debug
+!ENDIF
+
+####################################################
+# Specifying name of temporary resource file used only in incremental builds:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res
+!else
+_VC_MANIFEST_AUTO_RES=
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1
+
+!endif
+
+####################################################
+# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+#MT_SPECIAL_RETURN=1090650113
+#MT_SPECIAL_SWITCH=-notify_resource_update
+MT_SPECIAL_RETURN=0
+MT_SPECIAL_SWITCH=
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \
+if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \
+rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \
+link $** /out:$@ $(LFLAGS)
+
+!else
+
+_VC_MANIFEST_EMBED_EXE= \
+if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2
+
+!endif
+####################################################
+# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily:
+
+!if "$(_VC_MANIFEST_INC)" == "1"
+
+_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \
+ $(_VC_MANIFEST_BASENAME).auto.rc \
+ $(_VC_MANIFEST_BASENAME).auto.manifest
+
+!else
+
+_VC_MANIFEST_CLEAN=
+
+!endif
+
+!IF "$(CFG)" == "nsupdate - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Release\nsupdate.exe"
+
+!ELSE
+
+ALL : "libbind9 - Win32 Release" "libisc - Win32 Release" "libdns - Win32 Release" "..\..\..\Build\Release\nsupdate.exe"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libdns - Win32 ReleaseCLEAN" "libisc - Win32 ReleaseCLEAN" "libbind9 - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\nsupdate.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "..\..\..\Build\Release\nsupdate.exe"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/bind9/include" /D "WIN32" /D "__STDC__" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\nsupdate.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+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 ../../../lib/bind9/win32/Release/libbind9.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\nsupdate.pdb" /machine:I386 /out:"../../../Build/Release/nsupdate.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\nsupdate.obj" \
+ "..\..\..\lib\dns\win32\Release\libdns.lib" \
+ "..\..\..\lib\isc\win32\Release\libisc.lib" \
+ "..\..\..\lib\bind9\win32\Release\libbind9.lib"
+
+"..\..\..\Build\Release\nsupdate.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_EXE)
+
+!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\..\..\Build\Debug\nsupdate.exe" "$(OUTDIR)\nsupdate.bsc"
+
+!ELSE
+
+ALL : "libbind9 - Win32 Debug" "libisc - Win32 Debug" "libdns - Win32 Debug" "..\..\..\Build\Debug\nsupdate.exe" "$(OUTDIR)\nsupdate.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"libdns - Win32 DebugCLEAN" "libisc - Win32 DebugCLEAN" "libbind9 - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@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"
+ -@$(_VC_MANIFEST_CLEAN)
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../include" /I "../../../" /I "../../../lib/isc/win32" /I "../../../lib/isc/win32/include" /I "../../../lib/isc/include" /I "../../../lib/isc/noatomic/include" /I "../../../lib/lwres/win32/include" /I "../../../lib/lwres/include" /I "../../../lib/lwres/win32/include/lwres" /I "../../../lib/dns/include" /I "../../../lib/bind9/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"$(INTDIR)\\" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
+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 ../../../lib/bind9/win32/Debug/libbind9.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" \
+ "..\..\..\lib\dns\win32\Debug\libdns.lib" \
+ "..\..\..\lib\isc\win32\Debug\libisc.lib" \
+ "..\..\..\lib\bind9\win32\Debug\libbind9.lib"
+
+"..\..\..\Build\Debug\nsupdate.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+ $(_VC_MANIFEST_EMBED_EXE)
+
+!ENDIF
+
+.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) $<
+<<
+
+
+!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
+
+!IF "$(CFG)" == "nsupdate - Win32 Release"
+
+"libdns - Win32 Release" :
+ cd "..\..\..\lib\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - Win32 Release"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libdns - Win32 ReleaseCLEAN" :
+ cd "..\..\..\lib\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug"
+
+"libdns - Win32 Debug" :
+ cd "..\..\..\lib\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - Win32 Debug"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libdns - Win32 DebugCLEAN" :
+ cd "..\..\..\lib\dns\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libdns.mak" CFG="libdns - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ENDIF
+
+!IF "$(CFG)" == "nsupdate - Win32 Release"
+
+"libisc - Win32 Release" :
+ cd "..\..\..\lib\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - Win32 Release"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libisc - Win32 ReleaseCLEAN" :
+ cd "..\..\..\lib\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug"
+
+"libisc - Win32 Debug" :
+ cd "..\..\..\lib\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - Win32 Debug"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libisc - Win32 DebugCLEAN" :
+ cd "..\..\..\lib\isc\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libisc.mak" CFG="libisc - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ENDIF
+
+!IF "$(CFG)" == "nsupdate - Win32 Release"
+
+"libbind9 - Win32 Release" :
+ cd "..\..\..\lib\bind9\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libbind9.mak" CFG="libbind9 - Win32 Release"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libbind9 - Win32 ReleaseCLEAN" :
+ cd "..\..\..\lib\bind9\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libbind9.mak" CFG="libbind9 - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ELSEIF "$(CFG)" == "nsupdate - Win32 Debug"
+
+"libbind9 - Win32 Debug" :
+ cd "..\..\..\lib\bind9\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libbind9.mak" CFG="libbind9 - Win32 Debug"
+ cd "..\..\..\bin\nsupdate\win32"
+
+"libbind9 - Win32 DebugCLEAN" :
+ cd "..\..\..\lib\bind9\win32"
+ $(MAKE) /$(MAKEFLAGS) /F ".\libbind9.mak" CFG="libbind9 - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\..\bin\nsupdate\win32"
+
+!ENDIF
+
+
+!ENDIF
+
+####################################################
+# Commands to generate initial empty manifest file and the RC file
+# that references it, and for generating the .res file:
+
+$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc
+
+$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest
+ type <<$@
+#include <winuser.h>
+1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest"
+<< KEEP
+
+$(_VC_MANIFEST_BASENAME).auto.manifest :
+ type <<$@
+<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
+</assembly>
+<< KEEP