[v9_10] further restrict update-policy local

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]
This commit is contained in:
Evan Hunt
2017-10-06 15:36:18 -07:00
parent 3402ce550a
commit dddf97d534
18 changed files with 280 additions and 73 deletions

View File

@@ -171,6 +171,7 @@ EXTERN isc_boolean_t ns_g_notcp INIT(ISC_FALSE);
EXTERN isc_boolean_t ns_g_disable6 INIT(ISC_FALSE);
EXTERN isc_boolean_t ns_g_disable4 INIT(ISC_FALSE);
EXTERN unsigned int ns_g_tat_interval INIT(24*3600);
EXTERN isc_boolean_t ns_g_fixedlocal INIT(ISC_FALSE);
#ifdef HAVE_GEOIP

View File

@@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp $ */
/*! \file */
#include <config.h>
@@ -949,11 +947,22 @@ 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 (ns_g_fixedlocal &&
!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);

View File

@@ -611,17 +611,25 @@ parse_command_line(int argc, char *argv[]) {
dns_zone_mkey_month = atoi(p);
if (dns_zone_mkey_month < dns_zone_mkey_day)
ns_main_earlyfatal("bad mkeytimer");
} else if (!strcmp(isc_commandline_argument, "notcp"))
} else if (!strcmp(isc_commandline_argument, "notcp")) {
ns_g_notcp = ISC_TRUE;
else if (!strncmp(isc_commandline_argument, "tat=", 4))
} else if (!strncmp(isc_commandline_argument,
"tat=", 4))
{
ns_g_tat_interval =
atoi(isc_commandline_argument + 4);
else if (!strcmp(isc_commandline_argument,
"keepstderr"))
} else if (!strcmp(isc_commandline_argument,
"keepstderr"))
{
ns_g_keepstderr = ISC_TRUE;
else
} else if (!strcmp(isc_commandline_argument,
"fixedlocal"))
{
ns_g_fixedlocal = ISC_TRUE;
} else {
fprintf(stderr, "unknown -T flag '%s\n",
isc_commandline_argument);
}
break;
case 'U':
ns_g_udpdisp = parse_int(isc_commandline_argument,

View File

@@ -813,8 +813,11 @@ 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;
/* Whether the request was sent via TCP. */
isc_boolean_t tcp;
/* The ssu table to check against. */
dns_ssutable_t *table;
@@ -835,16 +838,17 @@ 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, &ns_g_server->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, isc_boolean_t tcp, dst_key_t *key)
{
isc_result_t result;
ssu_check_t ssuinfo;
@@ -852,7 +856,8 @@ 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.tcp = tcp;
ssuinfo.key = key;
result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
return (ISC_TF(result == ISC_R_SUCCESS));
@@ -2686,38 +2691,33 @@ 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)),
&ns_g_server->aclenv,
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,
ISC_TF(TCPCLIENT(client)),
tsigkey))
{
FAILC(DNS_R_REFUSED,
"rejected by secure update");
}
}
}
}

View File

@@ -378,7 +378,7 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
result = dns_ssutable_addrule(table, ISC_TRUE,
ns_g_server->session_keyname,
DNS_SSUMATCHTYPE_SUBDOMAIN,
DNS_SSUMATCHTYPE_LOCAL,
dns_zone_getorigin(zone),
1, &any);

View File

@@ -20,13 +20,12 @@
#
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 ns1/example.db ns1/unixtime.db ns1/update.db ns1/other.db ns1/keytests.db
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/md5.key ns1/sha1.key ns1/sha224.key ns1/sha256.key ns1/sha384.key
@@ -42,6 +41,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

View File

@@ -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

View File

@@ -0,0 +1 @@
-m record,size,mctx -T clienttest -c named.conf -d 99 -g -U 4 -T fixedlocal

View File

@@ -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;
};

View File

@@ -66,3 +66,5 @@ $DDNSCONFGEN -q -r $RANDFILE -a hmac-sha512 -k sha512-key -z keytests.nil > ns1/
cp ns1/sample.db.in ns1/sample.db
cp ns2/sample.db.in ns2/sample.db
cp -f ns5/local.db.in ns5/local.db

View File

@@ -475,6 +475,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)"