Files
geedge-jira/attachment/63428/vpn_detect.lua
2025-09-14 22:00:20 +00:00

85 lines
4.0 KiB
Lua

-- Declare protocol for VPN detection
vpn_detect_proto = Proto("VPNDetect", "VPN Detection Protocol")
-- Create fields for OpenVPN, Shadowsocks, WireGuard, and DoH detection
local f_openvpn = ProtoField.string("vpndetect.openvpn", "OpenVPN Traffic Detected")
local f_shadowsocks_handshake = ProtoField.string("vpndetect.shadowsocks_handshake", "Shadowsocks Handshake Detected")
local f_shadowsocks_padding = ProtoField.string("vpndetect.shadowsocks_padding", "Shadowsocks Padding Detected")
local f_wireguard = ProtoField.string("vpndetect.wireguard", "WireGuard Traffic Detected")
local f_doh_google = ProtoField.string("vpndetect.doh_google", "DNS over HTTPS (Google) Detected")
local f_doh_cloudflare = ProtoField.string("vpndetect.doh_cloudflare", "DNS over HTTPS (Cloudflare) Detected")
local f_ssl_long_session = ProtoField.string("vpndetect.ssl_long_session", "Long-duration SSL Session Detected")
local f_encrypted_high_volume = ProtoField.string("vpndetect.encrypted_high_volume", "High Volume Encrypted Traffic Detected")
-- Register fields with the protocol
vpn_detect_proto.fields = {
f_openvpn, f_shadowsocks_handshake, f_shadowsocks_padding, f_wireguard,
f_doh_google, f_doh_cloudflare, f_ssl_long_session, f_encrypted_high_volume
}
-- Main dissector function
function vpn_detect_proto.dissector(buffer, pinfo, tree)
local pkt_len = buffer:len()
local protocol = pinfo.dst_port
local payload = buffer():raw(0, pkt_len)
-- Create a subtree for VPN detection results in the packet details pane
local subtree = tree:add(vpn_detect_proto, buffer(), "VPN Detection")
-- Detect OpenVPN over TLS (port 443, TLS handshake detection)
if protocol == 443 and payload:find("|16 03|") and payload:find("OpenVPN") then
subtree:add(f_openvpn, "OpenVPN TLS Handshake Detected")
pinfo.cols.info:append(" [OpenVPN]")
end
-- Detect Shadowsocks (handshake detection and padding pattern)
if payload:find("|01 03 00 05|") then
subtree:add(f_shadowsocks_handshake, "Shadowsocks Handshake Detected")
pinfo.cols.info:append(" [Shadowsocks Handshake]")
end
-- Detect Shadowsocks padding (packet size between 1300 and 1500 bytes)
if pkt_len >= 1300 and pkt_len <= 1500 then
subtree:add(f_shadowsocks_padding, "Shadowsocks Padding Detected")
pinfo.cols.info:append(" [Shadowsocks Padding]")
end
-- Detect WireGuard traffic (UDP and specific packet size)
if protocol == 51820 and pkt_len >= 1280 and pkt_len <= 1420 and payload:find("|01 00|") then
subtree:add(f_wireguard, "WireGuard Traffic Detected")
pinfo.cols.info:append(" [WireGuard]")
end
-- Detect DNS over HTTPS (Google DNS)
if protocol == 443 and payload:find("dns.google") then
subtree:add(f_doh_google, "DNS over HTTPS (Google) Detected")
pinfo.cols.info:append(" [DoH - Google]")
end
-- Detect DNS over HTTPS (Cloudflare DNS)
if protocol == 443 and payload:find("cloudflare-dns.com") then
subtree:add(f_doh_cloudflare, "DNS over HTTPS (Cloudflare) Detected")
pinfo.cols.info:append(" [DoH - Cloudflare]")
end
-- Detect long-duration SSL/TLS sessions
if protocol == 443 and pinfo.rel_ts > 300 then -- 300 seconds or more
subtree:add(f_ssl_long_session, "Long-duration SSL Session Detected")
pinfo.cols.info:append(" [Long SSL Session]")
end
-- Detect high-volume encrypted traffic (packet size greater than 1000 bytes)
if protocol == 443 and pkt_len > 1000 then
subtree:add(f_encrypted_high_volume, "High Volume Encrypted Traffic Detected")
pinfo.cols.info:append(" [High Volume Encrypted Traffic]")
end
end
-- Register the dissector for TCP and UDP traffic
local tcp_table = DissectorTable.get("tcp.port")
local udp_table = DissectorTable.get("udp.port")
-- Register for OpenVPN (port 443), Shadowsocks, WireGuard (port 51820), and DoH
tcp_table:add(443, vpn_detect_proto) -- OpenVPN, DoH
udp_table:add(51820, vpn_detect_proto) -- WireGuard