OpenWrt-Tools/DynDNS/dyndns.lua

196 lines
4.4 KiB
Lua

-- Configuration Start
local lookup_dhcp_leases = true
local dhcp_leases_file = "/tmp/dhcp.leases"
local lookup_ip_neigh = true
local non_fqdn = true
local network_domain = ".lan"
local whitelisted_networks = {"192.168.0.0/16", "172.16.0.0/12", "10.0.0.0/8", "fd00::/8"}
local output_file = "/tmp/hosts/dyndns"
local reload_command = "/etc/init.d/dnsmasq reload"
-- Configuration End
local ip = require("ip")
function split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t = {}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
function new()
return {hostname = "?", ip = {}}
end
function contains(tab, val)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end
whitelisted_networks_v4 = {}
whitelisted_networks_v6 = {}
for index, value in ipairs(whitelisted_networks) do
local parsed_ip = ip.parse(value)
local ip_kind = parsed_ip:kind()
if ip_kind == "ipv4" then table.insert(whitelisted_networks_v4, parsed_ip) end
if ip_kind == "ipv6" then table.insert(whitelisted_networks_v6, parsed_ip) end
end
function ip_match(parsed_ip)
local ip_kind = parsed_ip:kind()
if ip_kind == "ipv4" then whitelisted_list = whitelisted_networks_v4 end
if ip_kind == "ipv6" then whitelisted_list = whitelisted_networks_v6 end
for index, value in ipairs(whitelisted_list) do
if parsed_ip:match(value) then return true end
end
return false
end
function count(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
function read_file(path)
local file = io.open(path, "rb")
if not file then return nil end
local content = file:read "*a"
file:close()
return content
end
function pairs_by_keys(t, f)
local a = {}
for n in pairs(t) do
table.insert(a, n)
end
table.sort(a, f)
local i = 0
local iter = function ()
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
function sort_table(my_table)
local t = {}
for title,value in pairs_by_keys(my_table) do
table.insert(t, { title = title, value = value })
end
my_table = t
return my_table
end
function compare_tables(a,b)
if #a ~= #b then return false end
local t1,t2 = {}, {}
for k,v in pairs(a) do
t1[k] = (t1[k] or 0) + 1
end
for k,v in pairs(b) do
t2[k] = (t2[k] or 0) + 1
end
for k,v in pairs(t1) do
if v ~= t2[k] then return false end
end
return true
end
local array = {}
if lookup_dhcp_leases then
local dhcp_file = assert(io.popen('cat ' .. dhcp_leases_file, 'r'))
local dhcp_table = split(dhcp_file:read('*all'), "\r\n")
dhcp_file:close()
for key, value in pairs(dhcp_table) do
local dhcp_lease = split(value, " ")
local mac = dhcp_lease[2]
if not array[mac] then
array[mac] = new()
array[mac]["hostname"] = dhcp_lease[4]
end
if not contains(array[mac]["ip"], dhcp_lease[3]) then
table.insert(array[mac]["ip"], dhcp_lease[3])
end
end
end
if lookup_ip_neigh then
local neigh_file = assert(io.popen('ip neigh', 'r'))
local neigh_table = split(neigh_file:read('*all'), "\r\n")
neigh_file:close()
for key, value in pairs(neigh_table) do
local neigh = split(value, " ")
local mac = neigh[5]
local ip = neigh[1]
if mac and ip then
if not array[mac] then
array[mac] = new()
end
if not contains(array[mac]["ip"], ip) then
table.insert(array[mac]["ip"], ip)
end
end
end
end
local config = ""
for i1, value in pairs(array) do
local ip_list = value["ip"]
local hostname = value["hostname"]
if hostname ~= "?" and hostname ~= "*" then
for i2, ip_addr in pairs(ip_list) do
parsed_ip = ip.parse(ip_addr)
if ip_match(parsed_ip) then
local line = ip_addr
if non_fqdn then line = line .. " " .. hostname end
if network_domain then line = line .. " " .. (hostname .. network_domain) end
if line ~= ip_addr then config = config .. "\r\n" .. line end
end
end
end
end
local config_file = read_file(output_file)
if config_file == nil then config_file = "" end
local c1 = sort_table(split(config_file, "\r\n"))
local c2 = sort_table(split(config, "\r\n"))
if not compare_tables(c1, c2) then
local file = io.open(output_file, "w")
file:write(config)
file:close()
os.execute(reload_command)
end