]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] further restrict update-policy local
authorEvan Hunt <each@isc.org>
Fri, 6 Oct 2017 22:13:27 +0000 (15:13 -0700)
committerEvan Hunt <each@isc.org>
Fri, 6 Oct 2017 22:43:31 +0000 (15:43 -0700)
4762. [func] "update-policy local" is now restricted to updates
from local addresses. (Previously, other addresses
were allowed so long as updates were signed by the
local session key.) [RT #45492]

18 files changed:
CHANGES
bin/named/main.c
bin/named/zoneconf.c
bin/tests/system/nsupdate/clean.sh
bin/tests/system/nsupdate/ns5/local.db.in [new file with mode: 0644]
bin/tests/system/nsupdate/ns5/named.args [new file with mode: 0644]
bin/tests/system/nsupdate/ns5/named.conf [new file with mode: 0644]
bin/tests/system/nsupdate/setup.sh
bin/tests/system/nsupdate/tests.sh
doc/arm/Bv9ARM-book.xml
doc/arm/notes.xml
lib/dns/include/dns/ssu.h
lib/dns/ssu.c
lib/isc/include/isc/netaddr.h
lib/isc/netaddr.c
lib/ns/include/ns/server.h
lib/ns/interfacemgr.c
lib/ns/update.c

diff --git a/CHANGES b/CHANGES
index c4da40ae3152d838824c310c6a815f86e3ce4b83..1fa182cffc027de398020f3b4872bafbafce5048 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+4762.  [func]          "update-policy local" is now restricted to updates
+                       from local addresses. (Previously, other addresses
+                       were allowed so long as updates were signed by the
+                       local session key.) [RT #45492]
+
 4761.  [protocol]      Add support for DOA. [RT #45612]
 
 4760.  [func]          Add glue cache statistics counters. [RT #46028]
index 3f6034a2aa92444e8cbf660c08280f0790014ed3..979f81b5562feef3709f70f942843a26a461783d 100644 (file)
@@ -127,6 +127,7 @@ static isc_boolean_t noaa = ISC_FALSE;
 static unsigned int delay = 0;
 static isc_boolean_t nonearest = ISC_FALSE;
 static isc_boolean_t notcp = ISC_FALSE;
+static isc_boolean_t fixedlocal = ISC_FALSE;
 
 /*
  * -4 and -6
@@ -626,14 +627,21 @@ parse_command_line(int argc, char *argv[]) {
                        } else if (!strcmp(isc_commandline_argument, "notcp"))
                                notcp = ISC_TRUE;
                        else if (!strncmp(isc_commandline_argument, "tat=", 4))
+                       {
                                named_g_tat_interval =
                                           atoi(isc_commandline_argument + 4);
-                       else if (!strcmp(isc_commandline_argument,
+                       else if (!strcmp(isc_commandline_argument,
                                         "keepstderr"))
+                       {
                                named_g_keepstderr = ISC_TRUE;
-                       else
+                       } else if (!strcmp(isc_commandline_argument,
+                                          "fixedlocal"))
+                       {
+                               fixedlocal = ISC_TRUE;
+                       } else {
                                fprintf(stderr, "unknown -T flag '%s\n",
                                        isc_commandline_argument);
+                       }
                        break;
                case 'U':
                        named_g_udpdisp = parse_int(isc_commandline_argument,
@@ -1193,6 +1201,8 @@ setup(void) {
                ns_server_setoption(sctx, NS_SERVER_NONEAREST, ISC_TRUE);
        if (notcp)
                ns_server_setoption(sctx, NS_SERVER_NOTCP, ISC_TRUE);
+       if (fixedlocal)
+               ns_server_setoption(sctx, NS_SERVER_FIXEDLOCAL, ISC_TRUE);
        if (disable4)
                ns_server_setoption(sctx, NS_SERVER_DISABLE4, ISC_TRUE);
        if (disable6)
index 51325a4cf7f9b311050a9b3db788a9cb606b3473..610588ed9eae49203ad027b96b4d2e3b344bd439 100644 (file)
@@ -218,7 +218,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
                const char *str;
                isc_boolean_t grant = ISC_FALSE;
                isc_boolean_t usezone = ISC_FALSE;
-               unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
+               unsigned int mtype = dns_ssumatchtype_name;
                dns_fixedname_t fname, fident;
                isc_buffer_t b;
                dns_rdatatype_t *types;
@@ -234,34 +234,34 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
 
                str = cfg_obj_asstring(matchtype);
                if (strcasecmp(str, "name") == 0)
-                       mtype = DNS_SSUMATCHTYPE_NAME;
+                       mtype = dns_ssumatchtype_name;
                else if (strcasecmp(str, "subdomain") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
+                       mtype = dns_ssumatchtype_subdomain;
                else if (strcasecmp(str, "wildcard") == 0)
-                       mtype = DNS_SSUMATCHTYPE_WILDCARD;
+                       mtype = dns_ssumatchtype_wildcard;
                else if (strcasecmp(str, "self") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SELF;
+                       mtype = dns_ssumatchtype_self;
                else if (strcasecmp(str, "selfsub") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SELFSUB;
+                       mtype = dns_ssumatchtype_selfsub;
                else if (strcasecmp(str, "selfwild") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SELFWILD;
+                       mtype = dns_ssumatchtype_selfwild;
                else if (strcasecmp(str, "ms-self") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SELFMS;
+                       mtype = dns_ssumatchtype_selfms;
                else if (strcasecmp(str, "krb5-self") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SELFKRB5;
+                       mtype = dns_ssumatchtype_selfkrb5;
                else if (strcasecmp(str, "ms-subdomain") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
+                       mtype = dns_ssumatchtype_subdomainms;
                else if (strcasecmp(str, "krb5-subdomain") == 0)
-                       mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
+                       mtype = dns_ssumatchtype_subdomainkrb5;
                else if (strcasecmp(str, "tcp-self") == 0)
-                       mtype = DNS_SSUMATCHTYPE_TCPSELF;
+                       mtype = dns_ssumatchtype_tcpself;
                else if (strcasecmp(str, "6to4-self") == 0)
-                       mtype = DNS_SSUMATCHTYPE_6TO4SELF;
+                       mtype = dns_ssumatchtype_6to4self;
                else if (strcasecmp(str, "zonesub") == 0) {
-                       mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
+                       mtype = dns_ssumatchtype_subdomain;
                        usezone = ISC_TRUE;
                } else if (strcasecmp(str, "external") == 0)
-                       mtype = DNS_SSUMATCHTYPE_EXTERNAL;
+                       mtype = dns_ssumatchtype_external;
                else
                        INSIST(0);
 
@@ -373,7 +373,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
 
                result = dns_ssutable_addrule(table, ISC_TRUE,
                                              named_g_server->session_keyname,
-                                             DNS_SSUMATCHTYPE_SUBDOMAIN,
+                                             dns_ssumatchtype_local,
                                              dns_zone_getorigin(zone),
                                              1, &any);
 
index 5d90b312d61f0e13dbc3a3d63d52d8290979844a..71721ec469dd6ba70d7983b71fcf9a3313c394af 100644 (file)
 #
 
 rm -f */named.memstats
-rm -f */named.run
+rm -f */named.run */ans.run
 rm -f Kxxx.*
 rm -f dig.out.*
 rm -f jp.out.ns3.*
 rm -f ns*/named.lock
-rm -f ns1/*.jnl ns2/*.jnl ns3/*.jnl
+rm -f */*.jnl
 rm -f ns1/example.db ns1/unixtime.db ns1/yyyymmddvv.db ns1/update.db ns1/other.db ns1/keytests.db
 rm -f ns1/many.test.db
 rm -f ns1/maxjournal.db
@@ -33,6 +33,7 @@ rm -f ns3/example.db
 rm -f ns3/many.test.bk
 rm -f ns3/nsec3param.test.db
 rm -f ns3/too-big.test.db
+rm -f ns5/local.db
 rm -f nsupdate.out*
 rm -f typelist.out.*
 rm -f ns1/sample.db
diff --git a/bin/tests/system/nsupdate/ns5/local.db.in b/bin/tests/system/nsupdate/ns5/local.db.in
new file mode 100644 (file)
index 0000000..707d1be
--- /dev/null
@@ -0,0 +1,20 @@
+; Copyright (C) 2017  Internet Systems Consortium, Inc. ("ISC")
+;
+; This Source Code Form is subject to the terms of the Mozilla Public
+; License, v. 2.0. If a copy of the MPL was not distributed with this
+; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+$ORIGIN .
+$TTL 300       ; 5 minutes
+local.nil              IN SOA  ns5.local.nil. hostmaster.local.nil. (
+                               1          ; serial
+                               2000       ; refresh (2000 seconds)
+                               2000       ; retry (2000 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+local.nil.             NS      ns5.local.nil.
+ns5.local.nil.         A       10.53.0.5
+
+$ORIGIN local.nil.
+a                      A       10.10.10.10
diff --git a/bin/tests/system/nsupdate/ns5/named.args b/bin/tests/system/nsupdate/ns5/named.args
new file mode 100644 (file)
index 0000000..5d520de
--- /dev/null
@@ -0,0 +1 @@
+-m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -U 4 -T fixedlocal
diff --git a/bin/tests/system/nsupdate/ns5/named.conf b/bin/tests/system/nsupdate/ns5/named.conf
new file mode 100644 (file)
index 0000000..3632c7c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+controls { /* empty */ };
+
+options {
+       query-source address 10.53.0.5;
+       notify-source 10.53.0.5;
+       transfer-source 10.53.0.5;
+       port 5300;
+       pid-file "named.pid";
+       session-keyfile "session.key";
+       listen-on { 10.53.0.5; };
+       recursion no;
+       notify yes;
+       minimal-responses no;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm hmac-sha256;
+};
+
+controls {
+       inet 10.53.0.5 port 9953 allow { any; } keys { rndc_key; };
+};
+
+zone "local.nil" {
+       type master;
+       file "local.db";
+       update-policy local;
+};
index 872d26200abd67d44b5af0c5b855450f9426d969..1e12a1ca5fadaab23b3868cea4ea15411d1de129 100644 (file)
@@ -64,3 +64,5 @@ cp ns2/sample.db.in ns2/sample.db
 
 cp -f ns1/maxjournal.db.in ns1/maxjournal.db
 rm -f ns1/maxjournal.db.jnl
+
+cp -f ns5/local.db.in ns5/local.db
index 707ffe156ebe3519a74f1ef7c0f7e8b4001724ca..30b8b7c29f2fba446273cf6bf082430be03ec531 100755 (executable)
@@ -464,6 +464,44 @@ then
 echo "I:failed"; status=1
 fi
 
+n=`expr $n + 1`
+ret=0
+echo "I:check that 'update-policy local' works from localhost address ($n)"
+$NSUPDATE -p 5300 -k ns5/session.key > nsupdate.out.$n 2>&1 << END || ret=1
+server 10.53.0.5 5300
+local 127.0.0.1 5300
+update add fromlocal.local.nil. 600 A 1.2.3.4
+send
+END
+grep REFUSED nsupdate.out.$n > /dev/null 2>&1 && ret=1
+$DIG @10.53.0.5 -p 5300 \
+        +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd \
+        fromlocal.local.nil. > dig.out.ns5.$n || ret=1
+grep fromlocal dig.out.ns5.$n > /dev/null 2>&1 || ret=1
+if test $ret -ne 0
+then
+echo "I:failed"; status=1
+fi
+
+n=`expr $n + 1`
+ret=0
+echo "I:check that 'update-policy local' fails from non-localhost address ($n)"
+$NSUPDATE -p 5300 -k ns5/session.key > nsupdate.out.$n 2>&1 << END && ret=1
+server 10.53.0.5 5300
+local 10.53.0.1 5300
+update add nonlocal.local.nil. 600 A 4.3.2.1
+send
+END
+grep REFUSED nsupdate.out.$n > /dev/null 2>&1 || ret=1
+$DIG @10.53.0.5 -p 5300 \
+        +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd \
+        nonlocal.local.nil. > dig.out.ns5.$n || ret=1
+grep nonlocal dig.out.ns5.$n > /dev/null 2>&1 && ret=1
+if test $ret -ne 0
+then
+echo "I:failed"; status=1
+fi
+
 n=`expr $n + 1`
 ret=0
 echo "I:check that changes to the DNSKEY RRset TTL do not have side effects ($n)"
index 455266e78582f5c905c188d08af8f0aa04829f6f..f2ed4a08a32167dec7fd3a4aefc72c39c0fbe415 100644 (file)
@@ -13016,38 +13016,52 @@ example.com. NS ns2.example.net.
              is present, it is a configuration error for the
              <command>allow-update</command> statement to be
              present.  The <command>update-policy</command> statement
-             only examines the signer of a message; the source
+             (except when set to <literal>local</literal>) only
+             examines the signer of a message; the source
              address is not relevant.
            </para>
            <para>
-             There is a pre-defined <command>update-policy</command>
-             rule which can be switched on with the command
+             A pre-defined <command>update-policy</command> rule can be
+             switched on with the command
              <command>update-policy local;</command>.
              Switching on this rule in a zone causes
-             <command>named</command> to generate a TSIG session
-             key and place it in a file, and to allow that key
-             to update the zone.  (By default, the file is
-             <filename>/var/run/named/session.key</filename>, the key
-             name is "local-ddns" and the key algorithm is HMAC-SHA256,
-             but these values are configurable with the
+             <command>named</command> to generate a TSIG session key and
+             place it in a file. That key will then be allowed to update
+             the zone, if the update request is sent from localhost.
+             By default, the session key is stored in the file
+             <filename>/var/run/named/session.key</filename>; the key name
+             is "local-ddns" and the key algorithm is HMAC-SHA256.
+             These values are configurable with the
              <command>session-keyfile</command>,
              <command>session-keyname</command> and
              <command>session-keyalg</command> options, respectively).
            </para>
            <para>
-             A client running on the local system, and with appropriate
-             permissions, may read that file and use the key to sign update
-             requests.  The zone's update policy will be set to allow that
-             key to change any record within the zone.  Assuming the
-             key name is "local-ddns", this policy is equivalent to:
+             A client on the local system, if it is run with appropriate
+             permissions, may read the session key from the key file and
+             use the key to sign update requests.  The zone's update
+             policy will be set to allow that key to change any record
+             within the zone.  Assuming the key name is "local-ddns",
+             this policy is:
            </para>
 
            <programlisting>update-policy { grant local-ddns zonesub any; };
            </programlisting>
 
            <para>
-             The command <command>nsupdate -l</command> sends update
-             requests to localhost, and signs them using the session key.
+             ...with an additional restriction that only clients
+             connecting from the local system will be permitted to send
+             updates.
+           </para>
+           <para>
+             Note that only one session key is generated; all zones
+             configured to use <command>update-policy local</command>
+             will accept the same key.
+           </para>
+           <para>
+             The command <command>nsupdate -l</command> implements this
+             feature, sending requests to localhost and signing them using
+             the key retrieved from the session key file.
            </para>
 
            <para>
index 359881e9dca163537ccc746d653986d7136afd9e..d6f31ac27f1d43f230987247345ee7046b1cbc4c 100644 (file)
          anchor is now a fatal configuration error. [RT #46155]
        </para>
       </listitem>
+      <listitem>
+       <para>
+         Previously, <command>update-policy local;</command> accepted
+         updates from any source so long as they were signed by the
+         locally-generated session key. This has been further restricted;
+         updates are now only accepted from locally configured addresses.
+         [RT #45492]
+       </para>
+      </listitem>
       <listitem>
        <para>
          The lightweight resolver daemon and library (<command>lwresd</command>
index eda7ff8436a43162e26f8e1ac5da2c97e7e2df61..1b4510b050e39d5c1a3b980758ee92730bd01e53 100644 (file)
@@ -6,8 +6,6 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-/* $Id: ssu.h,v 1.28 2011/01/06 23:47:00 tbox Exp $ */
-
 #ifndef DNS_SSU_H
 #define DNS_SSU_H 1
 
 
 #include <isc/lang.h>
 
+#include <dns/acl.h>
 #include <dns/types.h>
 #include <dst/dst.h>
 
 ISC_LANG_BEGINDECLS
 
-#define DNS_SSUMATCHTYPE_NAME          0
-#define DNS_SSUMATCHTYPE_SUBDOMAIN     1
-#define DNS_SSUMATCHTYPE_WILDCARD      2
-#define DNS_SSUMATCHTYPE_SELF          3
-#define DNS_SSUMATCHTYPE_SELFSUB       4
-#define DNS_SSUMATCHTYPE_SELFWILD      5
-#define DNS_SSUMATCHTYPE_SELFKRB5      6
-#define DNS_SSUMATCHTYPE_SELFMS                7
-#define DNS_SSUMATCHTYPE_SUBDOMAINMS   8
-#define DNS_SSUMATCHTYPE_SUBDOMAINKRB5 9
-#define DNS_SSUMATCHTYPE_TCPSELF       10
-#define DNS_SSUMATCHTYPE_6TO4SELF      11
-#define DNS_SSUMATCHTYPE_EXTERNAL      12
-#define DNS_SSUMATCHTYPE_DLZ           13
-#define DNS_SSUMATCHTYPE_MAX           12  /* max value */
+typedef enum {
+       dns_ssumatchtype_name = 0,
+       dns_ssumatchtype_subdomain = 1,
+       dns_ssumatchtype_wildcard = 2,
+       dns_ssumatchtype_self    = 3,
+       dns_ssumatchtype_selfsub = 4,
+       dns_ssumatchtype_selfwild = 5,
+       dns_ssumatchtype_selfkrb5 = 6,
+       dns_ssumatchtype_selfms  = 7,
+       dns_ssumatchtype_subdomainms = 8,
+       dns_ssumatchtype_subdomainkrb5 = 9,
+       dns_ssumatchtype_tcpself = 10,
+       dns_ssumatchtype_6to4self = 11,
+       dns_ssumatchtype_external = 12,
+       dns_ssumatchtype_local = 13,
+       dns_ssumatchtype_max = 13,      /* max value */
+
+       dns_ssumatchtype_dlz = 14       /* intentionally higher than _max */
+} dns_ssumatchtype_t;
 
 isc_result_t
 dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table);
@@ -56,7 +59,7 @@ dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
                       dns_dlzdb_t *dlzdatabase);
 /*%<
  * Create an SSU table that contains a dlzdatabase pointer, and a
- * single rule with matchtype DNS_SSUMATCHTYPE_DLZ. This type of SSU
+ * single rule with matchtype dns_ssumatchtype_dlz. This type of SSU
  * table is used by writeable DLZ drivers to offload authorization for
  * updates to the driver.
  */
@@ -90,7 +93,7 @@ dns_ssutable_detach(dns_ssutable_t **tablep);
 
 isc_result_t
 dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
-                    const dns_name_t *identity, unsigned int matchtype,
+                    const dns_name_t *identity, dns_ssumatchtype_t matchtype,
                     const dns_name_t *name, unsigned int ntypes,
                     dns_rdatatype_t *types);
 /*%<
@@ -123,7 +126,12 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
 
 isc_boolean_t
 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
-                       const dns_name_t *name, const isc_netaddr_t *tcpaddr,
+                       const dns_name_t *name, const isc_netaddr_t *addr,
+                       dns_rdatatype_t type, const dst_key_t *key);
+isc_boolean_t
+dns_ssutable_checkrules2(dns_ssutable_t *table, const dns_name_t *signer,
+                       const dns_name_t *name, const isc_netaddr_t *addr,
+                       isc_boolean_t tcp, const dns_aclenv_t *env,
                        dns_rdatatype_t type, const dst_key_t *key);
 /*%<
  *     Checks that the attempted update of (name, type) is allowed according
@@ -131,18 +139,26 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
  *     no rules are matched, access is denied.
  *
  *     Notes:
- *             'tcpaddr' should only be set if the request received
- *             via TCP.  This provides a weak assurance that the
- *             request was not spoofed.  'tcpaddr' is to to validate
- *             DNS_SSUMATCHTYPE_TCPSELF and DNS_SSUMATCHTYPE_6TO4SELF
- *             rules.
- *
- *             For DNS_SSUMATCHTYPE_TCPSELF the addresses are mapped to
+ *             In dns_ssutable_checkrules(), 'addr' should only be
+ *             set if the request received via TCP.  This provides a
+ *             weak assurance that the request was not spoofed.
+ *             'addr' is to to validate dns_ssumatchtype_tcpself
+ *             and dns_ssumatchtype_6to4self rules.
+ *
+ *             In dns_ssutable_checkrules2(), 'addr' can also be passed for
+ *             UDP requests and TCP is specified via the 'tcp' parameter.
+ *             In addition to dns_ssumatchtype_tcpself and
+ *             tcp_ssumatchtype_6to4self  rules, the address
+ *             also be used to check dns_ssumatchtype_local rules.
+ *             If 'addr' is set then 'env' must also be set so that
+ *             requests from non-localhost addresses can be rejected.
+ *
+ *             For dns_ssumatchtype_tcpself the addresses are mapped to
  *             the standard reverse names under IN-ADDR.ARPA and IP6.ARPA.
  *             RFC 1035, Section 3.5, "IN-ADDR.ARPA domain" and RFC 3596,
  *             Section 2.5, "IP6.ARPA Domain".
  *
- *             For DNS_SSUMATCHTYPE_6TO4SELF, IPv4 address are converted
+ *             For dns_ssumatchtype_6to4self, IPv4 address are converted
  *             to a 6to4 prefix (48 bits) per the rules in RFC 3056.  Only
  *             the top 48 bits of the IPv6 address are mapped to the reverse
  *             name. This is independent of whether the most significant 16
@@ -151,8 +167,10 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
  *     Requires:
  *\li          'table' is a valid SSU table
  *\li          'signer' is NULL or a valid absolute name
- *\li          'tcpaddr' is NULL or a valid network address.
+ *\li          'addr' is NULL or a valid network address.
+ *\li          'aclenv' is NULL or a valid ACL environment.
  *\li          'name' is a valid absolute name
+ *\li          if 'addr' is not NULL, 'env' is not NULL.
  */
 
 
index f86d41b57a41c57304e4bb774ab147aa2bfac7a0..b2f201b1995234f521ecfed66ebfdfe114f115cb 100644 (file)
 
 struct dns_ssurule {
        unsigned int magic;
-       isc_boolean_t grant;    /*%< is this a grant or a deny? */
-       unsigned int matchtype; /*%< which type of pattern match? */
-       dns_name_t *identity;   /*%< the identity to match */
-       dns_name_t *name;       /*%< the name being updated */
-       unsigned int ntypes;    /*%< number of data types covered */
-       dns_rdatatype_t *types; /*%< the data types.  Can include ANY, */
-                               /*%< defaults to all but SIG,SOA,NS if NULL */
+       isc_boolean_t grant;            /*%< is this a grant or a deny? */
+       dns_ssumatchtype_t matchtype;   /*%< which type of pattern match? */
+       dns_name_t *identity;           /*%< the identity to match */
+       dns_name_t *name;               /*%< the name being updated */
+       unsigned int ntypes;            /*%< number of data types covered */
+       dns_rdatatype_t *types;         /*%< the data types.  Can include */
+                                       /*   ANY. if NULL, defaults to all */
+                                       /*   types except SIG, SOA, and NS */
        ISC_LINK(dns_ssurule_t) link;
 };
 
@@ -150,7 +151,7 @@ dns_ssutable_detach(dns_ssutable_t **tablep) {
 
 isc_result_t
 dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
-                    const dns_name_t *identity, unsigned int matchtype,
+                    const dns_name_t *identity, dns_ssumatchtype_t matchtype,
                     const dns_name_t *name, unsigned int ntypes,
                     dns_rdatatype_t *types)
 {
@@ -161,8 +162,8 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
        REQUIRE(VALID_SSUTABLE(table));
        REQUIRE(dns_name_isabsolute(identity));
        REQUIRE(dns_name_isabsolute(name));
-       REQUIRE(matchtype <= DNS_SSUMATCHTYPE_MAX);
-       if (matchtype == DNS_SSUMATCHTYPE_WILDCARD)
+       REQUIRE(matchtype <= dns_ssumatchtype_max);
+       if (matchtype == dns_ssumatchtype_wildcard)
                REQUIRE(dns_name_iswildcard(name));
        if (ntypes > 0)
                REQUIRE(types != NULL);
@@ -341,6 +342,17 @@ isc_boolean_t
 dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        const dns_name_t *name, const isc_netaddr_t *tcpaddr,
                        dns_rdatatype_t type, const dst_key_t *key)
+{
+       return (dns_ssutable_checkrules2
+               (table, signer, name, tcpaddr,
+                tcpaddr == NULL ? ISC_FALSE : ISC_TRUE,
+                NULL, type, key));
+}
+isc_boolean_t
+dns_ssutable_checkrules2(dns_ssutable_t *table, const dns_name_t *signer,
+                        const dns_name_t *name, const isc_netaddr_t *addr,
+                        isc_boolean_t tcp, const dns_aclenv_t *env,
+                        dns_rdatatype_t type, const dst_key_t *key)
 {
        dns_ssurule_t *rule;
        unsigned int i;
@@ -349,12 +361,14 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
        dns_name_t *tcpself;
        dns_name_t *stfself;
        isc_result_t result;
+       int match;
 
        REQUIRE(VALID_SSUTABLE(table));
        REQUIRE(signer == NULL || dns_name_isabsolute(signer));
        REQUIRE(dns_name_isabsolute(name));
+       REQUIRE(addr == NULL || env != NULL);
 
-       if (signer == NULL && tcpaddr == NULL)
+       if (signer == NULL && addr == NULL)
                return (ISC_FALSE);
 
        for (rule = ISC_LIST_HEAD(table->rules);
@@ -362,12 +376,13 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
             rule = ISC_LIST_NEXT(rule, link))
        {
                switch (rule->matchtype) {
-               case DNS_SSUMATCHTYPE_NAME:
-               case DNS_SSUMATCHTYPE_SUBDOMAIN:
-               case DNS_SSUMATCHTYPE_WILDCARD:
-               case DNS_SSUMATCHTYPE_SELF:
-               case DNS_SSUMATCHTYPE_SELFSUB:
-               case DNS_SSUMATCHTYPE_SELFWILD:
+               case dns_ssumatchtype_name:
+               case dns_ssumatchtype_local:
+               case dns_ssumatchtype_subdomain:
+               case dns_ssumatchtype_wildcard:
+               case dns_ssumatchtype_self:
+               case dns_ssumatchtype_selfsub:
+               case dns_ssumatchtype_selfwild:
                        if (signer == NULL)
                                continue;
                        if (dns_name_iswildcard(rule->identity)) {
@@ -379,42 +394,59 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                                        continue;
                        }
                        break;
-               case DNS_SSUMATCHTYPE_SELFKRB5:
-               case DNS_SSUMATCHTYPE_SELFMS:
-               case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
-               case DNS_SSUMATCHTYPE_SUBDOMAINMS:
+               case dns_ssumatchtype_selfkrb5:
+               case dns_ssumatchtype_selfms:
+               case dns_ssumatchtype_subdomainkrb5:
+               case dns_ssumatchtype_subdomainms:
                        if (signer == NULL)
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_TCPSELF:
-               case DNS_SSUMATCHTYPE_6TO4SELF:
-                       if (tcpaddr == NULL)
+               case dns_ssumatchtype_tcpself:
+               case dns_ssumatchtype_6to4self:
+                       if (!tcp || addr == NULL)
                                continue;
                        break;
+               case dns_ssumatchtype_external:
+               case dns_ssumatchtype_dlz:
+                       break;
                }
 
                switch (rule->matchtype) {
-               case DNS_SSUMATCHTYPE_NAME:
+               case dns_ssumatchtype_name:
                        if (!dns_name_equal(name, rule->name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SUBDOMAIN:
+               case dns_ssumatchtype_subdomain:
                        if (!dns_name_issubdomain(name, rule->name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_WILDCARD:
+               case dns_ssumatchtype_local:
+                       if (addr == NULL) {
+                               continue;
+                       }
+                       if (!dns_name_issubdomain(name, rule->name)) {
+
+                               continue;
+                       }
+                       dns_acl_match(addr, NULL, env->localhost,
+                                     NULL, &match, NULL);
+                       if (match == 0) {
+                               continue;
+                       }
+                       break;
+               case dns_ssumatchtype_wildcard:
                        if (!dns_name_matcheswildcard(name, rule->name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SELF:
+               case dns_ssumatchtype_self:
                        if (!dns_name_equal(signer, name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SELFSUB:
+               case dns_ssumatchtype_selfsub:
                        if (!dns_name_issubdomain(name, signer))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SELFWILD:
+               case dns_ssumatchtype_selfwild:
                        dns_fixedname_init(&fixed);
                        wildcard = dns_fixedname_name(&fixed);
                        result = dns_name_concatenate(dns_wildcardname, signer,
@@ -424,34 +456,34 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        if (!dns_name_matcheswildcard(name, wildcard))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SELFKRB5:
+               case dns_ssumatchtype_selfkrb5:
                        if (!dst_gssapi_identitymatchesrealmkrb5(signer, name,
                                                               rule->identity))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SELFMS:
+               case dns_ssumatchtype_selfms:
                        if (!dst_gssapi_identitymatchesrealmms(signer, name,
                                                               rule->identity))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
+               case dns_ssumatchtype_subdomainkrb5:
                        if (!dns_name_issubdomain(name, rule->name))
                                continue;
                        if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
                                                               rule->identity))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_SUBDOMAINMS:
+               case dns_ssumatchtype_subdomainms:
                        if (!dns_name_issubdomain(name, rule->name))
                                continue;
                        if (!dst_gssapi_identitymatchesrealmms(signer, NULL,
                                                               rule->identity))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_TCPSELF:
+               case dns_ssumatchtype_tcpself:
                        dns_fixedname_init(&fixed);
                        tcpself = dns_fixedname_name(&fixed);
-                       reverse_from_address(tcpself, tcpaddr);
+                       reverse_from_address(tcpself, addr);
                        if (dns_name_iswildcard(rule->identity)) {
                                if (!dns_name_matcheswildcard(tcpself,
                                                              rule->identity))
@@ -463,10 +495,10 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        if (!dns_name_equal(tcpself, name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_6TO4SELF:
+               case dns_ssumatchtype_6to4self:
                        dns_fixedname_init(&fixed);
                        stfself = dns_fixedname_name(&fixed);
-                       stf_from_address(stfself, tcpaddr);
+                       stf_from_address(stfself, addr);
                        if (dns_name_iswildcard(rule->identity)) {
                                if (!dns_name_matcheswildcard(stfself,
                                                              rule->identity))
@@ -478,15 +510,15 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                        if (!dns_name_equal(stfself, name))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_EXTERNAL:
+               case dns_ssumatchtype_external:
                        if (!dns_ssu_external_match(rule->identity, signer,
-                                                   name, tcpaddr, type, key,
+                                                   name, addr, type, key,
                                                    table->mctx))
                                continue;
                        break;
-               case DNS_SSUMATCHTYPE_DLZ:
+               case dns_ssumatchtype_dlz:
                        if (!dns_dlz_ssumatch(table->dlzdatabase, signer,
-                                             name, tcpaddr, type, key))
+                                             name, addr, type, key))
                                continue;
                        break;
                }
@@ -497,7 +529,7 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
                         * checks will have already checked
                         * the type.
                         */
-                       if (rule->matchtype != DNS_SSUMATCHTYPE_DLZ &&
+                       if (rule->matchtype != dns_ssumatchtype_dlz &&
                            !isusertype(type))
                                continue;
                } else {
@@ -592,7 +624,7 @@ dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
        rule->name = NULL;
        rule->types = NULL;
        rule->grant = ISC_TRUE;
-       rule->matchtype = DNS_SSUMATCHTYPE_DLZ;
+       rule->matchtype = dns_ssumatchtype_dlz;
        rule->ntypes = 0;
        rule->types = NULL;
        rule->magic = SSURULEMAGIC;
index b333ec423f02f5c087264fb5e9c5d6381cfffd60..86cf6da2b482c718fc8ec2f20045e77ca6973861 100644 (file)
@@ -178,6 +178,12 @@ isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen);
  *     ISC_R_FAILURE           extra bits.
  */
 
+isc_boolean_t
+isc_netaddr_isloopback(const isc_netaddr_t *na);
+/*
+ * Test whether the netaddr 'na' is a loopback IPv4 or IPv6 address (in
+ * 127.0.0.0/8 or ::1).
+ */
 ISC_LANG_ENDDECLS
 
 #endif /* ISC_NETADDR_H */
index 2ecd992e8a62213d2a08ab5704439feb4a034f15..483d240fbd5cd9bf3190494b5cadd384f8622576 100644 (file)
@@ -445,3 +445,16 @@ isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) {
        memmove(&t->type.in, (char *)&src->type.in6 + 12, 4);
        return;
 }
+
+isc_boolean_t
+isc_netaddr_isloopback(const isc_netaddr_t *na) {
+       switch (na->family) {
+       case AF_INET:
+               return (ISC_TF((ntohl(na->type.in.s_addr) & 0xff000000U) ==
+                              0x7f000000U));
+       case AF_INET6:
+               return (IN6_IS_ADDR_LOOPBACK(&na->type.in6));
+       default:
+               return (ISC_FALSE);
+       }
+}
index 32493d89ef6f9d1b4a995b9ef743131f7238e6e1..9e6c73edd89765ed56c4136474648f51215ed112 100644 (file)
@@ -35,7 +35,8 @@
 #define NS_SERVER_DROPEDNS     0x00000040U     /*%< -T dropedns */
 #define NS_SERVER_NOTCP                0x00000080U     /*%< -T notcp */
 #define NS_SERVER_DISABLE4     0x00000100U     /*%< -6 */
-#define NS_SERVER_DISABLE6     0x00000100U     /*%< -4 */
+#define NS_SERVER_DISABLE6     0x00000200U     /*%< -4 */
+#define NS_SERVER_FIXEDLOCAL   0x00000400U     /*%< -T fixedlocal */
 
 /*%
  * Type for callback function to get hostname.
index 3c0e427dad5fda21776b8932ec6e777f544b7752..35d59c47d7bd19c0b4e717d08fee6cfd45b8d486 100644 (file)
@@ -997,11 +997,23 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
                }
 
                if (adjusting == ISC_FALSE) {
+                       /*
+                        * If running with -T fixedlocal, then we only
+                        * want 127.0.0.1 and ::1 in the localhost ACL.
+                        */
+                       if (((mgr->sctx->options &
+                             NS_SERVER_FIXEDLOCAL) != 0) &&
+                           !isc_netaddr_isloopback(&interface.address))
+                       {
+                               goto listenon;
+                       }
+
                        result = setup_locals(mgr, &interface);
                        if (result != ISC_R_SUCCESS)
                                goto ignore_interface;
                }
 
+ listenon:
                ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
                dolistenon = ISC_TRUE;
                for (le = ISC_LIST_HEAD(ll->elts);
index f598204f8983ff2b733fe8445a475a4022247145..6dcb4a988ddf6038a7cd4ce0931651246650f475 100644 (file)
@@ -42,6 +42,7 @@
 #include <dns/zt.h>
 
 #include <ns/client.h>
+#include <ns/interfacemgr.h>
 #include <ns/log.h>
 #include <ns/server.h>
 #include <ns/stats.h>
@@ -863,8 +864,14 @@ typedef struct {
        /* The signature's name if the request was signed. */
        dns_name_t *signer;
 
-       /* The address of the client if the request was received via TCP. */
-       isc_netaddr_t *tcpaddr;
+       /* The address of the client. */
+       isc_netaddr_t *addr;
+
+       /* The ACL environment */
+       dns_aclenv_t *aclenv;
+
+       /* Whether the request was sent via TCP. */
+       isc_boolean_t tcp;
 
        /* The ssu table to check against. */
        dns_ssutable_t *table;
@@ -885,16 +892,18 @@ ssu_checkrule(void *data, dns_rdataset_t *rrset) {
        if (rrset->type == dns_rdatatype_rrsig ||
            rrset->type == dns_rdatatype_nsec)
                return (ISC_R_SUCCESS);
-       result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
-                                        ssuinfo->name, ssuinfo->tcpaddr,
-                                        rrset->type, ssuinfo->key);
+       result = dns_ssutable_checkrules2(ssuinfo->table, ssuinfo->signer,
+                                         ssuinfo->name, ssuinfo->addr,
+                                         ssuinfo->tcp, ssuinfo->aclenv,
+                                         rrset->type, ssuinfo->key);
        return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
 }
 
 static isc_boolean_t
 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
             dns_ssutable_t *ssutable, dns_name_t *signer,
-            isc_netaddr_t *tcpaddr, dst_key_t *key)
+            isc_netaddr_t *addr, dns_aclenv_t *aclenv, isc_boolean_t tcp,
+            dst_key_t *key)
 {
        isc_result_t result;
        ssu_check_t ssuinfo;
@@ -902,7 +911,9 @@ ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
        ssuinfo.name = name;
        ssuinfo.table = ssutable;
        ssuinfo.signer = signer;
-       ssuinfo.tcpaddr = tcpaddr;
+       ssuinfo.addr = addr;
+       ssuinfo.aclenv = aclenv;
+       ssuinfo.tcp = tcp;
        ssuinfo.key = key;
        result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
        return (ISC_TF(result == ISC_R_SUCCESS));
@@ -2497,6 +2508,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
        dns_ttl_t maxttl = 0;
        isc_uint32_t maxrecords;
        isc_uint64_t records;
+       dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr);
 
        INSIST(event->ev_type == DNS_EVENT_UPDATE);
 
@@ -2565,7 +2577,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                                   rdata.type, covers, &flag));
                                if (! flag) {
                                        /* RRset does not exist. */
-                                       PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type,
+                                       PREREQFAILNT(DNS_R_NXRRSET,
+                                                    name, rdata.type,
                                        "'rrset exists (value independent)' "
                                        "prerequisite not satisfied");
                                }
@@ -2726,38 +2739,32 @@ update_action(isc_task_t *task, isc_event_t *event) {
                }
 
                if (ssutable != NULL) {
-                       isc_netaddr_t *tcpaddr, netaddr;
+                       isc_netaddr_t netaddr;
                        dst_key_t *tsigkey = NULL;
-                       /*
-                        * If this is a TCP connection then pass the
-                        * address of the client through for tcp-self
-                        * and 6to4-self otherwise pass NULL.  This
-                        * provides weak address based authentication.
-                        */
-                       if (TCPCLIENT(client)) {
-                               isc_netaddr_fromsockaddr(&netaddr,
-                                                        &client->peeraddr);
-                               tcpaddr = &netaddr;
-                       } else
-                               tcpaddr = NULL;
+                       isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
 
                        if (client->message->tsigkey != NULL)
                                tsigkey = client->message->tsigkey->key;
 
                        if (rdata.type != dns_rdatatype_any) {
-                               if (!dns_ssutable_checkrules(ssutable,
-                                                            client->signer,
-                                                            name, tcpaddr,
-                                                            rdata.type,
-                                                            tsigkey))
+                               if (!dns_ssutable_checkrules2
+                                   (ssutable, client->signer, name, &netaddr,
+                                    ISC_TF(TCPCLIENT(client)),
+                                    env, rdata.type, tsigkey))
+                               {
                                        FAILC(DNS_R_REFUSED,
                                              "rejected by secure update");
+                               }
                        } else {
                                if (!ssu_checkall(db, ver, name, ssutable,
-                                                 client->signer, tcpaddr,
+                                                 client->signer,
+                                                 &netaddr, env,
+                                                 ISC_TF(TCPCLIENT(client)),
                                                  tsigkey))
+                               {
                                        FAILC(DNS_R_REFUSED,
                                              "rejected by secure update");
+                               }
                        }
                }
        }