]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
modules/block: block policies for queries
authorMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 15 Jun 2015 08:28:15 +0000 (10:28 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 15 Jun 2015 08:30:50 +0000 (10:30 +0200)
by default it blocks queries to private zones, can be extended to match anything in the query content (i.e. water torture style attacks)

doc/modules.rst
modules/block/README.rst [new file with mode: 0644]
modules/block/block.lua [new file with mode: 0644]
modules/block/block.mk [new file with mode: 0644]
modules/modules.mk

index 2bfcc3eeac14c672cf0781b2d6744eb70dd0150c..2a1e4cfd89d73ed1018fa0ae227d5d750e7d9623 100644 (file)
@@ -10,6 +10,7 @@ Implemented modules
    :local:
 
 .. include:: ../modules/hints/README.rst
+.. include:: ../modules/block/README.rst
 .. include:: ../modules/stats/README.rst
 .. include:: ../modules/cachectl/README.rst
 .. include:: ../modules/graphite/README.rst
diff --git a/modules/block/README.rst b/modules/block/README.rst
new file mode 100644 (file)
index 0000000..9e52d11
--- /dev/null
@@ -0,0 +1,11 @@
+.. _mod-block:
+
+Query blocking
+--------------
+
+This module can block queries (and subqueries) based on user-defined policies.
+By default, it blocks queries to reverse lookups in private subnets as per :rfc:`1918`,:rfc:`5735` and :rfc:`5737`.
+
+Example configuration
+^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/modules/block/block.lua b/modules/block/block.lua
new file mode 100644 (file)
index 0000000..002ebc5
--- /dev/null
@@ -0,0 +1,102 @@
+local block = {
+       -- Policies
+       PASS = 1, DENY = 2, DROP = 3,
+       -- Special values
+       ANY = 0,
+       -- Private, local, broadcast, test and special zones 
+       private_zones = {
+               -- RFC1918
+               '10.in-addr.arpa.',
+               '16.172.in-addr.arpa.',
+               '17.172.in-addr.arpa.',
+               '18.172.in-addr.arpa.',
+               '19.172.in-addr.arpa.',
+               '20.172.in-addr.arpa.',
+               '21.172.in-addr.arpa.',
+               '22.172.in-addr.arpa.',
+               '23.172.in-addr.arpa.',
+               '24.172.in-addr.arpa.',
+               '25.172.in-addr.arpa.',
+               '26.172.in-addr.arpa.',
+               '27.172.in-addr.arpa.',
+               '28.172.in-addr.arpa.',
+               '29.172.in-addr.arpa.',
+               '30.172.in-addr.arpa.',
+               '31.172.in-addr.arpa.',
+               '168.192.in-addr.arpa.',
+               -- RFC5735, RFC5737
+               '0.in-addr.arpa.',
+               '127.in-addr.arpa.',
+               '254.169.in-addr.arpa.',
+               '2.0.192.in-addr.arpa.',
+               '100.51.198.in-addr.arpa.',
+               '113.0.203.in-addr.arpa.',
+               '255.255.255.255.in-addr.arpa.',
+               -- IPv6 local, example
+               '0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.',
+               '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.',
+               'd.f.ip6.arpa.',
+               '8.e.f.ip6.arpa.',
+               '9.e.f.ip6.arpa.',
+               'a.e.f.ip6.arpa.',
+               'b.e.f.ip6.arpa.',
+               '8.b.d.0.1.0.0.2.ip6.arpa',
+       }
+}
+
+-- @function Block requests which QNAME matches given zone list
+function block.in_zone(zone_list)
+       return function(pkt, qry)
+               local qname = pkt:qname()
+               for _,zone in pairs(zone_list) do
+                       if qname:sub(-zone:len()) == zone then
+                               return block.DENY
+                       end
+               end
+               return nil
+       end
+end
+
+-- @function Evaluate packet in given rules to determine block action
+function block.evaluate(block, pkt, qry)
+       for _,rule in pairs(block.rules) do
+               local action = rule(pkt, qry)
+               if action then
+                       return action
+               end
+       end
+       return block.PASS
+end
+
+-- @function Block layer implementation
+block.layer = {
+       produce = function(state, data, pkt)
+               -- Only when a query isn't already answered
+               if state ~= kres.CONSUME then
+                       return state
+               end
+               -- @todo Interpret QUERY (as it has final name)
+               -- Interpret packet in Lua and evaluate
+               local pkt = kres.packet(pkt)
+               local action = block:evaluate(pkt, nil)
+               if action == block.DENY then
+                       pkt:flag(kres.wire.QR)
+                       pkt:flag(kres.wire.AA)
+                       pkt:flag(kres.wire.CD)
+                       pkt:rcode(kres.rcode.NXDOMAIN)
+                       -- @todo add SOA record
+                       return kres.DONE
+               elseif action == block.DROP then
+                       return kres.FAIL
+               else
+                       return state
+               end
+
+               
+       end
+}
+
+-- @var Default rules
+block.rules = { block.in_zone(block.private_zones) }
+
+return block
diff --git a/modules/block/block.mk b/modules/block/block.mk
new file mode 100644 (file)
index 0000000..fba7b34
--- /dev/null
@@ -0,0 +1,2 @@
+block_SOURCES := block.lua
+$(call make_lua_module,block)
index 41bbb8c90fabd3901ce38ced548c5f16c943439c..1717714590fca54672094a6ee07cce5aae36e9a0 100644 (file)
@@ -15,7 +15,8 @@ endif
 # List of Lua modules
 ifeq ($(HAS_lua),yes)
 modules_TARGETS += ketcd \
-                   graphite
+                   graphite \
+                   block
 endif
 
 # List of Golang modules