]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
NXNSAttack mitigation tests
authorPetr Špaček <petr.spacek@nic.cz>
Tue, 5 May 2020 15:01:38 +0000 (17:01 +0200)
committerPetr Špaček <petr.spacek@nic.cz>
Mon, 18 May 2020 19:51:19 +0000 (21:51 +0200)
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.

.gitlab-ci.yml
lib/layer/test.integr/iter_limit_bad_glueless.rpl [new file with mode: 0644]
lib/layer/test.integr/iter_limit_refuse.rpl [new file with mode: 0644]
lib/layer/test.integr/kresd_config.j2
lib/meson.build
tests/integration/deckard
tests/integration/meson.build

index bc903cc1e461b8445cdfb7072184de70c8f8a055..2dc91d270e41fa59f73b842e8fe955277204b7e4 100644 (file)
@@ -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 (file)
index 0000000..fdd7285
--- /dev/null
@@ -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 (file)
index 0000000..5641be3
--- /dev/null
@@ -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
index 72cd06b88f6c2687fa293ee9663d48be378e82f8..7ae66b941bb01db582898fe85f71683eb6bf0343 100644 (file)
@@ -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}}' }
index 87cefebd75dcbf714d5f9ffa412dc729ff39de42..f60304c07d2f8f25ebea98d1cb7d563fe70b036a 100644 (file)
@@ -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('..')
index ed0a316cfd1bbcb0f8697e5860b3409fcde52dde..21ac6777893f89363f38a16a041754aae976bac3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ed0a316cfd1bbcb0f8697e5860b3409fcde52dde
+Subproject commit 21ac6777893f89363f38a16a041754aae976bac3
index f64cf6240b1dd0fd275c4da00c7e8120f7bb770a..439633adb17d7cc3a4dc5d28d2e61e727b850396 100644 (file)
@@ -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