]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
add filterForward function, plus initialiser helper in newNMG 10463/head
authorPeter van Dijk <peter.van.dijk@powerdns.com>
Tue, 1 Jun 2021 13:54:02 +0000 (15:54 +0200)
committerPeter van Dijk <peter.van.dijk@powerdns.com>
Sun, 6 Jun 2021 17:40:46 +0000 (19:40 +0200)
docs/lua-records/functions.rst
docs/lua-records/reference/netmask.rst
pdns/lua-base4.cc
pdns/lua-record.cc
pdns/recursordist/docs/lua-scripting/netmask.rst
regression-tests.auth-py/test_LuaRecords.py

index 2f72a8eda71a49cbb44274b0174a4cab64dac506..52bce72556d2735c26e674ea6f20f3958d6f0b50 100644 (file)
@@ -185,11 +185,10 @@ Reverse DNS functions
 ~~~~~~~~~~~~~~~~~~~~~
 
 .. warning::
-  The reverse DNS functions are under active development. **They may**
-  **not be safe for production use.** The syntax of these functions may change at any
-  time.
+  For :func:`createForward` and :func:`createForward6`, we recommend filtering with :func:`filterForward`, to prevent PowerDNS from generating A/AAAA responses to addresses outside of your network.
+  Not limiting responses like this may, in some situations, help attackers with impersonation and attacks like such as cookie stealing.
 
-.. function:: createReverse(format)
+.. function:: createReverse(format, [exceptions])
 
   Used for generating default hostnames from IPv4 wildcard reverse DNS records, e.g. ``*.0.0.127.in-addr.arpa`` 
   
@@ -200,7 +199,8 @@ Reverse DNS functions
   Returns a formatted hostname based on the format string passed.
 
   :param format: A hostname string to format, for example ``%1%.%2%.%3%.%4%.static.example.com``.
-  
+  :param exceptions: An optional table of overrides. For example ``{['10.10.10.10'] = 'quad10.example.com.'}`` would, when generating a name for IP ``10.10.10.10``, return ``quad10.example.com`` instead of something like ``10.10.10.10.example.com``.
+
   **Formatting options:**
 
   - ``%1%`` to ``%4%`` are individual octets
@@ -251,7 +251,7 @@ Reverse DNS functions
     $ dig +short A 127.0.0.5.static.example.com @ns1.example.com
     127.0.0.5
   
-.. function:: createReverse6(format)
+.. function:: createReverse6(format[, exceptions])
 
   Used for generating default hostnames from IPv6 wildcard reverse DNS records, e.g. ``*.1.0.0.2.ip6.arpa``
   
@@ -265,7 +265,8 @@ Reverse DNS functions
   Returns a formatted hostname based on the format string passed.
 
   :param format: A hostname string to format, for example ``%33%.static6.example.com``.
-  
+  :param exceptions: An optional table of overrides. For example ``{['2001:db8::1'] = 'example.example.com.'}`` would, when generating a name for IP ``2001:db8::1``, return ``example.example.com`` instead of something like ``2001--db8.example.com``.
+
   Formatting options:
    
   - ``%1%`` to ``%32%`` are individual characters (nibbles)
@@ -317,6 +318,18 @@ Reverse DNS functions
     $ dig +short AAAA 2001-a-b--1.static6.example.com @ns1.example.com
     2001:a:b::1
 
+.. function:: filterForward(address, masks[, fallback])
+
+  Used for limiting the output of :func:`createForward` and :func:`createForward6` to a set of netmasks.
+
+  :param address: A string containing an address, usually taken directly from :func:`createForward: or :func:`createForward6`.
+  :param masks: A NetmaskGroup; any address not matching the NMG will be replaced by the fallback address.
+  :param fallback: A string containing the fallback address. Defaults to ``0.0.0.0`` or ``::``.
+
+  Example::
+
+    *.static4.example.com IN LUA A "filterForward(createForward(), newNMG():addMasks{'192.0.2.0/24', '10.0.0.0/8'})"
+
 Helper functions
 ~~~~~~~~~~~~~~~~
 
index f50ad8f101dc3134d28dc196b75480de98c8d605..8c248c4283e70a79cfedadf6f625e0e03fd6484e 100644 (file)
@@ -86,7 +86,7 @@ They can be matched against netmasks objects:
   nmg = newNMG()
   nmg:addMask("127.0.0.0/8")
   nmg:addMasks({"213.244.168.0/24", "130.161.0.0/16"})
-  nmg:addMasks(dofile("bad.ips")) -- contains return {"ip1","ip2"..}
+  nmg:addMasks(dofile("bad-ips.lua")) -- contains return {"ip1","ip2"..}
 
   if nmg:match(dq.remoteaddr) then
     print("Intercepting query from ", dq.remoteaddr)
@@ -94,9 +94,15 @@ They can be matched against netmasks objects:
 
 Prefixing a mask with ``!`` excludes that mask from matching.
 
-.. function:: newNMG() -> NetMaskGroup
+.. function:: newNMG([masks]) -> NetMaskGroup
 
-  Returns a new, empty :class:`NetMaskGroup`.
+  .. versionchanged:: 4.5.0
+    Added the optional ``masks`` parameter.
+
+  Returns a new :class:`NetMaskGroup`.
+  If no masks are passed, the object is empty.
+
+  :param {str} masks: The masks to add.
 
 .. class:: NetMaskGroup
 
index ba48fc617aeb8ca48e3f62f607b38bf84300e909..e00ac5cd2f05e3950f9365f6e4361b52d8014fe1 100644 (file)
@@ -171,7 +171,18 @@ void BaseLua4::prepareContext() {
   d_lw->registerToStringFunction(&Netmask::toString);
 
   // NetmaskGroup
-  d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
+  d_lw->writeFunction("newNMG", [](boost::optional<vector<pair<unsigned int, std::string>>> masks) {
+    auto nmg = NetmaskGroup();
+
+    if (masks) {
+      for(const auto& mask: *masks) {
+        nmg.addMask(mask.second);
+      }
+    }
+
+    return nmg;
+  });
+  // d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
   d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) { nmg.addMask(mask); });
   d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>("addMasks", [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks) { for(const auto& mask: masks) { nmg.addMask(mask.second); } });
   d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
index b81aaa775d14c9dd504f3b9237e446360b18dcf0..49dd69fd4ee33448c61fd7bca7879dba4e324636 100644 (file)
@@ -579,10 +579,8 @@ static void setupLuaRecords()
         
         vector<ComboAddress> candidates;
         
-        // exceptions are relative to zone
         // so, query comes in for 4.3.2.1.in-addr.arpa, zone is called 2.1.in-addr.arpa
-        // e["1.2.3.4"]="bert.powerdns.com" - should match, easy enough to do
-        // the issue is with classless delegation..
+        // e["1.2.3.4"]="bert.powerdns.com" then provides an exception
         if(e) {
           ComboAddress req(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], 0);
           const auto& uom = *e;
@@ -729,6 +727,24 @@ static void setupLuaRecords()
       return std::string("unknown");
     });
 
+  lua.writeFunction("filterForward", [](string address, NetmaskGroup& nmg, boost::optional<string> fallback) {
+      ComboAddress ca(address);
+
+      if (nmg.match(ComboAddress(address))) {
+        return address;
+      } else {
+        if (fallback) {
+          return *fallback;
+        }
+
+        if (ca.isIPv4()) {
+          return string("0.0.0.0");
+        } else {
+          return string("::");
+        }
+      }
+    });
+
   /*
    * Simplistic test to see if an IP address listens on a certain port
    * Will return a single IP address from the set of available IP addresses. If
index b6c09f579b1d5cc6d4b1b298b6d716076f851665..3f2f8aa7ca8febdcb15e3055e6413eefde4e2579 100644 (file)
@@ -94,9 +94,14 @@ They can be matched against netmasks objects:
 
 Prefixing a mask with ``!`` excludes that mask from matching.
 
-.. function:: newNMG() -> NetMaskGroup
+.. function:: newNMG([masks]) -> NetMaskGroup
+  .. versionchanged:: 4.6.0
+    Added the optional ``masks`` parameter.
 
-  Returns a new, empty :class:`NetMaskGroup`.
+  Returns a new :class:`NetMaskGroup`.
+  If no masks are passed, the object is empty.
+
+  :param {str} masks: The masks to add.
 
 .. class:: NetMaskGroup
 
index b585b21712442f00c6189f45de676a06f47d1518..32ff9f0a32a3b3ea15c652d9daf4963936d510ee 100644 (file)
@@ -117,7 +117,7 @@ any              IN           TXT "hello there"
 
 resolve          IN    LUA    A   ";local r=resolve('localhost', 1) local t={{}} for _,v in ipairs(r) do table.insert(t, v:toString()) end return t"
 
-*.createforward  IN    LUA    A     "createForward()"
+*.createforward  IN    LUA    A     "filterForward(createForward(), newNMG{{'1.0.0.0/8', '64.0.0.0/8'}})"
 *.createreverse  IN    LUA    PTR   "createReverse('%5%.example.com', {{['10.10.10.10'] = 'quad10.example.com.'}})"
 *.createreverse6 IN    LUA    PTR   "createReverse6('%33%.example.com', {{['2001:db8::1'] = 'example.example.com.'}})"
 
@@ -126,7 +126,7 @@ resolve          IN    LUA    A   ";local r=resolve('localhost', 1) local t={{}}
 createforward6.example.org.                 3600 IN SOA  {soa}
 createforward6.example.org.                 3600 IN NS   ns1.example.org.
 createforward6.example.org.                 3600 IN NS   ns2.example.org.
-*                                                IN    LUA    AAAA  "createForward6()"
+*                                                IN    LUA    AAAA  "filterForward(createForward6(), newNMG{{'2000::/3'}}, 'fe80::1')"
         """
 # the separate createforward6 zone is because some of the code in lua-record.cc insists on working relatively to the zone apex
     }
@@ -641,17 +641,19 @@ createforward6.example.org.                 3600 IN NS   ns2.example.org.
                 "ip40414243": "64.65.66.67",
                 "ipp40414243": "0.0.0.0",
                 "ip4041424": "0.0.0.0",
+                "2.2.2.2": "0.0.0.0"   # filtered
             }),
             ".createreverse.example.org." : (dns.rdatatype.PTR, {
                 "4.3.2.1": "1-2-3-4.example.com.",
-                "10.10.10.10": "quad10.example.com."
+                "10.10.10.10": "quad10.example.com."   # exception
             }),
             ".createforward6.example.org." : (dns.rdatatype.AAAA, {
-                "2001--db8" : "2001::db8"
+                "2001--db8" : "2001::db8",
+                "4000-db8--1" : "fe80::1"   # filtered, with fallback address override
             }),
             ".createreverse6.example.org." : (dns.rdatatype.PTR, {
                 "8.b.d.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.1.0.0.2" : "2001--db8.example.com.",
-                "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2" : "example.example.com."
+                "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2" : "example.example.com."   # exception
             })
         }