Replies: 1 comment
|
Sent it as #6661 — the field, the dispatcher check and tests, with before/after numbers in the PR body. Happy to reshape or drop it if the form is wrong. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
What this is about
Content sniffing costs a fixed ~200 ms on every connection whose server speaks first — SSH, IMAP, SMTP, MySQL, RDP. The client sends nothing, so
sniffer()inapp/dispatcher/default.gospends its whole budget before giving up:The outcome is graceful —
contentErr != nil && metadataErr == nilreturns the metadata result and the connection proceeds — but the wait has already been paid.Measurement
Xray-core v26.7.28. One host, SOCKS inbound →
freedomoutbound, destinationgithub.com:22. Time from the SOCKS reply to the first byte of the SSH banner, median of 9 runs each:enabled: falseenabled: trueenabled: true+domainsExcluded: ["github.com"]enabled: true+metadataOnly: trueThe penalty is a constant ~198 ms, independent of how far the destination is.
Config used — runs as is
{ "log": { "loglevel": "warning" }, "inbounds": [ { "tag": "sniffing-off", "port": 10801, "listen": "127.0.0.1", "protocol": "socks", "settings": { "auth": "noauth", "udp": false }, "sniffing": { "enabled": false } }, { "tag": "sniffing-on", "port": 10802, "listen": "127.0.0.1", "protocol": "socks", "settings": { "auth": "noauth", "udp": false }, "sniffing": { "enabled": true, "destOverride": ["http", "tls", "quic"] } }, { "tag": "domains-excluded", "port": 10803, "listen": "127.0.0.1", "protocol": "socks", "settings": { "auth": "noauth", "udp": false }, "sniffing": { "enabled": true, "destOverride": ["http", "tls", "quic"], "domainsExcluded": ["github.com"] } }, { "tag": "metadata-only", "port": 10804, "listen": "127.0.0.1", "protocol": "socks", "settings": { "auth": "noauth", "udp": false }, "sniffing": { "enabled": true, "destOverride": ["http", "tls", "quic"], "metadataOnly": true } } ], "outbounds": [{ "protocol": "freedom" }] }Measured by opening the SOCKS connection, requesting
github.com:22, then timing the first byte returned after the SOCKS reply.Why the existing options don't cover this
domainsExcludedandipsExcludedare evaluated inshouldOverride, aftersniffer()has returned. The third row shows the consequence: excluding the exact destination changes the latency by nothing. That matches their documented purpose — they suppress the destination rewrite — and #5927 reads as though this placement is deliberate, so this is not a report that they are broken. The point is only that there is no knob acting before the read.metadataOnly: truedoes avoid the wait, but it is per-inbound and disables content sniffing for everything on that inbound. It is unusable where the same inbound also carries HTTP/TLS traffic that routing rules match by domain — which is the common case.Proposal
A
portsExcludedinSniffingConfig, checked in the dispatcher immediately before thesniffer()call. The destination port is already known there, so this is a lookup with no extra parsing, and no behavioural change for anyone who leaves it unset.An operator running a mixed workload behind one inbound — browser, mail client, git over SSH — could then keep domain-based routing and stop paying ~200 ms on every mail and SSH connection.
Happy to open a PR if the idea is welcome, and if
portsExcludedis the shape you would want rather than, say, aportsIncludedwhitelist.Checked before posting
Searched issues and discussions for prior art. The closest is #5927 (
domainsExcludedsupportinggeosite:) and theipsExcludedfollow-up discussed in it; neither touches the pre-sniff case.All reactions