A production Python pipeline queries the TSG session-log ClickHouse database roughly every 5 minutes for sessions matching either a fixed set of VPN-associated TCP ports (18000, 3320, 8099) or a domain-generation heuristic (FQDN = 10-14 lowercase letters + '.xyz' or '.info' TLD, hosted on Cloudflare IP ranges 104.21.0.0/16 or 172.67.0.0/16), and automatically inserts newly-observed matching IPs/FQDNs into the live 'VPNLite_ip'/'VPNLite_fqdn' blocking objects via a config-management API, with no human review step.
查询近1小时 session符合特征的VPNLite对象并插入cm中 / 1.一级域名为['xyz', 'info']中一个 / 2.实际承载ip位于地址段[104.21.0.0/16, 172.67.0.0/16]中 / 3.fqdn 形式为 10-14位 随机字母 + 一级域名 / fqdn加入到VPNLite fqdn 对象, 同时将server ip 加入VPNLite ip 对象
Defense implications
- Fully-automated, unsupervised blocklist generation from a behavioral heuristic (random-looking subdomain + specific cheap TLDs + specific CDN IP ranges + specific ports) means any circumvention system reusing this exact shape gets auto-blocked within roughly 5-60 minutes of first use, with no wait for a human analyst.
- Avoid combining all three heuristic signals at once (random alphabetic subdomain length 10-14, .xyz/.info TLD, and a well-known CDN's IP range) -- breaking any one of the three (e.g. using a real-looking word list instead of random letters, a broader TLD mix, or non-Cloudflare hosting) defeats this specific detector.
- Do not reuse fixed, well-known TCP ports (18000, 3320, 8099 observed here) for a tunnel's data channel; this heuristic is checked independently of the domain-pattern heuristic.
Related findings
Leaked per-app JSON signature-rule exports show the detection engine layers multiple independent signals per VPN product: Windscribe VPN is matched via fixed-offset hex-byte keywords inside the OpenVPN UDP handshake payload (offset 73/depth 78 and offset 81/depth 85); "Super Unlimited VPN" (the SuperUnlimitedVPN app) gets three parallel signatures — a JA3 TLS-fingerprint match, an FQDN match, and an OpenVPN c2s-payload-prefix/length match; Hide.me VPN is matched on OpenVPN UDP payload; FastVPN is matched purely by known source/destination IP; and "V2VPN" (Google Play com.v2ray.v2vpn, a V2Ray-based VPN app) has its own dedicated signature — evidencing a deliberately layered (protocol-fingerprint + TLS-fingerprint + FQDN + IP) detection strategy per circumvention product.
Side-by-side internal performance comparison across Xinjiang (China Mobile carrier deployment, hostname cmcc-xj-server1-sapp-244), Fujian (domestic), and Ethiopia (E21) explicitly references the same 'app_sketch_maat' diagnostic log format at all three sites, confirming the identical AppSketch app-fingerprinting stack is used for domestic Xinjiang surveillance and for the exported Ethiopia deployment.
TSG's app/protocol detection ("AppSketch" / context_based_detector plugin, part of the SAPP packet pipeline) is not purely static-signature: each detection rule can be an arbitrary Lua script (APP_SIG_LUA_SCRIPTS table) executed per-session in a per-worker-thread LuaJIT VM, with access to packet payload, session context counters, and helper functions (APP.data, APP.context.c2s_count, APP.log_debug, APP.append_extra_info). A validation CLI tool (luac-tool) checks script syntax, timeout, and return-value type before import.
Root-caused an Ethiopia SNI-block-failure incident to the detection mechanism itself: APP_SKETCH's FQDN-scanning module -- which exists specifically to identify Psiphon3 and Freegate via top-N SNI matching -- was CPU-expensive enough to saturate cores, triggering sapp's fail-open DDoS bypass and letting some target connections through uninspected. A signature-structure fix roughly doubled throughput (33K/s to 73K/s new connections) and disabling the fail-open bypass restored reliable blocking.
Reveals internal architecture of TSG's traffic classification engine: the 'sapp' process (binary at /opt/tsg/sapp/sapp, version sapp-4.2.90) uses a packet-I/O layer called 'marsio', a custom app-identification plugin 'app_sketch_local' (identify_app_by_tcp_payload / identify_app_by_user_define_attributes), and an embedded LuaJIT ('libelua') for user-defined protocol signatures (e.g. custom Modbus detection) — concurrent LUA script loading crashes the classification worker.
TSG's DPI signature engine is organized around named internal components confirmed by config paths and error logs: SAPP (installed at /home/mesasoft/sapp_run or /opt/tsg/sapp), MAAT (config at .../tsgconf/maat.conf, tied to a Redis-backed APP_SIG_SESSION_ATTRIBUTE_STRING table), and App-SketchDB (a versioned, centrally-maintained app-identification signature database pulled periodically by field deployments). One deployment's provincial gateway alone had 1,667 TCP/UDP first-packet payload signature entries active (396 at the IDC site), confirming payload-prefix matching as a live, large-scale detection method, including custom byte-prefix entries for DingTalk and WeChat.