Skip to content

Instantly share code, notes, and snippets.

@Earu
Last active September 27, 2022 16:58
Show Gist options
  • Save Earu/a3ede23bb5600f8cb980ac8b815ed6ed to your computer and use it in GitHub Desktop.
Save Earu/a3ede23bb5600f8cb980ac8b815ed6ed to your computer and use it in GitHub Desktop.
Find IPs that match known VPNs and proxy servers in Garry's Mod.
local BASE_URL = "https://raw.githubusercontent.com/X4BNet/lists_vpn/main/ipv4.txt"
local IP_PATTERN = "(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)"
local IP_RANGE_PATTERN = "(%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?)/(%d+)"
local function str_to_ip(str)
local o1, o2, o3, o4 = str:match(IP_PATTERN)
o1, o2, o3, o4 = tonumber(o1), tonumber(o2), tonumber(o3), tonumber(o4)
return bit.bor(
o1 * 2 ^ 24,
o2 * 2 ^ 16,
o3 * 2 ^ 8,
o4
)
end
local lookup = {}
local lookup_count = 0
http.Fetch(BASE_URL, function(body)
for str_ip, net_mask_str in body:gmatch(IP_RANGE_PATTERN) do
local ip = str_to_ip(str_ip)
if not lookup[ip] then
lookup[ip] = {}
lookup_count = lookup_count + 1
end
local net_mask = tonumber(net_mask_str)
if not net_mask then continue end
table.insert(lookup[ip], net_mask)
end
end)
local function compare_ips(source_ip, net_ip, net_mask)
local mask = bit.bnot(2 ^ (32 - net_mask) - 1)
return bit.band(source_ip, mask) == bit.band(net_ip, mask)
end
local function check_vpn(ip_str, callback)
return coroutine.create(function()
if lookup_count == 0 then
callback(false, -1, -1)
return
end
local i = 0
local source_ip = str_to_ip(ip_str)
for target_ip, net_masks in pairs(lookup) do
for _, net_mask in ipairs(net_masks) do
local is_in_range = compare_ips(source_ip, target_ip, net_mask)
if is_in_range then
callback(true, target_ip, net_mask)
return
end
i = i + 1
if i % 1000 == 0 then
coroutine.yield()
end
end
end
callback(false, -1, -1)
end)
end
local callback_id = 0
function util.CheckVPN(ip_addr, callback)
local co = check_vpn(ip_addr, callback)
local hook_name = ("CheckVPN_[%d]"):format(callback_id)
hook.Add("Think", hook_name, function()
local status, result = coroutine.resume(co)
if not status then
hook.Remove("Think", hook_name)
error(result)
end
if result or coroutine.status(co) == "dead" then
hook.Remove("Think", hook_name)
end
end)
callback_id = callback_id + 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment