diff --git a/CHANGES b/CHANGES index 2f285cdbbc..e75e77a199 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4329. [func] Warn about a common misconfiguration when forwarding + RFC 1918 zones. [RT #41441] + 4328. [performance] Add dns_name_fromwire() benchmark test. [RT #41694] 4327. [func] Log query and depth counters during fetches when diff --git a/bin/tests/system/forward/rfc1918-inherited.conf b/bin/tests/system/forward/rfc1918-inherited.conf new file mode 100644 index 0000000000..3d40b986d3 --- /dev/null +++ b/bin/tests/system/forward/rfc1918-inherited.conf @@ -0,0 +1,4 @@ +zone 10.in-addr.arpa { + type forward; + forwarders { 1.2.3.4; }; +}; diff --git a/bin/tests/system/forward/rfc1918-notinherited.conf b/bin/tests/system/forward/rfc1918-notinherited.conf new file mode 100644 index 0000000000..37dc0a9f9d --- /dev/null +++ b/bin/tests/system/forward/rfc1918-notinherited.conf @@ -0,0 +1,5 @@ +zone 10.in-addr.arpa { + type forward; + forward first; + forwarders { 1.2.3.4; }; +}; diff --git a/bin/tests/system/forward/tests.sh b/bin/tests/system/forward/tests.sh index 2a908347b7..b8d270ad19 100644 --- a/bin/tests/system/forward/tests.sh +++ b/bin/tests/system/forward/tests.sh @@ -123,5 +123,19 @@ grep "status: NOERROR" dig.out.q4 > /dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:checking that rfc1918 inherited 'forward first;' zones are warned about" +ret=0 +$CHECKCONF rfc1918-inherited.conf | grep "forward first;" >/dev/null || ret=1 +$CHECKCONF rfc1918-notinherited.conf | grep "forward first;" >/dev/null && ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +echo "I:checking that ULA inherited 'forward first;' zones are warned about" +ret=0 +$CHECKCONF ula-inherited.conf | grep "forward first;" >/dev/null || ret=1 +$CHECKCONF ula-notinherited.conf | grep "forward first;" >/dev/null && ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/bin/tests/system/forward/ula-inherited.conf b/bin/tests/system/forward/ula-inherited.conf new file mode 100644 index 0000000000..242bf9e732 --- /dev/null +++ b/bin/tests/system/forward/ula-inherited.conf @@ -0,0 +1,4 @@ +zone d.f.ip6.arpa { + type forward; + forwarders { 1.2.3.4; }; +}; diff --git a/bin/tests/system/forward/ula-notinherited.conf b/bin/tests/system/forward/ula-notinherited.conf new file mode 100644 index 0000000000..b3860e2658 --- /dev/null +++ b/bin/tests/system/forward/ula-notinherited.conf @@ -0,0 +1,5 @@ +zone d.f.ip6.arpa { + type forward; + forward first; + forwarders { 1.2.3.4; }; +}; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index baeb701b58..768913c709 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -1504,6 +1504,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, dns_name_t *zname = NULL; isc_buffer_t b; isc_boolean_t root = ISC_FALSE; + isc_boolean_t rfc1918 = ISC_FALSE; + isc_boolean_t ula = ISC_FALSE; const cfg_listelt_t *element; isc_boolean_t dlz; dns_masterformat_t masterformat; @@ -1699,6 +1701,10 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, result = tresult; if (dns_name_equal(zname, dns_rootname)) root = ISC_TRUE; + else if (dns_name_isrfc1918(zname)) + rfc1918 = ISC_TRUE; + else if (dns_name_isula(zname)) + ula = ISC_TRUE; } /* @@ -1968,6 +1974,32 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS) result = ISC_R_FAILURE; + /* + * Check that a RFC 1918 / ULA reverse zone is not forward first + * unless explictly configured to be so. + */ + if (ztype == FORWARDZONE && (rfc1918 || ula)) { + obj = NULL; + (void)cfg_map_get(zoptions, "forward", &obj); + if (obj == NULL) { + /* + * Forward mode not explicity configured. + */ + if (voptions != NULL) + cfg_map_get(voptions, "forward", &obj); + if (obj == NULL && goptions != NULL) + cfg_map_get(goptions, "forward", &obj); + if (obj == NULL || + strcasecmp(cfg_obj_asstring(obj), "first") == 0) + cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING, + "inherited 'forward first;' for " + "%s zone '%s' - did you want " + "'forward only;'?", + rfc1918 ? "rfc1918" : "ula", + znamestr); + } + } + /* * Check validity of static stub server addresses. */ diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index d3d466a886..7ec75758e7 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -1292,6 +1292,18 @@ dns_name_isdnssd(const dns_name_t *owner); * Determine if the 'owner' is a DNS-SD prefix. */ +isc_boolean_t +dns_name_isrfc1918(const dns_name_t *owner); +/*%< + * Determine if the 'name' is in the RFC 1918 reverse namespace. + */ + +isc_boolean_t +dns_name_isula(const dns_name_t *owner); +/*%< + * Determine if the 'name' is in the ULA reverse namespace. + */ + ISC_LANG_ENDDECLS /* diff --git a/lib/dns/name.c b/lib/dns/name.c index 90a9c0b46e..51ef7a9e03 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -2636,3 +2636,87 @@ dns_name_isdnssd(const dns_name_t *name) { return (ISC_FALSE); } + +#define NS_NAME_INIT(A,B) \ + { \ + DNS_NAME_MAGIC, \ + A, sizeof(A), sizeof(B), \ + DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \ + B, NULL, { (void *)-1, (void *)-1}, \ + {NULL, NULL} \ + } + +static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 }; +static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 }; +static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 }; + +static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA"; + +static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA"; +static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA"; + +static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA"; + +static dns_name_t const rfc1918names[] = { + NS_NAME_INIT(inaddr10, inaddr10_offsets), + NS_NAME_INIT(inaddr16172, inaddr172_offsets), + NS_NAME_INIT(inaddr17172, inaddr172_offsets), + NS_NAME_INIT(inaddr18172, inaddr172_offsets), + NS_NAME_INIT(inaddr19172, inaddr172_offsets), + NS_NAME_INIT(inaddr20172, inaddr172_offsets), + NS_NAME_INIT(inaddr21172, inaddr172_offsets), + NS_NAME_INIT(inaddr22172, inaddr172_offsets), + NS_NAME_INIT(inaddr23172, inaddr172_offsets), + NS_NAME_INIT(inaddr24172, inaddr172_offsets), + NS_NAME_INIT(inaddr25172, inaddr172_offsets), + NS_NAME_INIT(inaddr26172, inaddr172_offsets), + NS_NAME_INIT(inaddr27172, inaddr172_offsets), + NS_NAME_INIT(inaddr28172, inaddr172_offsets), + NS_NAME_INIT(inaddr29172, inaddr172_offsets), + NS_NAME_INIT(inaddr30172, inaddr172_offsets), + NS_NAME_INIT(inaddr31172, inaddr172_offsets), + NS_NAME_INIT(inaddr168192, inaddr192_offsets) +}; + +isc_boolean_t +dns_name_isrfc1918(const dns_name_t *name) { + size_t i; + + for (i = 0; i < (sizeof(rfc1918names)/sizeof(*rfc1918names)); i++) + if (dns_name_issubdomain(name, &rfc1918names[i])) + return (ISC_TRUE); + return (ISC_FALSE); +} + +static unsigned char ulaoffsets[] = { 0, 2, 4, 8, 13 }; +static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA"; +static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA"; + +static dns_name_t const ulanames[] = { + NS_NAME_INIT(ip6fc, ulaoffsets), + NS_NAME_INIT(ip6fd, ulaoffsets), +}; + +isc_boolean_t +dns_name_isula(const dns_name_t *name) { + size_t i; + + for (i = 0; i < (sizeof(ulanames)/sizeof(*ulanames)); i++) + if (dns_name_issubdomain(name, &ulanames[i])) + return (ISC_TRUE); + return (ISC_FALSE); +}