123 lines
3.8 KiB
Lua
123 lines
3.8 KiB
Lua
if not verbana then verbana = {} end
|
|
if not verbana.ip then dofile('ipmanip.lua') end
|
|
if not verbana.log then function verbana.log(_, message, ...) print(message:format(...)) end end
|
|
verbana.asn_db = {}
|
|
|
|
local ASN_DESCRIPTION_FILE = 'data-used-autnums'
|
|
local NETWORK_ASN_FILE = 'data-raw-table'
|
|
|
|
local function load_file(filename)
|
|
local file = io.open(filename, 'r')
|
|
if not file then
|
|
verbana.log('error', 'error opening "%s"', filename)
|
|
return
|
|
end
|
|
local contents = file:read('*a')
|
|
file:close()
|
|
return contents
|
|
end
|
|
|
|
local function refresh_asn_descriptions()
|
|
local contents = load_file(ASN_DESCRIPTION_FILE)
|
|
local description = {}
|
|
|
|
for line in contents:gmatch('[^\r\n]+') do
|
|
local asn, desc = line:match('^%s*(%d+)%s+(.*)$')
|
|
if not asn or not desc then
|
|
verbana.log('warning', 'could not interpret description line "%s"', line)
|
|
else
|
|
asn = tonumber(asn)
|
|
description[asn] = desc
|
|
end
|
|
end
|
|
|
|
verbana.asn_db.description = description
|
|
end
|
|
|
|
local function refresh_asn_table()
|
|
local contents = load_file(NETWORK_ASN_FILE)
|
|
|
|
local networks = {}
|
|
for line in contents:gmatch('[^\r\n]+') do
|
|
local net, asn = line:match('^%s*(%S*)%s+(%S*)%s*$')
|
|
if not asn or not net then
|
|
verbana.log('warning', 'could not interpret network line "%s"', line)
|
|
else
|
|
asn = tonumber(asn)
|
|
local start, end_ = verbana.ip.netstr_to_bounds(net)
|
|
|
|
if #networks == 0 then
|
|
table.insert(networks, {start, end_, asn})
|
|
else
|
|
local prev_net = networks[#networks]
|
|
local prev_start = prev_net[1]
|
|
local prev_end = prev_net[2]
|
|
local prev_asn = prev_net[3]
|
|
|
|
if prev_start <= start and prev_end >= end_ and prev_asn == asn then
|
|
-- redundant data, skip
|
|
elseif start <= prev_end then
|
|
-- subnet delegated to someone else; split the prev network
|
|
table.remove(networks)
|
|
if prev_start ~= (start - 1) then
|
|
table.insert(networks, {prev_start, start - 1, prev_asn })
|
|
end
|
|
table.insert(networks, {start, end_, asn })
|
|
if (end_ + 1) ~= prev_end then
|
|
table.insert(networks, {end_ + 1, prev_end, prev_asn })
|
|
end
|
|
elseif (prev_end + 1) == start and prev_asn == asn then
|
|
-- adjacent networks belong to the same ASN; just extend the existing network
|
|
networks[#networks][2] = end_
|
|
else
|
|
-- default case
|
|
table.insert(networks, {start, end_, asn})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
verbana.asn_db.network = networks
|
|
end
|
|
|
|
function verbana.asn_db.refresh()
|
|
local start = os.clock()
|
|
refresh_asn_descriptions()
|
|
refresh_asn_table()
|
|
|
|
verbana.log('action', 'refreshed ASN tables in %s seconds', os.clock() - start)
|
|
end
|
|
|
|
verbana.asn_db.refresh()
|
|
|
|
local function find(ipint)
|
|
local t = verbana.asn_db.network
|
|
local low = 0
|
|
local high = #t
|
|
while low <= high do
|
|
local mid = math.floor((low + high) / 2)
|
|
local element = t[mid]
|
|
local start = element[1]
|
|
local end_ = element[2]
|
|
local asn = element[3]
|
|
|
|
if start <= ipint and ipint <= end_ then
|
|
return asn
|
|
elseif start > ipint then
|
|
low = mid + 1
|
|
else
|
|
high = mid - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function verbana.asn_db.lookup(ipstr)
|
|
local ipint = verbana.ip.ipstr_to_number(ipstr)
|
|
local asn = find(ipint)
|
|
if asn then
|
|
return asn, verbana.asn_db.description[asn]
|
|
else
|
|
return nil, nil
|
|
end
|
|
end
|