]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
renumber: get rid of netmask limitation, now support any netmask
authorcronfy <cronfy@gmail.com>
Sat, 4 Jun 2022 13:48:44 +0000 (17:48 +0400)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 9 Jun 2022 09:46:43 +0000 (11:46 +0200)
(with minor cleanups from vcunat)

NEWS
modules/renumber/README.rst
modules/renumber/renumber.lua

diff --git a/NEWS b/NEWS
index 6c08885177e17ee4a1bf68a9406fe4c442664e1a..593796b0d60217ae25e63e1de3819658ddbd3202 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Improvements
 - daemon/tls: disable TLS resumption via tickets for TLS <= 1.2 (#742, !1295)
 - daemon/http: DoH now responds with proper HTTP codes (#728, !1279)
 - renumber module: allow rewriting subnet to a single IP (!1302)
+- renumber module: allow arbitrary netmask (!1306)
 - nameserver selection algorithm: improve IPv6 avoidance if broken (!1298)
 
 Bugfixes
index a41ceb032e22d353b04dba25ea4c1da42a2ed591..2e6899168cf1d7bca0e906f927fe59e0b79daf0c 100644 (file)
@@ -15,9 +15,6 @@ in local zones, that will be remapped to real addresses by the resolver.
    breaks signatures. You can see whether an answer was valid or not based on
    the AD flag.
 
-.. warning:: The module is currently limited to rewriting complete octets of
-   the IP addresses, i.e. only /8, /16, /24 etc. network masks are supported.
-
 Example configuration
 ---------------------
 
@@ -29,6 +26,8 @@ Example configuration
                        {'10.10.10.0/24', '192.168.1.0'},
                        -- Remap /16 block to localhost address range
                        {'166.66.0.0/16', '127.0.0.0'},
+                       -- Remap /26 subnet (64 ip addresses)
+                       {'166.55.77.128/26', '127.0.0.192'},
                        -- Remap a /32 block to a single address
                        {'2001:db8::/32', '::1!'},
                }
index 406df141d8148dfc013571c1bc31567d244a31e2..bd5e4e9d4a56c550131e8325851e8d2bee4faef3 100644 (file)
@@ -15,6 +15,38 @@ local function extract_address(target)
        return string.sub(target, 1, idx - 1), true
 end
 
+-- Create bitmask from integer mask for single octet: 2 -> 11000000
+local function getOctetBitmask(intMask)
+       return bit.lshift(bit.rshift(255, 8 - intMask), 8 - intMask)
+end
+
+-- Merge ipNet with ipHost, using intMask
+local function mergeIps(ipNet, ipHost, intMask)
+       local octetMask
+       local result = ""
+
+       if (#ipNet ~= #ipHost) then
+               return nil
+       end
+
+       for currentOctetNo = 1, #ipNet do
+               if intMask >= 8 then
+                       result = result .. ipNet:sub(currentOctetNo,currentOctetNo)
+                       intMask = intMask - 8
+               elseif (intMask <= 0) then
+                       result = result .. ipHost:sub(currentOctetNo,currentOctetNo)
+               else
+                       octetMask = getOctetBitmask(intMask)
+                       result = result .. string.char(bit.bor(
+                                       bit.band(string.byte(ipNet:sub(currentOctetNo,currentOctetNo)), octetMask),
+                                       bit.band(string.byte(ipHost:sub(currentOctetNo,currentOctetNo)), bit.bnot(octetMask))
+                       ))
+               end
+       end
+
+       return result
+end
+
 -- Create subnet prefix rule
 local function matchprefix(subnet, addr)
        local is_exact
@@ -43,10 +75,6 @@ end
 -- Add subnet prefix rewrite rule
 local function add_prefix(subnet, addr)
        local prefix = matchprefix(subnet, addr)
-       local bitlen = prefix[2]
-       if bitlen ~= nil and bitlen % 8 ~= 0 then
-               log_warn(ffi.C.LOG_GRP_RENUMBER, 'network mask: only /8, /16, /24 etc. are supported (entire octets are rewritten)')
-       end
        table.insert(prefixes_global, prefix)
 end
 
@@ -58,7 +86,6 @@ local function match_subnet(subnet, bitlen, addrtype, rr)
 end
 
 -- Renumber address record
-local addr_buf = ffi.new('char[16]')
 local function renumber_record(tbl, rr)
        for i = 1, #tbl do
                local prefix = tbl[i]
@@ -71,19 +98,13 @@ local function renumber_record(tbl, rr)
                -- Match record type to address family and record address to given subnet
                -- If provided, compare record owner to prefix name
                if match_subnet(subnet, bitlen, addrtype, rr) then
-                       -- Replace part or whole address
-                       local to_copy
-                       if bitlen and not is_exact then
-                               to_copy = bitlen
+                       if is_exact then
+                               rr.rdata = target
                        else
-                               to_copy = #target * 8
+                               local mergedHost = mergeIps(target, rr.rdata, bitlen)
+                               if mergedHost ~= nil then rr.rdata = mergedHost end
                        end
-                       local chunks = to_copy / 8
-                       local rdlen = #rr.rdata
-                       if rdlen < chunks then return rr end -- Address length mismatch
-                       ffi.copy(addr_buf, rr.rdata, rdlen)
-                       ffi.copy(addr_buf, target, chunks) -- Rewrite prefix
-                       rr.rdata = ffi.string(addr_buf, rdlen)
+
                        return rr
                end
        end