Sniffing: Add portsExcluded to skip the sniffer for given destination ports - #6661
Sniffing: Add portsExcluded to skip the sniffer for given destination ports#6661rokokol wants to merge 1 commit into
portsExcluded to skip the sniffer for given destination ports#6661Conversation
…on ports
Sniffing costs a fixed ~200ms on every connection whose peer speaks
first - SSH, IMAP, SMTP - because the client sends nothing for the
sniffer to read, so cacheDeadline in app/dispatcher burns down in full
before the dispatch continues.
domainsExcluded and ipsExcluded do not help: both are consulted in
shouldOverride, after the sniffer has already waited, and they only
suppress the destination override. portsExcluded is checked before any
payload is read, so a listed port takes the same path as sniffing being
switched off.
Measured through a socks inbound and a freedom outbound against a
loopback server that sends its banner on connect, 30 connections each,
median time from CONNECT to the first byte:
direct, no proxy 0.2 ms
sniffing disabled 66.3 ms
sniffing on, port excluded 67.0 ms
sniffing on, port not excluded 268.1 ms
The last two rows are one instance configured with "portsExcluded":
"2222": port 2222 answers in 66.8 ms and port 2223 in 267.7 ms, so the
exclusion stays scoped to the ports listed.
Refs XTLS#6654
|
IAMP和SMTP很少被个人用户用作代理 专门的邮件用途完全可以关嗅探 ssh的并发也不多是典型的长时间连接 我觉得这点延迟就算了 主要是不想xxxxExcluded过于膨胀 如果目标已知那么合理使用 domainsExcluded 也行 |
|
Fair on ssh, and I checked rather than argued: OpenSSH sends its ident first, without waiting for the server. 22 bytes on connect, so the sniffers reject immediately, What is left is protocols where the server genuinely opens: SMTP, IMAP, POP3, and also MySQL, PostgreSQL, FTP. On turning sniffing off for mail — that works when mail has its own inbound. The setup I hit this on is a single client-facing inbound carrying everything, where there is nothing to split on: disabling sniffing there costs the domain routing it is enabled for. That is the case the field was meant for, and I did not state it clearly enough in the description. Not asking to reopen — the call on the config surface is yours. Leaving this here for whoever arrives with the same setup. |
Adds
portsExcludedtosniffing: a port list checked in the dispatcher before the sniffer reads anything, so a connection to a listed destination port takes the same path as sniffing being switched off.Follows up on discussion #6654 — sending the patch since it is small enough to judge from the diff. Close it if the shape is unwanted.
The problem
Where the peer speaks first — SSH, IMAP, SMTP — the client sends nothing for the sniffer to read, so
cacheDeadlineinapp/dispatcher/default.goburns down in full before the dispatch continues. The cost is fixed and paid on every such connection.domainsExcludedandipsExcludeddo not help: both are consulted inshouldOverride, i.e. after the sniffer has already waited, and they only suppress the destination override. #5927 shows that placement is deliberate, which is why this is a separate knob rather than a change to those.The change
ports_excludedinSniffingConfig(field 7),portsExcludedin the JSON config, taking the usual port-list syntax:"22,143,993-995"SniffingRequest.ExcludeForPortas anet.MemoryPortList, filled byBuildSniffingRequestshouldSniff(request, destination)replaces the barerequest.Enabledtest at both call sitesMeasurements
socks inbound → freedom outbound, against a loopback server that sends its banner on connect, 30 connections each, median from SOCKS5 CONNECT to the first byte:
The excluded row lands on the sniffing-disabled row. Scope check on a single instance configured with
"portsExcluded": "2222": port 2222 answers in 66.8 ms, port 2223 in 267.7 ms, so the exclusion stays on the listed ports.Tests
shouldSnifftable test inapp/dispatcher— disabled, no exclusions, single port, both range ends, just past the rangeBuildSniffingRequestwith and withoutportsExcludedinapp/proxyman; the nil case would panic inPortListFromProtowithout the guardTestSniffingConfig_Buildininfra/confextended over the JSON → proto pathgo build ./...andgo test ./...pass andgo run ./infra/vformat/main.go -mode checkis clean.config.pb.gowas regenerated with protoc v33.5 and protoc-gen-go v1.36.11, so its header still matches every other.pb.gofor thecheck-protojob. One local failure,TestTCPLocalNameServerinapp/dns, reproduces identically on a clean checkout here — network-dependent, unrelated.Docs for the field belong in Xray-docs-next; happy to send that too if this lands.