From: cronfy Date: Sat, 4 Jun 2022 13:48:44 +0000 (+0400) Subject: renumber: get rid of netmask limitation, now support any netmask X-Git-Tag: v5.5.1~2^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22f558843f0427cd374e967704cf6ea6eef3b1a6;p=thirdparty%2Fknot-resolver.git renumber: get rid of netmask limitation, now support any netmask (with minor cleanups from vcunat) --- diff --git a/NEWS b/NEWS index 6c0888517..593796b0d 100644 --- 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 diff --git a/modules/renumber/README.rst b/modules/renumber/README.rst index a41ceb032..2e6899168 100644 --- a/modules/renumber/README.rst +++ b/modules/renumber/README.rst @@ -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!'}, } diff --git a/modules/renumber/renumber.lua b/modules/renumber/renumber.lua index 406df141d..bd5e4e9d4 100644 --- a/modules/renumber/renumber.lua +++ b/modules/renumber/renumber.lua @@ -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