将IPv4地址拆分为最小和最大范围

时间:2014-02-11 13:58:06

标签: lua

使用Lua如何分割给定的IP地址以获得最小和最大范围,例如:

94.19.21.119

我有这样的csv:

18087936,18153471,"AU"
18153472,18219007,"JP"
18219008,18350079,"IN"
18350080,18874367,"CN"

那是读到3个表,而csv是最小,最大,国家代码:

IPfrom = {}
IPto = {}
IPCountry = {}

他们像这样填充:

IPfrom[18087936] = L
IPto[L] = 18153471
IPCountry[L] = "AU"

L是io.read的行号,我接下来要做的是得到最小范围所以我可以不用循环检查它是否存在然后如果它确实该键保存最大范围的索引并且如果ip在最小值/最大值内我得到国家代码。可能是一种不同的做事方式,但表格超过100000个条目,因此循环需要一些时间。

2 个答案:

答案 0 :(得分:3)

以下内容可能对您有用:

--
-- Converts an IPv4 address into its integer value
--
function iptoint(ip)
    local ipint = 0
    local iter = string.gmatch(ip, "%d+")
    for i = 3, 0, -1 do
        local piece = tonumber(iter())
        if piece == nil or piece < 0 or piece > 255 then
            return nil
        end
        ipint = bit32.bor(ipint, bit32.lshift(piece, 8 * i))
    end
    return ipint
end

--
-- Looks up an IPv4 address in a multidimensional table, with the entries:
-- {start_address, end_address, country}
-- and returns the matching country
--
function iptocountry(ip, tbl)
    local ipint = iptoint(ip)
    if ipint == nil then
        return nil
    end
    for _,v in pairs(tbl) do
        if ipint >= v[1] and ipint <= v[2] then
            return v[3]
        end
    end
    return nil
end

使用示例:

local countries = {
    {16777216, 17367039, "US"},
    {1578300000, 1678300000, "CAN"}
    -- ... rest of entries loaded from CSV file
}

local ip = "94.19.21.119"
print (iptocountry(ip, countries)) -- prints CAN

答案 1 :(得分:1)

哈希表(Lua中的基本类型)将为您提供O(N)。一个数组(没有从someMinAddr到someMaxAddr的索引的孔的表)将给你O(1),但使用大量的内存。通过正确排序的结构化表格进行二进制搜索可以得到O(log N),这对于100000个地址来说可能是值得的。我想你可以有这样的结构:

IPfrom = {
    {line=L1, addFrom=from1, addrTo=to1, c=country1}, 
    {line=L2, addFrom=from2, addrTo=to2, c=country2}, 
    {line=L3, addFrom=from3, addrTo=to3, c=country3}, 
    {line=L4, addFrom=from4, addrTo=to4, c=country4}, 
    ...
}

因为我没有看到将to和country字段与其他信息分开的意义,只是意味着更多的表查找。无论如何,如果你真的想要将它们分开,以下内容不会受到影响:

-- init: 
create table from CSV file
sort IPFrom on addFrom field

-- as many times as required: 
function findIP(addr)
    is addr smaller than IPfrom[middle].addrTo3?
    if yes, is addr smaller than IPfrom[middle of middle]?
        etc
end

这是递归的,所以如果你正确地构造它你可以使用尾调用而不用担心堆栈溢出(;),比如

function findIPRecurs(addr, ipTbl, indxMin, indxMax)
    local middle = (indxMin + indxMax )/2
    local midAddr = ipTbl[middle].addrFrom
    if addr < midAddr then
        return findIPRecurs(addr, ipTbl, indxMin, middle)
    else if addr > midAddr then
        return findIPRecurs(addr, ipTbl, middle, indxMax)
    else -- have entry:
        return middle
    end
end

function findIP(addr)
    return findIPRecurs(addr, ipTbl, 1, #ipTbl)
end

我没有对此进行测试,所以可能会有一些修复工作,但你明白了。这将使用与O(N)方法相同的内存,但对于大型数组将更快;比O(1)方法少得多的内存,可能会慢得多。