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