-- 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