mirror of
https://github.com/ntop/ntopng.git
synced 2026-04-30 07:59:35 +00:00
196 lines
4 KiB
Lua
196 lines
4 KiB
Lua
--
|
|
-- (C) 2017-24 - ntop.org
|
|
--
|
|
|
|
local ipv4_utils = {}
|
|
|
|
local function ip_to_bit(ip)
|
|
local x = 0
|
|
local parts = string.split(ip, "%.")
|
|
|
|
for i=0,3 do
|
|
x = (x | (tonumber(parts[i+1]) << ((3-i)*8)))
|
|
end
|
|
|
|
return x
|
|
end
|
|
|
|
local function bit_to_ip(bits)
|
|
local parts = {}
|
|
|
|
for i=0, 3 do
|
|
parts[i+1] = ((bits >> ((3-i)*8)) & 0xFF)
|
|
end
|
|
|
|
return table.concat(parts, ".")
|
|
end
|
|
|
|
--
|
|
-- Get the number of bits allocated for the network specified by the ip netmask
|
|
-- nil is returned on error
|
|
function ipv4_utils.netmask(ip)
|
|
if not ipv4_utils.valid(ip) then
|
|
-- bad netmask
|
|
return nil
|
|
end
|
|
|
|
local parts = string.split(ip, "%.")
|
|
local netmask = 0
|
|
|
|
for i=1,4 do
|
|
local val = tonumber(parts[i])
|
|
local x = nil
|
|
|
|
if val == 255 then x = 8
|
|
elseif val == 254 then x = 7
|
|
elseif val == 252 then x = 6
|
|
elseif val == 248 then x = 5
|
|
elseif val == 240 then x = 4
|
|
elseif val == 224 then x = 3
|
|
elseif val == 192 then x = 2
|
|
elseif val == 128 then x = 1
|
|
elseif val == 0 then x = 0
|
|
end
|
|
|
|
if x == nil then
|
|
-- bad netmask
|
|
return nil
|
|
end
|
|
|
|
netmask = netmask + x
|
|
|
|
if val ~= 255 then
|
|
for j=i+1,4 do
|
|
if tonumber(parts[j]) ~= 0 then
|
|
-- bad netmask
|
|
return nil
|
|
end
|
|
end
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
return netmask
|
|
end
|
|
|
|
function ipv4_utils.cidr_2_addr(cidr)
|
|
local parts = split(cidr, "/")
|
|
|
|
if #parts ~= 2 then
|
|
return nil
|
|
end
|
|
|
|
local addr = parts[1]
|
|
local num_netmask = tonumber(parts[2])
|
|
local netmask = 0x100000000 - (1 << (32-num_netmask))
|
|
|
|
return addr, bit_to_ip(netmask)
|
|
end
|
|
|
|
--
|
|
-- Compares IPv4 addresses
|
|
-- Precondition: a and b are valid ipv4 addresses
|
|
-- Returns:
|
|
-- >0 if a > b
|
|
-- <0 if a < b
|
|
-- 0 if a == b
|
|
--
|
|
function ipv4_utils.cmp(a, b)
|
|
local a_parts = string.split(a, "%.")
|
|
local b_parts = string.split(b, "%.")
|
|
|
|
for i=1,4 do
|
|
local a_part = tonumber(a_parts[i])
|
|
local b_part = tonumber(b_parts[i])
|
|
|
|
if a_part > b_part then
|
|
return 1
|
|
elseif a_part < b_part then
|
|
return -1
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
-- Assumption: 32bit integer are used. This is already assumed by http://bitop.luajit.org/semantics.html
|
|
function ipv4_utils.ipToInt(ip)
|
|
local intrepr = 0
|
|
|
|
for byte in string.gmatch(ip, "%d+") do
|
|
intrepr = intrepr * 256 + byte
|
|
end
|
|
|
|
return intrepr
|
|
end
|
|
|
|
function ipv4_utils.intToIp(int)
|
|
local parts = {
|
|
((int >> 24) & 0xFF),
|
|
((int >> 16) & 0xFF),
|
|
((int >> 8) & 0xFF),
|
|
(int & 0xFF)
|
|
}
|
|
|
|
return table.concat(parts, ".")
|
|
end
|
|
|
|
-- Returns possible DHCP range
|
|
function ipv4_utils.get_possible_dhcp_range(ip, network, broadcast_addr)
|
|
local ip_int = ipv4_utils.ipToInt(ip)
|
|
local broadcast_int = ipv4_utils.ipToInt(broadcast_addr)
|
|
local first_ip
|
|
local last_ip
|
|
|
|
if ip_int >= broadcast_int - 1 then
|
|
first_ip = ipv4_utils.ipToInt(network) + 1
|
|
last_ip = ip_int - 1
|
|
else
|
|
first_ip = ip_int + 1
|
|
last_ip = broadcast_int - 1
|
|
end
|
|
|
|
return {
|
|
first_ip = ipv4_utils.intToIp(first_ip),
|
|
last_ip = ipv4_utils.intToIp(last_ip),
|
|
}
|
|
end
|
|
|
|
function ipv4_utils.includes(network, netmask, ip)
|
|
local lower = network
|
|
local upper = ipv4_utils.broadcast_address(network, netmask)
|
|
|
|
return (ipv4_utils.cmp(ip, lower) >= 0) and
|
|
(ipv4_utils.cmp(ip, upper) <= 0)
|
|
end
|
|
|
|
-- Get the broadcast address for the given netmask
|
|
function ipv4_utils.broadcast_address(ip, netmask)
|
|
local ipbit = ip_to_bit(ip)
|
|
local maskbit = ip_to_bit(netmask)
|
|
|
|
return bit_to_ip((~(maskbit) | ipbit))
|
|
end
|
|
|
|
-- https://stackoverflow.com/questions/10975935/lua-function-check-if-ipv4-or-ipv6-or-string
|
|
function ipv4_utils.valid(address)
|
|
local chunks = {address:match("(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
|
|
|
|
if #chunks == 4 then
|
|
for _, v in pairs(chunks) do
|
|
if (tonumber(v) < 0) or (tonumber(v) > 255) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
end
|
|
|
|
function ipv4_utils.addressToNetwork(address, netmask)
|
|
local mask = ipv4_utils.netmask(netmask)
|
|
return ntop.networkPrefix(address, mask) .. "/" .. mask
|
|
end
|
|
|
|
return ipv4_utils
|