From: Petr Špaček Date: Tue, 5 May 2020 15:01:38 +0000 (+0200) Subject: NXNSAttack mitigation tests X-Git-Tag: v5.1.1~1^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89570bdc13cd1bd7a851a3a89fdd126e96a8e08c;p=thirdparty%2Fknot-resolver.git NXNSAttack mitigation tests New Deckard repo without conflicting iter_refused.rpl test does not contain libswrap and libfaketime anymore so I had to remove hacks in build system for these. --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bc903cc1e..2dc91d270 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -242,7 +242,7 @@ lint:scan-build: script: - export SCANBUILD="scan-build --status-bugs -no-failure-reports $(./scripts/get-scanbuild-args.sh)" - ninja -C build_ci* scan-build || true - - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 30 # we have this many errors ATM :-) + - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 23 # we have this many errors ATM :-) lint:tidy: <<: *test diff --git a/lib/layer/test.integr/iter_limit_bad_glueless.rpl b/lib/layer/test.integr/iter_limit_bad_glueless.rpl new file mode 100644 index 000000000..fdd728504 --- /dev/null +++ b/lib/layer/test.integr/iter_limit_bad_glueless.rpl @@ -0,0 +1,219 @@ +; config options +; target-fetch-policy: "0 0 0 0 0" +; name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test resolution with lame reply looks like nodata with noSOA + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +; com +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +; net +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +net. IN NS +SECTION AUTHORITY +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.30 +ENTRY_END + +RANGE_END + +; a.gtld-servers.net. - com +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +victim.com. IN NS +SECTION AUTHORITY +victim.com. IN NS ns.victim.com. +SECTION ADDITIONAL +ns.victim.com. IN A 1.2.3.55 +ENTRY_END +RANGE_END + +; e.gtld-servers.net. - net +RANGE_BEGIN 0 100 + ADDRESS 192.12.94.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +net. IN NS +SECTION ANSWER +net. IN NS e.gtld-servers.net. +SECTION ADDITIONAL +e.gtld-servers.net. IN A 192.12.94.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +attacker.net. IN NS +SECTION AUTHORITY +attacker.net. IN NS ns.attacker.net. +SECTION ADDITIONAL +ns.attacker.net. IN A 1.2.3.44 +ENTRY_END +RANGE_END + +; ns.attacker.net. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.44 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +attacker.net. IN NS +SECTION ANSWER +attacker.net. IN NS ns.attacker.net. +SECTION ADDITIONAL +ns.attacker.net. IN A 1.2.3.44 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.attacker.net. IN A +SECTION ANSWER +ns.attacker.net. IN A 1.2.3.44 +SECTION AUTHORITY +attacker.net. IN NS ns.attacker.net. +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.attacker.net. IN AAAA +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +sub.attacker.net. IN NS +SECTION AUTHORITY +sub.attacker.net. IN NS ns1.victim.com. +sub.attacker.net. IN NS ns2.victim.com. +sub.attacker.net. IN NS ns3.victim.com. +sub.attacker.net. IN NS ns4.victim.com. +sub.attacker.net. IN NS ns5.victim.com. +sub.attacker.net. IN NS ns6.victim.com. +sub.attacker.net. IN NS ns7.victim.com. +sub.attacker.net. IN NS ns8.victim.com. +sub.attacker.net. IN NS ns9.victim.com. +ENTRY_END +RANGE_END + +; ns.victim.com. +; returns NXDOMAIN for all queries (attacker generated NS names are not present) +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.55 +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NXDOMAIN +SECTION QUESTION +victim.com. IN NS +SECTION AUTHORITY +victim.com. 0 IN SOA . . 1 1 1 1 1 +SECTION ADDITIONAL +ENTRY_END +RANGE_END + + +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.sub.attacker.net. IN A +ENTRY_END + +; in any case we must get SERVFAIL, no deleation works +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA SERVFAIL +SECTION QUESTION +www.sub.attacker.net. IN A +SECTION ANSWER +ENTRY_END + +; recursion happens here +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +glueless.trigger.check.max.number.of.upstream.queries. IN TXT +ENTRY_END + +STEP 21 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +glueless.trigger.check.max.number.of.upstream.queries. IN TXT +SECTION ANSWER +glueless.trigger.check.max.number.of.upstream.queries. IN TXT "pass" +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + + +SCENARIO_END diff --git a/lib/layer/test.integr/iter_limit_refuse.rpl b/lib/layer/test.integr/iter_limit_refuse.rpl new file mode 100644 index 000000000..5641be34b --- /dev/null +++ b/lib/layer/test.integr/iter_limit_refuse.rpl @@ -0,0 +1,149 @@ +; config options +;server: + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Outrageous number of auth servers return REFUSED. Simulates NXNSAttack misusing wildcard which points to victim's DNS server. Lua config checks if number of outgoing queries is within limits. + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +com. IN A +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns10.example.com. +example.com. IN NS ns11.example.com. +example.com. IN NS ns12.example.com. +example.com. IN NS ns13.example.com. +example.com. IN NS ns14.example.com. +example.com. IN NS ns15.example.com. +example.com. IN NS ns16.example.com. +example.com. IN NS ns17.example.com. +example.com. IN NS ns18.example.com. +example.com. IN NS ns19.example.com. +SECTION ADDITIONAL +ns10.example.com. IN A 1.2.3.10 +ns11.example.com. IN A 1.2.3.11 +ns12.example.com. IN A 1.2.3.12 +ns13.example.com. IN A 1.2.3.13 +ns14.example.com. IN A 1.2.3.14 +ns15.example.com. IN A 1.2.3.15 +ns16.example.com. IN A 1.2.3.16 +ns17.example.com. IN A 1.2.3.17 +ns18.example.com. IN A 1.2.3.18 +ns19.example.com. IN A 1.2.3.19 + +ENTRY_END +RANGE_END + +; ns1.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.10 + ADDRESS 1.2.3.11 + ADDRESS 1.2.3.12 + ADDRESS 1.2.3.13 + ADDRESS 1.2.3.14 + ADDRESS 1.2.3.15 + ADDRESS 1.2.3.16 + ADDRESS 1.2.3.17 + ADDRESS 1.2.3.18 + ADDRESS 1.2.3.19 +ENTRY_BEGIN +MANDATORY +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA REFUSED +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END +RANGE_END + + +; recursion happens here +STEP 10 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; in any case we must get SERVFAIL, no auth works +STEP 11 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO SERVFAIL +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +; recursion happens here +STEP 20 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +refused.trigger.check.max.number.of.upstream.queries. IN TXT +ENTRY_END + +STEP 21 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR AA RD RA NOERROR +SECTION QUESTION +refused.trigger.check.max.number.of.upstream.queries. IN TXT +SECTION ANSWER +refused.trigger.check.max.number.of.upstream.queries. IN TXT "pass" +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +SCENARIO_END diff --git a/lib/layer/test.integr/kresd_config.j2 b/lib/layer/test.integr/kresd_config.j2 index 72cd06b88..7ae66b941 100644 --- a/lib/layer/test.integr/kresd_config.j2 +++ b/lib/layer/test.integr/kresd_config.j2 @@ -1,4 +1,38 @@ -- SPDX-License-Identifier: GPL-3.0-or-later + +-- hook for iter_refuse_toomany.rpl +local function check_max_number_of_upstream_queries(maxcnt) + return function (state, req) + local vals = worker.stats() + local upstream_packets = vals.ipv4 + vals.ipv6 + log('%d packets sent to upstream', upstream_packets) + local answ_f + if upstream_packets > maxcnt then -- . + com. + ???? + answ_f = policy.ANSWER( + { [kres.type.TXT] = { ttl=300, rdata='\4fail' } }) + + else + answ_f = policy.ANSWER( + { [kres.type.TXT] = { ttl=300, rdata='\4pass' } }) + end + return answ_f(state, req) + end +end + +policy.add( + policy.suffix(check_max_number_of_upstream_queries(8), + policy.todnames({'refused.trigger.check.max.number.of.upstream.queries.'}) + ) +) +policy.add( + policy.suffix(check_max_number_of_upstream_queries(16), + policy.todnames({'glueless.trigger.check.max.number.of.upstream.queries.'}) + ) +) + +-- hook end iter_refuse_toomany.rpl + + trust_anchors.remove('.') {% for TAF in TRUST_ANCHOR_FILES %} -- trust_anchors.add_file('{{TAF}}') @@ -28,6 +62,7 @@ end _hint_root_file('hints') cache.size = 2*MB verbose(true) +policy.add(policy.all(policy.DEBUG_ALWAYS)) {% endraw %} net = { '{{SELF_ADDR}}' } diff --git a/lib/meson.build b/lib/meson.build index 87cefebd7..f60304c07 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -75,7 +75,7 @@ unit_tests += [ integr_tests += [ ['cache_minimal_nsec', join_paths(meson.current_source_dir(), 'cache', 'test.integr')], - ['iter_cname_length' , join_paths(meson.current_source_dir(), 'layer', 'test.integr')], + ['iter_limits' , join_paths(meson.current_source_dir(), 'layer', 'test.integr')], ] libkres_inc = include_directories('..') diff --git a/tests/integration/deckard b/tests/integration/deckard index ed0a316cf..21ac67778 160000 --- a/tests/integration/deckard +++ b/tests/integration/deckard @@ -1 +1 @@ -Subproject commit ed0a316cfd1bbcb0f8697e5860b3409fcde52dde +Subproject commit 21ac6777893f89363f38a16a041754aae976bac3 diff --git a/tests/integration/meson.build b/tests/integration/meson.build index f64cf6240..439633adb 100644 --- a/tests/integration/meson.build +++ b/tests/integration/meson.build @@ -19,16 +19,6 @@ py3_deps += [ prepare_deckard = find_program('../../scripts/test-integration-prepare.sh') -# compile libswrap, libfaketime -deckard_contrib = custom_target( - 'deckard_contrib', - command: [ - prepare_deckard, - '@0@'.format(join_paths(meson.current_source_dir(), 'deckard')), - ], - output: 'deckard_contrib', -) - deckard_env = environment() deckard_env.prepend('PATH', sbin_dir) @@ -47,7 +37,6 @@ test( ], is_parallel: false, timeout: 300, - depends: deckard_contrib, ) deckard_run = find_program('deckard/run.sh') @@ -69,6 +58,5 @@ foreach integr_test : integr_tests ], is_parallel: false, workdir: meson.source_root(), - depends: deckard_contrib, ) endforeach