]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
protection from DNS rebinding attack
authorPetr Špaček <petr.spacek@nic.cz>
Fri, 15 Jun 2018 11:01:50 +0000 (13:01 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 26 Jun 2018 12:47:55 +0000 (14:47 +0200)
Closes: #320
13 files changed:
NEWS
daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
distro/deb/debian/knot-resolver.install
doc/modules.rst
modules/modules.mk
modules/rebinding/README.rst [new file with mode: 0644]
modules/rebinding/rebinding.lua [new file with mode: 0644]
modules/rebinding/rebinding.mk [new file with mode: 0644]
modules/rebinding/test.integr/deckard.yaml [new file with mode: 0644]
modules/rebinding/test.integr/kresd_config.j2 [new file with mode: 0644]
modules/rebinding/test.integr/module_rebinding.rpl [new file with mode: 0644]
modules/renumber/renumber.lua

diff --git a/NEWS b/NEWS
index d4f69538ac100dc8694649774d6e7123cb115815..d68bfae7ee46ea83b7764161cff5a3e8b431ab89 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ New features
 ------------
 - TLS session resumption (RFC 5077), both server and client (!585, #105)
 - aggressive caching for NSEC3 zones
+- optional protection from DNS Rebinding attack (module rebinding)
 
 Bugfixes
 --------
index 8fc957d8e199a67b4336290b767128230923925a..e00ecb5e21b74a19631760619424bbeabe0e5fd8 100644 (file)
@@ -295,6 +295,7 @@ int kr_pkt_clear_payload(knot_pkt_t *);
 const char *kr_inaddr(const struct sockaddr *);
 int kr_inaddr_family(const struct sockaddr *);
 int kr_inaddr_len(const struct sockaddr *);
+int kr_inaddr_str(const struct sockaddr *, char *, size_t *);
 int kr_sockaddr_len(const struct sockaddr *);
 uint16_t kr_inaddr_port(const struct sockaddr *);
 int kr_straddr_family(const char *);
index 41a2b1ae7f4aafc8b391ccb249ba503ad3d9e588..53f4a2ecf6c02ae45c5404738a625ac8c2483a3c 100755 (executable)
@@ -155,6 +155,7 @@ EOF
        kr_inaddr
        kr_inaddr_family
        kr_inaddr_len
+       kr_inaddr_str
        kr_sockaddr_len
        kr_inaddr_port
        kr_straddr_family
index ea32c2dca5051deb1b37b5e9ffb935e99d61c1f4..e899478aac98679a5000ad526848d7f37c92c922 100644 (file)
@@ -22,6 +22,7 @@ usr/lib/knot-resolver/predict.lua
 usr/lib/knot-resolver/prefill.lua
 usr/lib/knot-resolver/priming.lua
 usr/lib/knot-resolver/prometheus.lua
+usr/lib/knot-resolver/rebinding.lua
 usr/lib/knot-resolver/renumber.lua
 usr/lib/knot-resolver/serve_stale.lua
 usr/lib/knot-resolver/ta_sentinel.lua
index 3f278ae61cdbd80703816c096fd8d6118449e8ee..0d2566f693005378af9d30febe9fe6e6e484e151 100644 (file)
@@ -15,6 +15,7 @@ Knot DNS Resolver modules
 .. include:: ../modules/predict/README.rst
 .. include:: ../modules/http/README.rst
 .. include:: ../modules/daf/README.rst
+.. include:: ../modules/rebinding/README.rst
 .. include:: ../modules/graphite/README.rst
 .. .. include:: ../modules/memcached/README.rst
 .. .. include:: ../modules/redis/README.rst
index e4e5f9268bba84247180ecd8b0dfa025002be610..3c6cbc65af7bea70ddc0787534ba3dd019b73d2c 100644 (file)
@@ -29,6 +29,7 @@ modules_TARGETS += etcd \
                    view \
                    predict \
                    dns64 \
+                   rebinding \
                    renumber \
                    http \
                    daf \
diff --git a/modules/rebinding/README.rst b/modules/rebinding/README.rst
new file mode 100644 (file)
index 0000000..26432e6
--- /dev/null
@@ -0,0 +1,25 @@
+.. _mod-rebinding:
+
+Rebinding protection
+--------------------
+
+This module provides protection from `DNS Rebinding attack`_ by blocking
+answers which cointain IPv4_ or IPv6_ addresses for private use
+(or some other special-use addresses).
+
+To enable this module insert following line into your configuration file:
+
+.. code-block:: lua
+
+  modules.load('rebinding < iterate')
+
+Please note that this module does not offer stable configuration interface
+yet. For this reason it is suitable mainly for public resolver operators
+who do not need to whitelist certain subnets.
+
+.. warning:: Some like to "misuse" such addresses, e.g. `127.*.*.*`
+  in blacklists served over DNS, and this module will block such uses.
+
+.. _`DNS Rebinding attack`: https://en.wikipedia.org/wiki/DNS_rebinding
+.. _IPv4: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+.. _IPv6: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
diff --git a/modules/rebinding/rebinding.lua b/modules/rebinding/rebinding.lua
new file mode 100644 (file)
index 0000000..dc90d20
--- /dev/null
@@ -0,0 +1,112 @@
+-- Protection from DNS rebinding attacks
+local kres = require('kres')
+local renumber = require('renumber')
+
+local M = {}
+M.layer = {}
+M.blacklist = {
+       -- https://www.iana.org/assignments/iana-ipv4-special-registry
+       -- + IPv4-to-IPv6 mapping
+       renumber.prefix('0.0.0.0/8', '0.0.0.0'),
+       renumber.prefix('::ffff:0.0.0.0/104', '::'),
+       renumber.prefix('10.0.0.0/8', '0.0.0.0'),
+       renumber.prefix('::ffff:10.0.0.0/104', '::'),
+       renumber.prefix('100.64.0.0/10', '0.0.0.0'),
+       renumber.prefix('::ffff:100.64.0.0/106', '::'),
+       renumber.prefix('127.0.0.0/8', '0.0.0.0'),
+       renumber.prefix('::ffff:127.0.0.0/104', '::'),
+       renumber.prefix('169.254.0.0/16', '0.0.0.0'),
+       renumber.prefix('::ffff:169.254.0.0/112', '::'),
+       renumber.prefix('172.16.0.0/12', '0.0.0.0'),
+       renumber.prefix('::ffff:172.16.0.0/108', '::'),
+       renumber.prefix('192.168.0.0/16', '0.0.0.0'),
+       renumber.prefix('::ffff:192.168.0.0/112', '::'),
+       -- https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
+       renumber.prefix('::/128', '::'),
+       renumber.prefix('::1/128', '::'),
+       renumber.prefix('fc00::/7', '::'),
+       renumber.prefix('fe80::/10', '::'),
+} -- second parameter for renumber module is ignored except for being v4 or v6
+
+local function is_rr_blacklisted(rr)
+       for i = 1, #M.blacklist do
+               local prefix = M.blacklist[i]
+               -- Match record type to address family and record address to given subnet
+               if renumber.match_subnet(prefix[1], prefix[2], prefix[4], rr) then
+                       return true
+               end
+       end
+       return false
+end
+
+local function check_section(pkt, section)
+       local records = pkt:section(section)
+       local count = #records
+       if count == 0 then
+               return nil end
+       for i = 1, count do
+               local rr = records[i]
+               if rr.type == kres.type.A or rr.type == kres.type.AAAA then
+                       local result = is_rr_blacklisted(rr)
+                       if result then
+                               return rr end
+               end
+       end
+end
+
+local function check_pkt(pkt)
+       for _, section in ipairs({kres.section.ANSWER,
+                                 kres.section.AUTHORITY,
+                                 kres.section.ADDITIONAL}) do
+               local bad_rr = check_section(pkt, section)
+               if bad_rr then
+                       return bad_rr
+               end
+       end
+end
+
+local function refuse(req)
+       -- we are deleting packet in consume() phase so other modules
+       -- might have chosen some RRs from the original packet already
+       req.answ_selected.len = 0
+       req.auth_selected.len = 0
+       req.add_selected.len = 0
+
+       -- construct brand new answer packet
+       local pkt = req.answer
+       pkt:clear_payload()
+       pkt:rcode(kres.rcode.REFUSED)
+       pkt:ad(false)
+       pkt:aa(false)
+       pkt:begin(kres.section.ADDITIONAL)
+
+       local msg = 'blocked by DNS rebinding protection'
+       pkt:put('\11explanation\7invalid\0', 10800, pkt:qclass(), kres.type.TXT,
+       string.char(#msg) .. msg)
+end
+
+-- act on DNS queries which were not answered from cache
+function M.layer.consume(state, req, pkt)
+       if state == kres.FAIL then
+               return state end
+
+       req = kres.request_t(req)
+       local qry = req:current()
+       if qry.flags.CACHED then  -- do not slow down cached queries
+               return state end
+
+       pkt = kres.pkt_t(pkt)
+       local bad_rr = check_pkt(pkt)
+       if not bad_rr then
+               return state end
+
+       qry.flags.RESOLVED = 1  -- stop iteration
+       qry.flags.CACHED = 1  -- do not cache
+       refuse(req)
+       log('[' .. string.format('%5d', qry.id) .. '][rebinding] '
+           .. 'blocking blacklisted IP \'' .. kres.rr2str(bad_rr)
+           .. '\' received from IP ' .. tostring(kres.sockaddr_t(req.upstream.addr)))
+       return kres.FAIL
+end
+
+return M
diff --git a/modules/rebinding/rebinding.mk b/modules/rebinding/rebinding.mk
new file mode 100644 (file)
index 0000000..560d910
--- /dev/null
@@ -0,0 +1,2 @@
+rebinding_SOURCES := rebinding.lua
+$(call make_lua_module,rebinding)
diff --git a/modules/rebinding/test.integr/deckard.yaml b/modules/rebinding/test.integr/deckard.yaml
new file mode 100644 (file)
index 0000000..58a2cee
--- /dev/null
@@ -0,0 +1,12 @@
+programs:
+- name: kresd
+  binary: kresd
+  additional:
+    - -f
+    - "1"
+  templates:
+    - modules/rebinding/test.integr/kresd_config.j2
+    - tests/hints_zone.j2
+  configs:
+    - config
+    - hints
diff --git a/modules/rebinding/test.integr/kresd_config.j2 b/modules/rebinding/test.integr/kresd_config.j2
new file mode 100644 (file)
index 0000000..742f8d3
--- /dev/null
@@ -0,0 +1,49 @@
+{% raw %}
+-- Disable RFC8145 signaling, scenario doesn't provide expected answers
+if ta_signal_query then
+        modules.unload('ta_signal_query')
+end
+
+-- Disable RFC8109 priming, scenario doesn't provide expected answers
+if priming then
+        modules.unload('priming')
+end
+
+-- Disable this module because it make one priming query
+if detect_time_skew then
+        modules.unload('detect_time_skew')
+end
+
+modules.load('rebinding < iterate')
+
+_hint_root_file('hints')
+cache.size = 2*MB
+verbose(true)
+{% endraw %}
+
+net = { '{{SELF_ADDR}}' }
+
+
+{% if QMIN == "false" %}
+option('NO_MINIMIZE', true)
+{% else %}
+option('NO_MINIMIZE', false)
+{% endif %}
+
+
+-- Self-checks on globals
+assert(help() ~= nil)
+assert(worker.id ~= nil)
+-- Self-checks on facilities
+assert(cache.count() == 0)
+assert(cache.stats() ~= nil)
+assert(cache.backends() ~= nil)
+assert(worker.stats() ~= nil)
+assert(net.interfaces() ~= nil)
+-- Self-checks on loaded stuff
+assert(net.list()['{{SELF_ADDR}}'])
+assert(#modules.list() > 0)
+-- Self-check timers
+ev = event.recurrent(1 * sec, function (ev) return 1 end)
+event.cancel(ev)
+ev = event.after(0, function (ev) return 1 end)
diff --git a/modules/rebinding/test.integr/module_rebinding.rpl b/modules/rebinding/test.integr/module_rebinding.rpl
new file mode 100644 (file)
index 0000000..bfaf273
--- /dev/null
@@ -0,0 +1,833 @@
+; config options
+;      target-fetch-policy: "0 0 0 0 0"
+;      module-config: "iterator"
+;      name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test protection from DNS rebinding
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 1000
+       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
+
+; net.
+ENTRY_BEGIN
+MATCH opcode qname
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION AUTHORITY
+.      IN SOA  . . 0 0 0 0 0
+ENTRY_END
+
+; root-servers.net.
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+root-servers.net. IN NS
+SECTION ANSWER
+root-servers.net.      IN NS   k.root-servers.net.
+SECTION ADDITIONAL
+k.root-servers.net.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+root-servers.net. IN A
+SECTION AUTHORITY
+root-servers.net.      IN      SOA     . . 0 0 0 0 0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+k.root-servers.net.    IN      A
+SECTION ANSWER
+k.root-servers.net.    IN      A       193.0.14.129
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+k.root-servers.net.    IN      AAAA
+SECTION AUTHORITY
+root-servers.net.      IN      SOA     . . 0 0 0 0 0
+ENTRY_END
+
+; gtld-servers.net.
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+gtld-servers.net. IN NS
+SECTION ANSWER
+gtld-servers.net.      IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+gtld-servers.net. IN A
+SECTION AUTHORITY
+gtld-servers.net.      IN      SOA     . . 0 0 0 0 0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN      A
+SECTION ANSWER
+a.gtld-servers.net.    IN      A       192.5.6.30
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+a.gtld-servers.net.    IN      AAAA
+SECTION AUTHORITY
+gtld-servers.net.      IN      SOA     . . 0 0 0 0 0
+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 1000
+       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   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+; NS with address pointing into a private range must not be followed
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+attacker.com. IN A
+SECTION AUTHORITY
+attacker.com.  IN NS   ns.attacker.com.
+SECTION ADDITIONAL
+ns.attacker.com.               IN      A       192.168.3.5
+ENTRY_END
+RANGE_END
+
+; ns.attacker.com.
+RANGE_BEGIN 0 1000
+       ADDRESS 19.168.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attacker.com. IN NS
+SECTION ANSWER
+attacker.com.  IN NS   ns.attacker.com.
+SECTION ADDITIONAL
+ns.attacker.com.               IN      A       192.168.3.5
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.attacker.com. IN A
+SECTION ANSWER
+www.attacker.com. IN A 192.0.2.55
+ENTRY_END
+RANGE_END
+
+
+; ns.example.com.
+RANGE_BEGIN 0 1000
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  192.0.2.40
+ENTRY_END
+
+; blacklisted IP addresses
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-0-0-0-0.example.com. IN A
+SECTION ANSWER
+attack-ipv4-0-0-0-0.example.com. IN A  0.0.0.0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-0-0-0-0.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-0-0-0-0.example.com. IN AAAA  ::ffff:0.0.0.0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-10-1-2-3.example.com. IN A
+SECTION ANSWER
+attack-ipv4-10-1-2-3.example.com. IN A 10.1.2.3
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-10-2-3-4.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-10-2-3-4.example.com. IN AAAA ::ffff:10.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-100-127-255-254.example.com. IN A
+SECTION ANSWER
+attack-ipv4-100-127-255-254.example.com. IN A  100.127.255.254
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-100-127-255-255.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-100-127-255-255.example.com. IN AAAA  ::ffff:100.127.255.255
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-127-0-0-1.example.com. IN A
+SECTION ANSWER
+attack-ipv4-127-0-0-1.example.com. IN A        127.0.0.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-127-0-0-1.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-127-0-0-1.example.com. IN AAAA        ::ffff:127.0.0.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-169-254-255-255.example.com. IN A
+SECTION ANSWER
+attack-ipv4-169-254-255-255.example.com. IN A  169.254.255.255
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-169-254-0-0.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-169-254-0-0.example.com. IN AAAA      ::ffff:169.254.0.0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-172-16-0-0.example.com. IN A
+SECTION ANSWER
+attack-ipv4-172-16-0-0.example.com. IN A       172.16.0.0
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-172-31-255-255.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-172-31-255-255.example.com. IN AAAA   ::ffff:172.31.255.255
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4-192-168-3-8.example.com. IN A
+SECTION ANSWER
+attack-ipv4-192-168-3-8.example.com. IN A      192.168.3.8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv4over6-192-168-254-210.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv4over6-192-168-254-210.example.com. IN AAAA  ::ffff:192.168.254.210
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv6-.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv6-.example.com. IN AAAA      ::
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv6-1.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv6-1.example.com. IN AAAA     ::1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv6-fc00.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv6-fc00.example.com. IN AAAA  fc00::
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+attack-ipv6-fe80.example.com. IN AAAA
+SECTION ANSWER
+attack-ipv6-fe80.example.com. IN AAAA  fe80::
+ENTRY_END
+
+RANGE_END
+
+STEP 11 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; recursion happens here, no blacklisted IP address is present
+STEP 12 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  192.0.2.40
+;SECTION AUTHORITY
+;example.com.  IN NS   ns.example.com.
+;SECTION ADDITIONAL
+;ns.example.com.               IN      A       1.2.3.4
+ENTRY_END
+
+; test that 0.0.0.0 is blacklisted
+STEP 201 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-0-0-0-0.example.com. IN A
+ENTRY_END
+
+STEP 202 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-0-0-0-0.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:0.0.0.0 is blacklisted
+STEP 211 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-0-0-0-0.example.com. IN AAAA
+ENTRY_END
+
+STEP 212 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-0-0-0-0.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 10.1.2.3 is blacklisted
+STEP 221 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-10-1-2-3.example.com. IN A
+ENTRY_END
+
+STEP 222 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-10-1-2-3.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:10.2.3.4 is blacklisted
+STEP 231 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-10-2-3-4.example.com. IN AAAA
+ENTRY_END
+
+STEP 232 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-10-2-3-4.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 100.127.255.254 is blacklisted
+STEP 241 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-100-127-255-254.example.com. IN A
+ENTRY_END
+
+STEP 242 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-100-127-255-254.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:100.127.255.255 is blacklisted
+STEP 251 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-100-127-255-255.example.com. IN AAAA
+ENTRY_END
+
+STEP 252 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-100-127-255-255.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 127.0.0.1 is blacklisted
+STEP 261 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-127-0-0-1.example.com. IN A
+ENTRY_END
+
+STEP 262 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-127-0-0-1.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:127.0.0.1 is blacklisted
+STEP 271 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-127-0-0-1.example.com. IN AAAA
+ENTRY_END
+
+STEP 272 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-127-0-0-1.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 169.254.255.255 is blacklisted
+STEP 281 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-169-254-255-255.example.com. IN A
+ENTRY_END
+
+STEP 282 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-169-254-255-255.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:169.254.0.0 is blacklisted
+STEP 291 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-169-254-0-0.example.com. IN AAAA
+ENTRY_END
+
+STEP 292 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-169-254-0-0.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 172.16.0.0 is blacklisted
+STEP 301 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-172-16-0-0.example.com. IN A
+ENTRY_END
+
+STEP 302 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-172-16-0-0.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:172.31.255.255 is blacklisted
+STEP 311 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-172-31-255-255.example.com. IN AAAA
+ENTRY_END
+
+STEP 312 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-172-31-255-255.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that 192.168.3.8 is blacklisted
+STEP 321 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4-192-168-3-8.example.com. IN A
+ENTRY_END
+
+STEP 322 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4-192-168-3-8.example.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::ffff:192.168.254.210 is blacklisted
+STEP 331 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv4over6-192-168-254-210.example.com. IN AAAA
+ENTRY_END
+
+STEP 332 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv4over6-192-168-254-210.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that :: is blacklisted
+STEP 341 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv6-.example.com. IN AAAA
+ENTRY_END
+
+STEP 342 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv6-.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that ::1 is blacklisted
+STEP 351 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv6-1.example.com. IN AAAA
+ENTRY_END
+
+STEP 352 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv6-1.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that fc00:: is blacklisted
+STEP 361 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv6-fc00.example.com. IN AAAA
+ENTRY_END
+
+STEP 362 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv6-fc00.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+; test that fe80:: is blacklisted
+STEP 371 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+attack-ipv6-fe80.example.com. IN AAAA
+ENTRY_END
+
+STEP 372 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+attack-ipv6-fe80.example.com. IN AAAA
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+STEP 401 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; it still works if no blacklisted IP address is present
+STEP 402 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  192.0.2.40
+ENTRY_END
+
+STEP 501 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.attacker.com. IN A
+ENTRY_END
+
+; NS for attacker.com. has IP address from private range, it must fail
+STEP 502 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all answer authority
+REPLY QR RD RA REFUSED
+SECTION QUESTION
+www.attacker.com. IN A
+SECTION ANSWER
+SECTION AUTHORITY
+SECTION ADDITIONAL
+explanation.invalid.   TXT     "blocked by DNS rebinding protection"
+ENTRY_END
+
+SCENARIO_END
index 457e06f4bc99c9a01fc8a7cf248f9da156dd331f..ca77b9475b1ab3eb92fa449794794e44d2788f38 100644 (file)
@@ -106,6 +106,7 @@ local M = {
        prefix = matchprefix,
        name = matchname,
        rule = rule,
+       match_subnet = match_subnet,
 }
 
 -- Config