Skip to content

Instantly share code, notes, and snippets.

@wildrun0
Created August 3, 2022 11:38
Show Gist options
  • Save wildrun0/f2e11676942b5a3592eee65d735ef2cf to your computer and use it in GitHub Desktop.
Save wildrun0/f2e11676942b5a3592eee65d735ef2cf to your computer and use it in GitHub Desktop.
DNS LATENCY TEST for Pi-hole (lua)
local cURL = require "cURL"
-- caching functions to get faster loop experience
local str_gmatch = string.gmatch
local str_find = string.find
function string:split(sep)
local i = 1
local t = {}
for token in str_gmatch(self, "[^" .. sep .. "]+") do
t[i] = token
i = i + 1
end
return t
end
local output_file_name = "dns-bench-output.txt"
local file, err = io.open(output_file_name,'a')
if not file then
print(err)
return
end
local function write_to_file(...)
for i = 1, select("#", ...) do
local text = select(i, ...)
file:write(text, "\n")
end
end
local print = function(...)
print(...)
write_to_file(...)
end
print("\nPerfoming a ping test through all Pi-hole upstream dns providers\nDownloading page...")
local body_html = ""
local function save_page(data)
body_html = body_html .. data
end
local c, err = cURL.easy{
url = "https://docs.pi-hole.net/guides/dns/upstream-dns-providers/",
ssl_verifypeer = false,
ssl_verifyhost = false,
writefunction=save_page
}:perform()
local status = c:getinfo_response_code()
print("curl status: " .. status..string.format(" [%s]", status == 200 and "Done" or "Fail"))
if status ~= 200 then return end
local function get_tag(body_text, tag, explict_tag)
local i = 1
local t = {}
local pattern = explict_tag and "<"..tag..".->(.-)</"..tag..">" or "<"..tag..">(.-)</"..tag..">"
for v in str_gmatch(body_text, pattern) do
t[i] = v
i = i + 1
end
return t
end
local dns_names = get_tag(body_html, "h3", true)
local uls = get_tag(body_html, "ul", false)
table.remove(uls, 3) -- we are not going to use opendns FamilyShield nah fam
local os_isWin = os.getenv('OS') and true or false
local ipv6_support = true
local pings = {}
for i = 1, #dns_names do
local dns_query = uls[i]:split("\n")
local dns_name = dns_names[i]:split("<")[1]
if dns_name == "Custom" then break end
print("\n"..dns_name)
local ping = {}
for v = 1, #dns_query do
local dns_ip = dns_query[v]:split("<li>")[1]
local is_v6 = false
if string.match(dns_ip, "(IPv6)") then
if not ipv6_support then
break
end
dns_ip = dns_ip:split(" ")[1]
is_v6 = true
end
print(dns_ip)
local ping_cmd = os_isWin and "ping "..dns_ip or "ping -c 4 "..dns_ip
if is_v6 then
ping_cmd = os_isWin and ping_cmd or "ping6 "..dns_ip
end
local pipe = io.popen(ping_cmd)
local output = pipe:read("*all")
local output_splitted = os_isWin and output:split("=") or output:split("/")
local measured_ping = output_splitted[os_isWin and #output_splitted or #output_splitted-2]
if ipv6_support then
if not measured_ping or str_find(measured_ping:gsub("%s+", ""), "4%(100%%") then -- 4(100% lost)
ipv6_support = false
print("IPv6 not supported. Skipping")
break
end
end
ping[v] = tonumber(measured_ping:match("%S+"))
pipe:close()
end
pings[dns_name] = ping
print("Measured ping: "..table.concat(ping, ", "))
end
local function get_lowest(table)
local min = math.huge
for i = 1, #table do
local num = table[i]
if min > num then
min = num
end
end
return min
end
print("\nPING DNS SERVICE")
local best_dns
local min = math.huge
for dns, dns_pings in pairs(pings) do
local dns_lowest_ping = get_lowest(dns_pings)
if min > dns_lowest_ping then
min = dns_lowest_ping
best_dns = dns
end
print(string.format("%.1f", dns_lowest_ping) .. "ms" .. " "..dns)
end
print("\nYour best choice would be: " .. best_dns .. "\nLatency(ms): " .. min)
print("\nOutput saved to "..output_file_name)
file:close()
@wildrun0
Copy link
Author

wildrun0 commented Aug 3, 2022

ATTENTION!
Lua-cURL required

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment