Are you an LLM? You can read better optimized documentation at /config/sniffing.md for this page in Markdown format
流量探测(Sniffing / Sniffer)
本页只讲 3 件事:
- 什么时候会嗅探
- 嗅探怎么分支执行
- 嗅探结果如何影响路由与目标地址
配置入口:见 入站代理 / SniffingObject。
1. 执行链路
嗅探发生在路由前,主路径如下:
- 入口:
app/dispatcher/default_dispatch.go - 读取缓存:
app/dispatcher/default_cached_reader.go - sniffer 组装:
app/dispatcher/sniffer.go - 嗅探循环:
app/dispatcher/default_sniffing.go
判定流程图(从任意流量进入)
说明:opt 表示该 sniffer 由上下文条件启用(例如 DNS/ECH/MTProto)。后处理分支是并列条件判断,不是串行依赖链。ALPN 仅在 http/tls/dot/ech/quic 进入。T-xx/U-xx 仅为映射编号,不代表执行顺序(实际为并发探测)。
2. 启用条件(结构化)
| 场景 | 是否依赖 sniffing.enabled | 说明 |
|---|---|---|
| 入站主动嗅探 | 是 | sniffing.enabled=true 时执行完整内容嗅探 |
| 路由驱动协议嗅探 | 否 | 为匹配 routing.rules.protocol 可被动启用 |
| DNS 嗅探 | 是 | 需同时满足:sniffing.enabled=true 且路由需要 protocol:"dns" |
| ECH 嗅探 | 否 | 路由需要 protocol:"ech" 时启用 |
| JA4 计算 | 否 | 路由规则存在 attrs.ja4 时启用(含空值) |
metadataOnly | 是 | 仅执行 metadata sniffer,不读 payload |
当前路由驱动支持协议:
wireguard/mtproto/zerotier/ech/dot/rdp/mqtt/ntp/postgres/ikev2/dtls/trojan
3. 分支与 Sniffer 清单
| 分支 | 已注册协议 |
|---|---|
| TCP 常规 | http socks4 socks5 ssh rdp mqtt postgres bittorrent stun |
| TCP TLS-only | tls(始终) dot(始终,命中看 ALPN/853) trojan(始终) ech(路由需要时) |
| UDP | zerotier wireguard ntp ikev2 dtls quic stun utp |
| Metadata | fakedns(可用时) |
可选动态加入:
dns(TCP/UDP)mtproto(TCP)
4. 超时与重试策略
| 项目 | 当前行为 |
|---|---|
| 基础预算 | 200ms |
| TLS-like 扩展预算 | 最长 2s |
| QUIC-like/UDP 扩展预算 | 最长 500ms |
ErrNoClue | 最多 2 次尝试 |
ErrProtoNeedMoreData | 不消耗尝试次数,继续读取 |
NeedMoreDataLen | 触发一次定向补读(补到至少 N 字节) |
5. 输出与路由影响
SniffResult
Protocol():用于routing.rules.protocolDomain():用于destOverride/routeOnly
attrs(路由可读)
| attr | 来源 | 用途 |
|---|---|---|
alpn | http/tls/quic/ech | routing.rules.protocol 的 alpn:* 匹配 |
tls_sni | TLS 嗅探 | 是否含 SNI(1/0) |
tls_version | TLS 嗅探 | TLS 版本匹配 |
ja4 | TLS 嗅探 + attrs.ja4 触发 | JA4 指纹匹配 |
:method :path + headers | HTTP 嗅探 | routing.rules.attrs 匹配 |
attrs 字段定义见 routing.rules.attrs。
关键协议产出字段(TLS / HTTP / QUIC)
| 协议 | SniffResult 产出 | attrs 产出 | 备注 |
|---|---|---|---|
tls | protocol=tlsdomain=SNI(可空)ALPN(可空)TLSVersion(可空)JA4(可空) | alpn、tls_sni、tls_version、ja4、ja4_tag(label, 条件) | ja4 仅在路由存在 attrs.ja4 意图时计算;ja4_tag 需 LookupJA4Tag 命中 |
http1 | protocol=http1domain=HostALPN=http/1.1 | alpn、:method、:path、HTTP headers | :method/:path/headers 仅在 content.Attributes 初始为空时写入 |
http2 | protocol=http2domain=空ALPN=h2 | alpn | 仅识别 HTTP/2 preface |
quic | protocol=quicdomain=SNI(可空)ALPN(可空)JA4(可空) | alpn、ja4、ja4_tag(label, 条件) | ja4/ja4_tag 条件与 TLS 相同 |
ech | protocol=echdomain=空ALPN(可空) | alpn | ECH 设计上不产出域名 |
ja4_tag(label) 触发条件(代码路径):app/dispatcher/default_dispatch_sniff.go 中 maybeSetJA4TagFromDB。
ALPN 匹配
- 写法:
protocol: ["alpn:h2"] - 可用反向:
!alpn:h2 - 字段定义:
routing.rules.protocol
destOverride / routeOnly
- 仅在
sniffing.enabled=true时允许目标重置。 routeOnly=true时只写RouteTarget,真实连接目标Target不变。- DNS 嗅探只影响
RouteTarget,不直接改实际拨号目标。
6. 支持协议(结构化清单)
按代码索引编号列出,与上方流程图节点一一对应。编号仅用于定位,不代表执行先后(实际为并发探测)。
| 匹配顺序 | 协议 | 网络 | 是否产出域名 | 是否产出 ALPN | 关键产出字段 | 额外启用条件 |
|---|---|---|---|---|---|---|
M-01 | fakedns | metadata | ✅ | ❌ | domain | FakeDNS 引擎可用 |
T-01 | tls | TCP (tlsOnly) | ✅(有 SNI 时) | ✅ | domain alpn tls_sni tls_version ja4 ja4_tag | 无 |
T-01a | dot | TCP (tlsOnly) | ❌ | ✅ | alpn tls_version ja4 ja4_tag | ALPN=dot/dns 或 853 端口 |
T-02 | http1 / http2 | TCP | http1 ✅ / http2 ❌ | ✅ | alpn;http1 另含 domain :method :path headers | 无 |
T-03 | socks4 | TCP | ❌ | ❌ | - | 无 |
T-04 | socks5 | TCP | ❌ | ❌ | - | 无 |
T-05 | ssh | TCP | ❌ | ❌ | - | 无 |
T-06 | dns(TCP) | TCP | ✅ | ❌ | domain | sniffing.enabled=true 且路由需要 protocol:"dns" |
T-07 | ech | TCP (tlsOnly) | ❌ | ✅ | alpn | 路由需要 protocol:"ech" |
T-08 | mtproto | TCP | ❌ | ❌ | - | 路由需要 protocol:"mtproto" |
T-09 | rdp | TCP | ❌ | ❌ | - | 无 |
T-10 | mqtt | TCP | ❌ | ❌ | - | 无 |
T-11 | postgres* | TCP | ❌ | ❌ | - | 无 |
T-12 | trojan | TCP (tlsOnly) | ❌ | ❌ | - | 无 |
T-13 | bittorrent | TCP | ❌ | ❌ | - | 无 |
T-14 | stun / turn(TCP) | TCP | ❌ | ❌ | - | 无 |
U-01 | dns(UDP) | UDP | ✅ | ❌ | domain | sniffing.enabled=true 且路由需要 protocol:"dns" |
U-02 | zerotier | UDP | ❌ | ❌ | - | 路由需要 protocol:"zerotier" |
U-03 | wireguard | UDP | ❌ | ❌ | - | 无 |
U-04 | ntp | UDP | ❌ | ❌ | - | 无 |
U-05 | ikev2 | UDP | ❌ | ❌ | - | 无 |
U-06 | dtls | UDP | ❌ | ❌ | - | 无 |
U-07 | quic | UDP | ✅(有 SNI 时) | ✅ | domain alpn ja4 ja4_tag | 无 |
U-08 | stun / turn(UDP) | UDP | ❌ | ❌ | - | 无 |
U-09 | utp(BitTorrent) | UDP | ❌ | ❌ | - | 无 |
R-EX | fakedns+others | 结果合成 | ✅ | 取决于合成协议 | 取决于合成协议 | FakeDNS in-pool 且“其它协议”命中时返回 |
7. 配置模板(逐协议)
7.1 前置(入站)
json
{
"inbounds": [
{
"port": 10808,
"protocol": "socks",
"settings": {},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic", "dns"],
"routeOnly": true
}
}
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
7.2 协议模板(每个协议一个规则)
以下片段都是 routing.rules 内的单条规则模板。
http1
- 用途:匹配 HTTP/1 流量
- 规则:
json
{
"type": "field",
"protocol": ["http1"],
"outboundTag": "http1-out"
}1
2
3
4
5
2
3
4
5
http2
- 用途:匹配 HTTP/2 流量
- 规则:
json
{
"type": "field",
"protocol": ["http2"],
"outboundTag": "http2-out"
}1
2
3
4
5
2
3
4
5
tls
- 用途:匹配 TLS 流量(可配合
attrs.tls_sni/tls_version/ja4) - 规则:
json
{
"type": "field",
"protocol": ["tls"],
"outboundTag": "tls-out"
}1
2
3
4
5
2
3
4
5
dot
- 用途:匹配 DNS over TLS(DoT)
- 说明:
dot只用于协议选路,不产出domain,不用于destOverride - 规则:
json
{
"type": "field",
"protocol": ["dot"],
"outboundTag": "dot-out"
}1
2
3
4
5
2
3
4
5
trojan
- 用途:匹配 Trojan-like TLS 握手特征
- 规则:
json
{
"type": "field",
"protocol": ["trojan"],
"outboundTag": "trojan-out"
}1
2
3
4
5
2
3
4
5
ech
- 用途:匹配 ECH(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["ech"],
"outboundTag": "ech-out"
}1
2
3
4
5
2
3
4
5
quic
- 用途:匹配 QUIC 流量
- 规则:
json
{
"type": "field",
"protocol": ["quic"],
"outboundTag": "quic-out"
}1
2
3
4
5
2
3
4
5
dns
- 用途:匹配 DNS 嗅探结果(需
sniffing.enabled=true且存在 DNS 规则) - 规则:
json
{
"type": "field",
"protocol": ["dns"],
"outboundTag": "dns-out"
}1
2
3
4
5
2
3
4
5
fakedns / fakedns+others
- 用途:匹配 FakeDNS 反查结果
- 规则:
json
{
"type": "field",
"protocol": ["fakedns", "fakedns+others"],
"outboundTag": "fakedns-out"
}1
2
3
4
5
2
3
4
5
socks4 / socks5
- 用途:匹配 SOCKS 握手流量
- 规则:
json
{
"type": "field",
"protocol": ["socks4", "socks5"],
"outboundTag": "socks-out"
}1
2
3
4
5
2
3
4
5
ssh
- 用途:匹配 SSH 流量
- 规则:
json
{
"type": "field",
"protocol": ["ssh"],
"outboundTag": "ssh-out"
}1
2
3
4
5
2
3
4
5
mtproto
- 用途:匹配 MTProto(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["mtproto"],
"outboundTag": "mtproto-out"
}1
2
3
4
5
2
3
4
5
rdp
- 用途:匹配 RDP(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["rdp"],
"outboundTag": "rdp-out"
}1
2
3
4
5
2
3
4
5
mqtt
- 用途:匹配 MQTT(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["mqtt"],
"outboundTag": "mqtt-out"
}1
2
3
4
5
2
3
4
5
postgres / postgres+ssl / postgres+gssenc / postgres+cancel
- 用途:匹配 Postgres 系列(路由驱动)
- 规则(全匹配):
json
{
"type": "field",
"protocol": ["postgres"],
"outboundTag": "pg-out"
}1
2
3
4
5
2
3
4
5
- 规则(只匹配 SSL):
json
{
"type": "field",
"protocol": ["postgres+ssl"],
"outboundTag": "pg-ssl-out"
}1
2
3
4
5
2
3
4
5
bittorrent
- 用途:匹配 BitTorrent(含 uTP)
- 规则:
json
{
"type": "field",
"protocol": ["bittorrent"],
"outboundTag": "bt-out"
}1
2
3
4
5
2
3
4
5
stun / turn
- 用途:匹配 STUN/TURN
- 规则:
json
{
"type": "field",
"protocol": ["stun", "turn"],
"outboundTag": "stun-turn-out"
}1
2
3
4
5
2
3
4
5
zerotier
- 用途:匹配 ZeroTier(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["zerotier"],
"outboundTag": "zerotier-out"
}1
2
3
4
5
2
3
4
5
wireguard
- 用途:匹配 WireGuard(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["wireguard"],
"outboundTag": "wireguard-out"
}1
2
3
4
5
2
3
4
5
ntp
- 用途:匹配 NTP(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["ntp"],
"outboundTag": "ntp-out"
}1
2
3
4
5
2
3
4
5
ikev2
- 用途:匹配 IKEv2(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["ikev2"],
"outboundTag": "ikev2-out"
}1
2
3
4
5
2
3
4
5
dtls
- 用途:匹配 DTLS(路由驱动)
- 规则:
json
{
"type": "field",
"protocol": ["dtls"],
"outboundTag": "dtls-out"
}1
2
3
4
5
2
3
4
5
7.3 attrs 模板(TLS 相关常用)
JA4 标签匹配
routing.rules.attrs.ja4 的匹配规则:
- 值是标准 JA4 指纹:按指纹精确匹配。
- 值不是指纹:按
ja4.db标签匹配(命中该标签下任一指纹即匹配)。 - 标签匹配大小写不敏感(内部会归一化为小写)。
推荐直接写标签本身,不再推荐旧写法 ja4:xxx / ext-ja4:xxx。
json
{
"type": "field",
"attrs": {
"ja4": "threat:malware"
},
"outboundTag": "block"
}1
2
3
4
5
6
7
2
3
4
5
6
7
或匹配更细标签:
json
{
"type": "field",
"attrs": {
"ja4": "ua:family:chromium-597"
},
"outboundTag": "proxy"
}1
2
3
4
5
6
7
2
3
4
5
6
7
TLS 版本 + 是否有 SNI
json
{
"type": "field",
"attrs": {
"tls_version": "^1\\.3$",
"tls_sni": "^1$"
},
"outboundTag": "direct"
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
8. 排错(最常见)
- 看不到图:确认不是四反引号包裹的纯代码块。
- DNS 不生效:确认
sniffing.enabled=true且 routing 中存在protocol:["dns"]规则。 - JA4 不生效:确认 routing 里存在
attrs.ja4规则。
同时确认未使用旧写法ja4:xxx/ext-ja4:xxx(当前推荐直接写标签,如threat:malware)。 - 命中率低:先检查是否走错网络分支(TCP/UDP),再看首包是否过短导致超时。