diff --git a/bind-9.9.3-P2.tar.gz b/bind-9.9.3-P2.tar.gz deleted file mode 100644 index 980de4c..0000000 --- a/bind-9.9.3-P2.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5e8ab06c7b73f38b47ce9ad12ca0afa7c714bbba2f6b7421c26c0d8b84b6c678 -size 7459422 diff --git a/bind-9.9.3-P2.tar.gz.asc b/bind-9.9.3-P2.tar.gz.asc deleted file mode 100644 index 6110bfc..0000000 --- a/bind-9.9.3-P2.tar.gz.asc +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1.4.12 (NetBSD) - -iQEcBAABAgAGBQJR8sogAAoJEEWseFcYnNvFyMUIAJ3AfF7bF4rUajtXA5cj8HoE -8pQsCvf1nYUoFQv1AwovA6PNc+EpQVtPkpQlItaIdacyN1ewjsoPEMcWdA8Xk0z1 -T0CpJIZfAlGl1QZBAqGnxt4KH4kHAuhQiT9S1boIPOdlHJ84NRD94et+hQfdqWIX -dG4vyChOAYlNFwfQd97JyxWjplRT0YbaWQ8YoWh3puH33jC6yX0v8VfY0g0ga7Ul -hz3PIiZo51JkVcWtsy5qf1WAVSqthzy6KB9MsXJZR7i+2H6t/1/7FK/niBPdASQB -czR7gLmjuk/G5dJ1ZkEosJVEILjfLn9rTLKwf2d8dkgJwrZDpMyNMTqSUJgsRHQ= -=Y9CU ------END PGP SIGNATURE----- diff --git a/bind-9.9.4-P2.tar.gz b/bind-9.9.4-P2.tar.gz new file mode 100644 index 0000000..da07c8c --- /dev/null +++ b/bind-9.9.4-P2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50f3c6431e26d3f322b69092a49c92e163e73029fe4a1933ce532dc97ec40a89 +size 7513077 diff --git a/bind-9.9.4-P2.tar.gz.asc b/bind-9.9.4-P2.tar.gz.asc new file mode 100644 index 0000000..bd3de92 --- /dev/null +++ b/bind-9.9.4-P2.tar.gz.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.12 (NetBSD) + +iQEcBAABAgAGBQJSxzKdAAoJEEWseFcYnNvFBRMH+QE4AkJ4CoZPcO0PcE6+2AFA +BEXCJJSyMfZr3R0Wblb+lhWehnnWpxqV8FCwM9gecFXn0J44aJ+U8nh3WA8ROAas +5NfXjll34YDDo8UU9wGZ7XmPpzUnn6DoncVz1BeV1VwqLIADv6WkoSx0HasYQ4Vf +bHwGJI1cFCLDpy8XhjLAb4iUkdE9NSmvJ+6OZJ0ZtgYymnnNWI2YvHn95DM3DQbS +lURMaiqiwNmhuk4Q4qzoAPrbpEqRG/PmFxRiZWk9irPhBsSoJKU/wbOFyTD+iJAv ++pugh+S9lXkqR5bWLKzR8rpW4ydV9KVuxo6jW4dT4kR7QbU+zdMC6CAW/99duqQ= +=F/NG +-----END PGP SIGNATURE----- diff --git a/bind.changes b/bind.changes index 86e04ac..80acb49 100644 --- a/bind.changes +++ b/bind.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Tue Jan 21 17:02:30 UTC 2014 - max@suse.com + +- Update to version 9.9.4P2 + * Fixes named crash when handling malformed NSEC3-signed zones + (CVE-2014-0591, bnc#858639) + * Obsoletes workaround-compile-problem.diff +- Replace rpz2+rl-9.9.3-P1.patch by rpz2-9.9.4.patch, rl is now + supported upstream (--enable-rrl). + ------------------------------------------------------------------- Mon Dec 9 12:16:42 UTC 2013 - max@suse.com diff --git a/bind.spec b/bind.spec index 2387005..df286a3 100644 --- a/bind.spec +++ b/bind.spec @@ -1,7 +1,7 @@ # # spec file for package bind # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ Name: bind %define pkg_name bind -%define pkg_vers 9.9.3-P2 +%define pkg_vers 9.9.4-P2 BuildRequires: krb5-devel BuildRequires: libcap BuildRequires: libcap-devel @@ -33,7 +33,7 @@ BuildRequires: update-desktop-files Summary: Domain Name System (DNS) Server (named) License: ISC Group: Productivity/Networking/DNS/Servers -Version: 9.9.3P2 +Version: 9.9.4P2 Release: 0 Provides: bind8 Provides: bind9 @@ -59,15 +59,14 @@ Patch4: perl-path.diff Patch51: pie_compile.diff Patch52: named-bootconf.diff Patch100: configure.in.diff2 -Patch110: workaround-compile-problem.diff %if 0%{?suse_version} > 1220 BuildRequires: gpg-offline %endif # Rate limiting patch by Paul Vixie et.al. for reflection DoS protection # see http://www.redbarn.org/dns/ratelimits -#Patch200: http://ss.vix.su/~vjs/rpz2+rl-9.9.3-P1.patch -Patch200: rpz2+rl-9.9.3-P1.patch +#Patch200: http://ss.vix.su/~vjs/rpz2-9.9.4.patch +Patch200: rpz2-9.9.4.patch Source60: dlz-schema.txt %if %ul_version >= 1 @@ -210,7 +209,6 @@ Name Domain (BIND) DNS server is found in the package named bind. %if 0%{?suse_version} <= 1010 %patch100 -p1 %endif -%patch110 -p0 %patch200 -p0 # modify settings of some files regarding to OS version and vendor function replaceStrings() @@ -270,7 +268,8 @@ CONFIGURE_OPTIONS="\ --with-libtool \ --enable-runidn \ --with-libxml2 \ - --with-dlz-mysql --with-dlz-ldap + --with-dlz-mysql --with-dlz-ldap \ + --enable-rrl " cp -f -p config.guess config.sub contrib/idn/idnkit-1.0-src/ ./configure ${CONFIGURE_OPTIONS} diff --git a/configure.in.diff b/configure.in.diff index f1c4e92..a970833 100644 --- a/configure.in.diff +++ b/configure.in.diff @@ -1,6 +1,8 @@ ---- bind-9.9.3-P1/configure.in.xx 2013-06-26 14:23:25.536177163 +0200 -+++ bind-9.9.3-P1/configure.in 2013-06-26 14:23:26.401175186 +0200 -@@ -3099,7 +3099,7 @@ +Index: bind-9.9.4-P2/configure.in +=================================================================== +--- bind-9.9.4-P2.orig/configure.in 2013-12-20 01:28:28.000000000 +0100 ++++ bind-9.9.4-P2/configure.in 2014-01-21 17:55:51.063395215 +0100 +@@ -3142,7 +3142,7 @@ # empty). The variable VARIABLE will be substituted into output files. # diff --git a/rpz2+rl-9.9.3-P1.patch b/rpz2-9.9.4.patch similarity index 54% rename from rpz2+rl-9.9.3-P1.patch rename to rpz2-9.9.4.patch index 761ad4b..cea3701 100644 --- a/rpz2+rl-9.9.3-P1.patch +++ b/rpz2-9.9.4.patch @@ -1,130 +1,6 @@ -Index: bin/named/client.c -=================================================================== ---- bin/named/client.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/client.c 2013-08-05 14:14:45.875498002 +0200 -@@ -994,6 +994,11 @@ - } - if (result != ISC_R_SUCCESS) - goto done; -+ /* -+ * Stop after the question if TC was set for rate limiting. -+ */ -+ if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) -+ goto renderend; - result = dns_message_rendersection(client->message, - DNS_SECTION_ANSWER, - DNS_MESSAGERENDER_PARTIAL | -@@ -1134,6 +1139,51 @@ - #endif - - /* -+ * Try to rate limit error responses. -+ */ -+ if (client->view != NULL && client->view->rrl != NULL) { -+ isc_boolean_t wouldlog; -+ char log_buf[DNS_RRL_LOG_BUF_LEN]; -+ dns_rrl_result_t rrl_result; -+ -+ INSIST(rcode != dns_rcode_noerror && -+ rcode != dns_rcode_nxdomain); -+ wouldlog = isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP); -+ rrl_result = dns_rrl(client->view, &client->peeraddr, -+ TCP_CLIENT(client), -+ dns_rdataclass_in, dns_rdatatype_none, -+ NULL, result, client->now, -+ wouldlog, log_buf, sizeof(log_buf)); -+ if (rrl_result != DNS_RRL_RESULT_OK) { -+ /* -+ * Log dropped errors in the query category -+ * so that they are not lost in silence. -+ * Starts of rate-limited bursts are logged in -+ * NS_LOGCATEGORY_RRL. -+ */ -+ if (wouldlog) { -+ ns_client_log(client, -+ NS_LOGCATEGORY_QUERY_EERRORS, -+ NS_LOGMODULE_CLIENT, -+ DNS_RRL_LOG_DROP, -+ "%s", log_buf); -+ } -+ /* -+ * Some error responses cannot be 'slipped', -+ * so don't try to slip any error responses. -+ */ -+ if (!client->view->rrl->log_only) { -+ isc_stats_increment(ns_g_server->nsstats, -+ dns_nsstatscounter_ratedropped); -+ isc_stats_increment(ns_g_server->nsstats, -+ dns_nsstatscounter_dropped); -+ ns_client_next(client, DNS_R_DROP); -+ return; -+ } -+ } -+ } -+ -+ /* - * Message may be an in-progress reply that we had trouble - * with, in which case QR will be set. We need to clear QR before - * calling dns_message_reply() to avoid triggering an assertion. -Index: bin/named/config.c -=================================================================== ---- bin/named/config.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/config.c 2013-08-05 14:14:45.875498002 +0200 -@@ -228,6 +228,13 @@ - notify no;\n\ - allow-new-zones no;\n\ - \n\ -+ # Prevent use of this zone in DNS amplified reflection DoS attacks\n\ -+ rate-limit {\n\ -+ responses-per-second 3;\n\ -+ slip 0;\n\ -+ min-table-size 10;\n\ -+ };\n\ -+\n\ - zone \"version.bind\" chaos {\n\ - type master;\n\ - database \"_builtin version\";\n\ -Index: bin/named/include/named/query.h -=================================================================== ---- bin/named/include/named/query.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/include/named/query.h 2013-08-05 14:14:45.875498002 +0200 -@@ -85,6 +85,7 @@ - #define NS_QUERYATTR_CACHEACLOK 0x2000 - #define NS_QUERYATTR_DNS64 0x4000 - #define NS_QUERYATTR_DNS64EXCLUDE 0x8000 -+#define NS_QUERYATTR_RRL_CHECKED 0x10000 - - - isc_result_t -Index: bin/named/include/named/server.h -=================================================================== ---- bin/named/include/named/server.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/include/named/server.h 2013-08-05 14:14:45.875498002 +0200 -@@ -167,7 +167,10 @@ - - dns_nsstatscounter_rpz_rewrites = 36, - -- dns_nsstatscounter_max = 37 -+ dns_nsstatscounter_ratedropped = 37, -+ dns_nsstatscounter_rateslipped = 38, -+ -+ dns_nsstatscounter_max = 39 - }; - - void -Index: bin/named/query.c -=================================================================== ---- bin/named/query.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/query.c 2013-08-05 14:14:45.877498027 +0200 -@@ -193,7 +193,7 @@ - #ifdef NEWSTATS - /* Do query type statistics - * -- * We only increment per-type if we're using the authoriative -+ * We only increment per-type if we're using the authoritative - * answer counter, preventing double-counting. - */ - if (counter == dns_nsstatscounter_authans) { +diff -r -u bin/named/query.c-orig bin/named/query.c +--- bin/named/query.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/named/query.c 2004-01-01 00:00:00.000000000 +0000 @@ -879,11 +879,11 @@ static void rpz_log_rewrite(ns_client_t *client, isc_boolean_t disabled, @@ -150,7 +26,7 @@ Index: bin/named/query.c if (zonestats != NULL) isc_stats_increment(zonestats, dns_nsstatscounter_rpz_rewrites); -@@ -904,22 +904,21 @@ +@@ -904,68 +904,73 @@ return; dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf)); @@ -176,23 +52,31 @@ Index: bin/named/query.c - char namebuf2[DNS_NAME_FORMATSIZE]; + char qnamebuf[DNS_NAME_FORMATSIZE]; + char p_namebuf[DNS_NAME_FORMATSIZE]; ++ const char *failed; if (!isc_log_wouldlog(ns_g_lctx, level)) return; -@@ -927,44 +926,44 @@ + /* - * bin/tests/system/rpz/tests.sh looks for "rpz.*failed". +- * bin/tests/system/rpz/tests.sh looks for "rpz.*failed". ++ * bin/tests/system/rpz/tests.sh looks for "rpz.*failed" for problems. */ - dns_name_format(client->query.qname, namebuf1, sizeof(namebuf1)); - dns_name_format(name, namebuf2, sizeof(namebuf2)); ++ if (level <= DNS_RPZ_DEBUG_LEVEL1) ++ failed = "failed: "; ++ else ++ failed = ": "; + dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf)); + dns_name_format(p_name, p_namebuf, sizeof(p_namebuf)); ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY, level, - "rpz %s rewrite %s via %s %sfailed: %s", +- "rpz %s rewrite %s via %s %sfailed: %s", ++ "rpz %s rewrite %s via %s%s%s%s", dns_rpz_type2str(rpz_type), - namebuf1, namebuf2, str, isc_result_totext(result)); -+ qnamebuf, p_namebuf, str, isc_result_totext(result)); ++ qnamebuf, p_namebuf, ++ str, failed, isc_result_totext(result)); } /* @@ -232,11 +116,13 @@ Index: bin/named/query.c return (ISC_R_SUCCESS); } - rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, rpz_type, rpz_qname, +- "query_getzonedb() ", result); + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, - "query_getzonedb() ", result); ++ " query_getzonedb()", result); return (result); } -@@ -3913,7 +3912,7 @@ + +@@ -3913,7 +3918,7 @@ dns_rdataset_disassociate(*rdatasetp); } @@ -245,7 +131,7 @@ Index: bin/named/query.c rpz_match_clear(dns_rpz_st_t *st) { rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset); -@@ -3921,16 +3920,16 @@ +@@ -3921,16 +3926,16 @@ } static inline isc_result_t @@ -265,7 +151,7 @@ Index: bin/named/query.c } return (ISC_R_SUCCESS); } -@@ -3959,13 +3958,83 @@ +@@ -3959,13 +3964,83 @@ st->m.policy = DNS_RPZ_POLICY_MISS; } @@ -353,7 +239,7 @@ Index: bin/named/query.c dns_rdataset_t **rdatasetp, isc_boolean_t resuming) { dns_rpz_st_t *st; -@@ -3977,15 +4046,13 @@ +@@ -3977,15 +4052,13 @@ dns_clientinfomethods_t cm; dns_clientinfo_t ci; @@ -370,7 +256,7 @@ Index: bin/named/query.c st->state &= ~DNS_RPZ_RECURSING; *dbp = st->r.db; st->r.db = NULL; -@@ -3995,16 +4062,15 @@ +@@ -3995,16 +4068,15 @@ st->r.r_rdataset = NULL; result = st->r.r_result; if (result == DNS_R_DELEGATION) { @@ -378,7 +264,7 @@ Index: bin/named/query.c - rpz_type, name, - "rpz_rrset_find(1) ", result); + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name, -+ rpz_type, "rpz_rrset_find(1) ", result); ++ rpz_type, " rpz_rrset_find(1)", result); st->m.policy = DNS_RPZ_POLICY_ERROR; result = DNS_R_SERVFAIL; } @@ -390,7 +276,7 @@ Index: bin/named/query.c if (result != ISC_R_SUCCESS) { st->m.policy = DNS_RPZ_POLICY_ERROR; return (result); -@@ -4019,9 +4085,8 @@ +@@ -4019,9 +4091,8 @@ result = query_getdb(client, name, type, 0, &zone, dbp, &version, &is_zone); if (result != ISC_R_SUCCESS) { @@ -398,11 +284,11 @@ Index: bin/named/query.c - rpz_type, name, - "rpz_rrset_find(2) ", result); + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name, -+ rpz_type, "rpz_rrset_find(2) ", result); ++ rpz_type, " rpz_rrset_find(2)", result); st->m.policy = DNS_RPZ_POLICY_ERROR; if (zone != NULL) dns_zone_detach(&zone); -@@ -4034,6 +4099,8 @@ +@@ -4034,6 +4105,8 @@ node = NULL; dns_fixedname_init(&fixed); found = dns_fixedname_name(&fixed); @@ -411,7 +297,7 @@ Index: bin/named/query.c result = dns_db_findext(*dbp, name, version, type, DNS_DBFIND_GLUEOK, client->now, &node, found, &cm, &ci, *rdatasetp, NULL); -@@ -4072,177 +4139,97 @@ +@@ -4072,177 +4145,97 @@ } /* @@ -423,16 +309,15 @@ Index: bin/named/query.c static isc_result_t -rpz_rewrite_ip(ns_client_t *client, dns_rdataset_t *rdataset, - dns_rpz_type_t rpz_type) --{ ++rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, ++ dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, ++ dns_name_t *trig_name) + { - dns_rpz_st_t *st; - dns_dbversion_t *version; - dns_zone_t *zone; - dns_db_t *db; - dns_rpz_zone_t *rpz; -+rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, -+ dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, -+ dns_name_t *trig_name) -+{ + dns_offsets_t prefix_offsets; + dns_name_t prefix, *suffix; + unsigned int first, labels; @@ -614,7 +499,7 @@ Index: bin/named/query.c + */ + if (labels-first < 2) { + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, suffix, -+ rpz_type, "concatentate() ", result); ++ rpz_type, " concatentate()", result); + return (ISC_R_FAILURE); + } + /* @@ -622,7 +507,7 @@ Index: bin/named/query.c + */ + if (first == 0) { + rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, suffix, -+ rpz_type, "concatentate() ", result); ++ rpz_type, " concatentate()", result); + } + ++first; } @@ -661,7 +546,7 @@ Index: bin/named/query.c dns_name_t *found; isc_result_t result; dns_clientinfomethods_t cm; -@@ -4250,31 +4237,28 @@ +@@ -4250,31 +4243,28 @@ REQUIRE(nodep != NULL); @@ -708,7 +593,7 @@ Index: bin/named/query.c if (result == ISC_R_SUCCESS) { dns_rdatasetiter_t *rdsiter; -@@ -4282,10 +4266,8 @@ +@@ -4282,10 +4272,8 @@ result = dns_db_allrdatasets(*dbp, *nodep, *versionp, 0, &rdsiter); if (result != ISC_R_SUCCESS) { @@ -717,11 +602,11 @@ Index: bin/named/query.c - qnamef, "allrdatasets() ", result); - *policyp = DNS_RPZ_POLICY_ERROR; + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, -+ rpz_type, "allrdatasets() ", result); ++ rpz_type, " allrdatasets()", result); return (DNS_R_SERVFAIL); } for (result = dns_rdatasetiter_first(rdsiter); -@@ -4301,9 +4283,8 @@ +@@ -4301,9 +4289,8 @@ if (result != ISC_R_SUCCESS) { if (result != ISC_R_NOMORE) { rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, @@ -729,11 +614,11 @@ Index: bin/named/query.c - result); - *policyp = DNS_RPZ_POLICY_ERROR; + p_name, rpz_type, -+ "rdatasetiter ", result); ++ " rdatasetiter", result); return (DNS_R_SERVFAIL); } /* -@@ -4318,7 +4299,7 @@ +@@ -4318,7 +4305,7 @@ qtype == dns_rdatatype_sig) result = DNS_R_NXRRSET; else @@ -742,7 +627,7 @@ Index: bin/named/query.c qtype, 0, client->now, nodep, found, &cm, &ci, *rdatasetp, NULL); -@@ -4327,162 +4308,477 @@ +@@ -4327,162 +4314,476 @@ switch (result) { case ISC_R_SUCCESS: if ((*rdatasetp)->type != dns_rdatatype_cname) { @@ -1079,14 +964,13 @@ Index: bin/named/query.c + case DNS_R_CNAME: + case DNS_R_DNAME: + rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, name, rpz_type, -+ "NS address rewrite rrset ", result); ++ " NS address rewrite rrset", result); + return (ISC_R_SUCCESS); -+ break; + default: + if (client->query.rpz_st->m.policy != DNS_RPZ_POLICY_ERROR) { + client->query.rpz_st->m.policy = DNS_RPZ_POLICY_ERROR; + rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name, -+ rpz_type, "NS address rewrite rrset ", ++ rpz_type, " NS address rewrite rrset", + result); + } + return (DNS_R_SERVFAIL); @@ -1216,7 +1100,7 @@ Index: bin/named/query.c + * the bit mask of policy zones with policies for this trigger name. + * x&-x is the least significant bit set in x + */ -+ if (zbits != (zbits & -zbits)) { ++ if (zbits != (zbits & (~zbits + 1))) { + zbits = dns_rpz_find_name(client->view->rpzs, + rpz_type, zbits, trig_name); + if (zbits == 0) @@ -1313,7 +1197,7 @@ Index: bin/named/query.c continue; #if 0 /* -@@ -4505,11 +4801,12 @@ +@@ -4505,11 +4806,12 @@ * names in TLDs that start with "rpz-" should * ICANN ever allow such TLDs. */ @@ -1328,7 +1212,7 @@ Index: bin/named/query.c if (label.length >= sizeof(DNS_RPZ_PREFIX)-1 && strncasecmp((const char *)label.base+1, DNS_RPZ_PREFIX, -@@ -4517,46 +4814,29 @@ +@@ -4517,46 +4819,29 @@ continue; } #endif @@ -1393,7 +1277,7 @@ Index: bin/named/query.c return (ISC_R_SUCCESS); } -@@ -4569,7 +4849,7 @@ +@@ -4569,7 +4854,7 @@ st = client->query.rpz_st; if (str != NULL) @@ -1402,18 +1286,17 @@ Index: bin/named/query.c str, result); if (st->r.ns_rdataset != NULL && dns_rdataset_isassociated(st->r.ns_rdataset)) -@@ -4589,7 +4869,9 @@ +@@ -4589,7 +4874,8 @@ dns_rdataset_t *rdataset; dns_fixedname_t nsnamef; dns_name_t *nsname; - isc_boolean_t ck_ip; + int qresult_type; + dns_rpz_zbits_t zbits; -+ isc_netaddr_t netaddr; isc_result_t result; st = client->query.rpz_st; -@@ -4603,10 +4885,10 @@ +@@ -4603,10 +4889,10 @@ st->m.policy = DNS_RPZ_POLICY_MISS; memset(&st->r, 0, sizeof(st->r)); memset(&st->q, 0, sizeof(st->q)); @@ -1426,7 +1309,7 @@ Index: bin/named/query.c st->r_name = dns_fixedname_name(&st->_r_namef); st->fname = dns_fixedname_name(&st->_fnamef); client->query.rpz_st = st; -@@ -4619,7 +4901,7 @@ +@@ -4619,7 +4905,7 @@ case ISC_R_SUCCESS: case DNS_R_GLUE: case DNS_R_ZONECUT: @@ -1435,7 +1318,7 @@ Index: bin/named/query.c break; case DNS_R_EMPTYNAME: case DNS_R_NXRRSET: -@@ -4629,73 +4911,136 @@ +@@ -4629,73 +4915,155 @@ case DNS_R_NCACHENXRRSET: case DNS_R_CNAME: case DNS_R_DNAME: @@ -1445,7 +1328,15 @@ Index: bin/named/query.c case DNS_R_DELEGATION: case ISC_R_NOTFOUND: - return (ISC_R_SUCCESS); -+ qresult_type = 2; ++ /* ++ * If recursion is on, do only tentative rewriting. ++ * If recursion is off, this the normal and only time we ++ * can rewrite. ++ */ ++ if (RECURSIONOK(client)) ++ qresult_type = 2; ++ else ++ qresult_type = 1; + break; case ISC_R_FAILURE: case ISC_R_TIMEDOUT: @@ -1456,93 +1347,110 @@ Index: bin/named/query.c - qresult); + rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, client->query.qname, + DNS_RPZ_TYPE_QNAME, -+ "stop on qresult in rpz_rewrite() ", qresult); ++ " stop on qresult in rpz_rewrite()", qresult); return (ISC_R_SUCCESS); default: - rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, DNS_RPZ_TYPE_QNAME, - client->query.qname, +- "stop on unrecognized qresult in rpz_rewrite() ", + rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, client->query.qname, + DNS_RPZ_TYPE_QNAME, - "stop on unrecognized qresult in rpz_rewrite() ", ++ " stop on unrecognized qresult in rpz_rewrite()", qresult); return (ISC_R_SUCCESS); } rdataset = NULL; +- if ((st->state & DNS_RPZ_DONE_QNAME) == 0) { + -+ /* -+ * Check triggers for the client IP address once. -+ */ -+ if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) { -+ st->state |= DNS_RPZ_DONE_CLIENT_IP; -+ zbits = rpz_get_zbits(client, dns_rdatatype_none, -+ DNS_RPZ_TYPE_CLIENT_IP); -+ if (zbits != 0) { -+ isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); -+ result = rpz_rewrite_ip(client, &netaddr, qtype, -+ DNS_RPZ_TYPE_CLIENT_IP, -+ zbits, &rdataset); -+ if (result != ISC_R_SUCCESS) -+ goto cleanup; -+ } -+ } ++ if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) != ++ (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) { ++ isc_netaddr_t netaddr; ++ dns_rpz_zbits_t allowed; + -+ /* -+ * Check triggers for the query name if this is the first time -+ * for the current qname. -+ * There is a first time for each name in a CNAME chain. -+ */ - if ((st->state & DNS_RPZ_DONE_QNAME) == 0) { + if (qresult_type == 2) { + /* + * This request needs recursion that has not been done. -+ * Get bits for the policy zones that do not -+ * require recursion be done before applying their -+ * policies. By not recursing after applying their -+ * policies, those policy zones leak information -+ * to operators of the targeted zones. -+ * Bail out to wait for recursion if there are no -+ * such policies. ++ * Get bits for the policy zones that do not need ++ * to wait for the results of recursion. + */ -+ zbits = client->view->rpzs->have.qname_skip_recurse; -+ if (zbits == 0) { -+ result = ISC_R_SUCCESS; -+ goto cleanup; -+ } ++ allowed = client->view->rpzs->have.qname_skip_recurse; ++ if (allowed == 0) ++ return (ISC_R_SUCCESS); + } else { -+ zbits = DNS_RPZ_ALL_ZBITS; ++ allowed = DNS_RPZ_ALL_ZBITS; + } -+ result = rpz_rewrite_name(client, client->query.qname, qtype, -+ DNS_RPZ_TYPE_QNAME, zbits, &rdataset); -+ if (result != ISC_R_SUCCESS) -+ goto cleanup; + /* - * Check rules for the query name if this is the first time - * for the current qname, i.e. we've not been recursing. - * There is a first time for each name in a CNAME chain. -+ * This may have been an attempt to find a qname trigger -+ * before required recursion (qresult_type == 2). -+ * If so and no pre-recursion triggers hit, then quit and -+ * do everything again after recursing. Do not bother saving -+ * the work already done, because recursion is so slow. -+ * If a pre-recursion trigger hit, then no other triggers -+ * can be relevant and so quit. ++ * Check once for triggers for the client IP address. */ - result = rpz_rewrite_name(client, qtype, client->query.qname, - DNS_RPZ_TYPE_QNAME, &rdataset); - if (result != ISC_R_SUCCESS) -+ if (qresult_type == 2) - goto cleanup; - - st->r.label = dns_name_countlabels(client->query.qname); - +- goto cleanup; ++ if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) { ++ zbits = rpz_get_zbits(client, dns_rdatatype_none, ++ DNS_RPZ_TYPE_CLIENT_IP); ++ zbits &= allowed; ++ if (zbits != 0) { ++ isc_netaddr_fromsockaddr(&netaddr, ++ &client->peeraddr); ++ result = rpz_rewrite_ip(client, &netaddr, qtype, ++ DNS_RPZ_TYPE_CLIENT_IP, ++ zbits, &rdataset); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup; ++ } ++ } ++ + /* -+ * Check IP addresses for the qname next, -+ * starting with IPv4 addresses. ++ * Check triggers for the query name if this is the first time ++ * for the current qname. ++ * There is a first time for each name in a CNAME chain + */ - st->state &= ~(DNS_RPZ_DONE_QNAME_IP | DNS_RPZ_DONE_IPv4); - st->state |= DNS_RPZ_DONE_QNAME; ++ if ((st->state & DNS_RPZ_DONE_QNAME) == 0) { ++ result = rpz_rewrite_name(client, client->query.qname, ++ qtype, DNS_RPZ_TYPE_QNAME, ++ allowed, &rdataset); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup; ++ ++ /* ++ * Check IPv4 addresses in A RRs next. ++ * Reset to the start of the NS names. ++ */ ++ st->r.label = dns_name_countlabels(client->query.qname); ++ st->state &= ~(DNS_RPZ_DONE_QNAME_IP | ++ DNS_RPZ_DONE_IPv4); + +- st->r.label = dns_name_countlabels(client->query.qname); ++ } + +- st->state &= ~(DNS_RPZ_DONE_QNAME_IP | DNS_RPZ_DONE_IPv4); +- st->state |= DNS_RPZ_DONE_QNAME; ++ /* ++ * Quit if this was an attempt to find a qname or ++ * client-IP trigger before recursion. ++ * We will be back if no pre-recursion triggers hit. ++ * For example, consider 2 policy zones, both with qname and ++ * IP address triggers. If the qname misses the 1st zone, ++ * then we cannot know whether a hit for the qname in the ++ * 2nd zone matters until after recursing to get the A RRs and ++ * testing them in the first zone. ++ * Do not bother saving the work from this attempt, ++ * because recusion is so slow. ++ */ ++ if (qresult_type == 2) ++ goto cleanup; ++ ++ /* ++ * DNS_RPZ_DONE_QNAME but not DNS_RPZ_DONE_CLIENT_IP ++ * is reset at the end of dealing with each CNAME. ++ */ ++ st->state |= (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME); } /* @@ -1597,7 +1505,7 @@ Index: bin/named/query.c /* * Get NS rrset for each domain in the current qname. */ -@@ -4709,8 +5054,8 @@ +@@ -4709,8 +5077,8 @@ if (st->r.ns_rdataset == NULL || !dns_rdataset_isassociated(st->r.ns_rdataset)) { dns_db_t *db = NULL; @@ -1608,16 +1516,33 @@ Index: bin/named/query.c &db, NULL, &st->r.ns_rdataset, resuming); if (db != NULL) -@@ -4765,7 +5110,7 @@ +@@ -4744,12 +5112,12 @@ + case ISC_R_FAILURE: + rpz_rewrite_ns_skip(client, nsname, result, + DNS_RPZ_DEBUG_LEVEL3, +- "NS db_find() "); ++ " NS db_find()"); + continue; + default: + rpz_rewrite_ns_skip(client, nsname, result, + DNS_RPZ_INFO_LEVEL, +- "unrecognized NS db_find() "); ++ " unrecognized NS db_find()"); + continue; + } + } +@@ -4765,8 +5133,8 @@ dns_rdata_reset(&nsrdata); if (result != ISC_R_SUCCESS) { rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, - DNS_RPZ_TYPE_NSIP, nsname, +- "rdata_tostruct() ", result); + nsname, DNS_RPZ_TYPE_NSIP, - "rdata_tostruct() ", result); ++ " rdata_tostruct()", result); st->m.policy = DNS_RPZ_POLICY_ERROR; goto cleanup; -@@ -4782,11 +5127,11 @@ + } +@@ -4782,11 +5150,11 @@ * Check this NS name if we did not handle it * during a previous recursion. */ @@ -1633,7 +1558,7 @@ Index: bin/named/query.c &rdataset); if (result != ISC_R_SUCCESS) { dns_rdata_freestruct(&ns); -@@ -4797,9 +5142,9 @@ +@@ -4797,9 +5165,9 @@ /* * Check all IP addresses for this NS name. */ @@ -1646,7 +1571,7 @@ Index: bin/named/query.c dns_rdata_freestruct(&ns); if (result != ISC_R_SUCCESS) goto cleanup; -@@ -4809,10 +5154,16 @@ +@@ -4809,10 +5177,16 @@ } while (result == ISC_R_SUCCESS); dns_rdataset_disassociate(st->r.ns_rdataset); st->r.label--; @@ -1664,7 +1589,7 @@ Index: bin/named/query.c */ result = ISC_R_SUCCESS; -@@ -4827,7 +5178,7 @@ +@@ -4827,7 +5201,7 @@ if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU && result != DNS_R_DELEGATION) rpz_log_rewrite(client, ISC_FALSE, st->m.policy, @@ -1673,7 +1598,7 @@ Index: bin/named/query.c rpz_match_clear(st); } if (st->m.policy == DNS_RPZ_POLICY_ERROR) { -@@ -4846,19 +5197,25 @@ +@@ -4846,19 +5220,25 @@ * by the client in DNSSEC or a lack of signatures. */ static isc_boolean_t @@ -1702,7 +1627,7 @@ Index: bin/named/query.c if (sigrdataset == NULL) return (ISC_TRUE); if (dns_rdataset_isassociated(sigrdataset)) -@@ -4938,7 +5295,7 @@ +@@ -4938,7 +5318,7 @@ if (result != ISC_R_SUCCESS) return (result); rpz_log_rewrite(client, ISC_FALSE, st->m.policy, @@ -1711,160 +1636,88 @@ Index: bin/named/query.c ns_client_qnamereplace(client, fname); /* * Turn off DNSSEC because the results of a -@@ -5865,8 +6222,130 @@ - resume: - CTRACE("query_find: resume"); +@@ -5992,13 +6372,15 @@ + } + #endif /* USE_RRL */ - if (!ISC_LIST_EMPTY(client->view->rpz_zones) && - (RECURSIONOK(client) || !client->view->rpz_recursive_only) && -+ /* -+ * Rate limit these responses to this client. -+ * Do not delay counting and handling obvious referrals, -+ * since those won't come here again. -+ * Delay handling delegations for which we are certain to recurse and -+ * return here (DNS_R_DELEGATION, not a child of one of our -+ * own zones, and recursion enabled) -+ * Count each response at most once. -+ */ -+ if (client->view->rrl != NULL && -+ ((fname != NULL && dns_name_isabsolute(fname)) || -+ (result == ISC_R_NOTFOUND && !RECURSIONOK(client))) && -+ !(result == DNS_R_DELEGATION && !is_zone && RECURSIONOK(client)) && -+ (client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0) { -+ dns_rdataset_t nc_rdataset; -+ isc_boolean_t wouldlog; -+ char log_buf[DNS_RRL_LOG_BUF_LEN]; -+ isc_result_t nc_result, resp_result; -+ dns_rrl_result_t rrl_result; -+ -+ client->query.attributes |= NS_QUERYATTR_RRL_CHECKED; -+ -+ wouldlog = isc_log_wouldlog(ns_g_lctx, DNS_RRL_LOG_DROP); -+ tname = fname; -+ if (result == DNS_R_NXDOMAIN) { -+ /* -+ * Use the database origin name to rate limit NXDOMAIN -+ */ -+ if (db != NULL) -+ tname = dns_db_origin(db); -+ resp_result = result; -+ } else if (result == DNS_R_NCACHENXDOMAIN && -+ rdataset != NULL && -+ dns_rdataset_isassociated(rdataset) && -+ (rdataset->attributes & -+ DNS_RDATASETATTR_NEGATIVE) != 0) { -+ /* -+ * Try to use owner name in the negative cache SOA. -+ */ -+ dns_fixedname_init(&fixed); -+ dns_rdataset_init(&nc_rdataset); -+ for (nc_result = dns_rdataset_first(rdataset); -+ nc_result == ISC_R_SUCCESS; -+ nc_result = dns_rdataset_next(rdataset)) { -+ dns_ncache_current(rdataset, -+ dns_fixedname_name(&fixed), -+ &nc_rdataset); -+ if (nc_rdataset.type == dns_rdatatype_soa) { -+ dns_rdataset_disassociate(&nc_rdataset); -+ tname = dns_fixedname_name(&fixed); -+ break; -+ } -+ dns_rdataset_disassociate(&nc_rdataset); -+ } -+ resp_result = DNS_R_NXDOMAIN; -+ } else if (result == DNS_R_NXRRSET || -+ result == DNS_R_EMPTYNAME) { -+ resp_result = DNS_R_NXRRSET; -+ } else if (result == DNS_R_DELEGATION) { -+ resp_result = result; -+ } else if (result == ISC_R_NOTFOUND) { -+ /* -+ * Handle referral to ".", including when recursion -+ * is off or not requested and the hints have not -+ * been loaded or we have "additional-from-cache no". -+ */ -+ tname = dns_rootname; -+ resp_result = DNS_R_DELEGATION; -+ } else { -+ resp_result = ISC_R_SUCCESS; -+ } -+ rrl_result = dns_rrl(client->view, &client->peeraddr, -+ ISC_TF((client->attributes -+ & NS_CLIENTATTR_TCP) != 0), -+ client->message->rdclass, qtype, tname, -+ resp_result, client->now, -+ wouldlog, log_buf, sizeof(log_buf)); -+ if (rrl_result != DNS_RRL_RESULT_OK) { -+ /* -+ * Log dropped or slipped responses in the query -+ * category so that requests are not silently lost. -+ * Starts of rate-limited bursts are logged in -+ * DNS_LOGCATEGORY_RRL. -+ * -+ * Dropped responses are counted with dropped queries -+ * in QryDropped while slipped responses are counted -+ * with other truncated responses in RespTruncated. -+ */ -+ if (wouldlog) { -+ ns_client_log(client, -+ NS_LOGCATEGORY_QUERY_EERRORS, -+ NS_LOGMODULE_QUERY, -+ DNS_RRL_LOG_DROP, -+ "%s", log_buf); -+ } -+ if (!client->view->rrl->log_only) { -+ if (rrl_result == DNS_RRL_RESULT_DROP) { -+ /* -+ * These will also be counted in -+ * dns_nsstatscounter_dropped -+ */ -+ inc_stats(client, -+ dns_nsstatscounter_ratedropped); -+ QUERY_ERROR(DNS_R_DROP); -+ } else { -+ /* -+ * These will also be counted in -+ * dns_nsstatscounter_truncatedresp -+ */ -+ inc_stats(client, -+ dns_nsstatscounter_rateslipped); -+ client->message->flags |= -+ DNS_MESSAGEFLAG_TC; -+ if (resp_result == DNS_R_NXDOMAIN) -+ client->message->rcode = -+ dns_rcode_nxdomain; -+ } -+ goto cleanup; -+ } -+ } -+ } -+ -+ if (client->view->rpzs != NULL && client->view->rpzs->p.num_zones != 0 && ++ if (client->view->rpzs != NULL && ++ client->view->rpzs->p.num_zones != 0 && + (RECURSIONOK(client) || client->view->rpzs->p.no_rd_ok != 0) && rpz_ck_dnssec(client, result, rdataset, sigrdataset) && !RECURSING(client) && (client->query.rpz_st == NULL || -@@ -5910,7 +6389,8 @@ + (client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) && +- !dns_name_equal(client->query.qname, dns_rootname)) { ++ !dns_name_equal(client->query.qname, dns_rootname)) ++ { + isc_result_t rresult; + + rresult = rpz_rewrite(client, qtype, result, resuming); +@@ -6036,12 +6418,17 @@ + rpz_st->state |= DNS_RPZ_REWRITTEN; if (rpz_st->m.policy != DNS_RPZ_POLICY_MISS && rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU && ++ (rpz_st->m.policy != DNS_RPZ_POLICY_TCP_ONLY || ++ (client->attributes & NS_CLIENTATTR_TCP) == 0) && rpz_st->m.policy != DNS_RPZ_POLICY_ERROR) { - if (rpz_st->m.type == DNS_RPZ_TYPE_QNAME) { -+ if (rpz_st->m.type == DNS_RPZ_TYPE_QNAME || -+ rpz_st->m.type == DNS_RPZ_TYPE_CLIENT_IP) { - result = dns_name_copy(client->query.qname, - fname, NULL); - RUNTIME_CHECK(result == ISC_R_SUCCESS); -@@ -5934,6 +6414,9 @@ +- result = dns_name_copy(client->query.qname, +- fname, NULL); +- RUNTIME_CHECK(result == ISC_R_SUCCESS); +- } ++ /* We got a hit and are going to answer with our ++ * fiction. Ensure that we answer with the name ++ * we looked up even if we were stopped short ++ * in recursion or for a deferral. ++ */ ++ rresult = dns_name_copy(client->query.qname, ++ fname, NULL); ++ RUNTIME_CHECK(rresult == ISC_R_SUCCESS); + rpz_clean(&zone, &db, &node, NULL); + if (rpz_st->m.rdataset != NULL) { + query_putrdataset(client, &rdataset); +@@ -6061,6 +6448,27 @@ rpz_st->m.zone = NULL; switch (rpz_st->m.policy) { ++ case DNS_RPZ_POLICY_TCP_ONLY: ++ client->message->flags |= DNS_MESSAGEFLAG_TC; ++ if (result == DNS_R_NXDOMAIN || ++ result == DNS_R_NCACHENXDOMAIN) ++ client->message->rcode = ++ dns_rcode_nxdomain; ++ else ++ result = ISC_R_SUCCESS; ++ rpz_log_rewrite(client, ISC_FALSE, ++ rpz_st->m.policy, ++ rpz_st->m.type, zone, ++ rpz_st->p_name); ++ goto cleanup; + case DNS_RPZ_POLICY_DROP: ++ result = ISC_R_SUCCESS; + QUERY_ERROR(DNS_R_DROP); -+ break; ++ rpz_log_rewrite(client, ISC_FALSE, ++ rpz_st->m.policy, ++ rpz_st->m.type, zone, ++ rpz_st->p_name); ++ goto cleanup; case DNS_RPZ_POLICY_NXDOMAIN: result = DNS_R_NXDOMAIN; break; -@@ -6002,7 +6485,7 @@ +@@ -6073,8 +6481,8 @@ + result != DNS_R_CNAME) { + /* + * We will add all of the rdatasets of +- * the node by iterating, setting the +- * TTL then. ++ * the node by iterating later, ++ * and set the TTL then. + */ + if (dns_rdataset_isassociated(rdataset)) + dns_rdataset_disassociate(rdataset); +@@ -6129,7 +6537,7 @@ rpz_st->q.is_zone = is_zone; is_zone = ISC_TRUE; rpz_log_rewrite(client, ISC_FALSE, rpz_st->m.policy, @@ -1873,29 +1726,10 @@ Index: bin/named/query.c } } -@@ -7318,12 +7801,14 @@ - } - - if (eresult != ISC_R_SUCCESS && -- (!PARTIALANSWER(client) || WANTRECURSION(client))) { -+ (!PARTIALANSWER(client) || WANTRECURSION(client) -+ || eresult == DNS_R_DROP)) { - if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) { - /* - * This was a duplicate query that we are -- * recursing on. Don't send a response now. -- * The original query will still cause a response. -+ * recursing on or the result of rate limiting. -+ * Don't send a response now for a duplicate query, -+ * because the original will still cause a response. - */ - query_next(client, eresult); - } else { -Index: bin/named/server.c -=================================================================== ---- bin/named/server.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/server.c 2013-08-05 14:14:45.879498052 +0200 -@@ -373,7 +373,8 @@ +diff -r -u bin/named/server.c-orig bin/named/server.c +--- bin/named/server.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/named/server.c 2004-01-01 00:00:00.000000000 +0000 +@@ -375,7 +375,8 @@ static isc_result_t configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, @@ -1905,7 +1739,7 @@ Index: bin/named/server.c static isc_result_t add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx); -@@ -1549,17 +1550,24 @@ +@@ -1551,17 +1552,24 @@ } static isc_result_t @@ -1934,7 +1768,7 @@ Index: bin/named/server.c if (new == NULL) { cfg_obj_log(rpz_obj, ns_g_lctx, DNS_RPZ_ERROR_LEVEL, "no memory for response policy zones"); -@@ -1567,20 +1575,28 @@ +@@ -1569,20 +1577,29 @@ } memset(new, 0, sizeof(*new)); @@ -1950,6 +1784,7 @@ Index: bin/named/server.c + dns_name_init(&new->nsip, NULL); dns_name_init(&new->passthru, NULL); + dns_name_init(&new->drop, NULL); ++ dns_name_init(&new->tcp_only, NULL); dns_name_init(&new->cname, NULL); - ISC_LIST_INITANDAPPEND(view->rpz_zones, new, link); + new->num = view->rpzs->p.num_zones++; @@ -1969,7 +1804,7 @@ Index: bin/named/server.c obj = cfg_tuple_get(rpz_obj, "max-policy-ttl"); if (cfg_obj_isuint32(obj)) { -@@ -1588,6 +1604,8 @@ +@@ -1590,6 +1607,8 @@ } else { new->max_policy_ttl = ttl_def; } @@ -1978,7 +1813,7 @@ Index: bin/named/server.c str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name")); result = configure_rpz_name(view, rpz_obj, &new->origin, str, "zone"); -@@ -1598,25 +1616,45 @@ +@@ -1600,25 +1619,50 @@ "invalid zone name '%s'", str); return (DNS_R_EMPTYLABEL); } @@ -2027,10 +1862,15 @@ Index: bin/named/server.c + + result = configure_rpz_name(view, rpz_obj, &new->drop, + DNS_RPZ_DROP_NAME, "name"); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ ++ result = configure_rpz_name(view, rpz_obj, &new->tcp_only, ++ DNS_RPZ_TCP_ONLY_NAME, "name"); if (result != ISC_R_SUCCESS) return (result); -@@ -1635,8 +1673,280 @@ +@@ -1637,6 +1681,116 @@ return (result); } } @@ -2144,183 +1984,19 @@ Index: bin/named/server.c + } + if (pview != NULL) + dns_view_detach(&pview); -+ -+ return (ISC_R_SUCCESS); -+} -+ -+#define CHECK_RRL(cond, pat, val1, val2) \ -+ do { \ -+ if (!(cond)) { \ -+ cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR, \ -+ pat, val1, val2); \ -+ result = ISC_R_RANGE; \ -+ goto cleanup; \ -+ } \ -+ } while (0) -+ -+#define CHECK_RRL_RATE(rate, def, max_rate, name) \ -+ do { \ -+ obj = NULL; \ -+ rrl->rate.str = name; \ -+ result = cfg_map_get(map, name, &obj); \ -+ if (result == ISC_R_SUCCESS) { \ -+ rrl->rate.r = cfg_obj_asuint32(obj); \ -+ CHECK_RRL(rrl->rate.r <= max_rate, \ -+ name" %d > %d", \ -+ rrl->rate.r, max_rate); \ -+ } else { \ -+ rrl->rate.r = def; \ -+ } \ -+ rrl->rate.scaled = rrl->rate.r; \ -+ } while (0) -+ -+static isc_result_t -+configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) { -+ const cfg_obj_t *obj; -+ dns_rrl_t *rrl; -+ isc_result_t result; -+ int min_entries, i, j; -+ -+ /* -+ * Most DNS servers have few clients, but intentinally open -+ * recursive and authoritative servers often have many. -+ * So start with a small number of entries unless told otherwise -+ * to reduce cold-start costs. -+ */ -+ min_entries = 500; -+ obj = NULL; -+ result = cfg_map_get(map, "min-table-size", &obj); -+ if (result == ISC_R_SUCCESS) { -+ min_entries = cfg_obj_asuint32(obj); -+ if (min_entries < 1) -+ min_entries = 1; -+ } -+ result = dns_rrl_init(&rrl, view, min_entries); -+ if (result != ISC_R_SUCCESS) -+ return (result); -+ -+ i = ISC_MAX(20000, min_entries); -+ obj = NULL; -+ result = cfg_map_get(map, "max-table-size", &obj); -+ if (result == ISC_R_SUCCESS) { -+ i = cfg_obj_asuint32(obj); -+ CHECK_RRL(i >= min_entries, -+ "max-table-size %d < min-table-size %d", -+ i, min_entries); -+ } -+ rrl->max_entries = i; -+ -+ CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE, -+ "responses-per-second"); -+ CHECK_RRL_RATE(referrals_per_second, -+ rrl->responses_per_second.r, DNS_RRL_MAX_RATE, -+ "referrals-per-second"); -+ CHECK_RRL_RATE(nodata_per_second, -+ rrl->responses_per_second.r, DNS_RRL_MAX_RATE, -+ "nodata-per-second"); -+ CHECK_RRL_RATE(nxdomains_per_second, -+ rrl->responses_per_second.r, DNS_RRL_MAX_RATE, -+ "nxdomains-per-second"); -+ CHECK_RRL_RATE(errors_per_second, -+ rrl->responses_per_second.r, DNS_RRL_MAX_RATE, -+ "errors-per-second"); -+ -+ CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, -+ "all-per-second"); -+ -+ CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, -+ "slip"); -+ -+ i = 15; -+ obj = NULL; -+ result = cfg_map_get(map, "window", &obj); -+ if (result == ISC_R_SUCCESS) { -+ i = cfg_obj_asuint32(obj); -+ CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW, -+ "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW); -+ } -+ rrl->window = i; -+ -+ i = 0; -+ obj = NULL; -+ result = cfg_map_get(map, "qps-scale", &obj); -+ if (result == ISC_R_SUCCESS) { -+ i = cfg_obj_asuint32(obj); -+ CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, ""); -+ } -+ rrl->qps_scale = i; -+ rrl->qps = 1.0; -+ -+ i = 24; -+ obj = NULL; -+ result = cfg_map_get(map, "ipv4-prefix-length", &obj); -+ if (result == ISC_R_SUCCESS) { -+ i = cfg_obj_asuint32(obj); -+ CHECK_RRL(i >= 8 && i <= 32, -+ "invalid 'ipv4-prefix-length %d'%s", i, ""); -+ } -+ rrl->ipv4_prefixlen = i; -+ if (i == 32) -+ rrl->ipv4_mask = 0xffffffff; -+ else -+ rrl->ipv4_mask = htonl(0xffffffff << (32-i)); -+ -+ i = 56; -+ obj = NULL; -+ result = cfg_map_get(map, "ipv6-prefix-length", &obj); -+ if (result == ISC_R_SUCCESS) { -+ i = cfg_obj_asuint32(obj); -+ CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX, -+ "ipv6-prefix-length %d < 16 or > %d", -+ i, DNS_RRL_MAX_PREFIX); -+ } -+ rrl->ipv6_prefixlen = i; -+ for (j = 0; j < 4; ++j) { -+ if (i <= 0) { -+ rrl->ipv6_mask[j] = 0; -+ } else if (i < 32) { -+ rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i)); -+ } else { -+ rrl->ipv6_mask[j] = 0xffffffff; -+ } -+ i -= 32; -+ } -+ -+ obj = NULL; -+ result = cfg_map_get(map, "exempt-clients", &obj); -+ if (result == ISC_R_SUCCESS) { -+ result = cfg_acl_fromconfig(obj, config, ns_g_lctx, -+ ns_g_aclconfctx, ns_g_mctx, -+ 0, &rrl->exempt); -+ CHECK_RRL(result == ISC_R_SUCCESS, -+ "invalid %s%s", "address match list", ""); -+ } -+ -+ obj = NULL; -+ result = cfg_map_get(map, "log-only", &obj); -+ if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj)) -+ rrl->log_only = ISC_TRUE; -+ else -+ rrl->log_only = ISC_FALSE; return (ISC_R_SUCCESS); -+ -+ cleanup: -+ dns_rrl_view_destroy(view); -+ return (result); } - - /* -@@ -1705,7 +2015,7 @@ +@@ -2096,7 +2250,7 @@ dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; unsigned int query_timeout, ndisp; struct cfg_context *nzctx; - dns_rpz_zone_t *rpz; -+ isc_boolean_t old_rpz_ok; ++ isc_boolean_t old_rpz_ok = ISC_FALSE; REQUIRE(DNS_VIEW_VALID(view)); -@@ -1810,44 +2120,7 @@ +@@ -2194,44 +2348,7 @@ obj = NULL; if (view->rdclass == dns_rdataclass_in && need_hints && ns_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) { @@ -2366,7 +2042,7 @@ Index: bin/named/server.c } /* -@@ -1868,22 +2141,29 @@ +@@ -2252,22 +2369,29 @@ { const cfg_obj_t *zconfig = cfg_listelt_value(element); CHECK(configure_zone(config, zconfig, vconfig, mctx, view, @@ -2409,7 +2085,7 @@ Index: bin/named/server.c } } -@@ -1909,7 +2189,7 @@ +@@ -2293,7 +2417,7 @@ const cfg_obj_t *zconfig = cfg_listelt_value(element); CHECK(configure_zone(config, zconfig, vconfig, mctx, view, actx, @@ -2418,22 +2094,7 @@ Index: bin/named/server.c } } -@@ -3043,6 +3323,14 @@ - } - } - -+ obj = NULL; -+ result = ns_config_get(maps, "rate-limit", &obj); -+ if (result == ISC_R_SUCCESS) { -+ result = configure_rrl(view, config, obj); -+ if (result != ISC_R_SUCCESS) -+ goto cleanup; -+ } -+ - result = ISC_R_SUCCESS; - - cleanup: -@@ -3375,7 +3663,8 @@ +@@ -3737,7 +3861,8 @@ static isc_result_t configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view, @@ -2443,7 +2104,7 @@ Index: bin/named/server.c { dns_view_t *pview = NULL; /* Production view */ dns_zone_t *zone = NULL; /* New or reused zone */ -@@ -3396,8 +3685,7 @@ +@@ -3758,8 +3883,7 @@ const char *zname; dns_rdataclass_t zclass; const char *ztypestr; @@ -2453,7 +2114,7 @@ Index: bin/named/server.c options = NULL; (void)cfg_map_get(config, "options", &options); -@@ -3559,18 +3847,15 @@ +@@ -3921,18 +4045,15 @@ INSIST(dupzone == NULL); /* @@ -2478,7 +2139,7 @@ Index: bin/named/server.c } /* -@@ -3581,7 +3866,9 @@ +@@ -3943,7 +4064,9 @@ * - The zone is compatible with the config * options (e.g., an existing master zone cannot * be reused if the options specify a slave zone) @@ -2489,7 +2150,7 @@ Index: bin/named/server.c */ result = dns_viewlist_find(&ns_g_server->viewlist, view->name, view->rdclass, &pview); -@@ -3595,7 +3882,8 @@ +@@ -3957,7 +4080,8 @@ if (zone != NULL && !ns_zone_reusable(zone, zconfig)) dns_zone_detach(&zone); @@ -2499,7 +2160,7 @@ Index: bin/named/server.c dns_zone_detach(&zone); if (zone != NULL) { -@@ -3620,8 +3908,8 @@ +@@ -3982,8 +4106,8 @@ dns_zone_setstats(zone, ns_g_server->zonestats); } @@ -2510,7 +2171,7 @@ Index: bin/named/server.c if (result != ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_ERROR, -@@ -7834,7 +8122,8 @@ +@@ -8219,7 +8343,8 @@ RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_view_thaw(view); result = configure_zone(cfg->config, parms, vconfig, @@ -2520,170 +2181,569 @@ Index: bin/named/server.c dns_view_freeze(view); isc_task_endexclusive(server->task); if (result != ISC_R_SUCCESS) -Index: bin/named/statschannel.c -=================================================================== ---- bin/named/statschannel.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/named/statschannel.c 2013-08-05 14:14:45.879498052 +0200 -@@ -206,6 +206,10 @@ - SET_NSSTATDESC(updatebadprereq, - "updates rejected due to prerequisite failure", - "UpdateBadPrereq"); -+ SET_NSSTATDESC(ratedropped, "responses dropped for rate limits", -+ "RateDropped"); -+ SET_NSSTATDESC(rateslipped, "responses truncated for rate limits", -+ "RateSlipped"); - SET_NSSTATDESC(rpz_rewrites, "response policy zone rewrites", - "RPZRewrites"); - INSIST(i == dns_nsstatscounter_max); -Index: bin/tests/system/README -=================================================================== ---- bin/tests/system/README.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/README 2013-08-05 14:14:45.879498052 +0200 -@@ -17,6 +17,7 @@ - nsupdate/ Dynamic update and IXFR tests - resolver/ Regression tests for resolver bugs that have been fixed - (not a complete resolver test suite) -+ rrl/ query rate limiting - rpz/ Tests of response policy zone (RPZ) rewriting - stub/ Tests of stub zone functionality - unknown/ Unknown type and class tests -Index: bin/tests/system/conf.sh.in -=================================================================== ---- bin/tests/system/conf.sh.in.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/conf.sh.in 2013-08-05 14:14:45.879498052 +0200 -@@ -62,7 +62,7 @@ - database dlv dlvauto dlz dlzexternal dname dns64 dnssec ecdsa - formerr forward glue gost ixfr inline limits logfileconfig - lwresd masterfile masterformat metadata notify nsupdate pending -- pkcs11 redirect resolver rndc rpz rrsetorder rsabigexponent -+ pkcs11 redirect resolver rndc rpz rrl rrsetorder rsabigexponent - smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown - upforwd verify views wildcard xfer xferquota zonechecks" - -Index: bin/tests/system/rpz/Makefile.in -=================================================================== ---- bin/tests/system/rpz/Makefile.in.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/Makefile.in 2013-08-05 14:14:45.879498052 +0200 -@@ -12,8 +12,6 @@ - # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - # PERFORMANCE OF THIS SOFTWARE. - --# $Id$ -- - - srcdir = @srcdir@ - VPATH = @srcdir@ -Index: bin/tests/system/rpz/clean.sh -=================================================================== ---- bin/tests/system/rpz/clean.sh.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/clean.sh 2013-08-05 14:14:45.879498052 +0200 -@@ -12,8 +12,6 @@ - # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - # PERFORMANCE OF THIS SOFTWARE. - --# $Id$ -- - - +diff -r -u bin/tests/system/rpz/Makefile-orig bin/tests/system/rpz/Makefile +--- bin/tests/system/rpz/Makefile-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/Makefile 2004-01-01 00:00:00.000000000 +0000 +@@ -0,0 +1,478 @@ ++# Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") ++# ++# 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$ ++ ++ ++srcdir = . ++ ++top_srcdir = ../../../.. ++ ++VERSION=9.10.0pre-alpha ++ ++# Copyright (C) 2004, 2005, 2007, 2012 Internet Systems Consortium, Inc. ("ISC") ++# Copyright (C) 1999-2001 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: includes.in,v 1.21 2007/06/19 23:47:24 tbox Exp $ ++ ++# Search for machine-generated header files in the build tree, ++# and for normal headers in the source tree (${top_srcdir}). ++# We only need to look in OS-specific subdirectories for the ++# latter case, because there are no machine-generated OS-specific ++# headers. ++ ++ISC_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/isc/include \ ++ -I${top_srcdir}/lib/isc \ ++ -I${top_srcdir}/lib/isc/include \ ++ -I${top_srcdir}/lib/isc/unix/include \ ++ -I${top_srcdir}/lib/isc/pthreads/include \ ++ -I${top_srcdir}/lib/isc/x86_32/include ++ ++ISCCC_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/isccc/include \ ++ -I${top_srcdir}/lib/isccc/include ++ ++ISCCFG_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/isccfg/include \ ++ -I${top_srcdir}/lib/isccfg/include ++ ++DNS_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/dns/include \ ++ -I${top_srcdir}/lib/dns/include ++ ++LWRES_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/lwres/include \ ++ -I${top_srcdir}/lib/lwres/unix/include \ ++ -I${top_srcdir}/lib/lwres/include ++ ++BIND9_INCLUDES = -I/usr/home/vjs/isc/work/rpz3/lib/bind9/include \ ++ -I${top_srcdir}/lib/bind9/include ++ ++TEST_INCLUDES = \ ++ -I${top_srcdir}/lib/tests/include ++ ++CINCLUDES = ++ ++CDEFINES = ++CWARNINGS = ++ ++DNSLIBS = ++ISCLIBS = . ++ ++DNSDEPLIBS = ++ISCDEPLIBS = ++ ++DEPLIBS = ++ ++LIBS = -L/usr/local/lib -lxml2 -lz -L/usr/local/lib -liconv -lm ++ ++TARGETS = rpz ++ ++RPZOBJS = rpz.o ++ ++SRCS = rpz.c ++ ++# Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") ++# Copyright (C) 1998-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$ ++ ++### ++### Common Makefile rules for BIND 9. ++### ++ ++### ++### Paths ++### ++### Note: paths that vary by Makefile MUST NOT be listed ++### here, or they won't get expanded correctly. ++ ++prefix = /usr ++exec_prefix = ${prefix} ++bindir = ${exec_prefix}/bin ++sbindir = ${exec_prefix}/sbin ++includedir = ${prefix}/include ++libdir = ${exec_prefix}/lib ++sysconfdir = /etc/namedb ++localstatedir = ${prefix}/var ++mandir = ${datarootdir}/man ++datarootdir = ${prefix}/share ++ ++DESTDIR = ++ ++ ++ ++top_builddir = /usr/home/vjs/isc/work/rpz3 ++ ++### ++### All ++### ++### Makefile may define: ++### TARGETS ++ ++all: subdirs ${TARGETS} testdirs ++ ++### ++### Subdirectories ++### ++### Makefile may define: ++### SUBDIRS ++ ++ALL_SUBDIRS = ${SUBDIRS} nulldir ++ALL_TESTDIRS = ${TESTDIRS} nulldir ++ ++# ++# We use a single-colon rule so that additional dependencies of ++# subdirectories can be specified after the inclusion of this file. ++# The "depend" and "testdirs" targets are treated the same way. ++# ++subdirs: ++ @for i in ${ALL_SUBDIRS}; do \ ++ if [ "$$i" != "nulldir" -a -d $$i ]; then \ ++ echo "making all in `pwd`/$$i"; \ ++ (cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" all) || exit 1; \ ++ fi; \ ++ done ++ ++# ++# Tests are built after the targets instead of before ++# ++testdirs: ++ @for i in ${ALL_TESTDIRS}; do \ ++ if [ "$$i" != "nulldir" -a -d $$i ]; then \ ++ echo "making all in `pwd`/$$i"; \ ++ (cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" all) || exit 1; \ ++ fi; \ ++ done ++ ++install:: all ++ ++install clean distclean maintainer-clean doc docclean man manclean:: ++ @for i in ${ALL_SUBDIRS} ${ALL_TESTDIRS}; do \ ++ if [ "$$i" != "nulldir" -a -d $$i ]; then \ ++ echo "making $@ in `pwd`/$$i"; \ ++ (cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" $@) || exit 1; \ ++ fi; \ ++ done ++ ++### ++### C Programs ++### ++### Makefile must define ++### CC ++### Makefile may define ++### CFLAGS ++### LDFLAGS ++### CINCLUDES ++### CDEFINES ++### CWARNINGS ++### User may define externally ++### EXT_CFLAGS ++ ++CC = gcc -pthread ++CFLAGS = -g -I/usr/local/include/libxml2 -I/usr/local/include ++LDFLAGS = ++STD_CINCLUDES = ++STD_CDEFINES = -D_THREAD_SAFE ++STD_CWARNINGS = -W -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wformat -Wpointer-arith -fno-strict-aliasing ++ ++BUILD_CC = gcc -pthread ++BUILD_CFLAGS = -g -I/usr/local/include/libxml2 -I/usr/local/include ++BUILD_CPPFLAGS = ++BUILD_LDFLAGS = ++BUILD_LIBS = -L/usr/local/lib -lxml2 -lz -L/usr/local/lib -liconv -lm ++ ++.SUFFIXES: ++.SUFFIXES: .c .o ++ ++ALWAYS_INCLUDES = -I${top_builddir} ++ALWAYS_DEFINES = -D_REENTRANT ++ALWAYS_WARNINGS = ++ ++ALL_CPPFLAGS = \ ++ ${ALWAYS_INCLUDES} ${CINCLUDES} ${STD_CINCLUDES} \ ++ ${ALWAYS_DEFINES} ${CDEFINES} ${STD_CDEFINES} ++ ++ALL_CFLAGS = ${EXT_CFLAGS} ${ALL_CPPFLAGS} ${CFLAGS} \ ++ ${ALWAYS_WARNINGS} ${STD_CWARNINGS} ${CWARNINGS} ++ ++.c.o: ++ ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c $< ++ ++SHELL = /bin/sh ++LIBTOOL = ++LIBTOOL_MODE_COMPILE = ${LIBTOOL} ++LIBTOOL_MODE_INSTALL = ${LIBTOOL} ++LIBTOOL_MODE_LINK = ${LIBTOOL} ++PURIFY = ++ ++MKDEP = ${SHELL} ${top_builddir}/make/mkdep ++ ++### ++### This is a template compound command to build an executable binary with ++### an internal symbol table. ++### This process is tricky. We first link all objects including a tentative ++### empty symbol table, then get a tentative list of symbols from the resulting ++### binary ($@tmp0). Next, we re-link all objects, but this time with the ++### symbol table just created ($tmp@1). The set of symbols should be the same, ++### but the corresponding addresses would be changed due to the difference on ++### the size of symbol tables. So we create the symbol table and re-create the ++### objects once again. Finally, we check the symbol table embedded in the ++### final binaryis consistent with the binary itself; otherwise the process is ++### terminated. ++### ++### To minimize the overhead of creating symbol tables, the autoconf switch ++### --enable-symtable takes an argument so that the symbol table can be created ++### on a per application basis: unless the argument is set to "all", the symbol ++### table is created only when a shell (environment) variable "MAKE_SYMTABLE" is ++### set to a non-null value in the rule to build the executable binary. ++### ++### Each Makefile.in that uses this macro is expected to define "LIBS" and ++### "NOSYMLIBS"; the former includes libisc with an empty symbol table, and ++### the latter includes libisc without the definition of a symbol table. ++### The rule to make the executable binary will look like this ++### binary: ${OBJS} ++### #export MAKE_SYMTABLE="yes"; \ <- enable if symtable is always needed ++### export BASEOBJS="${OBJS}"; \ ++### ${FINALBUILDCMD} ++### ++### Normally, ${LIBS} includes all necessary libraries to build the binary; ++### there are some exceptions however, where the rule lists some of the ++### necessary libraries explicitly in addition to (or instead of) ${LIBS}, ++### like this: ++### binary: ${OBJS} ++### cc -o $@ ${OBJS} ${OTHERLIB1} ${OTHERLIB2} ${lIBS} ++### in order to modify such a rule to use this compound command, a separate ++### variable "LIBS0" should be deinfed for the explicitly listed libraries, ++### while making sure ${LIBS} still includes libisc. So the above rule would ++### be modified as follows: ++### binary: ${OBJS} ++### export BASEOBJS="${OBJS}"; \ ++### export LIBS0="${OTHERLIB1} ${OTHERLIB2}"; \ ++### ${FINALBUILDCMD} ++### See bin/check/Makefile.in for a complete example of the use of LIBS0. ++### ++FINALBUILDCMD = if [ X"${MKSYMTBL_PROGRAM}" = X -o X"$${MAKE_SYMTABLE:-${ALWAYS_MAKE_SYMTABLE}}" = X ] ; then \ ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ $${BASEOBJS} $${LIBS0} ${LIBS}; \ ++ else \ ++ rm -f $@tmp0; \ ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@tmp0 $${BASEOBJS} $${LIBS0} ${LIBS} || exit 1; \ ++ rm -f $@-symtbl.c $@-symtbl.o; \ ++ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ ++ -o $@-symtbl.c $@tmp0 || exit 1; \ ++ $(MAKE) $@-symtbl.o || exit 1; \ ++ rm -f $@tmp1; \ ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@tmp1 $${BASEOBJS} $@-symtbl.o $${LIBS0} ${NOSYMLIBS} || exit 1; \ ++ rm -f $@-symtbl.c $@-symtbl.o; \ ++ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ ++ -o $@-symtbl.c $@tmp1 || exit 1; \ ++ $(MAKE) $@-symtbl.o || exit 1; \ ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@tmp2 $${BASEOBJS} $@-symtbl.o $${LIBS0} ${NOSYMLIBS}; \ ++ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ ++ -o $@-symtbl2.c $@tmp2; \ ++ count=0; \ ++ until diff $@-symtbl.c $@-symtbl2.c > /dev/null ; \ ++ do \ ++ count=`expr $$count + 1` ; \ ++ test $$count = 42 && exit 1 ; \ ++ rm -f $@-symtbl.c $@-symtbl.o; \ ++ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ ++ -o $@-symtbl.c $@tmp2 || exit 1; \ ++ $(MAKE) $@-symtbl.o || exit 1; \ ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} \ ++ ${LDFLAGS} -o $@tmp2 $${BASEOBJS} $@-symtbl.o \ ++ $${LIBS0} ${NOSYMLIBS}; \ ++ ${MKSYMTBL_PROGRAM} ${top_srcdir}/util/mksymtbl.pl \ ++ -o $@-symtbl2.c $@tmp2; \ ++ done ; \ ++ mv $@tmp2 $@; \ ++ rm -f $@tmp0 $@tmp1 $@tmp2 $@-symtbl2.c; \ ++ fi ++ ++cleandir: distclean ++superclean: maintainer-clean ++ ++clean distclean maintainer-clean:: ++ rm -f *.o *.o *.lo *.la core *.core *-symtbl.c *tmp0 *tmp1 *tmp2 ++ rm -rf .depend .libs ++ ++distclean maintainer-clean:: ++ rm -f Makefile ++ ++depend: ++ @for i in ${ALL_SUBDIRS}; do \ ++ if [ "$$i" != "nulldir" -a -d $$i ]; then \ ++ echo "making depend in `pwd`/$$i"; \ ++ (cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" $@) || exit 1; \ ++ fi; \ ++ done ++ @if [ X"${srcdir}" != X. ] ; then \ ++ if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \ ++ echo ${MKDEP} -vpath ${srcdir} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${MKDEP} -vpath ${srcdir} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ echo ${MKDEP} -vpath ${srcdir} -ap ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${MKDEP} -vpath ${srcdir} -ap ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${DEPENDEXTRA} \ ++ elif [ X"${SRCS}" != X ] ; then \ ++ echo ${MKDEP} -vpath ${srcdir} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${MKDEP} -vpath ${srcdir} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${DEPENDEXTRA} \ ++ elif [ X"${PSRCS}" != X ] ; then \ ++ echo ${MKDEP} -vpath ${srcdir} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${MKDEP} -vpath ${srcdir} -p ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${DEPENDEXTRA} \ ++ fi \ ++ else \ ++ if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \ ++ echo ${MKDEP} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${MKDEP} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${MKDEP} -ap ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${DEPENDEXTRA} \ ++ elif [ X"${SRCS}" != X ] ; then \ ++ echo ${MKDEP} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${MKDEP} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${SRCS}; \ ++ ${DEPENDEXTRA} \ ++ elif [ X"${PSRCS}" != X ] ; then \ ++ echo ${MKDEP} ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${MKDEP} -p ${ALL_CPPFLAGS} ${ALL_CFLAGS} ${PSRCS}; \ ++ ${DEPENDEXTRA} \ ++ fi \ ++ fi ++ ++FORCE: ++ ++### ++### Libraries ++### ++ ++AR = /usr/local/bin/ar ++ARFLAGS = cruv ++RANLIB = ranlib ++ ++### ++### Installation ++### ++ ++INSTALL = /usr/bin/install -c ++INSTALL_PROGRAM = ${INSTALL} ++LINK_PROGRAM = ln -s ++INSTALL_SCRIPT = ${INSTALL} ++INSTALL_DATA = ${INSTALL} -m 644 ++ ++### ++### Programs used when generating documentation. It's ok for these ++### not to exist when not generating documentation. ++### ++ ++XSLTPROC = xsltproc --novalid --xinclude --nonet ++PERL = /usr/local/bin/perl5 ++LATEX = latex ++PDFLATEX = pdflatex ++W3M = w3m ++ ++### ++### Script language program used to create internal symbol tables ++### ++MKSYMTBL_PROGRAM = /usr/local/bin/perl5 ++ ++### ++### Switch to create internal symbol table selectively ++### ++ALWAYS_MAKE_SYMTABLE = ++ ++### ++### DocBook -> HTML ++### DocBook -> man page ++### ++ ++.SUFFIXES: .docbook .html .1 .2 .3 .4 .5 .6 .7 .8 ++ ++.docbook.html: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-docbook-html.xsl $< ++ ++.docbook.1: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.2: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.3: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.4: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.5: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.6: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.7: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++.docbook.8: ++ ${XSLTPROC} -o $@ ${top_srcdir}/doc/xsl/isc-manpage.xsl $< ++ ++### ++### Python executable ++### ++.SUFFIXES: .py ++.py: ++ cp -f $< $@ ++ chmod +x $@ ++ ++ ++all: rpz ++ ++rpz: ${RPZOBJS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${RPZOBJS} ${LIBS} ++ ++clean distclean:: ++ rm -f ${TARGETS} ++ ++# DO NOT DELETE THIS LINE -- mkdep uses it. ++# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. ++ ++rpz.o: rpz.c /usr/home/vjs/isc/work/rpz3/config.h /usr/include/stdlib.h \ ++ /usr/include/sys/cdefs.h /usr/include/sys/_null.h \ ++ /usr/include/sys/_types.h /usr/include/machine/_types.h \ ++ /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h ++ ++# IF YOU PUT ANYTHING HERE IT WILL GO AWAY +diff -r -u bin/tests/system/rpz/clean.sh-orig bin/tests/system/rpz/clean.sh +--- bin/tests/system/rpz/clean.sh-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/clean.sh 2004-01-01 00:00:00.000000000 +0000 +@@ -19,7 +19,7 @@ # Clean up after rpz tests. -Index: bin/tests/system/rpz/ns1/named.conf -=================================================================== ---- bin/tests/system/rpz/ns1/named.conf.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns1/named.conf 2013-08-05 14:14:45.880498065 +0200 -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ --/* $Id$ */ + rm -f proto.* dsset-* random.data trusted.conf dig.out* nsupdate.tmp ns*/*tmp +-rm -f ns*/*.key ns*/*.private ns2/tld2s.db ns2/bl.tld2.db ++rm -f ns*/*.key ns*/*.private ns2/tld2s.db + rm -f ns3/bl*.db ns*/*switch ns5/requests ns5/example.db ns5/bl.db ns5/*.perf + rm -f */named.memstats */named.run */named.stats */session.key + rm -f */*.jnl */*.core */*.pid +diff -r -u bin/tests/system/rpz/ns1/root.db-orig bin/tests/system/rpz/ns1/root.db +--- bin/tests/system/rpz/ns1/root.db-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns1/root.db 2004-01-01 00:00:00.000000000 +0000 +@@ -38,3 +38,6 @@ + ; performance test + tld5. NS ns.tld5. + ns.tld5. A 10.53.0.5 ++ ++; generate SERVFAIL ++servfail NS ns.tld2. +diff -r -u bin/tests/system/rpz/ns2/bl.tld2.db-orig bin/tests/system/rpz/ns2/bl.tld2.db +--- bin/tests/system/rpz/ns2/bl.tld2.db-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns2/bl.tld2.db 2004-01-01 00:00:00.000000000 +0000 +@@ -0,0 +1,27 @@ ++; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++; ++; 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$ ++ ++ ++ ++; master for slave RPZ zone ++ ++$TTL 3600 ++@ SOA rpz.tld2. hostmaster.ns.tld2. ( 1 3600 1200 604800 60 ) ++ NS ns ++ns A 10.53.0.2 ++ A 10.53.0.3 ++ ++32.1.7.168.192.rpz-ip CNAME . +diff -r -u bin/tests/system/rpz/ns2/named.conf-orig bin/tests/system/rpz/ns2/named.conf +--- bin/tests/system/rpz/ns2/named.conf-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns2/named.conf 2004-01-01 00:00:00.000000000 +0000 +@@ -32,14 +32,6 @@ + notify no; + }; + +-key rndc_key { +- secret "1234abcd8765"; +- algorithm hmac-sha256; +-}; +-controls { +- inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; +-}; - + include "../trusted.conf"; + zone "." { type hint; file "hints"; }; - controls { /* empty */ }; +@@ -53,4 +45,4 @@ -Index: bin/tests/system/rpz/ns1/root.db -=================================================================== ---- bin/tests/system/rpz/ns1/root.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns1/root.db 2013-08-05 14:14:45.880498065 +0200 -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. + zone "tld2s." {type master; file "tld2s.db";}; --; $Id$ -- - - $TTL 120 - . SOA ns. hostmaster.ns. ( 1 3600 1200 604800 60 ) -Index: bin/tests/system/rpz/ns2/base-tld2s.db -=================================================================== ---- bin/tests/system/rpz/ns2/base-tld2s.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns2/base-tld2s.db 2013-08-05 14:14:45.880498065 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ -- - - - ; RPZ rewrite responses from this signed zone -Index: bin/tests/system/rpz/ns2/hints -=================================================================== ---- bin/tests/system/rpz/ns2/hints.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns2/hints 2013-08-05 14:14:45.880498065 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ -- - - . 120 NS ns. - ns. 120 A 10.53.0.1 -Index: bin/tests/system/rpz/ns2/named.conf -=================================================================== ---- bin/tests/system/rpz/ns2/named.conf.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns2/named.conf 2013-08-05 14:14:45.880498065 +0200 -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ - --/* $Id$ */ -- - - - controls { /* empty */ }; -Index: bin/tests/system/rpz/ns2/tld2.db -=================================================================== ---- bin/tests/system/rpz/ns2/tld2.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns2/tld2.db 2013-08-05 14:14:45.880498065 +0200 -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ -- - - - ; RPZ rewrite responses from this zone -@@ -111,6 +109,9 @@ +-zone "bl.tld2." {type master; file "bl.tld2.db"; notify yes; notify-delay 1;}; ++zone "bl.tld2." {type master; file "bl.tld2.db";}; +diff -r -u bin/tests/system/rpz/ns2/tld2.db-orig bin/tests/system/rpz/ns2/tld2.db +--- bin/tests/system/rpz/ns2/tld2.db-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns2/tld2.db 2004-01-01 00:00:00.000000000 +0000 +@@ -111,6 +111,9 @@ A 192.168.5.2 TXT "a5-1-2 tld2 text" @@ -2693,64 +2753,66 @@ Index: bin/tests/system/rpz/ns2/tld2.db a5-3 A 192.168.5.3 TXT "a5-3 tld2 text" -Index: bin/tests/system/rpz/ns3/base.db -=================================================================== ---- bin/tests/system/rpz/ns3/base.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns3/base.db 2013-08-05 14:14:45.880498065 +0200 -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. +diff -r -u bin/tests/system/rpz/ns3/base.db-orig bin/tests/system/rpz/ns3/base.db +--- bin/tests/system/rpz/ns3/base.db-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns3/base.db 2004-01-01 00:00:00.000000000 +0000 +@@ -21,30 +21,7 @@ + ; Its contents are also changed with nsupdate --; $Id$ + +-$TTL 120 ++$TTL 300 + @ SOA blx. hostmaster.ns.blx. ( 1 3600 1200 604800 60 ) +- NS ns +-ns A 10.53.0.3 ++ NS ns.tld3. + +-; Poke the radix tree a little. +-128.1111.2222.3333.4444.5555.6666.7777.8888.rpz-ip CNAME . +-128.1111.2222.3333.4444.5555.6666.zz.rpz-ip CNAME . +-128.1111.2222.3333.4444.5555.zz.8888.rpz-ip CNAME . +-128.1111.2222.3333.4444.zz.8888.rpz-ip CNAME . +-128.zz.3333.4444.0.0.8888.rpz-ip CNAME . +-128.zz.3333.4444.0.7777.8888.rpz-ip CNAME . +-128.zz.3333.4444.0.8777.8888.rpz-ip CNAME . +-127.zz.3333.4444.0.8777.8888.rpz-ip CNAME . - - - - ; RPZ test -Index: bin/tests/system/rpz/ns3/hints -=================================================================== ---- bin/tests/system/rpz/ns3/hints.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns3/hints 2013-08-05 14:14:45.909498434 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ - - - . 120 NS ns. - ns. 120 A 10.53.0.1 -Index: bin/tests/system/rpz/ns3/named.conf -=================================================================== ---- bin/tests/system/rpz/ns3/named.conf.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns3/named.conf 2013-08-05 14:14:45.909498434 +0200 -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ - --/* $Id$ */ +-; regression testing for some old crashes +-redirect A 127.0.0.1 +-*.redirect A 127.0.0.1 +-*.credirect CNAME google.com. - - - - /* -@@ -46,7 +44,10 @@ +- +-; names in the RPZ TLDs that some say should not be rewritten. +-; This is not a bug, because any data leaked by writing 24.4.3.2.10.rpz-ip +-; (or whatever) is available by publishing "foo A 10.2.3.4" and then +-; resolving foo. +-32.3.2.1.127.rpz-ip CNAME walled.invalid. +diff -r -u bin/tests/system/rpz/ns3/named.conf-orig bin/tests/system/rpz/ns3/named.conf +--- bin/tests/system/rpz/ns3/named.conf-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns3/named.conf 2004-01-01 00:00:00.000000000 +0000 +@@ -46,20 +46,24 @@ zone "bl-cname" policy cname txt-only.tld2.; zone "bl-wildcname" policy cname *.tld4.; zone "bl-garden" policy cname a12.tld2.; -- } min-ns-dots 0; + zone "bl-drop" policy drop; -+ } min-ns-dots 0 -+ # qname-wait-recurse no ++ zone "bl-tcp-only" policy tcp-only; + zone "bl.tld2"; +- } min-ns-dots 0; ++ } ++ min-ns-dots 0 ++ qname-wait-recurse yes + ; }; key rndc_key { -@@ -58,7 +59,6 @@ + secret "1234abcd8765"; +- algorithm hmac-md5; ++ algorithm hmac-sha256; + }; + controls { + inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; }; }; @@ -2758,94 +2820,42 @@ Index: bin/tests/system/rpz/ns3/named.conf zone "." { type hint; file "hints"; }; zone "bl." {type master; file "bl.db"; -@@ -83,6 +83,8 @@ +@@ -84,9 +88,13 @@ allow-update {any;};}; zone "bl-garden." {type master; file "bl-garden.db"; allow-update {any;};}; +zone "bl-drop." {type master; file "bl-drop.db"; + allow-update {any;};}; ++zone "bl-tcp-only." {type master; file "bl-tcp-only.db"; ++ allow-update {any;};}; + + zone "bl.tld2." {type slave; file "bl.tld2.db"; masters {10.53.0.2;}; +- request-ixfr no; masterfile-format text;}; ++ masterfile-format text;}; zone "crash1.tld2" {type master; file "crash1";}; zone "crash2.tld3." {type master; file "crash2";}; -Index: bin/tests/system/rpz/ns4/hints -=================================================================== ---- bin/tests/system/rpz/ns4/hints.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns4/hints 2013-08-05 14:14:45.909498434 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. +diff -r -u bin/tests/system/rpz/ns5/named.args-orig bin/tests/system/rpz/ns5/named.args +--- bin/tests/system/rpz/ns5/named.args-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns5/named.args 2004-01-01 00:00:00.000000000 +0000 +@@ -1,3 +1,3 @@ + # run the performace test close to real life --; $Id$ -- +--c named.conf -g ++-c named.conf -gd3 +diff -r -u bin/tests/system/rpz/ns5/named.conf-orig bin/tests/system/rpz/ns5/named.conf +--- bin/tests/system/rpz/ns5/named.conf-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns5/named.conf 2004-01-01 00:00:00.000000000 +0000 +@@ -40,7 +40,7 @@ - . 120 NS ns. - ns. 120 A 10.53.0.1 -Index: bin/tests/system/rpz/ns4/named.conf -=================================================================== ---- bin/tests/system/rpz/ns4/named.conf.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns4/named.conf 2013-08-05 14:14:45.910498444 +0200 -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ - --/* $Id$ */ -- - - controls { /* empty */ }; - -Index: bin/tests/system/rpz/ns4/tld4.db -=================================================================== ---- bin/tests/system/rpz/ns4/tld4.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns4/tld4.db 2013-08-05 14:14:45.910498444 +0200 -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ -- - - ; RPZ rewrite responses from this zone - -Index: bin/tests/system/rpz/ns5/hints -=================================================================== ---- bin/tests/system/rpz/ns5/hints.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns5/hints 2013-08-05 14:14:45.910498444 +0200 -@@ -12,8 +12,6 @@ - ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - ; PERFORMANCE OF THIS SOFTWARE. - --; $Id$ -- - - . 120 NS ns. - ns. 120 A 10.53.0.1 -Index: bin/tests/system/rpz/ns5/named.conf -=================================================================== ---- bin/tests/system/rpz/ns5/named.conf.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns5/named.conf 2013-08-05 14:14:45.910498444 +0200 -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ - --/* $Id$ */ -- - - - /* -@@ -56,3 +54,20 @@ + key rndc_key { + secret "1234abcd8765"; +- algorithm hmac-md5; ++ algorithm hmac-sha256; + }; + controls { + inet 10.53.0.5 port 9953 allow { any; } keys { rndc_key; }; +@@ -56,3 +56,20 @@ zone "bl0." {type master; file "bl.db"; }; zone "bl1." {type master; file "bl.db"; }; zone "bl2." {type master; file "bl.db"; }; @@ -2866,74 +2876,80 @@ Index: bin/tests/system/rpz/ns5/named.conf +zone "bl17." {type master; file "bl.db"; }; +zone "bl18." {type master; file "bl.db"; }; +zone "bl19." {type master; file "bl.db"; }; -Index: bin/tests/system/rpz/ns5/tld5.db -=================================================================== ---- bin/tests/system/rpz/ns5/tld5.db.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/ns5/tld5.db 2013-08-05 14:14:45.910498444 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -Index: bin/tests/system/rpz/qperf.sh -=================================================================== ---- bin/tests/system/rpz/qperf.sh.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/qperf.sh 2013-08-05 14:14:45.910498444 +0200 -@@ -1,6 +1,6 @@ - #! /bin/sh - # --# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") - # - # Permission to use, copy, modify, and/or distribute this software for any - # purpose with or without fee is hereby granted, provided that the above -@@ -14,8 +14,6 @@ - # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - # PERFORMANCE OF THIS SOFTWARE. +diff -r -u bin/tests/system/rpz/ns5/tld5.db-orig bin/tests/system/rpz/ns5/tld5.db +--- bin/tests/system/rpz/ns5/tld5.db-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/ns5/tld5.db 2004-01-01 00:00:00.000000000 +0000 +@@ -22,42 +22,10 @@ + NS ns1 + NS ns2 + NS ns3 +- NS ns4 +- NS ns5 +- NS ns6 +- NS ns7 +- NS ns8 +- NS ns9 +- NS ns10 +- NS ns11 +- NS ns12 +- NS ns13 +- NS ns14 +- NS ns15 +- NS ns16 +- NS ns17 +- NS ns18 +- NS ns19 + ns A 10.53.0.5 + ns1 A 10.53.0.5 + ns2 A 10.53.0.5 + ns3 A 10.53.0.5 +-ns4 A 10.53.0.5 +-ns5 A 10.53.0.5 +-ns6 A 10.53.0.5 +-ns7 A 10.53.0.5 +-ns8 A 10.53.0.5 +-ns9 A 10.53.0.5 +-ns10 A 10.53.0.5 +-ns11 A 10.53.0.5 +-ns12 A 10.53.0.5 +-ns13 A 10.53.0.5 +-ns14 A 10.53.0.5 +-ns15 A 10.53.0.5 +-ns16 A 10.53.0.5 +-ns17 A 10.53.0.5 +-ns18 A 10.53.0.5 +-ns19 A 10.53.0.5 --# $Id$ -- - for QDIR in `echo "$PATH" | tr : ' '` ../../../../contrib/queryperf; do - QPERF=$QDIR/queryperf -Index: bin/tests/system/rpz/rpz.c -=================================================================== ---- bin/tests/system/rpz/rpz.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/rpz.c 2013-08-05 14:14:45.910498444 +0200 -@@ -14,8 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ + $ORIGIN example.tld5. +diff -r -u bin/tests/system/rpz/setup.sh-orig bin/tests/system/rpz/setup.sh +--- bin/tests/system/rpz/setup.sh-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/setup.sh 2004-01-01 00:00:00.000000000 +0000 +@@ -26,11 +26,13 @@ --/* $Id$ */ -- + sh clean.sh - #include - -Index: bin/tests/system/rpz/setup.sh -=================================================================== ---- bin/tests/system/rpz/setup.sh.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/setup.sh 2013-08-05 14:14:45.910498444 +0200 -@@ -14,8 +14,6 @@ - # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - # PERFORMANCE OF THIS SOFTWARE. - --# $Id$ -- - - set -e - -@@ -30,7 +28,7 @@ - # bl-{given,disabled,passthru,no-data,nxdomain,cname,wildcard,garden} - # are used to check policy overrides in named.conf. - # NO-OP is an obsolete synonym for PASSHTRU +-# set up test policy zones. bl-2 is used to check competing zones. +-# bl-{given,disabled,passthru,no-data,nxdomain,cname,wildcard,garden} +-# are used to check policy overrides in named.conf. +-# NO-OP is an obsolete synonym for PASSHTRU -for NM in '' -2 -given -disabled -passthru -no-op -nodata -nxdomain -cname -wildcname -garden; do -+for NM in '' -2 -given -disabled -passthru -no-op -nodata -nxdomain -cname -wildcname -garden -drop; do ++# set up test policy zones. ++# bl is the main test zone ++# bl-2 is used to check competing zones. ++# bl-{given,disabled,passthru,no-data,nxdomain,cname,wildcard,garden, ++# drop,tcp-only} are used to check policy overrides in named.conf. ++# NO-OP is an obsolete synonym for PASSHTRU ++for NM in '' -2 -given -disabled -passthru -no-op -nodata -nxdomain -cname -wildcname -garden -drop -tcp-only; do sed -e "/SOA/s/blx/bl$NM/g" ns3/base.db >ns3/bl$NM.db done -@@ -51,7 +49,10 @@ - # Performance checks. +@@ -48,18 +50,22 @@ + signzone ns2 tld2s. base-tld2s.db tld2s.db + + +-# Performance checks. ++# Performance and a few other checks. cat <ns5/rpz-switch response-policy { - zone "bl0"; zone "bl1"; zone "bl2"; @@ -2942,12 +2958,63 @@ Index: bin/tests/system/rpz/setup.sh + zone "bl10"; zone "bl11"; zone "bl12"; zone "bl13"; zone "bl14"; + zone "bl15"; zone "bl16"; zone "bl17"; zone "bl18"; zone "bl19"; } recursive-only no - max-policy-ttl 90 - # min-ns-dots 0 -Index: bin/tests/system/rpz/test1 -=================================================================== ---- bin/tests/system/rpz/test1.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test1 2013-08-05 14:14:45.910498444 +0200 +- max-policy-ttl 90 +- # min-ns-dots 0 +- break-dnssec yes; ++ max-policy-ttl 90 ++ break-dnssec yes ++ qname-wait-recurse no ++ ; + EOF + + cat <ns5/example.db +-\$TTL 120 ++\$TTL 300 + @ SOA . hostmaster.ns.example.tld5. ( 1 3600 1200 604800 60 ) + NS ns + NS ns1 +@@ -68,15 +74,16 @@ + EOF + + cat <ns5/bl.db +-\$TTL 120 ++\$TTL 300 + @ SOA . hostmaster.ns.blperf. ( 1 3600 1200 604800 60 ) +- NS ns +-ns A 10.53.0.5 ++ NS ns.tld5. + +-; used only in failure for "recursive-only no" in #8 test5 +-a3-5.tld2 CNAME *. ++; for "qname-wait-recurse no" in #35 test1 ++x.servfail A 35.35.35.35 ++; for "recursive-only no" in #8 test5 ++a3-5.tld2 CNAME . + ; for "break-dnssec" in #9 & #10 test5 +-a3-5.tld2s CNAME *. ++a3-5.tld2s CNAME . + ; for "max-policy-ttl 90" in #17 test5 + a3-17.tld2 500 A 17.17.17.17 + +@@ -85,8 +92,7 @@ + EOF + + if test -n "$QPERF"; then +- # do not build the full zones if we will not use them to avoid the long +- # time otherwise required to shut down the server ++ # Do not build the full zones if we will not use them. + $PERL -e 'for ($val = 1; $val <= 65535; ++$val) { + printf("host-%05d\tA 192.168.%d.%d\n", $val, $val/256, $val%256); + }' >>ns5/example.db +@@ -110,5 +116,3 @@ + printf("host-%05d.example.tld5 A\n", $val); + $val = ($val * 9 + 32771) % 65536; + }' >ns5/requests +- +-cp ns2/bl.tld2.db.in ns2/bl.tld2.db +diff -r -u bin/tests/system/rpz/test1-orig bin/tests/system/rpz/test1 +--- bin/tests/system/rpz/test1-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/test1 2004-01-01 00:00:00.000000000 +0000 @@ -24,13 +24,13 @@ ; QNAME tests @@ -2980,17 +3047,20 @@ Index: bin/tests/system/rpz/test1 ; ; assert in rbtdb.c ; 24 -@@ -84,4 +92,6 @@ +@@ -84,4 +92,10 @@ ; DO=1 without signatures, DO=0 with signatures are rewritten ; 26 - 27 update add a0-1.tld2s.bl. 300 CNAME . +; 32 +update add a3-8.tld2.bl. 300 CNAME rpz-drop. ++; 33 ++update add a3-9.tld2.bl. 300 CNAME rpz-tcp-only. ++; 34 qname-wait-recurse yes ++update add x.servfail.bl. 300 A 127.0.0.34 send -Index: bin/tests/system/rpz/test2 -=================================================================== ---- bin/tests/system/rpz/test2.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test2 2013-08-05 14:14:45.910498444 +0200 +diff -r -u bin/tests/system/rpz/test2-orig bin/tests/system/rpz/test2 +--- bin/tests/system/rpz/test2-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/test2 2004-01-01 00:00:00.000000000 +0000 @@ -58,7 +58,7 @@ send @@ -3009,61 +3079,79 @@ Index: bin/tests/system/rpz/test2 +; 17 +update add 32.1.0.53.10.rpz-client-ip.bl 300 A 127.0.0.17 +send -Index: bin/tests/system/rpz/test3 -=================================================================== ---- bin/tests/system/rpz/test3.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test3 2013-08-05 14:14:45.910498444 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -Index: bin/tests/system/rpz/test4 -=================================================================== ---- bin/tests/system/rpz/test4.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test4 2013-08-05 14:14:45.911498455 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2011, 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -Index: bin/tests/system/rpz/test4a -=================================================================== ---- bin/tests/system/rpz/test4a.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test4a 2013-08-05 14:14:45.911498455 +0200 -@@ -1,4 +1,4 @@ --; Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") -+; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") - ; - ; Permission to use, copy, modify, and/or distribute this software for any - ; purpose with or without fee is hereby granted, provided that the above -Index: bin/tests/system/rpz/test5 -=================================================================== ---- bin/tests/system/rpz/test5.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/test5 2013-08-05 14:14:45.911498455 +0200 -@@ -57,3 +57,6 @@ +diff -r -u bin/tests/system/rpz/test5-orig bin/tests/system/rpz/test5 +--- bin/tests/system/rpz/test5-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/test5 2004-01-01 00:00:00.000000000 +0000 +@@ -35,10 +35,8 @@ + ; 4 + update add a3-4.tld2.bl-disabled. 300 A 127.0.0.4 + send +-; 5 - 8 ++; 5 - 7 + update add a3-5.tld2.bl-nodata. 300 A 127.0.0.5 +-; 9 - 10 +-update add a3-5.tld2s.bl-nodata. 300 A 127.0.0.9 + send + ; 11 + update add a3-6.tld2.bl-nxdomain. 300 A 127.0.0.11 +@@ -57,3 +55,9 @@ ; 16 update add a3-16.tld2.bl. 300 A 127.0.0.16 send +; 18 +update add a3-18.tld2.bl-drop. 300 A 127.0.0.18 +send -Index: bin/tests/system/rpz/tests.sh -=================================================================== ---- bin/tests/system/rpz/tests.sh.orig 2013-07-17 00:13:06.000000000 +0200 -+++ bin/tests/system/rpz/tests.sh 2013-08-05 14:14:45.911498455 +0200 -@@ -12,8 +12,6 @@ - # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - # PERFORMANCE OF THIS SOFTWARE. - --# $Id$ -- - - # test response policy zones (RPZ) - -@@ -21,15 +19,19 @@ ++; 19 ++update add a3-19.tld2.bl-tcp-only. 300 A 127.0.0.19 ++send +diff -r -u bin/tests/system/rpz/test6-orig bin/tests/system/rpz/test6 +--- bin/tests/system/rpz/test6-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/test6 2004-01-01 00:00:00.000000000 +0000 +@@ -0,0 +1,40 @@ ++; Copyright (C) 2011-2013 Internet Systems Consortium, Inc. ("ISC") ++; ++; 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. ++ ++ ++ ++; Use comment lines instead of blank lines to combine update requests into ++; single requests ++; Separate update requests for distinct TLDs with blank lines or 'send' ++; End the file with a blank line or 'send' ++ ++server 10.53.0.3 5300 ++ ++; Poke the radix tree a little. ++update add 128.1111.2222.3333.4444.5555.6666.7777.8888.rpz-ip.bl. 300 CNAME . ++update add 128.1111.2222.3333.4444.5555.6666.zz.rpz-ip.bl. 300 CNAME . ++update add 128.1111.2222.3333.4444.5555.zz.8888.rpz-ip.bl. 300 CNAME . ++update add 128.1111.2222.3333.4444.zz.8888.rpz-ip.bl. 300 CNAME . ++update add 128.zz.3333.4444.0.0.8888.rpz-ip.bl. 300 CNAME . ++update add 128.zz.3333.4444.0.7777.8888.rpz-ip.bl. 300 CNAME . ++update add 128.zz.3333.4444.0.8777.8888.rpz-ip.bl. 300 CNAME . ++update add 127.zz.3333.4444.0.8777.8888.rpz-ip.bl. 300 CNAME . ++; ++; ++; regression testing for some old crashes ++update add redirect.bl. 300 A 127.0.0.1 ++update add *.redirect.bl. 300 A 127.0.0.1 ++update add *.credirect.bl. 300 CNAME google.com. ++; ++send +diff -r -u bin/tests/system/rpz/tests.sh-orig bin/tests/system/rpz/tests.sh +--- bin/tests/system/rpz/tests.sh-orig 2004-01-01 00:00:00.000000000 +0000 ++++ bin/tests/system/rpz/tests.sh 2004-01-01 00:00:00.000000000 +0000 +@@ -21,15 +21,15 @@ . $SYSTEMTESTTOP/conf.sh ns=10.53.0 @@ -3073,72 +3161,138 @@ Index: bin/tests/system/rpz/tests.sh -ns4=$ns.4 # another server that is rewritten -ns5=$ns.5 # check performance with this server +ns1=$ns.1 # root, defining the others -+ns2=$ns.2 # authoritative server whose answers are rewritten -+ns3=$ns.3 # resolver that does the rewriting ++ns2=$ns.2 # authoritative server whose records are rewritten ++ns3=$ns.3 # main rewriting resolver +ns4=$ns.4 # another authoritative server that is rewritten -+ns5=$ns.5 # resolver to check performance and give un-rewritten -+ # responses for comparisons ++ns5=$ns.5 # another rewriting resolver HAVE_CORE= SAVE_RESULTS= -NS3_STATS=47 + -+# "response policy zone rewrites" from ns3/named.stats if none of the -+# conditional tests are done. -+NS3_STATS=50 USAGE="$0: [-x]" while getopts "x" c; do -@@ -87,10 +89,10 @@ +@@ -57,13 +57,16 @@ + RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s" + + digcmd () { ++ if test "$1" = TCP; then ++ shift ++ fi + # Default to +noauth and @$ns3 + # Also default to -bX where X is the @value so that OS X will choose +- # the right IP source address. +- digcmd_args=`echo "+noadd +time=1 +tries=1 -p 5300 $*" | \ +- sed -e "/@/!s/.*/& @$ns3/" \ +- -e '/-b/!s/@\([^ ]*\)/@\1 -b\1/' \ +- -e '/+n?o?auth/!s/.*/+noauth &/'` ++ # the right IP source address. ++ digcmd_args=`echo "+noadd +time=1 +tries=1 -p 5300 $*" | \ ++ sed -e "/@/!s/.*/& @$ns3/" \ ++ -e '/-b/!s/@\([^ ]*\)/@\1 -b\1/' \ ++ -e '/+n?o?auth/!s/.*/+noauth &/'` + #echo I:dig $digcmd_args 1>&2 + $DIG $digcmd_args + } +@@ -89,10 +92,13 @@ # (re)load the reponse policy zones with the rules in the file $TEST_FILE load_db () { if test -n "$TEST_FILE"; then - $NSUPDATE -v $TEST_FILE || { -+ if ! $NSUPDATE -v $TEST_FILE; then ++ if $NSUPDATE -v $TEST_FILE; then : ++ $RNDCCMD $ns3 sync ++ else echo "I:failed to update policy zone with $TEST_FILE" ++ $RNDCCMD $ns3 sync exit 1 - } + fi fi } -@@ -213,6 +215,13 @@ - ckresult "$*" proto.nodata +@@ -135,16 +141,20 @@ + return 1 } -+# check dropped response -+drop () { -+ make_dignm -+ digcmd $* >$DIGNM -+ ckresult "$*" proto.drop -+} -+ - # check rewrite to an address - # modify the output so that it is easily compared, but save the original line - # $1=IPv4 address $2=digcmd args $3=optional TTL -@@ -239,7 +248,7 @@ +-# check that statistics for $1 in $2 = $3 + ckstats () { +- rm -f $2/named.stats +- $RNDCCMD $1 stats +- CNT=`sed -n -e 's/[ ]*\([0-9]*\).response policy.*/\1/p' \ +- $2/named.stats` +- CNT=`expr 0$CNT + 0` +- if test "$CNT" -ne $3; then +- setret "I:wrong $2 statistics of $CNT instead of $3" ++ HOST=$1 ++ LABEL="$2" ++ NSDIR="$3" ++ EXPECTED="$4" ++ $RNDCCMD $HOST stats ++ NEW_CNT=0`sed -n -e 's/[ ]*\([0-9]*\).response policy.*/\1/p' \ ++ $NSDIR/named.stats | tail -1` ++ eval "OLD_CNT=0\$${NSDIR}_CNT" ++ GOT=`expr $NEW_CNT - $OLD_CNT` ++ if test "$GOT" -ne "$EXPECTED"; then ++ setret "I:wrong $LABEL $NSDIR statistics of $GOT instead of $EXPECTED" + fi ++ eval "${NSDIR}_CNT=$NEW_CNT" + } + + # $1=message $2=optional test file name +@@ -181,6 +191,12 @@ + ckresult () { + #ckalive "$1" "I:server crashed by 'dig $1'" || return 1 + if $PERL $SYSTEMTESTTOP/digcomp.pl $DIGNM $2 >/dev/null; then ++ NEED_TCP=`echo "$1" | sed -n -e 's/[Tt][Cc][Pp].*/TCP/p'` ++ RESULT_TCP=`sed -n -e 's/.*Truncated, retrying in TCP.*/TCP/p' $DIGNM` ++ if test "$NEED_TCP" != "$RESULT_TCP"; then ++ setret "I:'dig $1' wrong; no or unexpected truncation in $DIGNM" ++ return 1 ++ fi + clean_result ${DIGNM}* + return 0 + fi +@@ -237,12 +253,14 @@ + clean_result ${DIGNM}* + } + +-# check that a response is not rewritten +-# $1=target domain $2=optional query type ++# Check that a response is not rewritten ++# Use $ns1 instead of the authority for most test domains, $ns2 to prevent ++# spurious differences for `dig +norecurse` ++# $1=optional "TCP" remaining args for dig nochange () { make_dignm digcmd $* >$DIGNM - digcmd $* @$ns2 >${DIGNM}_OK -+ digcmd $* @$ns5 >${DIGNM}_OK ++ digcmd $* @$ns1 >${DIGNM}_OK ckresult "$*" ${DIGNM}_OK && clean_result ${DIGNM}_OK } -@@ -254,6 +263,12 @@ +@@ -254,6 +272,20 @@ + ckresult "$*" ${DIGNM}_OK + } + ++# check dropped response ++DROPPED='^;; connection timed out; no servers could be reached' ++drop () { ++ make_dignm ++ digcmd $* >$DIGNM ++ if grep "$DROPPED" $DIGNM >/dev/null; then ++ clean_result ${DIGNM}* ++ return 0 ++ fi ++ setret "I:'dig $1' wrong; response in $DIGNM" ++ return 1 ++} ++ ++ # make prototype files to check against rewritten results digcmd nonexistent @$ns2 >proto.nxdomain digcmd txt-only.tld2 @$ns2 >proto.nodata -+cat <proto.drop -+ -+; hello -+;; global options: -+;; connection timed out; no servers could be reached -+EOF - - - status=0 -@@ -278,18 +293,19 @@ +@@ -281,19 +313,27 @@ addr 57.57.57.57 a3-7.sub1.tld2 # 17 wildcard CNAME addr 127.0.0.16 a4-5-cname3.tld2 # 18 CNAME chain addr 127.0.0.17 a4-6-cname3.tld2 # 19 stop short in CNAME chain @@ -3161,11 +3315,19 @@ Index: bin/tests/system/rpz/tests.sh -nxdomain a0-1.tld2s srv # 31 +nochange a0-1.tld2s srv +auth +dnssec # 30 no write for DNSSEC and no record +nxdomain a0-1.tld2s srv +nodnssec # 31 -+drop a3-8.tld2 # 32 drop ++drop a3-8.tld2 any # 32 drop ++nochange tcp a3-9.tld2 # 33 tcp-only ++here x.servfail <<'EOF' # 34 qname-wait-recurse yes ++ ;; status: SERVFAIL, x ++EOF ++addr 35.35.35.35 "x.servfail @$ns5" # 35 qname-wait-recurse no end_group ++ckstats $ns3 test1 ns3 22 ++ckstats $ns5 test1 ns5 1 start_group "IP rewrites" test2 -@@ -305,10 +321,11 @@ + nodata a3-1.tld2 # 1 NODATA +@@ -308,35 +348,14 @@ nochange a4-1-aaaa.tld2 -taaaa # 10 addr 127.0.0.1 a5-1-2.tld2 # 11 prefer smallest policy address addr 127.0.0.1 a5-3.tld2 # 12 prefer first conflicting IP zone @@ -3175,11 +3337,55 @@ Index: bin/tests/system/rpz/tests.sh +addr 14.14.14.14 a5-4.tld2 # 14 prefer QNAME to IP nochange a4-4.tld2 # 15 PASSTHRU nxdomain c2.crash2.tld3 # 16 assert in rbtdb.c +-ckstats $ns3 ns3 29 +-nxdomain a7-1.tld2 # 17 slave policy zone (RT34450) +-cp ns2/blv2.tld2.db.in ns2/bl.tld2.db +-$RNDCCMD 10.53.0.2 reload bl.tld2 +-goodsoa="rpz.tld2. hostmaster.ns.tld2. 2 3600 1200 604800 60" +-for i in 0 1 2 3 4 5 6 7 8 9 10 +-do +- soa=`$DIG -p 5300 +short soa bl.tld2 @10.53.0.3 -b10.53.0.3` +- test "$soa" = "$goodsoa" && break +- sleep 1 +-done +-nochange a7-1.tld2 # 18 PASSTHRU +-sleep 1 # ensure that a clock tick has occured so that the reload takes effect +-cp ns2/blv3.tld2.db.in ns2/bl.tld2.db +-goodsoa="rpz.tld2. hostmaster.ns.tld2. 3 3600 1200 604800 60" +-$RNDCCMD 10.53.0.2 reload bl.tld2 +-for i in 0 1 2 3 4 5 6 7 8 9 10 +-do +- soa=`$DIG -p 5300 +short soa bl.tld2 @10.53.0.3 -b10.53.0.3` +- test "$soa" = "$goodsoa" && break +- sleep 1 +-done +-nxdomain a7-1.tld2 # 19 slave policy zone (RT34450) +-ckstats $ns3 ns3 31 +addr 127.0.0.17 "a4-4.tld2 -b $ns1" # 17 client-IP address trigger ++nxdomain a7-1.tld2 # 18 slave policy zone (RT34450) end_group ++ckstats $ns3 test2 ns3 11 # check that IP addresses for previous group were deleted from the radix tree -@@ -356,15 +373,15 @@ + start_group "radix tree deletions" +@@ -352,6 +371,7 @@ + nochange a4-1-aaaa.tld2 -tAAAA + nochange a5-1-2.tld2 + end_group ++ckstats $ns3 'radix tree deletions' ns3 0 + + if ./rpz nsdname; then + # these tests assume "min-ns-dots 0" +@@ -369,7 +389,7 @@ + addr 127.0.0.2 a3-1.subsub.sub3.tld2 + nxdomain xxx.crash1.tld2 # 12 dns_db_detachnode() crash + end_group +- NS3_STATS=`expr $NS3_STATS + 7` ++ ckstats $ns3 test3 ns3 7 + else + echo "I:NSDNAME not checked; named configured with --disable-rpz-nsdname" + fi +@@ -383,15 +403,15 @@ nochange a3-1.tld4 # 4 different NS IP address end_group @@ -3200,784 +3406,113 @@ Index: bin/tests/system/rpz/tests.sh + a3-1.tld2. x IN TXT "NSIP walled garden" +EOF + end_group -+ NS3_STATS=`expr $NS3_STATS + 4` ++ ckstats $ns3 test4 ns3 4 else echo "I:NSIP not checked; named configured with --disable-rpz-nsip" fi -@@ -393,6 +410,7 @@ +@@ -403,12 +423,12 @@ + nochange a3-2.tld2 # 2 bl-passthru + nochange a3-3.tld2 # 3 bl-no-op obsolete for passthru + nochange a3-4.tld2 # 4 bl-disabled +-nodata a3-5.tld2 # 5 bl-nodata +-nodata a3-5.tld2 +norecurse # 6 bl-nodata recursive-only no +-nodata a3-5.tld2 # 7 bl-nodata +-nodata a3-5.tld2 +norecurse @$ns5 # 8 bl-nodata recursive-only no +-nodata a3-5.tld2s @$ns5 # 9 bl-nodata +-nodata a3-5.tld2s +dnssec @$ns5 # 10 bl-nodata break-dnssec ++nodata a3-5.tld2 # 5 bl-nodata zone recursive-only no ++nodata a3-5.tld2 +norecurse # 6 bl-nodata zone recursive-only no ++nodata a3-5.tld2 # 7 bl-nodata not needed ++nxdomain a3-5.tld2 +norecurse @$ns5 # 8 bl-nodata global recursive-only no ++nxdomain a3-5.tld2s @$ns5 # 9 bl-nodata global break-dnssec ++nxdomain a3-5.tld2s +dnssec @$ns5 # 10 bl-nodata global break-dnssec + nxdomain a3-6.tld2 # 11 bl-nxdomain + here a3-7.tld2 -tany <<'EOF' + ;; status: NOERROR, x +@@ -420,10 +440,15 @@ addr 12.12.12.12 a3-15.tld2 # 15 bl-garden via CNAME to a12.tld2 addr 127.0.0.16 a3-16.tld2 100 # 16 bl max-policy-ttl 100 addr 17.17.17.17 "a3-17.tld2 @$ns5" 90 # 17 ns5 bl max-policy-ttl 90 -+drop a3-18.tld2 # 18 bl-drop ++drop a3-18.tld2 any # 18 bl-drop ++nxdomain TCP a3-19.tld2 # 19 bl-tcp-only end_group ++ckstats $ns3 test5 ns3 12 ++ckstats $ns5 test5 ns5 4 ++ # check that miscellaneous bugs are still absent -@@ -412,6 +430,9 @@ +-start_group "crashes" ++start_group "crashes" test6 + for Q in RRSIG SIG ANY 'ANY +dnssec'; do + nocrash a3-1.tld2 -t$Q + nocrash a3-2.tld2 -t$Q +@@ -437,6 +462,8 @@ + # resolving foo. + # nxdomain 32.3.2.1.127.rpz-ip end_group ++ckstats $ns3 bugs ns3 8 ++ -+ckstats $ns3 ns3 $NS3_STATS -+ -+ # superficial test for major performance bugs - QPERF=`sh qperf.sh` - if test -n "$QPERF"; then -@@ -464,8 +485,6 @@ +@@ -449,6 +476,7 @@ + $QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p 5300 >/dev/null + comment "before real test $1" + PFILE="ns5/$2.perf" ++ $RNDCCMD $ns5 notrace + $QPERF -c -1 -l30 -d ns5/requests -s $ns5 -p 5300 >$PFILE + comment "after test $1" + X=`sed -n -e 's/.*Returned *\([^ ]*:\) *\([0-9]*\) .*/\1\2/p' $PFILE \ +@@ -463,17 +491,17 @@ + } + + # get qps with rpz +- perf 'with rpz' rpz 'NOERROR:2900 NXDOMAIN:100 ' ++ perf 'with RPZ' rpz 'NOERROR:2900 NXDOMAIN:100 ' + RPZ=`trim rpz` + + # turn off rpz and measure qps again +- echo "# rpz off" >ns5/rpz-switch ++ echo "# RPZ off" >ns5/rpz-switch + RNDCCMD_OUT=`$RNDCCMD $ns5 reload` +- perf 'without rpz' norpz 'NOERROR:3000 ' ++ perf 'without RPZ' norpz 'NOERROR:3000 ' + NORPZ=`trim norpz` + + PERCENT=`expr \( "$RPZ" \* 100 + \( $NORPZ / 2 \) \) / $NORPZ` +- echo "I:$RPZ qps with rpz is $PERCENT% of $NORPZ qps without rpz" ++ echo "I:$RPZ qps with RPZ is $PERCENT% of $NORPZ qps without RPZ" + + MIN_PERCENT=30 + if test "$PERCENT" -lt $MIN_PERCENT; then +@@ -484,13 +512,12 @@ + setret "I:$RPZ qps with RPZ or $PERCENT% of $NORPZ qps without RPZ is too high" + fi + +- ckstats $ns5 ns5 203 ++ ckstats $ns5 performance ns5 200 + + else + echo "I:performance not checked; queryperf not available" fi +-ckstats $ns3 ns3 57 --ckstats $ns3 ns3 55 -- # restart the main test RPZ server to see if that creates a core file if test -z "$HAVE_CORE"; then - $PERL $SYSTEMTESTTOP/stop.pl . ns3 -Index: bin/tests/system/rrl/clean.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/clean.sh 2013-08-05 14:14:45.911498455 +0200 -@@ -0,0 +1,21 @@ -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+ -+# Clean up after rrl tests. -+ -+rm -f dig.out* -+rm -f */named.memstats */named.run */named.stats */log-* */session.key -+rm -f ns3/bl*.db */*.jnl */*.core */*.pid -Index: bin/tests/system/rrl/ns1/named.conf -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns1/named.conf 2013-08-05 14:14:45.911498455 +0200 -@@ -0,0 +1,32 @@ -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.1; -+ notify-source 10.53.0.1; -+ transfer-source 10.53.0.1; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ listen-on { 10.53.0.1; }; -+ listen-on-v6 { none; }; -+ notify no; -+}; -+ -+zone "." {type master; file "root.db";}; -Index: bin/tests/system/rrl/ns1/root.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns1/root.db 2013-08-05 14:14:45.911498455 +0200 -@@ -0,0 +1,31 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+$TTL 120 -+@ SOA ns. hostmaster.ns. ( 1 3600 1200 604800 60 ) -+@ NS ns. -+ns. A 10.53.0.1 -+. A 10.53.0.1 -+ -+; limit responses from here -+tld2. NS ns.tld2. -+ns.tld2. A 10.53.0.2 -+ -+; limit recursion to here -+tld3. NS ns.tld3. -+ns.tld3. A 10.53.0.3 -+ -+; generate SERVFAIL -+tld4. NS ns.tld3. -Index: bin/tests/system/rrl/ns2/hints -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns2/hints 2013-08-05 14:14:45.911498455 +0200 -@@ -0,0 +1,18 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+. 0 NS ns1. -+ns1. 0 A 10.53.0.1 -Index: bin/tests/system/rrl/ns2/named.conf -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns2/named.conf 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,71 @@ -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.2; -+ notify-source 10.53.0.2; -+ transfer-source 10.53.0.2; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ statistics-file "named.stats"; -+ listen-on { 10.53.0.2; }; -+ listen-on-v6 { none; }; -+ notify no; -+ -+ rate-limit { -+ responses-per-second 2; -+ all-per-second 50; -+ slip 3; -+ exempt-clients { 10.53.0.7; }; -+ -+ // small enough to force a table expansion -+ min-table-size 75; -+ }; -+ -+ additional-from-cache no; -+}; -+ -+key rndc_key { -+ secret "1234abcd8765"; -+ algorithm hmac-sha256; -+}; -+controls { -+ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; -+}; -+ -+/* -+ * These log settings have no effect unless "-g" is removed from ../../start.pl -+ */ -+logging { -+ channel debug { -+ file "log-debug"; -+ print-category yes; print-severity yes; severity debug 10; -+ }; -+ channel queries { -+ file "log-queries"; -+ print-category yes; print-severity yes; severity info; -+ }; -+ category rate-limit { debug; queries; }; -+ category queries { debug; queries; }; -+}; -+ -+zone "." { type hint; file "hints"; }; -+ -+zone "tld2."{ type master; file "tld2.db"; }; -Index: bin/tests/system/rrl/ns2/tld2.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns2/tld2.db 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,47 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+; rate limit response from this zone -+ -+$TTL 120 -+@ SOA tld2. hostmaster.ns.tld2. ( 1 3600 1200 604800 60 ) -+ NS ns -+ NS . -+ns A 10.53.0.2 -+ -+; basic rate limiting -+a1 A 192.0.2.1 -+ -+; wildcards -+*.a2 A 192.0.2.2 -+ -+; a3 is in tld3 -+ -+; a4 does not exist to give NXDOMAIN -+ -+; a5 for TCP requests -+a5 A 192.0.2.5 -+ -+; a6 for whitelisted clients -+a6 A 192.0.2.6 -+ -+; a7 for SERVFAIL -+ -+; a8 for NODATA -+a8 A 192.0.2.8 -+ -+; a9 for all-per-second limit -+$GENERATE 101-180 all$.a9 A 192.0.2.8 -Index: bin/tests/system/rrl/ns3/hints -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns3/hints 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,18 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+. 0 NS ns1. -+ns1. 0 A 10.53.0.1 -Index: bin/tests/system/rrl/ns3/named.conf -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns3/named.conf 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,50 @@ -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.3; -+ notify-source 10.53.0.3; -+ transfer-source 10.53.0.3; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ listen-on { 10.53.0.3; }; -+ listen-on-v6 { none; }; -+ notify no; -+ -+ // check that all of the options are parsed without limiting anything -+ rate-limit { -+ responses-per-second 200; -+ referrals-per-second 220; -+ nodata-per-second 230; -+ nxdomains-per-second 240; -+ errors-per-second 250; -+ all-per-second 700; -+ ipv4-prefix-length 24; -+ ipv6-prefix-length 64; -+ qps-scale 10; -+ window 1; -+ max-table-size 1000; -+ }; -+ -+}; -+ -+zone "." { type hint; file "hints"; }; -+ -+zone "tld3."{ type master; file "tld3.db"; }; -Index: bin/tests/system/rrl/ns3/tld3.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/ns3/tld3.db 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,25 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+; rate limit response from this zone -+ -+$TTL 120 -+@ SOA tld3. hostmaster.ns.tld3. ( 1 3600 1200 604800 60 ) -+ NS ns -+ NS . -+ns A 10.53.0.3 -+ -+*.a3 A 192.0.3.3 -Index: bin/tests/system/rrl/setup.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/setup.sh 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,21 @@ -+#!/bin/sh -+# -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+SYSTEMTESTTOP=.. -+. $SYSTEMTESTTOP/conf.sh -+. ./clean.sh -+ -Index: bin/tests/system/rrl/tests.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ bin/tests/system/rrl/tests.sh 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,258 @@ -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+# test response rate limiting -+ -+SYSTEMTESTTOP=.. -+. $SYSTEMTESTTOP/conf.sh -+ -+#set -x -+ -+ns1=10.53.0.1 # root, defining the others -+ns2=10.53.0.2 # test server -+ns3=10.53.0.3 # secondary test server -+ns7=10.53.0.7 # whitelisted client -+ -+USAGE="$0: [-x]" -+while getopts "x" c; do -+ case $c in -+ x) set -x;; -+ *) echo "$USAGE" 1>&2; exit 1;; -+ esac -+done -+shift `expr $OPTIND - 1 || true` -+if test "$#" -ne 0; then -+ echo "$USAGE" 1>&2 -+ exit 1 -+fi -+# really quit on control-C -+trap 'exit 1' 1 2 15 -+ -+ -+ret=0 -+setret () { -+ ret=1 -+ echo "$*" -+} -+ -+ -+# Wait until soon after the start of a second to make results consistent. -+# The start of a second credits a rate limit. -+# This would be far easier in C or by assuming a modern version of perl. -+sec_start () { -+ START=`date` -+ while true; do -+ NOW=`date` -+ if test "$START" != "$NOW"; then -+ return -+ fi -+ $PERL -e 'select(undef, undef, undef, 0.05)' || true -+ done -+} -+ -+ -+# turn off ${HOME}/.digrc -+HOME=/dev/null; export HOME -+ -+# $1=result name $2=domain name $3=dig options -+digcmd () { -+ OFILE=$1; shift -+ DIG_DOM=$1; shift -+ ARGS="+nosearch +time=1 +tries=1 +ignore -p 5300 $* $DIG_DOM @$ns2" -+ #echo I:dig $ARGS 1>&2 -+ START=`date +%y%m%d%H%M.%S` -+ RESULT=`$DIG $ARGS 2>&1 | tee $OFILE=TEMP \ -+ | sed -n -e '/^;; AUTHORITY/,/^$/d' \ -+ -e '/^;; ADDITIONAL/,/^$/d' \ -+ -e 's/^[^;].* \([^ ]\{1,\}\)$/\1/p' \ -+ -e 's/;; flags.* tc .*/TC/p' \ -+ -e 's/;; .* status: NXDOMAIN.*/NXDOMAIN/p' \ -+ -e 's/;; .* status: SERVFAIL.*/SERVFAIL/p' \ -+ -e 's/;; connection timed out.*/drop/p' \ -+ -e 's/;; communications error to.*/drop/p' \ -+ | tr -d '\n'` -+ mv "$OFILE=TEMP" "$OFILE=$RESULT" -+ touch -t $START "$OFILE=$RESULT" -+} -+ -+ -+# $1=number of tests $2=target domain $3=dig options -+QNUM=1 -+burst () { -+ BURST_LIMIT=$1; shift -+ BURST_DOM_BASE="$1"; shift -+ while test "$BURST_LIMIT" -ge 1; do -+ CNT=`expr "00$QNUM" : '.*\(...\)'` -+ eval BURST_DOM="$BURST_DOM_BASE" -+ FILE="dig.out-$BURST_DOM-$CNT" -+ digcmd $FILE $BURST_DOM $* & -+ QNUM=`expr $QNUM + 1` -+ BURST_LIMIT=`expr "$BURST_LIMIT" - 1` -+ done -+} -+ -+ -+# $1=domain $2=IP address $3=# of IP addresses $4=TC $5=drop -+# $6=NXDOMAIN $7=SERVFAIL or other errors -+ck_result() { -+ BAD= -+ wait -+ ADDRS=`ls dig.out-$1-*=$2 2>/dev/null | wc -l` -+ # count simple truncated and truncated NXDOMAIN as TC -+ TC=`ls dig.out-$1-*=TC dig.out-$1-*=NXDOMAINTC 2>/dev/null | wc -l` -+ DROP=`ls dig.out-$1-*=drop 2>/dev/null | wc -l` -+ # count NXDOMAIN and truncated NXDOMAIN as NXDOMAIN -+ NXDOMAIN=`ls dig.out-$1-*=NXDOMAIN dig.out-$1-*=NXDOMAINTC 2>/dev/null \ -+ | wc -l` -+ SERVFAIL=`ls dig.out-$1-*=SERVFAIL 2>/dev/null | wc -l` -+ if test $ADDRS -ne "$3"; then -+ setret "I:"$ADDRS" instead of $3 '$2' responses for $1" -+ BAD=yes -+ fi -+ if test $TC -ne "$4"; then -+ setret "I:"$TC" instead of $4 truncation responses for $1" -+ BAD=yes -+ fi -+ if test $DROP -ne "$5"; then -+ setret "I:"$DROP" instead of $5 dropped responses for $1" -+ BAD=yes -+ fi -+ if test $NXDOMAIN -ne "$6"; then -+ setret "I:"$NXDOMAIN" instead of $6 NXDOMAIN responses for $1" -+ BAD=yes -+ fi -+ if test $SERVFAIL -ne "$7"; then -+ setret "I:"$SERVFAIL" instead of $7 error responses for $1" -+ BAD=yes -+ fi -+ if test -z "$BAD"; then -+ rm -f dig.out-$1-* -+ fi -+} -+ -+ -+ckstats () { -+ LABEL="$1"; shift -+ TYPE="$1"; shift -+ EXPECTED="$1"; shift -+ C=`sed -n -e "s/[ ]*\([0-9]*\).responses $TYPE for rate limits.*/\1/p" \ -+ ns2/named.stats | tail -1` -+ C=`expr 0$C + 0` -+ if test "$C" -ne $EXPECTED; then -+ setret "I:wrong $LABEL $TYPE statistics of $C instead of $EXPECTED" -+ fi -+} -+ -+ -+######### -+sec_start -+ -+# Tests of referrals to "." must be done before the hints are loaded -+# or with "additional-from-cache no" -+burst 5 a1.tld3 +norec -+# basic rate limiting -+burst 3 a1.tld2 -+# 1 second delay allows an additional response. -+sleep 1 -+burst 10 a1.tld2 -+# Request 30 different qnames to try a wildcard. -+burst 30 'x$CNT.a2.tld2' -+# These should be counted and limited but are not. See RT33138. -+burst 10 'y.x$CNT.a2.tld2' -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# referrals to "." -+ck_result a1.tld3 '' 2 1 2 0 0 -+# check 13 results including 1 second delay that allows an additional response -+ck_result a1.tld2 192.0.2.1 3 4 6 0 0 -+ -+# Check the wild card answers. -+# The parent name of the 30 requests is counted. -+ck_result 'x*.a2.tld2' 192.0.2.2 2 10 18 0 0 -+ -+# These should be limited but are not. See RT33138. -+ck_result 'y.x*.a2.tld2' 192.0.2.2 10 0 0 0 0 -+ -+######### -+sec_start -+ -+burst 10 'x.a3.tld3' -+burst 10 'y$CNT.a3.tld3' -+burst 10 'z$CNT.a4.tld2' -+ -+# 10 identical recursive responses are limited -+ck_result 'x.a3.tld3' 192.0.3.3 2 3 5 0 0 -+ -+# 10 different recursive responses are not limited -+ck_result 'y*.a3.tld3' 192.0.3.3 10 0 0 0 0 -+ -+# 10 different NXDOMAIN responses are limited based on the parent name. -+# We count 13 responses because we count truncated NXDOMAIN responses -+# as both truncated and NXDOMAIN. -+ck_result 'z*.a4.tld2' x 0 3 5 5 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats first dropped 36 -+ckstats first truncated 21 -+ -+ -+######### -+sec_start -+ -+burst 10 a5.tld2 +tcp -+burst 10 a6.tld2 -b $ns7 -+burst 10 a7.tld4 -+burst 2 a8.tld2 AAAA -+burst 2 a8.tld2 TXT -+burst 2 a8.tld2 SPF -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# TCP responses are not rate limited -+ck_result a5.tld2 192.0.2.5 10 0 0 0 0 -+ -+# whitelisted client is not rate limited -+ck_result a6.tld2 192.0.2.6 10 0 0 0 0 -+ -+# Errors such as SERVFAIL are rate limited. -+ck_result a7.tld4 x 0 0 8 0 2 -+ -+# NODATA responses are counted as the same regardless of qtype. -+ck_result a8.tld2 '' 2 2 2 0 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats second dropped 46 -+ckstats second truncated 23 -+ -+ -+######### -+sec_start -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# all-per-second -+# The qnames are all unique but the client IP address is constant. -+QNUM=101 -+burst 60 'all$CNT.a9.tld2' -+ -+ck_result 'a*.a9.tld2' 192.0.2.8 50 0 10 0 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats final dropped 56 -+ckstats final truncated 23 -+ -+ -+echo "I:exit status: $ret" -+# exit $ret -+[ $ret -ne 0 ] && echo "I:test failure overridden" -+exit 0 -Index: clean.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ clean.sh 2013-08-05 14:14:45.912498466 +0200 -@@ -0,0 +1,21 @@ -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+ -+# Clean up after rrl tests. -+ -+rm -f dig.out* -+rm -f */named.memstats */named.run */named.stats */log-* */session.key -+rm -f ns3/bl*.db */*.jnl */*.core */*.pid -Index: doc/arm/Bv9ARM-book.xml -=================================================================== ---- doc/arm/Bv9ARM-book.xml.orig 2013-07-17 00:13:06.000000000 +0200 -+++ doc/arm/Bv9ARM-book.xml 2013-08-05 14:14:45.916498518 +0200 -@@ -4818,6 +4818,32 @@ - - - -+ -+ -+ rate-limit -+ -+ -+ -+ The start, periodic, and final notices of the -+ rate limiting of a stream of responses are logged at -+ info severity in this category. -+ These messages include a hash value of the domain name -+ of the response and the name itself, -+ except when there is insufficient memory to record -+ the name for the final notice -+ The final notice is normally delayed until about one -+ minute after rate limit stops. -+ A lack of memory can hurry the final notice, -+ in which case it starts with an asterisk (*). -+ Various internal events are logged at debug 1 level -+ and higher. -+ -+ -+ Rate limiting of individual requests -+ is logged in the query-errors category. -+ -+ -+ - - - -@@ -5318,7 +5344,7 @@ - match-mapped-addresses yes_or_no; - filter-aaaa-on-v4 ( yes_or_no | break-dnssec ); - filter-aaaa { address_match_list }; -- dns64 IPv6-prefix { -+ dns64 ipv6-prefix { - clients { address_match_list }; - mapped { address_match_list }; - exclude { address_match_list }; -@@ -5351,8 +5377,25 @@ - resolver-query-timeout number ; - deny-answer-addresses { address_match_list } except-from { namelist } ; - deny-answer-aliases { namelist } except-from { namelist } ; -+ rate-limit { -+ responses-per-second number ; -+ referrals-per-second number ; -+ nodata-per-second number ; -+ nxdomains-per-second number ; -+ errors-per-second number ; -+ all-per-second number ; -+ window number ; -+ log-only yes_or_no ; -+ qps-scale number ; -+ ipv4-prefix-length number ; -+ ipv6-prefix-length number ; -+ slip number ; -+ exempt-clients { address_match_list } ; -+ max-table-size number ; -+ min-table-size number ; -+ } ; +diff -r -u doc/arm/Bv9ARM-book.xml-orig doc/arm/Bv9ARM-book.xml +--- doc/arm/Bv9ARM-book.xml-orig 2004-01-01 00:00:00.000000000 +0000 ++++ doc/arm/Bv9ARM-book.xml 2004-01-01 00:00:00.000000000 +0000 +@@ -4870,7 +4870,7 @@ + min-table-size number ; + } ; response-policy { zone_name - policy given | disabled | passthru | nxdomain | nodata | cname domain + policy given | disabled | passthru | drop | nxdomain | nodata | cname domain recursive-only yes_or_no max-policy-ttl number ; } recursive-only yes_or_no max-policy-ttl number break-dnssec yes_or_no min-ns-dots number ; -@@ -9645,30 +9688,25 @@ +@@ -9164,77 +9164,122 @@ Response policy zones are named in the response-policy option for the view or among the global options if there is no response-policy option for the view. @@ -3996,7 +3531,27 @@ Index: doc/arm/Bv9ARM-book.xml - The owner name of a QNAME RPZ record is the query name relativized - to the RPZ. - -- ++ Five policy triggers can be encoded in RPZ records. ++ ++ ++ RPZ-CLIENT-IP ++ ++ ++ IP records are triggered by the IP address of the ++ DNS client. ++ Client IP address triggers are encoded in records that have ++ owner names that are subdomains of ++ rpz-client-ip relativized to the ++ policy zone origin name ++ and encode an address or address block. ++ IPv4 addresses are represented as ++ prefixlength.B4.B3.B2.B1.rpz-ip. ++ The IPv4 prefix length must be between 1 and 32. ++ All four bytes, B4, B3, B2, and B1, must be present. ++ B4 is the decimal value of the least significant byte of the ++ IPv4 address as in IN-ADDR.ARPA. ++ + - - The second kind of RPZ trigger is an IP address in an A and AAAA - record in the ANSWER section of a response. @@ -4004,63 +3559,130 @@ Index: doc/arm/Bv9ARM-book.xml - that are subdomains of rpz-ip relativized - to the RPZ origin name and encode an IP address or address block. - IPv4 trigger addresses are represented as -+ Five policy triggers can be encoded in RPZ records, CLIENT-IP, -+ QNAME, IP, NSDNAME, and NSIP. -+ CLIENT-IP records are triggered by the IP address of the -+ DNS client. -+ Client IP address triggers are encoded in records that have -+ owner names that are subdomains of -+ rpz-client-ip relativized to the -+ policy zone origin name -+ and encode an address or address block. -+ IPv4 addresses are represented as - prefixlength.B4.B3.B2.B1.rpz-ip. +- prefixlength.B4.B3.B2.B1.rpz-ip. - The prefix length must be between 1 and 32. -+ The IPv4 prefix length must be between 1 and 32. - All four bytes, B4, B3, B2, and B1, must be present. - B4 is the decimal value of the least significant byte of the - IPv4 address as in IN-ADDR.ARPA. -@@ -9678,10 +9716,25 @@ - Each of W8,...,W1 is a one to four digit hexadecimal number - representing 16 bits of the IPv6 address as in the standard text - representation of IPv6 addresses, but reversed as in IN-ADDR.ARPA. +- All four bytes, B4, B3, B2, and B1, must be present. +- B4 is the decimal value of the least significant byte of the +- IPv4 address as in IN-ADDR.ARPA. +- IPv6 addresses are encoded in a format similar to the standard +- IPv6 text representation, +- prefixlength.W8.W7.W6.W5.W4.W3.W2.W1.rpz-ip. +- Each of W8,...,W1 is a one to four digit hexadecimal number +- representing 16 bits of the IPv6 address as in the standard text +- representation of IPv6 addresses, but reversed as in IN-ADDR.ARPA. - All 8 words must be present except when consecutive - zero words are replaced with .zz. -+ All 8 words must be present except when one set of consecutive -+ zero words is replaced with .zz. - analogous to double colons (::) in standard IPv6 text encodings. +- analogous to double colons (::) in standard IPv6 text encodings. - The prefix length must be between 1 and 128. -+ The IPv6 prefix length must be between 64 and 128. -+ -+ -+ -+ QNAME policy records are triggered by query names of requests and -+ targets of CNAME records resolved to generate the response. -+ The owner name of a QNAME policy record is -+ the query name relativized to the policy zone. -+ -+ -+ -+ The third kind of trigger is an IP address in an A and AAAA -+ record in the ANSWER section of a response. -+ IP address triggers -+ IP triggers are encoded like client-IP triggers except as -+ subdomains of rpz-ip. - +- ++ ++ IPv6 addresses are encoded in a format similar ++ to the standard IPv6 text representation, ++ prefixlength.W8.W7.W6.W5.W4.W3.W2.W1.rpz-ip. ++ Each of W8,...,W1 is a one to four digit hexadecimal number ++ representing 16 bits of the IPv6 address as in the standard ++ text representation of IPv6 addresses, ++ but reversed as in IN-ADDR.ARPA. ++ All 8 words must be present except when one set of consecutive ++ zero words is replaced with .zz. ++ analogous to double colons (::) in standard IPv6 text ++ encodings. ++ The IPv6 prefix length must be between 64 and 128. ++ ++ ++ - -@@ -9703,7 +9756,7 @@ - +- +- NSDNAME triggers match names of authoritative servers +- for the query name, a parent of the query name, a CNAME for +- query name, or a parent of a CNAME. +- They are encoded as subdomains of +- rpz-nsdomain relativized +- to the RPZ origin name. +- NSIP triggers match IP addresses in A and +- AAAA RRsets for domains that can be checked against NSDNAME +- policy records. +- NSIP triggers are encoded like IP triggers except as subdomains of +- rpz-nsip. +- NSDNAME and NSIP triggers are checked only for names with at +- least min-ns-dots dots. +- The default value of min-ns-dots is 1 to +- exclude top level domains. +- ++ ++ QNAME ++ ++ ++ QNAME policy records are triggered by query names of ++ requests and targets of CNAME records resolved to generate ++ the response. ++ The owner name of a QNAME policy record is ++ the query name relativized to the policy zone. ++ ++ ++ ++ ++ ++ RPZ-IP ++ ++ ++ IP triggers are IP addresses in an ++ A or AAAA record in the ANSWER section of a response. ++ They are encoded like client-IP triggers except as ++ subdomains of rpz-ip. ++ ++ ++ ++ ++ ++ RPZ-NSDNAME ++ ++ ++ NSDNAME triggers match names of authoritative servers ++ for the query name, a parent of the query name, a CNAME for ++ query name, or a parent of a CNAME. ++ They are encoded as subdomains of ++ rpz-nsdname relativized ++ to the RPZ origin name. ++ NSIP triggers match IP addresses in A and ++ AAAA RRsets for domains that can be checked against NSDNAME ++ policy records. ++ ++ ++ ++ ++ ++ RPZ-NSIP ++ ++ ++ NSIP triggers are encoded like IP triggers except as ++ subdomains of rpz-nsip. ++ NSDNAME and NSIP triggers are checked only for names with at ++ least min-ns-dots dots. ++ The default value of min-ns-dots is 1 to ++ exclude top level domains. ++ ++ ++ ++ - The query response is checked against all RPZs, so -+ The query response is checked against all response policy zones, so - two or more policy records can be triggered by a response. - Because DNS responses can be rewritten according to at most one +- two or more policy records can be triggered by a response. +- Because DNS responses can be rewritten according to at most one ++ The query response is checked against all response policy zones, ++ so two or more policy records can be triggered by a response. ++ Because DNS responses are rewritten according to at most one policy record, a single record encoding an action (other than -@@ -9714,8 +9767,8 @@ + DISABLED actions) must be chosen. +- Triggers or the records that encode them are chosen in +- the following order: ++ Triggers or the records that encode them are chosen for the ++ rewriting in the following order: + Choose the triggered record in the zone that appears - first in the response-policy option. +- first in the response-policy option. ++ first in the response-policy option. - Prefer QNAME to IP to NSDNAME to NSIP triggers - in a single zone. @@ -4069,7 +3691,7 @@ Index: doc/arm/Bv9ARM-book.xml Among NSDNAME triggers, prefer the trigger that matches the smallest name under the DNSSEC ordering. -@@ -9734,14 +9787,25 @@ +@@ -9253,83 +9298,168 @@ When the processing of a response is restarted to resolve DNAME or CNAME records and a policy record set has not been triggered, @@ -4080,27 +3702,28 @@ Index: doc/arm/Bv9ARM-book.xml - RPZ record sets are sets of any types of DNS record except - DNAME or DNSSEC that encode actions or responses to queries. - -+ The PASSTHRU policy is specified -+ by a CNAME whose target is rpz-passthru. -+ It causes the response to not be rewritten -+ and is most often used to "poke holes" in policies for -+ CIDR blocks. -+ -+ The DROP policy is specified -+ by a CNAME whose target is rpz-drop. -+ It causes the response to discarded. -+ Nothing is sent to the DNS client. -+ - The NXDOMAIN response is encoded - by a CNAME whose target is the root domain (.) - -@@ -9761,23 +9825,16 @@ - The purpose for this special form is query logging in the - walled garden's authority DNS server. - +- RPZ record sets are sets of any types of DNS record except +- DNAME or DNSSEC that encode actions or responses to queries. +- +- The NXDOMAIN response is encoded +- by a CNAME whose target is the root domain (.) +- +- A CNAME whose target is the wildcard top-level +- domain (*.) specifies the NODATA action, +- which rewrites the response to NODATA or ANCOUNT=1. +- +- The Local Data action is +- represented by a set ordinary DNS records that are used +- to answer queries. Queries for record types not the +- set are answered with NODATA. +- +- A special form of local data is a CNAME whose target is a +- wildcard such as *.example.com. +- It is used as if were an ordinary CNAME after the astrisk (*) +- has been replaced with the query name. +- The purpose for this special form is query logging in the +- walled garden's authority DNS server. +- - The PASSTHRU policy is specified - by a CNAME whose target is rpz-passthru. - It causes the response to not be rewritten @@ -4109,23 +3732,188 @@ Index: doc/arm/Bv9ARM-book.xml - (A CNAME whose target is the variable part of its owner name - is an obsolete specification of the PASSTHRU policy.) - - +- ++ RPZ record sets are any types of DNS record except ++ DNAME or DNSSEC that encode actions or responses to ++ individual queries. ++ Any of the policies can be used with any of the triggers. ++ For example, while the TCP-only policy is ++ commonly used with client-IP triggers, ++ it cn be used with any type of trigger to force the use of ++ TCP for responses with owner names in a zone. ++ ++ ++ PASSTHRU ++ ++ ++ The whitelist policy is specified ++ by a CNAME whose target is rpz-passthru. ++ It causes the response to not be rewritten ++ and is most often used to "poke holes" in policies for ++ CIDR blocks. ++ ++ ++ ++ ++ ++ DROP ++ ++ ++ The blacklist policy is specified ++ by a CNAME whose target is rpz-drop. ++ It causes the response to be discarded. ++ Nothing is sent to the DNS client. ++ ++ ++ ++ ++ ++ TCP-Only ++ ++ ++ The "slip" policy is specified ++ by a CNAME whose target is rpz-tcp-only. ++ It changes UDP responses to short, truncated DNS responses ++ that require the DNS client to try again with TCP. ++ It is used to mitigate distributed DNS reflection attacks. ++ ++ ++ ++ ++ ++ NXDOMAIN ++ ++ ++ The domain undefined response is encoded ++ by a CNAME whose target is the root domain (.) ++ ++ ++ ++ ++ ++ NODATA ++ ++ ++ The empty set of resource records is specified by ++ CNAME whose target is the wildcard top-level ++ domain (*.). ++ It rewrites the response to NODATA or ANCOUNT=1. ++ ++ ++ ++ ++ ++ Local Data ++ ++ ++ A set of ordinary DNS records can be used to answer queries. ++ Queries for record types not the set are answered with ++ NODATA. ++ ++ ++ ++ A special form of local data is a CNAME whose target is a ++ wildcard such as *.example.com. ++ It is used as if were an ordinary CNAME after the astrisk (*) ++ has been replaced with the query name. ++ The purpose for this special form is query logging in the ++ walled garden's authority DNS server. ++ ++ ++ ++ - The actions specified in an RPZ can be overridden with a -+ The actions specified in a policy zone can be overridden with a - policy clause in the +- policy clause in the ++ All of the actions specified in all of the individual records ++ in a policy zone ++ can be overridden with a policy clause in the response-policy option. - An organization using an RPZ provided by another organization might - use this mechanism to redirect domains to its own walled garden. +- +- GIVEN says "do not override but +- perform the action specified in the zone." +- +- DISABLED causes policy records to do +- nothing but log what they might have done. +- The response to the DNS query will be written according to +- any triggered policy records that are not disabled. +- Disabled policy zones should appear first, +- because they will often not be logged +- if a higher precedence trigger is found first. +- +- PASSTHRU causes all policy records +- to act as if they were CNAME records with targets the variable +- part of their owner name. They protect the response from +- being changed. +- +- NXDOMAIN causes all RPZ records +- to specify NXDOMAIN policies. +- +- NODATA overrides with the +- NODATA policy +- +- CNAME domain causes all RPZ +- policy records to act as if they were "cname domain" records. +- +- + An organization using a policy zone provided by another + organization might use this mechanism to redirect domains + to its own walled garden. - - GIVEN says "do not override but - perform the action specified in the zone." -@@ -9808,9 +9865,10 @@ ++ ++ ++ GIVEN ++ ++ The placeholder policy says "do not override but ++ perform the action specified in the zone." ++ ++ ++ ++ ++ ++ DISABLED ++ ++ ++ The testing override policy causes policy zone records to do ++ nothing but log what they would have done if the ++ policy zone were not disabled. ++ The response to the DNS query will be written (or not) ++ according to any triggered policy records that are not ++ disabled. ++ Disabled policy zones should appear first, ++ because they will often not be logged ++ if a higher precedence trigger is found first. ++ ++ ++ ++ ++ ++ PASSTHRU, ++ DROP, ++ TCP-Only, ++ NXDOMAIN, ++ and ++ NODATA ++ ++ ++ override with the corresponding per-record policy. ++ ++ ++ ++ ++ ++ CNAME domain ++ ++ ++ causes all RPZ policy records to act as if they were ++ "cname domain" records. ++ ++ ++ ++ @@ -4139,7 +3927,7 @@ Index: doc/arm/Bv9ARM-book.xml with a recursive-only no clause. This feature is useful for serving the same zone files both inside and outside an RFC 1918 cloud and using RPZ to -@@ -9819,15 +9877,37 @@ +@@ -9338,15 +9468,43 @@ @@ -4164,354 +3952,79 @@ Index: doc/arm/Bv9ARM-book.xml + + + -+ No DNS records are needed to trigger a QNAME action. The name -+ itself is sufficient, so in principle the query name need not -+ be recursively resolved. However, not resolving the requested -+ name leaks the fact that response policy rewriting is in use ++ No DNS records are needed for a QNAME or Client-IP trigger. ++ The name or IP address itself is sufficient, ++ so in principle the query name need not be recursively resolved. ++ However, not resolving the requested ++ name can leak the fact that response policy rewriting is in use + and that the name is listed in a policy zone to operators of + servers for listed names. To prevent that information leak, by + default any recursion needed for a request is done before any + policy triggers are considered. Because listed domains often + have slow authoritative servers, this default behavior can cost -+ significant time. The qname-wait-recurse no -+ option overrides the default behavior when recursion cannot -+ change the response. qname-wait-recurse no -+ does not affect QNAME triggers in policy zones listed after -+ other zones containing IP, NSIP and NSDNAME triggers, because ++ significant time. ++ The qname-wait-recurse no option ++ overrides that default behavior when recursion cannot ++ change a non-error response. ++ The option does not affect QNAME or client-IP triggers ++ in policy zones listed ++ after other zones containing IP, NSIP and NSDNAME triggers, because + those may depend on the A, AAAA, and NS records that would be + found during recursive resolution. It also does not affect + DNSSEC requests (DO=1) unless break-dnssec yes + is in use, because the response would depend on whether or not + RRSIG records were found during resolution. ++ The option can cause appear to rewrite error responses ++ such as SERVFAIL when no recursion is done to discover problems ++ at the authoritative server. -@@ -9897,6 +9977,223 @@ - RPZRewrites statistics. - - -+ -+ -+ Response Rate Limiting -+ -+ Excessive almost-identical UDP responses -+ can be controlled by configuring a -+ rate-limit clause in an -+ options or view statement. -+ This mechanism keeps authoritative BIND 9 from being used -+ in amplifying reflection denial of service (DoS) attacks. -+ Short truncated (TC=1) responses can be sent to provide -+ rate-limited responses to legitimate clients within -+ a range of forged, attacked IP addresses. -+ Legitimate clients react to dropped or truncated response -+ by retrying with UDP or with TCP respectively. -+ -+ -+ -+ This mechanism is intended for authoritative DNS servers. -+ It can be used on recursive servers but can slow -+ applications such as SMTP servers (mail receivers) and -+ HTTP clients (web browsers) that repeatedly request the -+ same domains. -+ When possible, closing "open" recursive servers is better. -+ -+ -+ -+ Response rate limiting uses a "credit" or "token bucket" scheme. -+ Each combination of identical response and client -+ has a conceptual account that earns a specified number -+ of credits every second. -+ A prospective response debits its account by one. -+ Responses are dropped or truncated -+ while the account is negative. -+ Responses are tracked within a rolling window of time -+ which defaults to 15 seconds, but can be configured with -+ the window option to any value from -+ 1 to 3600 seconds (1 hour). -+ The account cannot become more positive than -+ the per-second limit -+ or more negative than window -+ times the per-second limit. -+ When the specified number of credits for a class of -+ responses is set to 0, those responses are not rate limited. -+ -+ -+ -+ The notions of "identical response" and "DNS client" -+ for rate limiting are not simplistic. -+ All responses to an address block are counted as if to a -+ single client. -+ The prefix lengths of addresses blocks are -+ specified with ipv4-prefix-length (default 24) -+ and ipv6-prefix-length (default 56). -+ -+ -+ -+ All non-empty responses for a valid domain name (qname) -+ and record type (qtype) are identical and have a limit specified -+ with responses-per-second -+ (default 0 or no limit). -+ All empty (NODATA) responses for a valid domain, -+ regardless of query type, are identical. -+ Responses in the NODATA class are limited by -+ nodata-per-second -+ (default responses-per-second). -+ Requests for any and all undefined subdomains of a given -+ valid domain result in NXDOMAIN errors, and are identical -+ regardless of query type. -+ They are limited by nxdomain-per-second -+ (default responses-per-second). -+ This controls some attacks using random names, but -+ can be relaxed or turned off (set to 0) -+ on servers that expect many legitimate -+ NXDOMAIN responses, such as from anti-spam blacklists. -+ Referrals or delegations to the server of a given -+ domain are identical and are limited by -+ referrals-per-second -+ (default responses-per-second). -+ -+ -+ -+ Responses generated from local wildcards are counted and limited -+ as if they were for the parent domain name. -+ This controls flooding using random.wild.example.com. -+ -+ -+ -+ All requests that result in DNS errors other -+ than NXDOMAIN, such as SERVFAIL and FORMERR, are identical -+ regardless of requested name (qname) or record type (qtype). -+ This controls attacks using invalid requests or distant, -+ broken authoritative servers. -+ By default the limit on errors is the same as the -+ responses-per-second value, -+ but it can be set separately with -+ errors-per-second. -+ -+ -+ -+ Many attacks using DNS involve UDP requests with forged source -+ addresses. -+ Rate limiting prevents the use of BIND 9 to flood a network -+ with responses to requests with forged source addresses, -+ but could let a third party block responses to legitimate requests. -+ There is a mechanism that can answer some legitimate -+ requests from a client whose address is being forged in a flood. -+ Setting slip to 2 (its default) causes every -+ other UDP request to be answered with a small truncated (TC=1) -+ response. -+ The small size and reduced frequency, and so lack of -+ amplification, of "slipped" responses make them unattractive -+ for reflection DoS attacks. -+ slip must be between 0 and 10. -+ A value of 0 does not "slip"; -+ no truncated responses are sent due to rate limiting. -+ Some error responses including REFUSED and SERVFAIL -+ cannot be replaced with truncated responses and are instead -+ leaked at the slip rate. -+ -+ -+ -+ When the approximate query per second rate exceeds -+ the qps-scale value, -+ then the responses-per-second, -+ errors-per-second, -+ nxdomains-per-second and -+ all-per-second values are reduced by the -+ ratio of the current rate to the qps-scale value. -+ This feature can tighten defenses during attacks. -+ For example, with -+ qps-scale 250; responses-per-second 20; and -+ a total query rate of 1000 queries/second for all queries from -+ all DNS clients including via TCP, -+ then the effective responses/second limit changes to -+ (250/1000)*20 or 5. -+ Responses sent via TCP are not limited -+ but are counted to compute the query per second rate. -+ -+ -+ -+ Communities of DNS clients can be given their own parameters or no -+ rate limiting by putting -+ rate-limit statements in view -+ statements instead of the global option -+ statement. -+ A rate-limit statement in a view replaces, -+ rather than supplementing, a rate-limit -+ statement among the main options. -+ DNS clients within a view can be exempted from rate limits -+ with the exempt-clients clause. -+ -+ -+ -+ UDP responses of all kinds can be limited with the -+ all-per-second phrase. -+ This rate limiting is unlike the rate limiting provided by -+ responses-per-second, -+ errors-per-second, and -+ nxdomains-per-second on a DNS server -+ which are often invisible to the victim of a DNS reflection attack. -+ Unless the forged requests of the attack are the same as the -+ legitimate requests of the victim, the victim's requests are -+ not affected. -+ Responses affected by an all-per-second limit -+ are always dropped; the slip value has no -+ effect. -+ An all-per-second limit should be -+ at least 4 times as large as the other limits, -+ because single DNS clients often send bursts of legitimate -+ requests. -+ For example, the receipt of a single mail message can prompt -+ requests from an SMTP server for NS, PTR, A, and AAAA records -+ as the incoming SMTP/TCP/IP connection is considered. -+ The SMTP server can need additional NS, A, AAAA, MX, TXT, and SPF -+ records as it considers the STMP Mail From -+ command. -+ Web browsers often repeatedly resolve the same names that -+ are repeated in HTML <IMG> tags in a page. -+ All-per-second is similar to the -+ rate limiting offered by firewalls but often inferior. -+ Attacks that justify ignoring the -+ contents of DNS responses are likely to be attacks on the -+ DNS server itself. -+ They usually should be discarded before the DNS server -+ spends resources make TCP connections or parsing DNS requesets, -+ but that rate limiting must be done before the -+ DNS server sees the requests. -+ -+ -+ -+ The maximum size of the table used to track requests and -+ rate limit responses is set with max-table-size. -+ Each entry in the table is between 40 and 80 bytes. -+ The table needs approximately as many entries as the number -+ of requests received per second. -+ The default is 20,000. -+ To reduce the cold start of growing the table, -+ min-table-size (default 500) -+ can set the minimum table size. -+ Enable rate-limit category logging to monitor -+ expansions of the table and inform -+ choices for the initial and maximum table size. -+ -+ -+ -+ Use log-only yes to test rate limiting parameters -+ without actually dropping any requests. -+ -+ -+ -+ Responses dropped by rate limits are included in the -+ RateDropped and QryDropped -+ statistics. -+ Responses that truncated by rate limits are included in -+ RateSlipped and RespTruncated. -+ - +@@ -9374,26 +9532,38 @@ - -@@ -14649,6 +14946,32 @@ - - - -+ -+ -+ RateDropped -+ -+ -+ -+ -+ -+ -+ Responses dropped by rate limits. -+ -+ -+ -+ -+ -+ RateSlipped -+ -+ -+ -+ -+ -+ -+ Responses truncated by rate limits. -+ -+ -+ - - - -Index: hints -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ hints 2013-08-05 14:14:45.916498518 +0200 -@@ -0,0 +1,36 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. + ; QNAME policy records. There are no periods (.) after the owner names. + nxdomain.domain.com CNAME . ; NXDOMAIN policy ++*.nxdomain.domain.com CNAME . ; NXDOMAIN policy + nodata.domain.com CNAME *. ; NODATA policy ++*.nodata.domain.com CNAME *. ; NODATA policy + bad.domain.com A 10.0.0.1 ; redirect to a walled garden + AAAA 2001:2::1 ++bzone.domain.com CNAME garden.example.com. + + ; do not rewrite (PASSTHRU) OK.DOMAIN.COM + ok.domain.com CNAME rpz-passthru. + +-bzone.domain.com CNAME garden.example.com. +- + ; redirect x.bzone.domain.com to x.bzone.domain.com.garden.example.com + *.bzone.domain.com CNAME *.garden.example.com. + + +-; IP policy records that rewrite all answers for 127/8 except 127.0.0.1 ++; IP policy records that rewrite all responses containing A records in 127/8 ++; except 127.0.0.1 + 8.0.0.0.127.rpz-ip CNAME . + 32.1.0.0.127.rpz-ip CNAME rpz-passthru. + + ; NSDNAME and NSIP policy records + ns.domain.com.rpz-nsdname CNAME . + 48.zz.2.2001.rpz-nsip CNAME . + ++; blacklist and whitelist some DNS clients ++112.zz.2001.rpz-client-ip CNAME rpz-drop. ++8.0.0.0.127.rpz-client-ip CNAME rpz-drop. + ++; force some DNS clients and responses in the example.com zone to TCP ++16.0.0.1.10.rpz-client-ip CNAME rpz-tcp-only. ++example.com CNAME rpz-tcp-only. ++*.example.com CNAME rpz-tcp-only. + -+. 0 NS ns1. -+ns1. 0 A 10.53.0.1 -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+. 0 NS ns1. -+ns1. 0 A 10.53.0.1 -Index: lib/dns/Makefile.in -=================================================================== ---- lib/dns/Makefile.in.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/Makefile.in 2013-08-05 14:14:45.916498518 +0200 -@@ -67,8 +67,8 @@ - portlist.@O@ private.@O@ \ - rbt.@O@ rbtdb.@O@ rbtdb64.@O@ rcode.@O@ rdata.@O@ \ - rdatalist.@O@ rdataset.@O@ rdatasetiter.@O@ rdataslab.@O@ \ -- request.@O@ resolver.@O@ result.@O@ rootns.@O@ rpz.@O@ \ -- rriterator.@O@ sdb.@O@ \ -+ request.@O@ resolver.@O@ result.@O@ rootns.@O@ \ -+ rpz.@O@ rrl.@O@ rriterator.@O@ sdb.@O@ \ - sdlz.@O@ soa.@O@ ssu.@O@ ssu_external.@O@ \ - stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \ - tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \ -@@ -95,7 +95,7 @@ - name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \ - rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \ - rdataset.c rdatasetiter.c rdataslab.c request.c \ -- resolver.c result.c rootns.c rpz.c rriterator.c \ -+ resolver.c result.c rootns.c rpz.c rrl.c rriterator.c \ - sdb.c sdlz.c soa.c ssu.c ssu_external.c \ - stats.c tcpmsg.c time.c timer.c tkey.c \ - tsec.c tsig.c ttl.c update.c validator.c \ -Index: lib/dns/db.c -=================================================================== ---- lib/dns/db.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/db.c 2013-08-05 14:14:45.916498518 +0200 + + + RPZ can affect server performance. +diff -r -u lib/dns/db.c-orig lib/dns/db.c +--- lib/dns/db.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/db.c 2004-01-01 00:00:00.000000000 +0000 @@ -1007,21 +1007,23 @@ (db->methods->resigned)(db, rdataset, version); } @@ -4551,10 +4064,9 @@ Index: lib/dns/db.c + return (ISC_R_SUCCESS); + return ((db->methods->rpz_ready)(db)); } -Index: lib/dns/ecdb.c -=================================================================== ---- lib/dns/ecdb.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/ecdb.c 2013-08-05 14:14:45.916498518 +0200 +diff -r -u lib/dns/ecdb.c-orig lib/dns/ecdb.c +--- lib/dns/ecdb.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/ecdb.c 2004-01-01 00:00:00.000000000 +0000 @@ -582,8 +582,8 @@ NULL, /* resigned */ NULL, /* isdnssec */ @@ -4566,10 +4078,9 @@ Index: lib/dns/ecdb.c NULL, /* findnodeext */ NULL /* findext */ }; -Index: lib/dns/include/dns/db.h -=================================================================== ---- lib/dns/include/dns/db.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/include/dns/db.h 2013-08-05 14:14:45.917498530 +0200 +diff -r -u lib/dns/include/dns/db.h-orig lib/dns/include/dns/db.h +--- lib/dns/include/dns/db.h-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/include/dns/db.h 2004-01-01 00:00:00.000000000 +0000 @@ -172,14 +172,9 @@ dns_dbversion_t *version); isc_boolean_t (*isdnssec)(dns_db_t *db); @@ -4627,31 +4138,10 @@ Index: lib/dns/include/dns/db.h */ ISC_LANG_ENDDECLS -Index: lib/dns/include/dns/log.h -=================================================================== ---- lib/dns/include/dns/log.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/include/dns/log.h 2013-08-05 14:14:45.917498530 +0200 -@@ -43,6 +43,7 @@ - #define DNS_LOGCATEGORY_DELEGATION_ONLY (&dns_categories[10]) - #define DNS_LOGCATEGORY_EDNS_DISABLED (&dns_categories[11]) - #define DNS_LOGCATEGORY_RPZ (&dns_categories[12]) -+#define DNS_LOGCATEGORY_RRL (&dns_categories[13]) - - /* Backwards compatibility. */ - #define DNS_LOGCATEGORY_GENERAL ISC_LOGCATEGORY_GENERAL -Index: lib/dns/include/dns/rpz.h -=================================================================== ---- lib/dns/include/dns/rpz.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/include/dns/rpz.h 2013-08-05 14:14:45.917498530 +0200 -@@ -14,7 +14,6 @@ - * PERFORMANCE OF THIS SOFTWARE. - */ - --/* $Id$ */ - - - #ifndef DNS_RPZ_H -@@ -25,19 +24,30 @@ +diff -r -u lib/dns/include/dns/rpz.h-orig lib/dns/include/dns/rpz.h +--- lib/dns/include/dns/rpz.h-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/include/dns/rpz.h 2004-01-01 00:00:00.000000000 +0000 +@@ -25,19 +25,31 @@ #include #include #include @@ -4673,6 +4163,7 @@ Index: lib/dns/include/dns/rpz.h + */ +#define DNS_RPZ_PASSTHRU_NAME DNS_RPZ_PREFIX"passthru" +#define DNS_RPZ_DROP_NAME DNS_RPZ_PREFIX"drop" ++#define DNS_RPZ_TCP_ONLY_NAME DNS_RPZ_PREFIX"tcp-only" -typedef isc_uint8_t dns_rpz_cidr_bits_t; + @@ -4684,16 +4175,16 @@ Index: lib/dns/include/dns/rpz.h DNS_RPZ_TYPE_QNAME, DNS_RPZ_TYPE_IP, DNS_RPZ_TYPE_NSDNAME, -@@ -45,45 +55,148 @@ +@@ -45,45 +57,151 @@ } dns_rpz_type_t; /* - * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_NXDOMAIN < - * DNS_RPZ_POLICY_NODATA < DNS_RPZ_POLICY_CNAME to choose among competing - * policies. -+ * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_DROP < -+ * DNS_RPZ_POLICY_NXDOMAIN < DNS_RPZ_POLICY_NODATA < DNS_RPZ_POLICY_CNAME -+ * to choose among competing policies. ++ * Require DNS_RPZ_POLICY_PASSTHRU < DNS_RPZ_POLICY_DROP ++ * < DNS_RPZ_POLICY_TCP_ONLY DNS_RPZ_POLICY_NXDOMAIN < DNS_RPZ_POLICY_NODATA ++ * < DNS_RPZ_POLICY_CNAME to choose among competing policies. */ typedef enum { DNS_RPZ_POLICY_GIVEN = 0, /* 'given': what policy record says */ @@ -4704,9 +4195,10 @@ Index: lib/dns/include/dns/rpz.h - DNS_RPZ_POLICY_NODATA = 4, /* 'nodata': answer with ANCOUNT=0 */ - DNS_RPZ_POLICY_CNAME = 5, /* 'cname x': answer with x's rrsets */ + DNS_RPZ_POLICY_DROP = 3, /* 'drop': do not respond */ -+ DNS_RPZ_POLICY_NXDOMAIN = 4, /* 'nxdomain': answer with NXDOMAIN */ -+ DNS_RPZ_POLICY_NODATA = 5, /* 'nodata': answer with ANCOUNT=0 */ -+ DNS_RPZ_POLICY_CNAME = 6, /* 'cname x': answer with x's rrsets */ ++ DNS_RPZ_POLICY_TCP_ONLY = 4, /* 'tcp-only': answer UDP with TC=1 */ ++ DNS_RPZ_POLICY_NXDOMAIN = 5, /* 'nxdomain': answer with NXDOMAIN */ ++ DNS_RPZ_POLICY_NODATA = 6, /* 'nodata': answer with ANCOUNT=0 */ ++ DNS_RPZ_POLICY_CNAME = 7, /* 'cname x': answer with x's rrsets */ DNS_RPZ_POLICY_RECORD, DNS_RPZ_POLICY_WILDCNAME, DNS_RPZ_POLICY_MISS, @@ -4778,10 +4270,10 @@ Index: lib/dns/include/dns/rpz.h + dns_name_t nsip; /* DNS_RPZ_NSIP_ZONE.origin. */ + dns_name_t passthru; /* DNS_RPZ_PASSTHRU_NAME. */ + dns_name_t drop; /* DNS_RPZ_DROP_NAME. */ ++ dns_name_t tcp_only; /* DNS_RPZ_TCP_ONLY_NAME. */ + dns_name_t cname; /* override value for ..._CNAME */ + dns_ttl_t max_policy_ttl; + dns_rpz_policy_t policy; /* DNS_RPZ_POLICY_GIVEN or override */ -+ dns_rpz_triggers_t triggers; }; /* @@ -4804,6 +4296,7 @@ Index: lib/dns/include/dns/rpz.h + dns_rpz_num_t num_zones; + } p; + dns_rpz_zone_t *zones[DNS_RPZ_MAX_ZONES]; ++ dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES]; + + dns_rpz_zbits_t defined; + @@ -4835,6 +4328,7 @@ Index: lib/dns/include/dns/rpz.h + dns_rpz_zbits_t nsip; + dns_rpz_zbits_t qname_skip_recurse; + } have; ++ dns_rpz_triggers_t total_triggers; + + isc_mem_t *mctx; + isc_refcount_t refs; @@ -4854,7 +4348,7 @@ Index: lib/dns/include/dns/rpz.h /* * context for finding the best policy -@@ -91,22 +204,19 @@ +@@ -91,22 +209,19 @@ typedef struct { unsigned int state; # define DNS_RPZ_REWRITTEN 0x0001 @@ -4884,7 +4378,7 @@ Index: lib/dns/include/dns/rpz.h dns_rpz_policy_t policy; dns_ttl_t ttl; isc_result_t result; -@@ -141,10 +251,15 @@ +@@ -141,10 +256,15 @@ dns_rdataset_t *sigrdataset; dns_rdatatype_t qtype; } q; @@ -4902,7 +4396,7 @@ Index: lib/dns/include/dns/rpz.h dns_fixedname_t _r_namef; dns_fixedname_t _fnamef; } dns_rpz_st_t; -@@ -171,32 +286,41 @@ +@@ -171,32 +291,41 @@ const char * dns_rpz_policy2str(dns_rpz_policy_t policy); @@ -4961,310 +4455,10 @@ Index: lib/dns/include/dns/rpz.h ISC_LANG_ENDDECLS -Index: lib/dns/include/dns/rrl.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ lib/dns/include/dns/rrl.h 2013-08-05 14:14:45.917498530 +0200 -@@ -0,0 +1,278 @@ -+/* -+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+#ifndef DNS_RRL_H -+#define DNS_RRL_H 1 -+ -+/* -+ * Rate limit DNS responses. -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+ISC_LANG_BEGINDECLS -+ -+ -+/* -+ * Memory allocation or other failures. -+ */ -+#define DNS_RRL_LOG_FAIL ISC_LOG_WARNING -+/* -+ * dropped or slipped responses. -+ */ -+#define DNS_RRL_LOG_DROP ISC_LOG_INFO -+/* -+ * Major events in dropping or slipping. -+ */ -+#define DNS_RRL_LOG_DEBUG1 ISC_LOG_DEBUG(3) -+/* -+ * Limit computations. -+ */ -+#define DNS_RRL_LOG_DEBUG2 ISC_LOG_DEBUG(4) -+/* -+ * Even less interesting. -+ */ -+#define DNS_RRL_LOG_DEBUG3 ISC_LOG_DEBUG(9) -+ -+ -+#define DNS_RRL_LOG_ERR_LEN 64 -+#define DNS_RRL_LOG_BUF_LEN (sizeof("would continue limiting") + \ -+ DNS_RRL_LOG_ERR_LEN + \ -+ sizeof(" responses to ") + \ -+ ISC_NETADDR_FORMATSIZE + \ -+ sizeof("/128 for IN ") + \ -+ DNS_RDATATYPE_FORMATSIZE + \ -+ DNS_NAME_FORMATSIZE) -+ -+ -+typedef struct dns_rrl_hash dns_rrl_hash_t; -+ -+/* -+ * Response types. -+ */ -+typedef enum { -+ DNS_RRL_RTYPE_FREE = 0, -+ DNS_RRL_RTYPE_QUERY, -+ DNS_RRL_RTYPE_REFERRAL, -+ DNS_RRL_RTYPE_NODATA, -+ DNS_RRL_RTYPE_NXDOMAIN, -+ DNS_RRL_RTYPE_ERROR, -+ DNS_RRL_RTYPE_ALL, -+ DNS_RRL_RTYPE_TCP, -+} dns_rrl_rtype_t; -+ -+/* -+ * A rate limit bucket key. -+ * This should be small to limit the total size of the database. -+ * The hash of the qname should be wide enough to make the probability -+ * of collisions among requests from a single IP address block less than 50%. -+ * We need a 32-bit hash value for 10000 qps (e.g. random qnames forged -+ * by attacker) to collide with legitimate qnames from the target with -+ * probability at most 1%. -+ */ -+#define DNS_RRL_MAX_PREFIX 64 -+typedef union dns_rrl_key dns_rrl_key_t; -+union dns_rrl_key { -+ struct { -+ isc_uint32_t ip[DNS_RRL_MAX_PREFIX/32]; -+ isc_uint32_t qname_hash; -+ dns_rdatatype_t qtype; -+ isc_uint8_t qclass; -+ dns_rrl_rtype_t rtype :4; /* 3 bits + sign bit */ -+ isc_boolean_t ipv6 :1; -+ } s; -+ isc_uint16_t w[1]; -+}; -+ -+/* -+ * A rate-limit entry. -+ * This should be small to limit the total size of the table of entries. -+ */ -+typedef struct dns_rrl_entry dns_rrl_entry_t; -+typedef ISC_LIST(dns_rrl_entry_t) dns_rrl_bin_t; -+struct dns_rrl_entry { -+ ISC_LINK(dns_rrl_entry_t) lru; -+ ISC_LINK(dns_rrl_entry_t) hlink; -+ dns_rrl_key_t key; -+# define DNS_RRL_RESPONSE_BITS 24 -+ signed int responses :DNS_RRL_RESPONSE_BITS; -+# define DNS_RRL_QNAMES_BITS 8 -+ unsigned int log_qname :DNS_RRL_QNAMES_BITS; -+ -+# define DNS_RRL_TS_GEN_BITS 2 -+ unsigned int ts_gen :DNS_RRL_TS_GEN_BITS; -+ isc_boolean_t ts_valid :1; -+# define DNS_RRL_HASH_GEN_BITS 1 -+ unsigned int hash_gen :DNS_RRL_HASH_GEN_BITS; -+ isc_boolean_t logged :1; -+# define DNS_RRL_LOG_BITS 11 -+ unsigned int log_secs :DNS_RRL_LOG_BITS; -+ -+# define DNS_RRL_TS_BITS 12 -+ unsigned int ts :DNS_RRL_TS_BITS; -+ -+# define DNS_RRL_MAX_SLIP 10 -+ unsigned int slip_cnt :4; -+}; -+ -+#define DNS_RRL_MAX_TIME_TRAVEL 5 -+#define DNS_RRL_FOREVER (1<= DNS_RRL_MAX_TS -+#error "DNS_RRL_MAX_WINDOW is too large" -+#endif -+#define DNS_RRL_MAX_RATE 1000 -+#if DNS_RRL_MAX_RATE >= (DNS_RRL_MAX_RESPONSES / DNS_RRL_MAX_WINDOW) -+#error "DNS_RRL_MAX_rate is too large" -+#endif -+ -+#if (1<= DNS_RRL_FOREVER -+#error DNS_RRL_LOG_BITS is too big -+#endif -+#define DNS_RRL_MAX_LOG_SECS 1800 -+#if DNS_RRL_MAX_LOG_SECS >= (1<= (1< - #include -+#include - #include - #include - #include -@@ -142,6 +143,7 @@ - dns_rbt_t * answeracl_exclude; - dns_rbt_t * denyanswernames; - dns_rbt_t * answernames_exclude; -+ dns_rrl_t * rrl; - isc_boolean_t provideixfr; - isc_boolean_t requestnsid; - dns_ttl_t maxcachettl; -@@ -162,10 +164,7 @@ +diff -r -u lib/dns/include/dns/view.h-orig lib/dns/include/dns/view.h +--- lib/dns/include/dns/view.h-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/include/dns/view.h 2004-01-01 00:00:00.000000000 +0000 +@@ -164,10 +164,7 @@ dns_acl_t * v4_aaaa_acl; dns_dns64list_t dns64; unsigned int dns64cnt; @@ -5276,11 +4470,10 @@ Index: lib/dns/include/dns/view.h /* * Configurable data for server use only, -Index: lib/dns/include/dns/zone.h -=================================================================== ---- lib/dns/include/dns/zone.h.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/include/dns/zone.h 2013-08-05 14:14:45.918498542 +0200 -@@ -2081,13 +2081,14 @@ +diff -r -u lib/dns/include/dns/zone.h-orig lib/dns/include/dns/zone.h +--- lib/dns/include/dns/zone.h-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/include/dns/zone.h 2004-01-01 00:00:00.000000000 +0000 +@@ -2081,19 +2081,20 @@ */ isc_result_t @@ -5291,6 +4484,13 @@ Index: lib/dns/include/dns/zone.h * Set the response policy associated with a zone. */ +-isc_result_t ++void + dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db); + /*% + * If a zone is a response policy zone, mark its new database. + */ + -isc_boolean_t -dns_zone_get_rpz(dns_zone_t *zone); +dns_rpz_num_t @@ -5298,22 +4498,9 @@ Index: lib/dns/include/dns/zone.h void dns_zone_setstatlevel(dns_zone_t *zone, dns_zonestat_level_t level); -Index: lib/dns/log.c -=================================================================== ---- lib/dns/log.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/log.c 2013-08-05 14:14:45.918498542 +0200 -@@ -45,6 +45,7 @@ - { "delegation-only", 0 }, - { "edns-disabled", 0 }, - { "rpz", 0 }, -+ { "rate-limit", 0 }, - { NULL, 0 } - }; - -Index: lib/dns/rbtdb.c -=================================================================== ---- lib/dns/rbtdb.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/rbtdb.c 2013-08-05 14:14:45.919498555 +0200 +diff -r -u lib/dns/rbtdb.c-orig lib/dns/rbtdb.c +--- lib/dns/rbtdb.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/rbtdb.c 2004-01-01 00:00:00.000000000 +0000 @@ -453,7 +453,9 @@ dns_rbt_t * tree; dns_rbt_t * nsec; @@ -5511,12 +4698,12 @@ Index: lib/dns/rbtdb.c - default: - continue; - } - +- - result = dns_rpz_cidr_find(rbtdb->rpz_cidr, &netaddr, rpz_type, - selfname, qname, &prefix); - if (result != ISC_R_SUCCESS) - continue; -- + - /* - * If we already have a rule, discard this new rule if - * is not better. @@ -5709,10 +4896,9 @@ Index: lib/dns/rbtdb.c /* * Version Initialization. -Index: lib/dns/rpz.c -=================================================================== ---- lib/dns/rpz.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/rpz.c 2013-08-05 14:14:45.921498580 +0200 +diff -r -u lib/dns/rpz.c-orig lib/dns/rpz.c +--- lib/dns/rpz.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/rpz.c 2004-01-01 00:00:00.000000000 +0000 @@ -37,6 +37,7 @@ #include #include @@ -5874,7 +5060,7 @@ Index: lib/dns/rpz.c case DNS_RPZ_TYPE_QNAME: return ("QNAME"); case DNS_RPZ_TYPE_IP: -@@ -138,32 +190,33 @@ +@@ -138,32 +190,34 @@ case DNS_RPZ_TYPE_BAD: break; } @@ -5894,10 +5080,11 @@ Index: lib/dns/rpz.c + {"disabled", DNS_RPZ_POLICY_DISABLED}, + {"passthru", DNS_RPZ_POLICY_PASSTHRU}, + {"drop", DNS_RPZ_POLICY_DROP}, ++ {"tcp-only", DNS_RPZ_POLICY_TCP_ONLY}, + {"nxdomain", DNS_RPZ_POLICY_NXDOMAIN}, + {"nodata", DNS_RPZ_POLICY_NODATA}, + {"cname", DNS_RPZ_POLICY_CNAME}, -+ {"no-op", DNS_RPZ_POLICY_PASSTHRU}, /* Obsolete */ ++ {"no-op", DNS_RPZ_POLICY_PASSTHRU}, /* old passthru */ + }; + unsigned int n; + @@ -5927,17 +5114,20 @@ Index: lib/dns/rpz.c return (DNS_RPZ_POLICY_ERROR); } -@@ -175,6 +228,9 @@ +@@ -175,6 +229,12 @@ case DNS_RPZ_POLICY_PASSTHRU: str = "PASSTHRU"; break; + case DNS_RPZ_POLICY_DROP: + str = "DROP"; ++ break; ++ case DNS_RPZ_POLICY_TCP_ONLY: ++ str = "TCP-ONLY"; + break; case DNS_RPZ_POLICY_NXDOMAIN: str = "NXDOMAIN"; break; -@@ -196,243 +252,276 @@ +@@ -196,243 +256,274 @@ return (str); } @@ -6230,53 +5420,8 @@ Index: lib/dns/rpz.c + const dns_rpz_cidr_key_t *tgt_ip, dns_rpz_prefix_t tgt_prefix, + isc_boolean_t inc) +{ -+ dns_rpz_zone_t *rpz; + int *cnt; + dns_rpz_zbits_t *have; -+ -+ rpz = rpzs->zones[rpz_num]; -+ switch (rpz_type) { -+ case DNS_RPZ_TYPE_CLIENT_IP: -+ REQUIRE(tgt_ip != NULL); -+ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { -+ cnt = &rpz->triggers.client_ipv4; -+ have = &rpzs->have.client_ipv4; -+ } else { -+ cnt = &rpz->triggers.client_ipv6; -+ have = &rpzs->have.client_ipv6; -+ } -+ break; -+ case DNS_RPZ_TYPE_QNAME: -+ cnt = &rpz->triggers.qname; -+ have = &rpzs->have.qname; -+ break; -+ case DNS_RPZ_TYPE_IP: -+ REQUIRE(tgt_ip != NULL); -+ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { -+ cnt = &rpz->triggers.ipv4; -+ have = &rpzs->have.ipv4; -+ } else { -+ cnt = &rpz->triggers.ipv6; -+ have = &rpzs->have.ipv6; -+ } -+ break; -+ case DNS_RPZ_TYPE_NSDNAME: -+ cnt = &rpz->triggers.nsdname; -+ have = &rpzs->have.nsdname; -+ break; -+ case DNS_RPZ_TYPE_NSIP: -+ REQUIRE(tgt_ip != NULL); -+ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { -+ cnt = &rpz->triggers.nsipv4; -+ have = &rpzs->have.nsipv4; -+ } else { -+ cnt = &rpz->triggers.nsipv6; -+ have = &rpzs->have.nsipv6; -+ } -+ break; -+ default: -+ INSIST(0); -+ } - flags = get_flags(&node->ip, node->bits, rpz_type); - node->flags |= flags; @@ -6286,6 +5431,49 @@ Index: lib/dns/rpz.c - if (node == NULL) - return; - node->flags |= flags; ++ switch (rpz_type) { ++ case DNS_RPZ_TYPE_CLIENT_IP: ++ REQUIRE(tgt_ip != NULL); ++ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { ++ cnt = &rpzs->triggers[rpz_num].client_ipv4; ++ have = &rpzs->have.client_ipv4; ++ } else { ++ cnt = &rpzs->triggers[rpz_num].client_ipv6; ++ have = &rpzs->have.client_ipv6; ++ } ++ break; ++ case DNS_RPZ_TYPE_QNAME: ++ cnt = &rpzs->triggers[rpz_num].qname; ++ have = &rpzs->have.qname; ++ break; ++ case DNS_RPZ_TYPE_IP: ++ REQUIRE(tgt_ip != NULL); ++ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { ++ cnt = &rpzs->triggers[rpz_num].ipv4; ++ have = &rpzs->have.ipv4; ++ } else { ++ cnt = &rpzs->triggers[rpz_num].ipv6; ++ have = &rpzs->have.ipv6; ++ } ++ break; ++ case DNS_RPZ_TYPE_NSDNAME: ++ cnt = &rpzs->triggers[rpz_num].nsdname; ++ have = &rpzs->have.nsdname; ++ break; ++ case DNS_RPZ_TYPE_NSIP: ++ REQUIRE(tgt_ip != NULL); ++ if (KEY_IS_IPV4(tgt_prefix, tgt_ip)) { ++ cnt = &rpzs->triggers[rpz_num].nsipv4; ++ have = &rpzs->have.nsipv4; ++ } else { ++ cnt = &rpzs->triggers[rpz_num].nsipv6; ++ have = &rpzs->have.nsipv6; ++ } ++ break; ++ default: ++ INSIST(0); ++ } ++ + if (inc) { + if (++*cnt == 1) { + *have |= DNS_RPZ_ZBIT(rpz_num); @@ -6389,7 +5577,7 @@ Index: lib/dns/rpz.c { #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 -@@ -440,22 +529,18 @@ +@@ -440,22 +531,18 @@ int w[DNS_RPZ_CIDR_WORDS*2]; char str[1+8+1+INET6_ADDRSTRLEN+1]; isc_buffer_t buffer; @@ -6414,7 +5602,7 @@ Index: lib/dns/rpz.c return (ISC_R_FAILURE); } else { for (i = 0; i < DNS_RPZ_CIDR_WORDS; i++) { -@@ -469,9 +554,9 @@ +@@ -469,9 +556,9 @@ return (ISC_R_FAILURE); i = 0; while (i < DNS_RPZ_CIDR_WORDS * 2) { @@ -6427,7 +5615,7 @@ Index: lib/dns/rpz.c INSIST((size_t)len <= sizeof(str)); n = snprintf(&str[len], sizeof(str) - len, ".%x", w[i++]); -@@ -495,48 +580,31 @@ +@@ -495,48 +582,31 @@ } } @@ -6488,7 +5676,7 @@ Index: lib/dns/rpz.c return (DNS_RPZ_TYPE_NSDNAME); #endif -@@ -545,73 +613,80 @@ +@@ -545,73 +615,80 @@ /* * Convert an IP address from canonical response policy domain name form @@ -6603,7 +5791,7 @@ Index: lib/dns/rpz.c tgt_ip->w[0] = 0; tgt_ip->w[1] = 0; tgt_ip->w[2] = ADDR_V4MAPPED; -@@ -621,7 +696,7 @@ +@@ -621,7 +698,7 @@ if (l > 255U || (*cp2 != '.' && *cp2 != '\0')) { if (*cp2 == '.') *cp2 = '\0'; @@ -6612,7 +5800,7 @@ Index: lib/dns/rpz.c "; invalid IPv4 octet ", cp); return (ISC_R_FAILURE); } -@@ -632,7 +707,7 @@ +@@ -632,7 +709,7 @@ /* * Convert a text IPv6 address. */ @@ -6621,7 +5809,7 @@ Index: lib/dns/rpz.c for (i = 0; ip_labels > 0 && i < DNS_RPZ_CIDR_WORDS * 2; ip_labels--) { -@@ -651,7 +726,7 @@ +@@ -651,7 +728,7 @@ (*cp2 != '.' && *cp2 != '\0')) { if (*cp2 == '.') *cp2 = '\0'; @@ -6630,7 +5818,7 @@ Index: lib/dns/rpz.c "; invalid IPv6 word ", cp); return (ISC_R_FAILURE); } -@@ -665,36 +740,37 @@ +@@ -665,36 +742,37 @@ } } if (cp != end) { @@ -6682,7 +5870,7 @@ Index: lib/dns/rpz.c return (ISC_R_FAILURE); } -@@ -702,10 +778,54 @@ +@@ -702,10 +780,54 @@ } /* @@ -6740,7 +5928,7 @@ Index: lib/dns/rpz.c int bit; bit = DNS_RPZ_CIDR_WORD_BITS-1; -@@ -731,17 +851,17 @@ +@@ -731,17 +853,17 @@ } /* @@ -6763,7 +5951,7 @@ Index: lib/dns/rpz.c /* * find the first differing words -@@ -751,7 +871,7 @@ +@@ -751,7 +873,7 @@ i++, bit += DNS_RPZ_CIDR_WORD_BITS) { delta = key1->w[i] ^ key2->w[i]; if (delta != 0) { @@ -6772,7 +5960,7 @@ Index: lib/dns/rpz.c break; } } -@@ -759,133 +879,170 @@ +@@ -759,133 +881,170 @@ } /* @@ -7007,7 +6195,7 @@ Index: lib/dns/rpz.c parent = cur; cur_num = DNS_RPZ_IP_BIT(tgt_ip, dbit); cur = cur->child[cur_num]; -@@ -894,7 +1051,7 @@ +@@ -894,7 +1053,7 @@ /* @@ -7016,7 +6204,7 @@ Index: lib/dns/rpz.c * so we failed to match both the target and the current node. * Insert a fork of a parent above the current node and * add the target as a sibling of the current node -@@ -902,17 +1059,17 @@ +@@ -902,17 +1061,17 @@ if (!create) return (find_result); @@ -7038,7 +6226,7 @@ Index: lib/dns/rpz.c else parent->child[cur_num] = new_parent; child_num = DNS_RPZ_IP_BIT(tgt_ip, dbit); -@@ -920,129 +1077,675 @@ +@@ -920,129 +1079,670 @@ new_parent->child[1-child_num] = cur; cur->parent = new_parent; sibling->parent = new_parent; @@ -7187,6 +6375,7 @@ Index: lib/dns/rpz.c - * internal rbt nodes get deleted. + * bin/tests/system/rpz/tests.sh looks for "rpz.*failed". */ +- return; + dns_name_format(trig_name, namebuf, sizeof(namebuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, + DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL, @@ -7327,10 +6516,7 @@ Index: lib/dns/rpz.c + *rpzp = NULL; + isc_refcount_decrement(&rpz->refs, &refs); + if (refs != 0) - return; -- case DNS_RPZ_TYPE_QNAME: -- case DNS_RPZ_TYPE_BAD: -- return; ++ return; + isc_refcount_destroy(&rpz->refs); + + if (dns_name_dynamic(&rpz->origin)) @@ -7347,6 +6533,8 @@ Index: lib/dns/rpz.c + dns_name_free(&rpz->passthru, rpzs->mctx); + if (dns_name_dynamic(&rpz->drop)) + dns_name_free(&rpz->drop, rpzs->mctx); ++ if (dns_name_dynamic(&rpz->tcp_only)) ++ dns_name_free(&rpz->tcp_only, rpzs->mctx); + if (dns_name_dynamic(&rpz->cname)) + dns_name_free(&rpz->cname, rpzs->mctx); + @@ -7436,6 +6624,9 @@ Index: lib/dns/rpz.c + LOCK(&rpzs->maint_lock); + LOCK(&rpzs->search_lock); + if ((rpzs->load_begun & tgt) == 0) { ++ /* ++ * There is no existing version of the target zone. ++ */ + rpzs->load_begun |= tgt; + dns_rpz_attach_rpzs(rpzs, load_rpzsp); + UNLOCK(&rpzs->search_lock); @@ -7450,6 +6641,11 @@ Index: lib/dns/rpz.c + return (result); + load_rpzs = *load_rpzsp; + load_rpzs->p.num_zones = rpzs->p.num_zones; ++ load_rpzs->total_triggers = rpzs->total_triggers; ++ memcpy(load_rpzs->triggers, rpzs->triggers, ++ sizeof(load_rpzs->triggers)); ++ memset(&load_rpzs->triggers[rpz_num], 0, ++ sizeof(load_rpzs->triggers[rpz_num])); + load_rpzs->zones[rpz_num] = rpz; + isc_refcount_increment(&rpz->refs, NULL); + } @@ -7458,35 +6654,53 @@ Index: lib/dns/rpz.c +} + +static void -+fix_triggers(dns_rpz_zones_t *rpzs, dns_rpz_triggers_t *totals) { -+ dns_rpz_num_t rpz_num; ++fix_triggers(dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num) { ++ dns_rpz_num_t n; + const dns_rpz_zone_t *rpz; ++ dns_rpz_triggers_t old_totals; + dns_rpz_zbits_t zbit; ++ char namebuf[DNS_NAME_FORMATSIZE]; + -+# define SET_TRIG(type) \ -+ if (rpz == NULL || rpz->triggers.type == 0) { \ ++# define SET_TRIG(n, zbit, type) \ ++ if (rpzs->triggers[n].type == 0) { \ + rpzs->have.type &= ~zbit; \ + } else { \ -+ totals->type += rpz->triggers.type; \ ++ rpzs->total_triggers.type += rpzs->triggers[n].type; \ + rpzs->have.type |= zbit; \ + } + -+ memset(totals, 0, sizeof(*totals)); -+ for (rpz_num = 0; rpz_num < rpzs->p.num_zones; ++rpz_num) { -+ rpz = rpzs->zones[rpz_num]; -+ zbit = DNS_RPZ_ZBIT(rpz_num); -+ SET_TRIG(client_ipv4); -+ SET_TRIG(client_ipv6); -+ SET_TRIG(qname); -+ SET_TRIG(ipv4); -+ SET_TRIG(ipv6); -+ SET_TRIG(nsdname); -+ SET_TRIG(nsipv4); -+ SET_TRIG(nsipv6); ++ memcpy(&old_totals, &rpzs->total_triggers, sizeof(old_totals)); ++ memset(&rpzs->total_triggers, 0, sizeof(rpzs->total_triggers)); ++ for (n = 0; n < rpzs->p.num_zones; ++n) { ++ rpz = rpzs->zones[n]; ++ zbit = DNS_RPZ_ZBIT(n); ++ SET_TRIG(n, zbit, client_ipv4); ++ SET_TRIG(n, zbit, client_ipv6); ++ SET_TRIG(n, zbit, qname); ++ SET_TRIG(n, zbit, ipv4); ++ SET_TRIG(n, zbit, ipv6); ++ SET_TRIG(n, zbit, nsdname); ++ SET_TRIG(n, zbit, nsipv4); ++ SET_TRIG(n, zbit, nsipv6); + } + + fix_qname_skip_recurse(rpzs); + ++ dns_name_format(&rpzs->zones[rpz_num]->origin, ++ namebuf, sizeof(namebuf)); ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, ++ DNS_LOGMODULE_RBTDB, DNS_RPZ_INFO_LEVEL, ++ "(re)loading policy zone '%s' changed from" ++ " %d to %d qname, %d to %d nsdname," ++ " %d to %d IP, %d to %d NSIP entries", ++ namebuf, ++ old_totals.qname, rpzs->total_triggers.qname, ++ old_totals.nsdname, rpzs->total_triggers.nsdname, ++ old_totals.ipv4 + old_totals.ipv6, ++ rpzs->total_triggers.ipv4 + rpzs->total_triggers.ipv6, ++ old_totals.nsipv4 + old_totals.nsipv6, ++ rpzs->total_triggers.nsipv4 + rpzs->total_triggers.nsipv6); ++ +# undef SET_TRIG +} + @@ -7498,7 +6712,6 @@ Index: lib/dns/rpz.c +dns_rpz_ready(dns_rpz_zones_t *rpzs, + dns_rpz_zones_t **load_rpzsp, dns_rpz_num_t rpz_num) +{ -+ char namebuf[DNS_NAME_FORMATSIZE]; + dns_rpz_zones_t *load_rpzs; + const dns_rpz_cidr_node_t *cnode, *next_cnode, *parent_cnode; + dns_rpz_cidr_node_t *found; @@ -7508,7 +6721,6 @@ Index: lib/dns/rpz.c + dns_rbtnodechain_t chain; + dns_rbtnode_t *nmnode; + dns_rpz_nm_data_t *nm_data, new_data; -+ dns_rpz_triggers_t old_totals, new_totals; + dns_fixedname_t labelf, originf, namef; + dns_name_t *label, *origin, *name; + isc_result_t result; @@ -7523,27 +6735,9 @@ Index: lib/dns/rpz.c + * This is a successful initial zone loading, + * perhaps for a new instance of a view. + */ -+ fix_triggers(rpzs, &new_totals); ++ fix_triggers(rpzs, rpz_num); + UNLOCK(&rpzs->maint_lock); + dns_rpz_detach_rpzs(load_rpzsp); -+ -+ if (rpz_num == rpzs->p.num_zones-1) -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, -+ DNS_LOGMODULE_RBTDB, DNS_RPZ_INFO_LEVEL, -+ "loaded policy %d zones with" -+ " %d client-IPv4, %d client-IPv6," -+ " %d qname, %d nsdname," -+ " %d IPv4, %d IPv6," -+ " %d NSIPv4, %d NSIPv6 entries", -+ rpzs->p.num_zones, -+ new_totals.client_ipv4, -+ new_totals.client_ipv6, -+ new_totals.qname, -+ new_totals.nsdname, -+ new_totals.ipv4, -+ new_totals.ipv6, -+ new_totals.nsipv4, -+ new_totals.nsipv6); + return (ISC_R_SUCCESS); + } + @@ -7551,8 +6745,8 @@ Index: lib/dns/rpz.c + LOCK(&load_rpzs->search_lock); + + /* -+ * Copy the other policy zones to the new summary databases -+ * unless there is only one policy zone. ++ * Unless there is only one policy zone, copy the other policy zones ++ * from the old policy structure to the new summary databases. + */ + if (rpzs->p.num_zones > 1) { + new_bit = ~DNS_RPZ_ZBIT(rpz_num); @@ -7642,32 +6836,13 @@ Index: lib/dns/rpz.c + isc_result_totext(result)); + goto unlock_and_detach; + } - } - -+ fix_triggers(rpzs, &old_totals); -+ fix_triggers(load_rpzs, &new_totals); ++ } + -+ dns_name_format(&load_rpzs->zones[rpz_num]->origin, -+ namebuf, sizeof(namebuf)); -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ, -+ DNS_LOGMODULE_RBTDB, DNS_RPZ_INFO_LEVEL, -+ "reloading policy zone '%s' changed from" -+ " %d to %d qname, %d to %d nsdname," -+ " %d to %d IP, %d to %d NSIP entries", -+ namebuf, -+ old_totals.qname, new_totals.qname, -+ old_totals.nsdname, new_totals.nsdname, -+ old_totals.ipv4 + old_totals.ipv6, -+ new_totals.ipv4 + new_totals.ipv6, -+ old_totals.nsipv4 + old_totals.nsipv6, -+ new_totals.nsipv4 + new_totals.nsipv6); ++ fix_triggers(load_rpzs, rpz_num); + - /* -- * Do not get excited about the deletion of interior rbt nodes. ++ /* + * Exchange the summary databases. - */ -- result = name2ipkey(cidr, DNS_RPZ_DEBUG_QUIET, name, -- type, &tgt_ip, &tgt_prefix); ++ */ + LOCK(&rpzs->search_lock); + + found = rpzs->cidr; @@ -7678,7 +6853,10 @@ Index: lib/dns/rpz.c + rpzs->rbt = load_rpzs->rbt; + load_rpzs->rbt = rbt; + ++ rpzs->total_triggers = load_rpzs->total_triggers; ++ + UNLOCK(&rpzs->search_lock); ++ + result = ISC_R_SUCCESS; + + unlock_and_detach: @@ -7709,7 +6887,7 @@ Index: lib/dns/rpz.c + LOCK(&rpzs->search_lock); + + switch (rpz_type) { -+ case DNS_RPZ_TYPE_QNAME: + case DNS_RPZ_TYPE_QNAME: + case DNS_RPZ_TYPE_NSDNAME: + result = add_name(rpzs, rpz_num, rpz_type, src_name); + break; @@ -7718,10 +6896,11 @@ Index: lib/dns/rpz.c + case DNS_RPZ_TYPE_NSIP: + result = add_cidr(rpzs, rpz_num, rpz_type, src_name); + break; -+ case DNS_RPZ_TYPE_BAD: + case DNS_RPZ_TYPE_BAD: +- return; + break; -+ } -+ + } + + UNLOCK(&rpzs->search_lock); + UNLOCK(&rpzs->maint_lock); + return (result); @@ -7740,11 +6919,14 @@ Index: lib/dns/rpz.c + dns_rpz_addr_zbits_t tgt_set; + dns_rpz_cidr_node_t *tgt, *parent, *child; + -+ /* + /* +- * Do not get excited about the deletion of interior rbt nodes. + * Do not worry about invalid rpz IP address names. If we + * are here, then something relevant was added and so was + * valid. Invalid names here are usually internal RBTDB nodes. -+ */ + */ +- result = name2ipkey(cidr, DNS_RPZ_DEBUG_QUIET, name, +- type, &tgt_ip, &tgt_prefix); + result = name2ipkey(DNS_RPZ_DEBUG_QUIET, rpzs, rpz_num, rpz_type, + src_name, &tgt_ip, &tgt_prefix, &tgt_set); if (result != ISC_R_SUCCESS) @@ -7794,7 +6976,7 @@ Index: lib/dns/rpz.c /* * We might need to delete 2 nodes. -@@ -1054,13 +1757,14 @@ +@@ -1054,13 +1754,14 @@ */ if ((child = tgt->child[0]) != NULL) { if (tgt->child[1] != NULL) @@ -7813,7 +6995,7 @@ Index: lib/dns/rpz.c /* * Replace the pointer to this node in the parent with -@@ -1068,7 +1772,7 @@ +@@ -1068,7 +1769,7 @@ */ parent = tgt->parent; if (parent == NULL) { @@ -7822,7 +7004,7 @@ Index: lib/dns/rpz.c } else { parent->child[parent->child[1] == tgt] = child; } -@@ -1077,26 +1781,144 @@ +@@ -1077,26 +1778,144 @@ */ if (child != NULL) child->parent = parent; @@ -7977,7 +7159,7 @@ Index: lib/dns/rpz.c int i; /* -@@ -1107,29 +1929,163 @@ +@@ -1107,29 +1926,163 @@ tgt_ip.w[1] = 0; tgt_ip.w[2] = ADDR_V4MAPPED; tgt_ip.w[3] = ntohl(netaddr->type.in.s_addr); @@ -8043,7 +7225,10 @@ Index: lib/dns/rpz.c + UNLOCK(&rpzs->search_lock); + return (DNS_RPZ_INVALID_NUM); + } -+ + +- *prefix = found->bits; +- return (ip2name(cidr, &found->ip, found->bits, type, +- canon_name, search_name)); + /* + * Construct the trigger name for the longest matching trigger + * in the first eligible zone with a match. @@ -8077,10 +7262,7 @@ Index: lib/dns/rpz.c + } + return (rpz_num); +} - -- *prefix = found->bits; -- return (ip2name(cidr, &found->ip, found->bits, type, -- canon_name, search_name)); ++ +/* + * Search the summary radix tree for policy zones with triggers matching + * a name. @@ -8149,7 +7331,7 @@ Index: lib/dns/rpz.c } /* -@@ -1144,10 +2100,10 @@ +@@ -1144,10 +2097,10 @@ isc_result_t result; result = dns_rdataset_first(rdataset); @@ -8162,12 +7344,18 @@ Index: lib/dns/rpz.c dns_rdata_reset(&rdata); /* -@@ -1174,7 +2130,13 @@ +@@ -1174,7 +2127,19 @@ } /* - * CNAME PASSTHRU.origin means "do not rewrite. -+ * CNAME rpz-drop. means "do respond." ++ * CNAME rpz-tcp-only. means "send truncated UDP responses." ++ */ ++ if (dns_name_equal(&cname.cname, &rpz->tcp_only)) ++ return (DNS_RPZ_POLICY_TCP_ONLY); ++ ++ /* ++ * CNAME rpz-drop. means "do not respond." + */ + if (dns_name_equal(&cname.cname, &rpz->drop)) + return (DNS_RPZ_POLICY_DROP); @@ -8177,1356 +7365,10 @@ Index: lib/dns/rpz.c */ if (dns_name_equal(&cname.cname, &rpz->passthru)) return (DNS_RPZ_POLICY_PASSTHRU); -Index: lib/dns/rrl.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ lib/dns/rrl.c 2013-08-05 14:14:45.921498580 +0200 -@@ -0,0 +1,1324 @@ -+/* -+ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+/*! \file */ -+ -+/* -+ * Rate limit DNS responses. -+ */ -+ -+/* #define ISC_LIST_CHECKINIT */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void -+log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_boolean_t early, -+ char *log_buf, unsigned int log_buf_len); -+ -+/* -+ * Get a modulus for a hash function that is tolerably likely to be -+ * relatively prime to most inputs. Of course, we get a prime for for initial -+ * values not larger than the square of the last prime. We often get a prime -+ * after that. -+ * This works well in practice for hash tables up to at least 100 -+ * times the square of the last prime and better than a multiplicative hash. -+ */ -+static int -+hash_divisor(unsigned int initial) { -+ static isc_uint16_t primes[] = { -+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, -+ 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, -+#if 0 -+ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, -+ 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, -+ 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, -+ 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, -+ 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, -+ 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, -+ 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, -+ 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, -+ 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, -+ 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, -+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, -+ 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,1009, -+#endif -+ }; -+ int divisions, tries; -+ unsigned int result; -+ isc_uint16_t *pp, p; -+ -+ result = initial; -+ -+ if (primes[sizeof(primes)/sizeof(primes[0])-1] >= result) { -+ pp = primes; -+ while (*pp < result) -+ ++pp; -+ return (*pp); -+ } -+ -+ if ((result & 1) == 0) -+ ++result; -+ -+ divisions = 0; -+ tries = 1; -+ pp = primes; -+ do { -+ p = *pp++; -+ ++divisions; -+ if ((result % p) == 0) { -+ ++tries; -+ result += 2; -+ pp = primes; -+ } -+ } while (pp < &primes[sizeof(primes) / sizeof(primes[0])]); -+ -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3, -+ "%d hash_divisor() divisions in %d tries" -+ " to get %d from %d", -+ divisions, tries, result, initial); -+ -+ return (result); -+} -+ -+/* -+ * Convert a timestamp to a number of seconds in the past. -+ */ -+static inline int -+delta_rrl_time(isc_stdtime_t ts, isc_stdtime_t now) { -+ int delta; -+ -+ delta = now - ts; -+ if (delta >= 0) -+ return (delta); -+ -+ /* -+ * The timestamp is in the future. That future might result from -+ * re-ordered requests, because we use timestamps on requests -+ * instead of consulting a clock. Timestamps in the distant future are -+ * assumed to result from clock changes. When the clock changes to -+ * the past, make existing timestamps appear to be in the past. -+ */ -+ if (delta < -DNS_RRL_MAX_TIME_TRAVEL) -+ return (DNS_RRL_FOREVER); -+ return (0); -+} -+ -+static inline int -+get_age(const dns_rrl_t *rrl, const dns_rrl_entry_t *e, isc_stdtime_t now) { -+ if (!e->ts_valid) -+ return (DNS_RRL_FOREVER); -+ return (delta_rrl_time(e->ts + rrl->ts_bases[e->ts_gen], now)); -+} -+ -+static inline void -+set_age(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_stdtime_t now) { -+ dns_rrl_entry_t *e_old; -+ unsigned int ts_gen; -+ int i, ts; -+ -+ ts_gen = rrl->ts_gen; -+ ts = now - rrl->ts_bases[ts_gen]; -+ if (ts < 0) { -+ if (ts < -DNS_RRL_MAX_TIME_TRAVEL) -+ ts = DNS_RRL_FOREVER; -+ else -+ ts = 0; -+ } -+ -+ /* -+ * Make a new timestamp base if the current base is too old. -+ * All entries older than DNS_RRL_MAX_WINDOW seconds are ancient, -+ * useless history. Their timestamps can be treated as if they are -+ * all the same. -+ * We only do arithmetic on more recent timestamps, so bases for -+ * older timestamps can be recycled provided the old timestamps are -+ * marked as ancient history. -+ * This loop is almost always very short because most entries are -+ * recycled after one second and any entries that need to be marked -+ * are older than (DNS_RRL_TS_BASES)*DNS_RRL_MAX_TS seconds. -+ */ -+ if (ts >= DNS_RRL_MAX_TS) { -+ ts_gen = (ts_gen + 1) % DNS_RRL_TS_BASES; -+ for (e_old = ISC_LIST_TAIL(rrl->lru), i = 0; -+ e_old != NULL && (e_old->ts_gen == ts_gen || -+ !ISC_LINK_LINKED(e_old, hlink)); -+ e_old = ISC_LIST_PREV(e_old, lru), ++i) -+ { -+ e_old->ts_valid = ISC_FALSE; -+ } -+ if (i != 0) -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1, -+ "rrl new time base scanned %d entries" -+ " at %d for %d %d %d %d", -+ i, now, rrl->ts_bases[ts_gen], -+ rrl->ts_bases[(ts_gen + 1) % -+ DNS_RRL_TS_BASES], -+ rrl->ts_bases[(ts_gen + 2) % -+ DNS_RRL_TS_BASES], -+ rrl->ts_bases[(ts_gen + 3) % -+ DNS_RRL_TS_BASES]); -+ rrl->ts_gen = ts_gen; -+ rrl->ts_bases[ts_gen] = now; -+ ts = 0; -+ } -+ -+ e->ts_gen = ts_gen; -+ e->ts = ts; -+ e->ts_valid = ISC_TRUE; -+} -+ -+static isc_result_t -+expand_entries(dns_rrl_t *rrl, int new) { -+ unsigned int bsize; -+ dns_rrl_block_t *b; -+ dns_rrl_entry_t *e; -+ double rate; -+ int i; -+ -+ if (rrl->num_entries+new >= rrl->max_entries && rrl->max_entries != 0) { -+ if (rrl->num_entries >= rrl->max_entries) -+ return (ISC_R_SUCCESS); -+ new = rrl->max_entries - rrl->num_entries; -+ if (new <= 0) -+ return (ISC_R_NOMEMORY); -+ } -+ -+ /* -+ * Log expansions so that the user can tune max-table-size -+ * and min-table-size. -+ */ -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && -+ rrl->hash != NULL) { -+ rate = rrl->probes; -+ if (rrl->searches != 0) -+ rate /= rrl->searches; -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, -+ "increase from %d to %d RRL entries with" -+ " %d bins; average search length %.1f", -+ rrl->num_entries, rrl->num_entries+new, -+ rrl->hash->length, rate); -+ } -+ -+ bsize = sizeof(dns_rrl_block_t) + (new-1)*sizeof(dns_rrl_entry_t); -+ b = isc_mem_get(rrl->mctx, bsize); -+ if (b == NULL) { -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_FAIL, -+ "isc_mem_get(%d) failed for RRL entries", -+ bsize); -+ return (ISC_R_NOMEMORY); -+ } -+ memset(b, 0, bsize); -+ b->size = bsize; -+ -+ e = b->entries; -+ for (i = 0; i < new; ++i, ++e) { -+ ISC_LINK_INIT(e, hlink); -+ ISC_LIST_INITANDAPPEND(rrl->lru, e, lru); -+ } -+ rrl->num_entries += new; -+ ISC_LIST_INITANDAPPEND(rrl->blocks, b, link); -+ -+ return (ISC_R_SUCCESS); -+} -+ -+static inline dns_rrl_bin_t * -+get_bin(dns_rrl_hash_t *hash, unsigned int hval) { -+ return (&hash->bins[hval % hash->length]); -+} -+ -+static void -+free_old_hash(dns_rrl_t *rrl) { -+ dns_rrl_hash_t *old_hash; -+ dns_rrl_bin_t *old_bin; -+ dns_rrl_entry_t *e, *e_next; -+ -+ old_hash = rrl->old_hash; -+ for (old_bin = &old_hash->bins[0]; -+ old_bin < &old_hash->bins[old_hash->length]; -+ ++old_bin) -+ { -+ for (e = ISC_LIST_HEAD(*old_bin); e != NULL; e = e_next) { -+ e_next = ISC_LIST_NEXT(e, hlink); -+ ISC_LINK_INIT(e, hlink); -+ } -+ } -+ -+ isc_mem_put(rrl->mctx, old_hash, -+ sizeof(*old_hash) -+ + (old_hash->length - 1) * sizeof(old_hash->bins[0])); -+ rrl->old_hash = NULL; -+} -+ -+static isc_result_t -+expand_rrl_hash(dns_rrl_t *rrl, isc_stdtime_t now) { -+ dns_rrl_hash_t *hash; -+ int old_bins, new_bins, hsize; -+ double rate; -+ -+ if (rrl->old_hash != NULL) -+ free_old_hash(rrl); -+ -+ /* -+ * Most searches fail and so go to the end of the chain. -+ * Use a small hash table load factor. -+ */ -+ old_bins = (rrl->hash == NULL) ? 0 : rrl->hash->length; -+ new_bins = old_bins/8 + old_bins; -+ if (new_bins < rrl->num_entries) -+ new_bins = rrl->num_entries; -+ new_bins = hash_divisor(new_bins); -+ -+ hsize = sizeof(dns_rrl_hash_t) + (new_bins-1)*sizeof(hash->bins[0]); -+ hash = isc_mem_get(rrl->mctx, hsize); -+ if (hash == NULL) { -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_FAIL, -+ "isc_mem_get(%d) failed for" -+ " RRL hash table", -+ hsize); -+ return (ISC_R_NOMEMORY); -+ } -+ memset(hash, 0, hsize); -+ hash->length = new_bins; -+ rrl->hash_gen ^= 1; -+ hash->gen = rrl->hash_gen; -+ -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP) && old_bins != 0) { -+ rate = rrl->probes; -+ if (rrl->searches != 0) -+ rate /= rrl->searches; -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, -+ "increase from %d to %d RRL bins for" -+ " %d entries; average search length %.1f", -+ old_bins, new_bins, rrl->num_entries, rate); -+ } -+ -+ rrl->old_hash = rrl->hash; -+ if (rrl->old_hash != NULL) -+ rrl->old_hash->check_time = now; -+ rrl->hash = hash; -+ -+ return (ISC_R_SUCCESS); -+} -+ -+static void -+ref_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, int probes, isc_stdtime_t now) { -+ /* -+ * Make the entry most recently used. -+ */ -+ if (ISC_LIST_HEAD(rrl->lru) != e) { -+ if (e == rrl->last_logged) -+ rrl->last_logged = ISC_LIST_PREV(e, lru); -+ ISC_LIST_UNLINK(rrl->lru, e, lru); -+ ISC_LIST_PREPEND(rrl->lru, e, lru); -+ } -+ -+ /* -+ * Expand the hash table if it is time and necessary. -+ * This will leave the newly referenced entry in a chain in the -+ * old hash table. It will migrate to the new hash table the next -+ * time it is used or be cut loose when the old hash table is destroyed. -+ */ -+ rrl->probes += probes; -+ ++rrl->searches; -+ if (rrl->searches > 100 && -+ delta_rrl_time(rrl->hash->check_time, now) > 1) { -+ if (rrl->probes/rrl->searches > 2) -+ expand_rrl_hash(rrl, now); -+ rrl->hash->check_time = now; -+ rrl->probes = 0; -+ rrl->searches = 0; -+ } -+} -+ -+static inline isc_boolean_t -+key_cmp(const dns_rrl_key_t *a, const dns_rrl_key_t *b) { -+ if (memcmp(a, b, sizeof(dns_rrl_key_t)) == 0) -+ return (ISC_TRUE); -+ return (ISC_FALSE); -+} -+ -+static inline isc_uint32_t -+hash_key(const dns_rrl_key_t *key) { -+ isc_uint32_t hval; -+ int i; -+ -+ hval = key->w[0]; -+ for (i = sizeof(*key) / sizeof(key->w[0]) - 1; i >= 0; --i) { -+ hval = key->w[i] + (hval<<1); -+ } -+ return (hval); -+} -+ -+/* -+ * Construct the hash table key. -+ * Use a hash of the DNS query name to save space in the database. -+ * Collisions result in legitimate rate limiting responses for one -+ * query name also limiting responses for other names to the -+ * same client. This is rare and benign enough given the large -+ * space costs compared to keeping the entire name in the database -+ * entry or the time costs of dynamic allocation. -+ */ -+static void -+make_key(const dns_rrl_t *rrl, dns_rrl_key_t *key, -+ const isc_sockaddr_t *client_addr, -+ dns_rdatatype_t qtype, dns_name_t *qname, dns_rdataclass_t qclass, -+ dns_rrl_rtype_t rtype) -+{ -+ dns_name_t base; -+ dns_offsets_t base_offsets; -+ int labels, i; -+ -+ memset(key, 0, sizeof(*key)); -+ -+ key->s.rtype = rtype; -+ if (rtype == DNS_RRL_RTYPE_QUERY) { -+ key->s.qtype = qtype; -+ key->s.qclass = qclass & 0xff; -+ } else if (rtype == DNS_RRL_RTYPE_REFERRAL || -+ rtype == DNS_RRL_RTYPE_NODATA) { -+ /* -+ * Because there is no qtype in the empty answer sections of -+ * referral and NODATA responses, count them as the same. -+ */ -+ key->s.qclass = qclass & 0xff; -+ } -+ -+ if (qname != NULL && qname->labels != 0) { -+ /* -+ * Ignore the first label of wildcards. -+ */ -+ if ((qname->attributes & DNS_NAMEATTR_WILDCARD) != 0 && -+ (labels = dns_name_countlabels(qname)) > 1) -+ { -+ dns_name_init(&base, base_offsets); -+ dns_name_getlabelsequence(qname, 1, labels-1, &base); -+ key->s.qname_hash = dns_name_hashbylabel(&base, -+ ISC_FALSE); -+ } else { -+ key->s.qname_hash = dns_name_hashbylabel(qname, -+ ISC_FALSE); -+ } -+ } -+ -+ switch (client_addr->type.sa.sa_family) { -+ case AF_INET: -+ key->s.ip[0] = (client_addr->type.sin.sin_addr.s_addr & -+ rrl->ipv4_mask); -+ break; -+ case AF_INET6: -+ key->s.ipv6 = ISC_TRUE; -+ memcpy(key->s.ip, &client_addr->type.sin6.sin6_addr, -+ sizeof(key->s.ip)); -+ for (i = 0; i < DNS_RRL_MAX_PREFIX/32; ++i) -+ key->s.ip[i] &= rrl->ipv6_mask[i]; -+ break; -+ } -+} -+ -+static inline dns_rrl_rate_t * -+get_rate(dns_rrl_t *rrl, dns_rrl_rtype_t rtype) { -+ switch (rtype) { -+ case DNS_RRL_RTYPE_QUERY: -+ return (&rrl->responses_per_second); -+ case DNS_RRL_RTYPE_REFERRAL: -+ return (&rrl->referrals_per_second); -+ case DNS_RRL_RTYPE_NODATA: -+ return (&rrl->nodata_per_second); -+ case DNS_RRL_RTYPE_NXDOMAIN: -+ return (&rrl->nxdomains_per_second); -+ case DNS_RRL_RTYPE_ERROR: -+ return (&rrl->errors_per_second); -+ case DNS_RRL_RTYPE_ALL: -+ return (&rrl->all_per_second); -+ default: -+ INSIST(0); -+ } -+ return (NULL); -+} -+ -+static int -+response_balance(dns_rrl_t *rrl, const dns_rrl_entry_t *e, int age) { -+ dns_rrl_rate_t *ratep; -+ int balance, rate; -+ -+ if (e->key.s.rtype == DNS_RRL_RTYPE_TCP) { -+ rate = 1; -+ } else { -+ ratep = get_rate(rrl, e->key.s.rtype); -+ rate = ratep->scaled; -+ } -+ -+ balance = e->responses + age * rate; -+ if (balance > rate) -+ balance = rate; -+ return (balance); -+} -+ -+/* -+ * Search for an entry for a response and optionally create it. -+ */ -+static dns_rrl_entry_t * -+get_entry(dns_rrl_t *rrl, const isc_sockaddr_t *client_addr, -+ dns_rdataclass_t qclass, dns_rdatatype_t qtype, dns_name_t *qname, -+ dns_rrl_rtype_t rtype, isc_stdtime_t now, isc_boolean_t create, -+ char *log_buf, unsigned int log_buf_len) -+{ -+ dns_rrl_key_t key; -+ isc_uint32_t hval; -+ dns_rrl_entry_t *e; -+ dns_rrl_hash_t *hash; -+ dns_rrl_bin_t *new_bin, *old_bin; -+ int probes, age; -+ -+ make_key(rrl, &key, client_addr, qtype, qname, qclass, rtype); -+ hval = hash_key(&key); -+ -+ /* -+ * Look for the entry in the current hash table. -+ */ -+ new_bin = get_bin(rrl->hash, hval); -+ probes = 1; -+ e = ISC_LIST_HEAD(*new_bin); -+ while (e != NULL) { -+ if (key_cmp(&e->key, &key)) { -+ ref_entry(rrl, e, probes, now); -+ return (e); -+ } -+ ++probes; -+ e = ISC_LIST_NEXT(e, hlink); -+ } -+ -+ /* -+ * Look in the old hash table. -+ */ -+ if (rrl->old_hash != NULL) { -+ old_bin = get_bin(rrl->old_hash, hval); -+ e = ISC_LIST_HEAD(*old_bin); -+ while (e != NULL) { -+ if (key_cmp(&e->key, &key)) { -+ ISC_LIST_UNLINK(*old_bin, e, hlink); -+ ISC_LIST_PREPEND(*new_bin, e, hlink); -+ e->hash_gen = rrl->hash_gen; -+ ref_entry(rrl, e, probes, now); -+ return (e); -+ } -+ e = ISC_LIST_NEXT(e, hlink); -+ } -+ -+ /* -+ * Discard prevous hash table when all of its entries are old. -+ */ -+ age = delta_rrl_time(rrl->old_hash->check_time, now); -+ if (age > rrl->window) -+ free_old_hash(rrl); -+ } -+ -+ if (!create) -+ return (NULL); -+ -+ /* -+ * The entry does not exist, so create it by finding a free entry. -+ * Keep currently penalized and logged entries. -+ * Try to make more entries if none are idle. -+ * Steal the oldest entry if we cannot create more. -+ */ -+ for (e = ISC_LIST_TAIL(rrl->lru); -+ e != NULL; -+ e = ISC_LIST_PREV(e, lru)) -+ { -+ if (!ISC_LINK_LINKED(e, hlink)) -+ break; -+ age = get_age(rrl, e, now); -+ if (age <= 1) { -+ e = NULL; -+ break; -+ } -+ if (!e->logged && response_balance(rrl, e, age) > 0) -+ break; -+ } -+ if (e == NULL) { -+ expand_entries(rrl, ISC_MIN((rrl->num_entries+1)/2, 1000)); -+ e = ISC_LIST_TAIL(rrl->lru); -+ } -+ if (e->logged) -+ log_end(rrl, e, ISC_TRUE, log_buf, log_buf_len); -+ if (ISC_LINK_LINKED(e, hlink)) { -+ if (e->hash_gen == rrl->hash_gen) -+ hash = rrl->hash; -+ else -+ hash = rrl->old_hash; -+ old_bin = get_bin(hash, hash_key(&e->key)); -+ ISC_LIST_UNLINK(*old_bin, e, hlink); -+ } -+ ISC_LIST_PREPEND(*new_bin, e, hlink); -+ e->hash_gen = rrl->hash_gen; -+ e->key = key; -+ e->ts_valid = ISC_FALSE; -+ ref_entry(rrl, e, probes, now); -+ return (e); -+} -+ -+static void -+debit_log(const dns_rrl_entry_t *e, int age, const char *action) { -+ char buf[sizeof("age=12345678")]; -+ const char *age_str; -+ -+ if (age == DNS_RRL_FOREVER) { -+ age_str = ""; -+ } else { -+ snprintf(buf, sizeof(buf), "age=%d", age); -+ age_str = buf; -+ } -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG3, -+ "rrl %08x %6s responses=%-3d %s", -+ hash_key(&e->key), age_str, e->responses, action); -+} -+ -+static inline dns_rrl_result_t -+debit_rrl_entry(dns_rrl_t *rrl, dns_rrl_entry_t *e, double qps, double scale, -+ const isc_sockaddr_t *client_addr, isc_stdtime_t now, -+ char *log_buf, unsigned int log_buf_len) -+{ -+ int rate, new_rate, slip, new_slip, age, log_secs, min; -+ dns_rrl_rate_t *ratep; -+ dns_rrl_entry_t const *credit_e; -+ -+ /* -+ * Pick the rate counter. -+ * Optionally adjust the rate by the estimated query/second rate. -+ */ -+ ratep = get_rate(rrl, e->key.s.rtype); -+ rate = ratep->r; -+ if (rate == 0) -+ return (DNS_RRL_RESULT_OK); -+ -+ if (scale < 1.0) { -+ /* -+ * The limit for clients that have used TCP is not scaled. -+ */ -+ credit_e = get_entry(rrl, client_addr, -+ 0, dns_rdatatype_none, NULL, -+ DNS_RRL_RTYPE_TCP, now, ISC_FALSE, -+ log_buf, log_buf_len); -+ if (credit_e != NULL) { -+ age = get_age(rrl, e, now); -+ if (age < rrl->window) -+ scale = 1.0; -+ } -+ } -+ if (scale < 1.0) { -+ new_rate = (int) (rate * scale); -+ if (new_rate < 1) -+ new_rate = 1; -+ if (ratep->scaled != new_rate) { -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, -+ DNS_RRL_LOG_DEBUG1, -+ "%d qps scaled %s by %.2f" -+ " from %d to %d", -+ (int)qps, ratep->str, scale, -+ rate, new_rate); -+ rate = new_rate; -+ ratep->scaled = rate; -+ } -+ } -+ -+ min = -rrl->window * rate; -+ -+ /* -+ * Treat time jumps into the recent past as no time. -+ * Treat entries older than the window as if they were just created -+ * Credit other entries. -+ */ -+ age = get_age(rrl, e, now); -+ if (age > 0) { -+ /* -+ * Credit tokens earned during elapsed time. -+ */ -+ if (age > rrl->window) { -+ e->responses = rate; -+ e->slip_cnt = 0; -+ } else { -+ e->responses += rate*age; -+ if (e->responses > rate) { -+ e->responses = rate; -+ e->slip_cnt = 0; -+ } -+ } -+ /* -+ * Find the seconds since last log message without overflowing -+ * small counter. This counter is reset when an entry is -+ * created. It is not necessarily reset when some requests -+ * are answered provided other requests continue to be dropped -+ * or slipped. This can happen when the request rate is just -+ * at the limit. -+ */ -+ if (e->logged) { -+ log_secs = e->log_secs; -+ log_secs += age; -+ if (log_secs > DNS_RRL_MAX_LOG_SECS || log_secs < 0) -+ log_secs = DNS_RRL_MAX_LOG_SECS; -+ e->log_secs = log_secs; -+ } -+ } -+ set_age(rrl, e, now); -+ -+ /* -+ * Debit the entry for this response. -+ */ -+ if (--e->responses >= 0) { -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) -+ debit_log(e, age, ""); -+ return (DNS_RRL_RESULT_OK); -+ } -+ -+ if (e->responses < min) -+ e->responses = min; -+ -+ /* -+ * Drop this response unless it should slip or leak. -+ */ -+ slip = rrl->slip.r; -+ if (slip > 2 && scale < 1.0) { -+ new_slip = (int) (slip * scale); -+ if (new_slip < 2) -+ new_slip = 2; -+ if (rrl->slip.scaled != new_slip) { -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, -+ DNS_RRL_LOG_DEBUG1, -+ "%d qps scaled slip" -+ " by %.2f from %d to %d", -+ (int)qps, scale, -+ slip, new_slip); -+ slip = new_slip; -+ rrl->slip.scaled = slip; -+ } -+ } -+ if (slip != 0 && e->key.s.rtype != DNS_RRL_RTYPE_ALL) { -+ if (e->slip_cnt++ == 0) { -+ if ((int) e->slip_cnt >= slip) -+ e->slip_cnt = 0; -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) -+ debit_log(e, age, "slip"); -+ return (DNS_RRL_RESULT_SLIP); -+ } else if ((int) e->slip_cnt >= slip) { -+ e->slip_cnt = 0; -+ } -+ } -+ -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG3)) -+ debit_log(e, age, "drop"); -+ return (DNS_RRL_RESULT_DROP); -+} -+ -+static inline dns_rrl_qname_buf_t * -+get_qname(dns_rrl_t *rrl, const dns_rrl_entry_t *e) { -+ dns_rrl_qname_buf_t *qbuf; -+ -+ qbuf = rrl->qnames[e->log_qname]; -+ if (qbuf == NULL || qbuf->e != e) -+ return (NULL); -+ return (qbuf); -+} -+ -+static inline void -+free_qname(dns_rrl_t *rrl, dns_rrl_entry_t *e) { -+ dns_rrl_qname_buf_t *qbuf; -+ -+ qbuf = get_qname(rrl, e); -+ if (qbuf != NULL) { -+ qbuf->e = NULL; -+ ISC_LIST_APPEND(rrl->qname_free, qbuf, link); -+ } -+} -+ -+static void -+add_log_str(isc_buffer_t *lb, const char *str, unsigned int str_len) { -+ isc_region_t region; -+ -+ isc_buffer_availableregion(lb, ®ion); -+ if (str_len >= region.length) { -+ if (region.length <= 0) -+ return; -+ str_len = region.length; -+ } -+ memcpy(region.base, str, str_len); -+ isc_buffer_add(lb, str_len); -+} -+ -+#define ADD_LOG_CSTR(eb, s) add_log_str(eb, s, sizeof(s)-1) -+ -+/* -+ * Build strings for the logs -+ */ -+static void -+make_log_buf(dns_rrl_t *rrl, dns_rrl_entry_t *e, -+ const char *str1, const char *str2, isc_boolean_t plural, -+ dns_name_t *qname, isc_boolean_t save_qname, -+ dns_rrl_result_t rrl_result, isc_result_t resp_result, -+ char *log_buf, unsigned int log_buf_len) -+{ -+ isc_buffer_t lb; -+ dns_rrl_qname_buf_t *qbuf; -+ isc_netaddr_t cidr; -+ char strbuf[ISC_MAX(sizeof("/123"), sizeof(" (12345678)"))]; -+ const char *rstr; -+ isc_result_t msg_result; -+ -+ if (log_buf_len <= 1) { -+ if (log_buf_len == 1) -+ log_buf[0] = '\0'; -+ return; -+ } -+ isc_buffer_init(&lb, log_buf, log_buf_len-1); -+ -+ if (str1 != NULL) -+ add_log_str(&lb, str1, strlen(str1)); -+ if (str2 != NULL) -+ add_log_str(&lb, str2, strlen(str2)); -+ -+ switch (rrl_result) { -+ case DNS_RRL_RESULT_OK: -+ break; -+ case DNS_RRL_RESULT_DROP: -+ ADD_LOG_CSTR(&lb, "drop "); -+ break; -+ case DNS_RRL_RESULT_SLIP: -+ ADD_LOG_CSTR(&lb, "slip "); -+ break; -+ default: -+ INSIST(0); -+ break; -+ } -+ -+ switch (e->key.s.rtype) { -+ case DNS_RRL_RTYPE_QUERY: -+ break; -+ case DNS_RRL_RTYPE_REFERRAL: -+ ADD_LOG_CSTR(&lb, "referral "); -+ break; -+ case DNS_RRL_RTYPE_NODATA: -+ ADD_LOG_CSTR(&lb, "NODATA "); -+ break; -+ case DNS_RRL_RTYPE_NXDOMAIN: -+ ADD_LOG_CSTR(&lb, "NXDOMAIN "); -+ break; -+ case DNS_RRL_RTYPE_ERROR: -+ if (resp_result == ISC_R_SUCCESS) { -+ ADD_LOG_CSTR(&lb, "error "); -+ } else { -+ rstr = isc_result_totext(resp_result); -+ add_log_str(&lb, rstr, strlen(rstr)); -+ ADD_LOG_CSTR(&lb, " error "); -+ } -+ break; -+ case DNS_RRL_RTYPE_ALL: -+ ADD_LOG_CSTR(&lb, "all "); -+ break; -+ default: -+ INSIST(0); -+ } -+ -+ if (plural) -+ ADD_LOG_CSTR(&lb, "responses to "); -+ else -+ ADD_LOG_CSTR(&lb, "response to "); -+ -+ memset(&cidr, 0, sizeof(cidr)); -+ if (e->key.s.ipv6) { -+ snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv6_prefixlen); -+ cidr.family = AF_INET6; -+ memset(&cidr.type.in6, 0, sizeof(cidr.type.in6)); -+ memcpy(&cidr.type.in6, e->key.s.ip, sizeof(e->key.s.ip)); -+ } else { -+ snprintf(strbuf, sizeof(strbuf), "/%d", rrl->ipv4_prefixlen); -+ cidr.family = AF_INET; -+ cidr.type.in.s_addr = e->key.s.ip[0]; -+ } -+ msg_result = isc_netaddr_totext(&cidr, &lb); -+ if (msg_result != ISC_R_SUCCESS) -+ ADD_LOG_CSTR(&lb, "?"); -+ add_log_str(&lb, strbuf, strlen(strbuf)); -+ -+ if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY || -+ e->key.s.rtype == DNS_RRL_RTYPE_REFERRAL || -+ e->key.s.rtype == DNS_RRL_RTYPE_NODATA || -+ e->key.s.rtype == DNS_RRL_RTYPE_NXDOMAIN) { -+ qbuf = get_qname(rrl, e); -+ if (save_qname && qbuf == NULL && -+ qname != NULL && dns_name_isabsolute(qname)) { -+ /* -+ * Capture the qname for the "stop limiting" message. -+ */ -+ qbuf = ISC_LIST_TAIL(rrl->qname_free); -+ if (qbuf != NULL) { -+ ISC_LIST_UNLINK(rrl->qname_free, qbuf, link); -+ } else if (rrl->num_qnames < DNS_RRL_QNAMES) { -+ qbuf = isc_mem_get(rrl->mctx, sizeof(*qbuf)); -+ if (qbuf != NULL) { -+ memset(qbuf, 0, sizeof(*qbuf)); -+ ISC_LINK_INIT(qbuf, link); -+ qbuf->index = rrl->num_qnames; -+ rrl->qnames[rrl->num_qnames++] = qbuf; -+ } else { -+ isc_log_write(dns_lctx, -+ DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, -+ DNS_RRL_LOG_FAIL, -+ "isc_mem_get(%d)" -+ " failed for RRL qname", -+ (int)sizeof(*qbuf)); -+ } -+ } -+ if (qbuf != NULL) { -+ e->log_qname = qbuf->index; -+ qbuf->e = e; -+ dns_fixedname_init(&qbuf->qname); -+ dns_name_copy(qname, -+ dns_fixedname_name(&qbuf->qname), -+ NULL); -+ } -+ } -+ if (qbuf != NULL) -+ qname = dns_fixedname_name(&qbuf->qname); -+ if (qname != NULL) { -+ ADD_LOG_CSTR(&lb, " for "); -+ (void)dns_name_totext(qname, ISC_TRUE, &lb); -+ } else { -+ ADD_LOG_CSTR(&lb, " for (?)"); -+ } -+ if (e->key.s.rtype != DNS_RRL_RTYPE_NXDOMAIN) { -+ ADD_LOG_CSTR(&lb, " "); -+ (void)dns_rdataclass_totext(e->key.s.qclass, &lb); -+ if (e->key.s.rtype == DNS_RRL_RTYPE_QUERY) { -+ ADD_LOG_CSTR(&lb, " "); -+ (void)dns_rdatatype_totext(e->key.s.qtype, &lb); -+ } -+ } -+ snprintf(strbuf, sizeof(strbuf), " (%08x)", -+ e->key.s.qname_hash); -+ add_log_str(&lb, strbuf, strlen(strbuf)); -+ } -+ -+ /* -+ * We saved room for '\0'. -+ */ -+ log_buf[isc_buffer_usedlength(&lb)] = '\0'; -+} -+ -+static void -+log_end(dns_rrl_t *rrl, dns_rrl_entry_t *e, isc_boolean_t early, -+ char *log_buf, unsigned int log_buf_len) -+{ -+ if (e->logged) { -+ make_log_buf(rrl, e, -+ early ? "*" : NULL, -+ rrl->log_only ? "would stop limiting " -+ : "stop limiting ", -+ ISC_TRUE, NULL, ISC_FALSE, -+ DNS_RRL_RESULT_OK, ISC_R_SUCCESS, -+ log_buf, log_buf_len); -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, -+ "%s", log_buf); -+ free_qname(rrl, e); -+ e->logged = ISC_FALSE; -+ --rrl->num_logged; -+ } -+} -+ -+/* -+ * Log messages for streams that have stopped being rate limited. -+ */ -+static void -+log_stops(dns_rrl_t *rrl, isc_stdtime_t now, int limit, -+ char *log_buf, unsigned int log_buf_len) -+{ -+ dns_rrl_entry_t *e; -+ int age; -+ -+ for (e = rrl->last_logged; e != NULL; e = ISC_LIST_PREV(e, lru)) { -+ if (!e->logged) -+ continue; -+ if (now != 0) { -+ age = get_age(rrl, e, now); -+ if (age < DNS_RRL_STOP_LOG_SECS || -+ response_balance(rrl, e, age) < 0) -+ break; -+ } -+ -+ log_end(rrl, e, now == 0, log_buf, log_buf_len); -+ if (rrl->num_logged <= 0) -+ break; -+ -+ /* -+ * Too many messages could stall real work. -+ */ -+ if (--limit < 0) { -+ rrl->last_logged = ISC_LIST_PREV(e, lru); -+ return; -+ } -+ } -+ if (e == NULL) { -+ INSIST(rrl->num_logged == 0); -+ rrl->log_stops_time = now; -+ } -+ rrl->last_logged = e; -+} -+ -+/* -+ * Main rate limit interface. -+ */ -+dns_rrl_result_t -+dns_rrl(dns_view_t *view, -+ const isc_sockaddr_t *client_addr, isc_boolean_t is_tcp, -+ dns_rdataclass_t qclass, dns_rdatatype_t qtype, -+ dns_name_t *qname, isc_result_t resp_result, isc_stdtime_t now, -+ isc_boolean_t wouldlog, char *log_buf, unsigned int log_buf_len) -+{ -+ dns_rrl_t *rrl; -+ dns_rrl_rtype_t rtype; -+ dns_rrl_entry_t *e; -+ isc_netaddr_t netclient; -+ int secs; -+ double qps, scale; -+ int exempt_match; -+ isc_result_t result; -+ dns_rrl_result_t rrl_result; -+ -+ INSIST(log_buf != NULL && log_buf_len > 0); -+ -+ rrl = view->rrl; -+ if (rrl->exempt != NULL) { -+ isc_netaddr_fromsockaddr(&netclient, client_addr); -+ result = dns_acl_match(&netclient, NULL, rrl->exempt, -+ &view->aclenv, &exempt_match, NULL); -+ if (result == ISC_R_SUCCESS && exempt_match > 0) -+ return (DNS_RRL_RESULT_OK); -+ } -+ -+ LOCK(&rrl->lock); -+ -+ /* -+ * Estimate total query per second rate when scaling by qps. -+ */ -+ if (rrl->qps_scale == 0) { -+ qps = 0.0; -+ scale = 1.0; -+ } else { -+ ++rrl->qps_responses; -+ secs = delta_rrl_time(rrl->qps_time, now); -+ if (secs <= 0) { -+ qps = rrl->qps; -+ } else { -+ qps = (1.0*rrl->qps_responses) / secs; -+ if (secs >= rrl->window) { -+ if (isc_log_wouldlog(dns_lctx, -+ DNS_RRL_LOG_DEBUG3)) -+ isc_log_write(dns_lctx, -+ DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, -+ DNS_RRL_LOG_DEBUG3, -+ "%d responses/%d seconds" -+ " = %d qps", -+ rrl->qps_responses, secs, -+ (int)qps); -+ rrl->qps = qps; -+ rrl->qps_responses = 0; -+ rrl->qps_time = now; -+ } else if (qps < rrl->qps) { -+ qps = rrl->qps; -+ } -+ } -+ scale = rrl->qps_scale / qps; -+ } -+ -+ /* -+ * Do maintenance once per second. -+ */ -+ if (rrl->num_logged > 0 && rrl->log_stops_time != now) -+ log_stops(rrl, now, 8, log_buf, log_buf_len); -+ -+ /* -+ * Notice TCP responses when scaling limits by qps. -+ * Do not try to rate limit TCP responses. -+ */ -+ if (is_tcp) { -+ if (scale < 1.0) { -+ e = get_entry(rrl, client_addr, -+ 0, dns_rdatatype_none, NULL, -+ DNS_RRL_RTYPE_TCP, now, ISC_TRUE, -+ log_buf, log_buf_len); -+ if (e != NULL) { -+ e->responses = -(rrl->window+1); -+ set_age(rrl, e, now); -+ } -+ } -+ UNLOCK(&rrl->lock); -+ return (ISC_R_SUCCESS); -+ } -+ -+ /* -+ * Find the right kind of entry, creating it if necessary. -+ * If that is impossible, then nothing more can be done -+ */ -+ switch (resp_result) { -+ case ISC_R_SUCCESS: -+ rtype = DNS_RRL_RTYPE_QUERY; -+ break; -+ case DNS_R_DELEGATION: -+ rtype = DNS_RRL_RTYPE_REFERRAL; -+ break; -+ case DNS_R_NXRRSET: -+ rtype = DNS_RRL_RTYPE_NODATA; -+ break; -+ case DNS_R_NXDOMAIN: -+ rtype = DNS_RRL_RTYPE_NXDOMAIN; -+ break; -+ default: -+ rtype = DNS_RRL_RTYPE_ERROR; -+ break; -+ } -+ e = get_entry(rrl, client_addr, qclass, qtype, qname, rtype, -+ now, ISC_TRUE, log_buf, log_buf_len); -+ if (e == NULL) { -+ UNLOCK(&rrl->lock); -+ return (DNS_RRL_RESULT_OK); -+ } -+ -+ if (isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DEBUG1)) { -+ /* -+ * Do not worry about speed or releasing the lock. -+ * This message appears before messages from debit_rrl_entry(). -+ */ -+ make_log_buf(rrl, e, "consider limiting ", NULL, ISC_FALSE, -+ qname, ISC_FALSE, DNS_RRL_RESULT_OK, resp_result, -+ log_buf, log_buf_len); -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DEBUG1, -+ "%s", log_buf); -+ } -+ -+ rrl_result = debit_rrl_entry(rrl, e, qps, scale, client_addr, now, -+ log_buf, log_buf_len); -+ -+ if (rrl->all_per_second.r != 0) { -+ /* -+ * We must debit the all-per-second token bucket if we have -+ * an all-per-second limit for the IP address. -+ * The all-per-second limit determines the log message -+ * when both limits are hit. -+ * The response limiting must continue if the -+ * all-per-second limiting lapses. -+ */ -+ dns_rrl_entry_t *e_all; -+ dns_rrl_result_t rrl_all_result; -+ -+ e_all = get_entry(rrl, client_addr, -+ 0, dns_rdatatype_none, NULL, -+ DNS_RRL_RTYPE_ALL, now, ISC_TRUE, -+ log_buf, log_buf_len); -+ if (e_all == NULL) { -+ UNLOCK(&rrl->lock); -+ return (DNS_RRL_RESULT_OK); -+ } -+ rrl_all_result = debit_rrl_entry(rrl, e_all, qps, scale, -+ client_addr, now, -+ log_buf, log_buf_len); -+ if (rrl_all_result != DNS_RRL_RESULT_OK) { -+ int level; -+ -+ e = e_all; -+ rrl_result = rrl_all_result; -+ if (rrl_result == DNS_RRL_RESULT_OK) -+ level = DNS_RRL_LOG_DEBUG2; -+ else -+ level = DNS_RRL_LOG_DEBUG1; -+ if (isc_log_wouldlog(dns_lctx, level)) { -+ make_log_buf(rrl, e, -+ "prefer all-per-second limiting ", -+ NULL, ISC_TRUE, qname, ISC_FALSE, -+ DNS_RRL_RESULT_OK, resp_result, -+ log_buf, log_buf_len); -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, level, -+ "%s", log_buf); -+ } -+ } -+ } -+ -+ if (rrl_result == DNS_RRL_RESULT_OK) { -+ UNLOCK(&rrl->lock); -+ return (DNS_RRL_RESULT_OK); -+ } -+ -+ /* -+ * Log occassionally in the rate-limit category. -+ */ -+ if ((!e->logged || e->log_secs >= DNS_RRL_MAX_LOG_SECS) && -+ isc_log_wouldlog(dns_lctx, DNS_RRL_LOG_DROP)) { -+ make_log_buf(rrl, e, rrl->log_only ? "would " : NULL, -+ e->logged ? "continue limiting " : "limit ", -+ ISC_TRUE, qname, ISC_TRUE, -+ DNS_RRL_RESULT_OK, resp_result, -+ log_buf, log_buf_len); -+ if (!e->logged) { -+ e->logged = ISC_TRUE; -+ if (++rrl->num_logged <= 1) -+ rrl->last_logged = e; -+ } -+ e->log_secs = 0; -+ -+ /* -+ * Avoid holding the lock. -+ */ -+ if (!wouldlog) { -+ UNLOCK(&rrl->lock); -+ e = NULL; -+ } -+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RRL, -+ DNS_LOGMODULE_REQUEST, DNS_RRL_LOG_DROP, -+ "%s", log_buf); -+ } -+ -+ /* -+ * Make a log message for the caller. -+ */ -+ if (wouldlog) -+ make_log_buf(rrl, e, -+ rrl->log_only ? "would rate limit " : "rate limit ", -+ NULL, ISC_FALSE, qname, ISC_FALSE, -+ rrl_result, resp_result, log_buf, log_buf_len); -+ -+ if (e != NULL) { -+ /* -+ * Do not save the qname unless we might need it for -+ * the ending log message. -+ */ -+ if (!e->logged) -+ free_qname(rrl, e); -+ UNLOCK(&rrl->lock); -+ } -+ -+ return (rrl_result); -+} -+ -+void -+dns_rrl_view_destroy(dns_view_t *view) { -+ dns_rrl_t *rrl; -+ dns_rrl_block_t *b; -+ dns_rrl_hash_t *h; -+ char log_buf[DNS_RRL_LOG_BUF_LEN]; -+ int i; -+ -+ rrl = view->rrl; -+ if (rrl == NULL) -+ return; -+ view->rrl = NULL; -+ -+ /* -+ * Assume the caller takes care of locking the view and anything else. -+ */ -+ -+ if (rrl->num_logged > 0) -+ log_stops(rrl, 0, ISC_INT32_MAX, log_buf, sizeof(log_buf)); -+ -+ for (i = 0; i < DNS_RRL_QNAMES; ++i) { -+ if (rrl->qnames[i] == NULL) -+ break; -+ isc_mem_put(rrl->mctx, rrl->qnames[i], sizeof(*rrl->qnames[i])); -+ } -+ -+ if (rrl->exempt != NULL) -+ dns_acl_detach(&rrl->exempt); -+ -+ DESTROYLOCK(&rrl->lock); -+ -+ while (!ISC_LIST_EMPTY(rrl->blocks)) { -+ b = ISC_LIST_HEAD(rrl->blocks); -+ ISC_LIST_UNLINK(rrl->blocks, b, link); -+ isc_mem_put(rrl->mctx, b, b->size); -+ } -+ -+ h = rrl->hash; -+ if (h != NULL) -+ isc_mem_put(rrl->mctx, h, -+ sizeof(*h) + (h->length - 1) * sizeof(h->bins[0])); -+ -+ h = rrl->old_hash; -+ if (h != NULL) -+ isc_mem_put(rrl->mctx, h, -+ sizeof(*h) + (h->length - 1) * sizeof(h->bins[0])); -+ -+ isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl)); -+} -+ -+isc_result_t -+dns_rrl_init(dns_rrl_t **rrlp, dns_view_t *view, int min_entries) { -+ dns_rrl_t *rrl; -+ isc_result_t result; -+ -+ *rrlp = NULL; -+ -+ rrl = isc_mem_get(view->mctx, sizeof(*rrl)); -+ if (rrl == NULL) -+ return (ISC_R_NOMEMORY); -+ memset(rrl, 0, sizeof(*rrl)); -+ isc_mem_attach(view->mctx, &rrl->mctx); -+ result = isc_mutex_init(&rrl->lock); -+ if (result != ISC_R_SUCCESS) { -+ isc_mem_putanddetach(&rrl->mctx, rrl, sizeof(*rrl)); -+ return (result); -+ } -+ isc_stdtime_get(&rrl->ts_bases[0]); -+ -+ view->rrl = rrl; -+ -+ result = expand_entries(rrl, min_entries); -+ if (result != ISC_R_SUCCESS) { -+ dns_rrl_view_destroy(view); -+ return (result); -+ } -+ result = expand_rrl_hash(rrl, 0); -+ if (result != ISC_R_SUCCESS) { -+ dns_rrl_view_destroy(view); -+ return (result); -+ } -+ -+ *rrlp = rrl; -+ return (ISC_R_SUCCESS); -+} -Index: lib/dns/view.c -=================================================================== ---- lib/dns/view.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/view.c 2013-08-05 14:14:45.922498593 +0200 -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -184,6 +185,7 @@ - view->answeracl_exclude = NULL; - view->denyanswernames = NULL; - view->answernames_exclude = NULL; -+ view->rrl = NULL; - view->provideixfr = ISC_TRUE; - view->maxcachettl = 7 * 24 * 3600; - view->maxncachettl = 3 * 3600; -@@ -195,9 +197,7 @@ +diff -r -u lib/dns/view.c-orig lib/dns/view.c +--- lib/dns/view.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/view.c 2004-01-01 00:00:00.000000000 +0000 +@@ -197,9 +197,7 @@ view->maxbits = 0; view->v4_aaaa = dns_v4_aaaa_ok; view->v4_aaaa_acl = NULL; @@ -9537,26 +7379,19 @@ Index: lib/dns/view.c dns_fixedname_init(&view->dlv_fixed); view->managed_keys = NULL; view->redirect = NULL; -@@ -334,10 +334,13 @@ +@@ -336,7 +334,8 @@ dns_acache_putdb(view->acache, view->cachedb); dns_acache_detach(&view->acache); } - dns_rpz_view_destroy(view); + if (view->rpzs != NULL) + dns_rpz_detach_rpzs(&view->rpzs); -+ dns_rrl_view_destroy(view); - #else - INSIST(view->acache == NULL); -- INSIST(ISC_LIST_EMPTY(view->rpz_zones)); -+ INSIST(view->rpzs == NULL); -+ INSIST(view->rrl == NULL); - #endif - if (view->requestmgr != NULL) - dns_requestmgr_detach(&view->requestmgr); -Index: lib/dns/win32/libdns.def -=================================================================== ---- lib/dns/win32/libdns.def.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/win32/libdns.def 2013-08-05 14:14:45.922498593 +0200 + #ifdef USE_RRL + dns_rrl_view_destroy(view); + #else /* USE_RRL */ +diff -r -u lib/dns/win32/libdns.def-orig lib/dns/win32/libdns.def +--- lib/dns/win32/libdns.def-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/win32/libdns.def 2004-01-01 00:00:00.000000000 +0000 @@ -130,8 +130,8 @@ dns_db_overmem dns_db_printnode @@ -9596,17 +7431,7 @@ Index: lib/dns/win32/libdns.def dns_rriterator_current dns_rriterator_destroy dns_rriterator_first -@@ -657,6 +662,9 @@ - dns_rriterator_next - dns_rriterator_nextrrset - dns_rriterator_pause -+dns_rrl -+dns_rrl_init -+dns_rrl_view_destroy - dns_sdb_putnamedrr - dns_sdb_putrdata - dns_sdb_putrr -@@ -806,7 +814,7 @@ +@@ -810,7 +815,7 @@ dns_zone_forcereload dns_zone_forwardupdate dns_zone_fulldumptostream @@ -9615,7 +7440,7 @@ Index: lib/dns/win32/libdns.def dns_zone_getadded dns_zone_getchecknames dns_zone_getclass -@@ -834,6 +842,7 @@ +@@ -838,6 +843,7 @@ dns_zone_getqueryonacl dns_zone_getraw dns_zone_getrequeststats @@ -9623,7 +7448,7 @@ Index: lib/dns/win32/libdns.def dns_zone_getserial dns_zone_getserial2 dns_zone_getserialupdatemethod -@@ -871,6 +880,7 @@ +@@ -875,6 +881,7 @@ dns_zone_refresh dns_zone_rekey dns_zone_replacedb @@ -9631,106 +7456,21 @@ Index: lib/dns/win32/libdns.def dns_zone_rpz_enable dns_zone_setacache dns_zone_setadded -Index: lib/dns/win32/libdns.dsp -=================================================================== ---- lib/dns/win32/libdns.dsp.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/win32/libdns.dsp 2013-08-05 14:14:45.922498593 +0200 -@@ -346,6 +346,10 @@ - # End Source File - # Begin Source File - -+SOURCE=..\include\dns\rrl.h -+# End Source File -+# Begin Source File -+ - SOURCE=..\include\dns\rriterator.h - # End Source File - # Begin Source File -@@ -650,6 +654,10 @@ - # End Source File - # Begin Source File - -+SOURCE=..\rrl.c -+# End Source File -+# Begin Source File -+ - SOURCE=..\rriterator.c - # End Source File - # Begin Source File -Index: lib/dns/win32/libdns.mak -=================================================================== ---- lib/dns/win32/libdns.mak.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/win32/libdns.mak 2013-08-05 14:14:45.922498593 +0200 -@@ -184,6 +184,7 @@ - -@erase "$(INTDIR)\result.obj" - -@erase "$(INTDIR)\rootns.obj" - -@erase "$(INTDIR)\rpz.obj" -+ -@erase "$(INTDIR)\rrl.obj" - -@erase "$(INTDIR)\sdb.obj" - -@erase "$(INTDIR)\sdlz.obj" - -@erase "$(INTDIR)\soa.obj" -@@ -309,6 +310,7 @@ - "$(INTDIR)\result.obj" \ - "$(INTDIR)\rootns.obj" \ - "$(INTDIR)\rpz.obj" \ -+ "$(INTDIR)\rrl.obj" \ - "$(INTDIR)\rriterator.obj" \ - "$(INTDIR)\sdb.obj" \ - "$(INTDIR)\sdlz.obj" \ -@@ -505,6 +507,8 @@ - -@erase "$(INTDIR)\rootns.sbr" - -@erase "$(INTDIR)\rpz.obj" - -@erase "$(INTDIR)\rpz.sbr" -+ -@erase "$(INTDIR)\rrl.obj" -+ -@erase "$(INTDIR)\rrl.sbr" - -@erase "$(INTDIR)\rriterator.obj" - -@erase "$(INTDIR)\rriterator.sbr" - -@erase "$(INTDIR)\sdb.obj" -@@ -651,6 +655,7 @@ - "$(INTDIR)\result.sbr" \ - "$(INTDIR)\rootns.sbr" \ - "$(INTDIR)\rpz.sbr" \ -+ "$(INTDIR)\rrl.sbr" \ - "$(INTDIR)\rriterator.sbr" \ - "$(INTDIR)\sdb.sbr" \ - "$(INTDIR)\sdlz.sbr" \ -@@ -748,6 +753,7 @@ - "$(INTDIR)\result.obj" \ - "$(INTDIR)\rootns.obj" \ - "$(INTDIR)\rpz.obj" \ -+ "$(INTDIR)\rrl.obj" \ - "$(INTDIR)\rriterator.obj" \ - "$(INTDIR)\sdb.obj" \ - "$(INTDIR)\sdlz.obj" \ -@@ -1724,6 +1730,24 @@ - $(CPP) $(CPP_PROJ) $(SOURCE) - - -+!ENDIF -+ -+SOURCE=..\rrl.c -+ -+!IF "$(CFG)" == "libdns - Win32 Release" -+ -+ -+"$(INTDIR)\rrl.obj" : $(SOURCE) "$(INTDIR)" -+ $(CPP) $(CPP_PROJ) $(SOURCE) -+ -+ -+!ELSEIF "$(CFG)" == "libdns - Win32 Debug" -+ -+ -+"$(INTDIR)\rrl.obj" "$(INTDIR)\rrl.sbr" : $(SOURCE) "$(INTDIR)" -+ $(CPP) $(CPP_PROJ) $(SOURCE) -+ -+ - !ENDIF - - SOURCE=..\rriterator.c -Index: lib/dns/zone.c -=================================================================== ---- lib/dns/zone.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/dns/zone.c 2013-08-05 14:14:45.925498630 +0200 +diff -r -u lib/dns/xfrin.c-orig lib/dns/xfrin.c +--- lib/dns/xfrin.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/xfrin.c 2004-01-01 00:00:00.000000000 +0000 +@@ -280,7 +280,7 @@ + 0, NULL, /* XXX guess */ + dbp); + if (result == ISC_R_SUCCESS) +- result = dns_zone_rpz_enable_db(xfr->zone, *dbp); ++ dns_zone_rpz_enable_db(xfr->zone, *dbp); + return (result); + } + +diff -r -u lib/dns/zone.c-orig lib/dns/zone.c +--- lib/dns/zone.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/dns/zone.c 2004-01-01 00:00:00.000000000 +0000 @@ -346,9 +346,10 @@ isc_boolean_t added; @@ -9744,7 +7484,7 @@ Index: lib/dns/zone.c /*% * Serial number update method. -@@ -917,7 +918,8 @@ +@@ -915,7 +916,8 @@ zone->nodes = 100; zone->privatetype = (dns_rdatatype_t)0xffffU; zone->added = ISC_FALSE; @@ -9754,7 +7494,7 @@ Index: lib/dns/zone.c ISC_LIST_INIT(zone->forwards); zone->raw = NULL; zone->secure = NULL; -@@ -1021,6 +1023,13 @@ +@@ -1019,6 +1021,13 @@ zone_detachdb(zone); if (zone->acache != NULL) dns_acache_detach(&zone->acache); @@ -9768,7 +7508,7 @@ Index: lib/dns/zone.c zone_freedbargs(zone); RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0) == ISC_R_SUCCESS); -@@ -1513,7 +1522,9 @@ +@@ -1511,7 +1520,9 @@ * Set the response policy index and information for a zone. */ isc_result_t @@ -9779,7 +7519,7 @@ Index: lib/dns/zone.c /* * Only RBTDB zones can be used for response policy zones, * because only they have the code to load the create the summary data. -@@ -1524,14 +1535,26 @@ +@@ -1522,26 +1533,37 @@ strcmp(zone->db_argv[0], "rbt64") != 0) return (ISC_R_NOTIMPLEMENTED); @@ -9809,22 +7549,36 @@ Index: lib/dns/zone.c + return (zone->rpz_num); } - static isc_result_t -@@ -1988,10 +2011,9 @@ - unsigned int options; - - #ifdef BIND9 -- if (zone->is_rpz) { -- result = dns_db_rpz_enabled(db, NULL); -- if (result != ISC_R_SUCCESS) -- return (result); + /* + * If a zone is a response policy zone, mark its new database. + */ +-isc_result_t ++void + dns_zone_rpz_enable_db(dns_zone_t *zone, dns_db_t *db) { +-#ifdef BIND9 +- if (zone->is_rpz) +- return (dns_db_rpz_enabled(db, NULL)); +-#endif +- return (ISC_R_SUCCESS); + if (zone->rpz_num != DNS_RPZ_INVALID_NUM) { + REQUIRE(zone->rpzs != NULL); + dns_db_rpz_attach(db, zone->rpzs, zone->rpz_num); - } - #endif ++ } + } -@@ -4120,6 +4142,11 @@ + static isc_result_t +@@ -1997,9 +2019,7 @@ + isc_result_t tresult; + unsigned int options; + +- result = dns_zone_rpz_enable_db(zone, db); +- if (result != ISC_R_SUCCESS) +- return (result); ++ dns_zone_rpz_enable_db(zone, db); + options = get_master_options(zone); + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS)) + options |= DNS_MASTER_MANYERRORS; +@@ -4177,6 +4197,11 @@ if (result != ISC_R_SUCCESS) goto cleanup; } else { @@ -9836,7 +7590,7 @@ Index: lib/dns/zone.c zone_attachdb(zone, db); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); DNS_ZONE_SETFLAG(zone, -@@ -13047,6 +13074,12 @@ +@@ -13142,6 +13167,12 @@ REQUIRE(DNS_ZONE_VALID(zone)); REQUIRE(LOCKED_ZONE(zone)); @@ -9849,16 +7603,15 @@ Index: lib/dns/zone.c result = zone_get_from_db(zone, db, &nscount, &soacount, NULL, NULL, NULL, NULL, NULL, NULL); if (result == ISC_R_SUCCESS) { -Index: lib/isccfg/namedconf.c -=================================================================== ---- lib/isccfg/namedconf.c.orig 2013-07-17 00:13:06.000000000 +0200 -+++ lib/isccfg/namedconf.c 2013-08-05 14:14:45.937498781 +0200 +diff -r -u lib/isccfg/namedconf.c-orig lib/isccfg/namedconf.c +--- lib/isccfg/namedconf.c-orig 2004-01-01 00:00:00.000000000 +0000 ++++ lib/isccfg/namedconf.c 2004-01-01 00:00:00.000000000 +0000 @@ -1054,11 +1054,12 @@ /*% * response-policy { - * zone [ policy (given|disabled|passthru| -+ * zone [ policy (given|disabled|passthru|drop| ++ * zone [ policy (given|disabled|passthru|drop|tcp-only| * nxdomain|nodata|cname ) ] * [ recursive-only yes|no ] [ max-policy-ttl number ] ; * } [ recursive-only yes|no ] [ max-policy-ttl number ] ; @@ -9873,11 +7626,11 @@ Index: lib/isccfg/namedconf.c /* * Parse - * given|disabled|passthru|nxdomain|nodata|cname -+ * given|disabled|passthru|drop|nxdomain|nodata|cname ++ * given|disabled|passthru|drop|tcp-only|nxdomain|nodata|cname */ static isc_result_t cfg_parse_rpz_policy(cfg_parser_t *pctx, const cfg_type_t *type, -@@ -1214,8 +1215,11 @@ +@@ -1214,9 +1215,12 @@ doc_keyvalue, &cfg_rep_string, &zone_kw }; @@ -9886,10 +7639,12 @@ Index: lib/isccfg/namedconf.c + */ static const char *rpz_policies[] = { - "given", "disabled", "passthru", "no-op", "nxdomain", "nodata", -+ "given", "disabled", "passthru", "no-op", "drop", "nxdomain", "nodata", - "cname", NULL +- "cname", NULL ++ "given", "disabled", "passthru", "no-op", "drop", "tcp-only", ++ "nxdomain", "nodata", "cname", NULL }; static cfg_type_t cfg_type_rpz_policy_name = { + "policy name", cfg_parse_enum, cfg_print_ustring, @@ -1261,6 +1265,7 @@ { "break-dnssec", &cfg_type_boolean, 0 }, { "max-policy-ttl", &cfg_type_uint32, 0 }, @@ -9898,629 +7653,14 @@ Index: lib/isccfg/namedconf.c { NULL, NULL, 0 } }; static cfg_type_t cfg_type_rpz = { -@@ -1270,6 +1275,40 @@ - }; - - -+/* -+ * rate-limit -+ */ -+static cfg_clausedef_t rrl_clauses[] = { -+ { "responses-per-second", &cfg_type_uint32, 0 }, -+ { "referrals-per-second", &cfg_type_uint32, 0 }, -+ { "nodata-per-second", &cfg_type_uint32, 0 }, -+ { "nxdomains-per-second", &cfg_type_uint32, 0 }, -+ { "errors-per-second", &cfg_type_uint32, 0 }, -+ { "all-per-second", &cfg_type_uint32, 0 }, -+ { "slip", &cfg_type_uint32, 0 }, -+ { "window", &cfg_type_uint32, 0 }, -+ { "log-only", &cfg_type_boolean, 0 }, -+ { "qps-scale", &cfg_type_uint32, 0 }, -+ { "ipv4-prefix-length", &cfg_type_uint32, 0 }, -+ { "ipv6-prefix-length", &cfg_type_uint32, 0 }, -+ { "exempt-clients", &cfg_type_bracketed_aml, 0 }, -+ { "max-table-size", &cfg_type_uint32, 0 }, -+ { "min-table-size", &cfg_type_uint32, 0 }, -+ { NULL, NULL, 0 } -+}; -+ -+static cfg_clausedef_t *rrl_clausesets[] = { -+ rrl_clauses, -+ NULL -+}; -+ -+static cfg_type_t cfg_type_rrl = { -+ "rate-limit", cfg_parse_map, cfg_print_map, cfg_doc_map, -+ &cfg_rep_map, rrl_clausesets -+}; -+ -+ -+ - /*% - * dnssec-lookaside - */ -@@ -1423,6 +1462,7 @@ - CFG_CLAUSEFLAG_NOTCONFIGURED }, - #endif - { "response-policy", &cfg_type_rpz, 0 }, -+ { "rate-limit", &cfg_type_rrl, 0 }, - { NULL, NULL, 0 } - }; - -Index: named.conf -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ named.conf 2013-08-05 14:14:45.937498781 +0200 -@@ -0,0 +1,153 @@ -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.3; -+ notify-source 10.53.0.3; -+ transfer-source 10.53.0.3; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ listen-on { 10.53.0.3; }; -+ listen-on-v6 { none; }; -+ notify no; -+ -+ // check that all of the options are parsed without limiting anything -+ rate-limit { -+ responses-per-second 200; -+ referrals-per-second 220; -+ nodata-per-second 230; -+ nxdomains-per-second 240; -+ errors-per-second 250; -+ all-per-second 700; -+ ipv4-prefix-length 24; -+ ipv6-prefix-length 64; -+ qps-scale 10; -+ window 1; -+ max-table-size 1000; -+ }; -+ -+}; -+ -+zone "." { type hint; file "hints"; }; -+ -+zone "tld3."{ type master; file "tld3.db"; }; -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.2; -+ notify-source 10.53.0.2; -+ transfer-source 10.53.0.2; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ statistics-file "named.stats"; -+ listen-on { 10.53.0.2; }; -+ listen-on-v6 { none; }; -+ notify no; -+ -+ rate-limit { -+ responses-per-second 2; -+ all-per-second 50; -+ slip 3; -+ exempt-clients { 10.53.0.7; }; -+ -+ // small enough to force a table expansion -+ min-table-size 75; -+ }; -+ -+ additional-from-cache no; -+}; -+ -+key rndc_key { -+ secret "1234abcd8765"; -+ algorithm hmac-md5; -+}; -+controls { -+ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; -+}; -+ -+/* -+ * These log settings have no effect unless "-g" is removed from ../../start.pl -+ */ -+logging { -+ channel debug { -+ file "log-debug"; -+ print-category yes; print-severity yes; severity debug 10; -+ }; -+ channel queries { -+ file "log-queries"; -+ print-category yes; print-severity yes; severity info; -+ }; -+ category rate-limit { debug; queries; }; -+ category queries { debug; queries; }; -+}; -+ -+zone "." { type hint; file "hints"; }; -+ -+zone "tld2."{ type master; file "tld2.db"; }; -+/* -+ * Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+ * -+ * 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. -+ */ -+ -+ -+controls { /* empty */ }; -+ -+options { -+ query-source address 10.53.0.1; -+ notify-source 10.53.0.1; -+ transfer-source 10.53.0.1; -+ port 5300; -+ session-keyfile "session.key"; -+ pid-file "named.pid"; -+ listen-on { 10.53.0.1; }; -+ listen-on-v6 { none; }; -+ notify no; -+}; -+ -+zone "." {type master; file "root.db";}; -Index: root.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ root.db 2013-08-05 14:14:45.938498793 +0200 -@@ -0,0 +1,31 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+$TTL 120 -+@ SOA ns. hostmaster.ns. ( 1 3600 1200 604800 60 ) -+@ NS ns. -+ns. A 10.53.0.1 -+. A 10.53.0.1 -+ -+; limit responses from here -+tld2. NS ns.tld2. -+ns.tld2. A 10.53.0.2 -+ -+; limit recursion to here -+tld3. NS ns.tld3. -+ns.tld3. A 10.53.0.3 -+ -+; generate SERVFAIL -+tld4. NS ns.tld3. -Index: setup.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ setup.sh 2013-08-05 14:14:45.938498793 +0200 -@@ -0,0 +1,21 @@ -+#!/bin/sh -+# -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+SYSTEMTESTTOP=.. -+. $SYSTEMTESTTOP/conf.sh -+. ./clean.sh -+ -Index: tests.sh -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ tests.sh 2013-08-05 14:14:45.938498793 +0200 -@@ -0,0 +1,258 @@ -+# Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+# -+# 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. -+ -+ -+# test response rate limiting -+ -+SYSTEMTESTTOP=.. -+. $SYSTEMTESTTOP/conf.sh -+ -+#set -x -+ -+ns1=10.53.0.1 # root, defining the others -+ns2=10.53.0.2 # test server -+ns3=10.53.0.3 # secondary test server -+ns7=10.53.0.7 # whitelisted client -+ -+USAGE="$0: [-x]" -+while getopts "x" c; do -+ case $c in -+ x) set -x;; -+ *) echo "$USAGE" 1>&2; exit 1;; -+ esac -+done -+shift `expr $OPTIND - 1 || true` -+if test "$#" -ne 0; then -+ echo "$USAGE" 1>&2 -+ exit 1 -+fi -+# really quit on control-C -+trap 'exit 1' 1 2 15 -+ -+ -+ret=0 -+setret () { -+ ret=1 -+ echo "$*" -+} -+ -+ -+# Wait until soon after the start of a second to make results consistent. -+# The start of a second credits a rate limit. -+# This would be far easier in C or by assuming a modern version of perl. -+sec_start () { -+ START=`date` -+ while true; do -+ NOW=`date` -+ if test "$START" != "$NOW"; then -+ return -+ fi -+ $PERL -e 'select(undef, undef, undef, 0.05)' || true -+ done -+} -+ -+ -+# turn off ${HOME}/.digrc -+HOME=/dev/null; export HOME -+ -+# $1=result name $2=domain name $3=dig options -+digcmd () { -+ OFILE=$1; shift -+ DIG_DOM=$1; shift -+ ARGS="+nosearch +time=1 +tries=1 +ignore -p 5300 $* $DIG_DOM @$ns2" -+ #echo I:dig $ARGS 1>&2 -+ START=`date +%y%m%d%H%M.%S` -+ RESULT=`$DIG $ARGS 2>&1 | tee $OFILE=TEMP \ -+ | sed -n -e '/^;; AUTHORITY/,/^$/d' \ -+ -e '/^;; ADDITIONAL/,/^$/d' \ -+ -e 's/^[^;].* \([^ ]\{1,\}\)$/\1/p' \ -+ -e 's/;; flags.* tc .*/TC/p' \ -+ -e 's/;; .* status: NXDOMAIN.*/NXDOMAIN/p' \ -+ -e 's/;; .* status: SERVFAIL.*/SERVFAIL/p' \ -+ -e 's/;; connection timed out.*/drop/p' \ -+ -e 's/;; communications error to.*/drop/p' \ -+ | tr -d '\n'` -+ mv "$OFILE=TEMP" "$OFILE=$RESULT" -+ touch -t $START "$OFILE=$RESULT" -+} -+ -+ -+# $1=number of tests $2=target domain $3=dig options -+QNUM=1 -+burst () { -+ BURST_LIMIT=$1; shift -+ BURST_DOM_BASE="$1"; shift -+ while test "$BURST_LIMIT" -ge 1; do -+ CNT=`expr "00$QNUM" : '.*\(...\)'` -+ eval BURST_DOM="$BURST_DOM_BASE" -+ FILE="dig.out-$BURST_DOM-$CNT" -+ digcmd $FILE $BURST_DOM $* & -+ QNUM=`expr $QNUM + 1` -+ BURST_LIMIT=`expr "$BURST_LIMIT" - 1` -+ done -+} -+ -+ -+# $1=domain $2=IP address $3=# of IP addresses $4=TC $5=drop -+# $6=NXDOMAIN $7=SERVFAIL or other errors -+ck_result() { -+ BAD= -+ wait -+ ADDRS=`ls dig.out-$1-*=$2 2>/dev/null | wc -l` -+ # count simple truncated and truncated NXDOMAIN as TC -+ TC=`ls dig.out-$1-*=TC dig.out-$1-*=NXDOMAINTC 2>/dev/null | wc -l` -+ DROP=`ls dig.out-$1-*=drop 2>/dev/null | wc -l` -+ # count NXDOMAIN and truncated NXDOMAIN as NXDOMAIN -+ NXDOMAIN=`ls dig.out-$1-*=NXDOMAIN dig.out-$1-*=NXDOMAINTC 2>/dev/null \ -+ | wc -l` -+ SERVFAIL=`ls dig.out-$1-*=SERVFAIL 2>/dev/null | wc -l` -+ if test $ADDRS -ne "$3"; then -+ setret "I:"$ADDRS" instead of $3 '$2' responses for $1" -+ BAD=yes -+ fi -+ if test $TC -ne "$4"; then -+ setret "I:"$TC" instead of $4 truncation responses for $1" -+ BAD=yes -+ fi -+ if test $DROP -ne "$5"; then -+ setret "I:"$DROP" instead of $5 dropped responses for $1" -+ BAD=yes -+ fi -+ if test $NXDOMAIN -ne "$6"; then -+ setret "I:"$NXDOMAIN" instead of $6 NXDOMAIN responses for $1" -+ BAD=yes -+ fi -+ if test $SERVFAIL -ne "$7"; then -+ setret "I:"$SERVFAIL" instead of $7 error responses for $1" -+ BAD=yes -+ fi -+ if test -z "$BAD"; then -+ rm -f dig.out-$1-* -+ fi -+} -+ -+ -+ckstats () { -+ LABEL="$1"; shift -+ TYPE="$1"; shift -+ EXPECTED="$1"; shift -+ C=`sed -n -e "s/[ ]*\([0-9]*\).responses $TYPE for rate limits.*/\1/p" \ -+ ns2/named.stats | tail -1` -+ C=`expr 0$C + 0` -+ if test "$C" -ne $EXPECTED; then -+ setret "I:wrong $LABEL $TYPE statistics of $C instead of $EXPECTED" -+ fi -+} -+ -+ -+######### -+sec_start -+ -+# Tests of referrals to "." must be done before the hints are loaded -+# or with "additional-from-cache no" -+burst 5 a1.tld3 +norec -+# basic rate limiting -+burst 3 a1.tld2 -+# 1 second delay allows an additional response. -+sleep 1 -+burst 10 a1.tld2 -+# Request 30 different qnames to try a wildcard. -+burst 30 'x$CNT.a2.tld2' -+# These should be counted and limited but are not. See RT33138. -+burst 10 'y.x$CNT.a2.tld2' -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# referrals to "." -+ck_result a1.tld3 '' 2 1 2 0 0 -+# check 13 results including 1 second delay that allows an additional response -+ck_result a1.tld2 192.0.2.1 3 4 6 0 0 -+ -+# Check the wild card answers. -+# The parent name of the 30 requests is counted. -+ck_result 'x*.a2.tld2' 192.0.2.2 2 10 18 0 0 -+ -+# These should be limited but are not. See RT33138. -+ck_result 'y.x*.a2.tld2' 192.0.2.2 10 0 0 0 0 -+ -+######### -+sec_start -+ -+burst 10 'x.a3.tld3' -+burst 10 'y$CNT.a3.tld3' -+burst 10 'z$CNT.a4.tld2' -+ -+# 10 identical recursive responses are limited -+ck_result 'x.a3.tld3' 192.0.3.3 2 3 5 0 0 -+ -+# 10 different recursive responses are not limited -+ck_result 'y*.a3.tld3' 192.0.3.3 10 0 0 0 0 -+ -+# 10 different NXDOMAIN responses are limited based on the parent name. -+# We count 13 responses because we count truncated NXDOMAIN responses -+# as both truncated and NXDOMAIN. -+ck_result 'z*.a4.tld2' x 0 3 5 5 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats first dropped 36 -+ckstats first truncated 21 -+ -+ -+######### -+sec_start -+ -+burst 10 a5.tld2 +tcp -+burst 10 a6.tld2 -b $ns7 -+burst 10 a7.tld4 -+burst 2 a8.tld2 AAAA -+burst 2 a8.tld2 TXT -+burst 2 a8.tld2 SPF -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# TCP responses are not rate limited -+ck_result a5.tld2 192.0.2.5 10 0 0 0 0 -+ -+# whitelisted client is not rate limited -+ck_result a6.tld2 192.0.2.6 10 0 0 0 0 -+ -+# Errors such as SERVFAIL are rate limited. -+ck_result a7.tld4 x 0 0 8 0 2 -+ -+# NODATA responses are counted as the same regardless of qtype. -+ck_result a8.tld2 '' 2 2 2 0 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats second dropped 46 -+ckstats second truncated 23 -+ -+ -+######### -+sec_start -+ -+# IP TC drop NXDOMAIN SERVFAIL -+# all-per-second -+# The qnames are all unique but the client IP address is constant. -+QNUM=101 -+burst 60 'all$CNT.a9.tld2' -+ -+ck_result 'a*.a9.tld2' 192.0.2.8 50 0 10 0 0 -+ -+$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p 9953 -s $ns2 stats -+ckstats final dropped 56 -+ckstats final truncated 23 -+ -+ -+echo "I:exit status: $ret" -+# exit $ret -+[ $ret -ne 0 ] && echo "I:test failure overridden" -+exit 0 -Index: tld2.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ tld2.db 2013-08-05 14:14:45.938498793 +0200 -@@ -0,0 +1,47 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+; rate limit response from this zone -+ -+$TTL 120 -+@ SOA tld2. hostmaster.ns.tld2. ( 1 3600 1200 604800 60 ) -+ NS ns -+ NS . -+ns A 10.53.0.2 -+ -+; basic rate limiting -+a1 A 192.0.2.1 -+ -+; wildcards -+*.a2 A 192.0.2.2 -+ -+; a3 is in tld3 -+ -+; a4 does not exist to give NXDOMAIN -+ -+; a5 for TCP requests -+a5 A 192.0.2.5 -+ -+; a6 for whitelisted clients -+a6 A 192.0.2.6 -+ -+; a7 for SERVFAIL -+ -+; a8 for NODATA -+a8 A 192.0.2.8 -+ -+; a9 for all-per-second limit -+$GENERATE 101-180 all$.a9 A 192.0.2.8 -Index: tld3.db -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ tld3.db 2013-08-05 14:14:45.938498793 +0200 -@@ -0,0 +1,25 @@ -+; Copyright (C) 2012, 2013 Internet Systems Consortium, Inc. ("ISC") -+; -+; 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. -+ -+ -+ -+; rate limit response from this zone -+ -+$TTL 120 -+@ SOA tld3. hostmaster.ns.tld3. ( 1 3600 1200 604800 60 ) -+ NS ns -+ NS . -+ns A 10.53.0.3 -+ -+*.a3 A 192.0.3.3 -Index: version -=================================================================== ---- version.orig 2013-07-17 00:13:06.000000000 +0200 -+++ version 2013-08-05 14:14:45.938498793 +0200 +diff -r -u version-orig version +--- version-orig 2004-01-01 00:00:00.000000000 +0000 ++++ version 2004-01-01 00:00:00.000000000 +0000 @@ -7,6 +7,6 @@ DESCRIPTION="(Extended Support Version)" MAJORVER=9 MINORVER=9 --PATCHVER=3 -+PATCHVER=3-rpz2+rl.156.01 - RELEASETYPE=-P - RELEASEVER=2 +-PATCHVER=4 ++PATCHVER=4-rpz2.13269.14 + RELEASETYPE= + RELEASEVER=