Sockopt
Sockopt is used to configure low-level network behavior.
It can be used to tune transparent proxying, DNS resolution strategy, and many other socket-level options.
SockoptObject
SockoptObject corresponds to the sockopt item in StreamSettingsObject.
{
// outbound example; also applies to inbound
"outbounds": [
{
// ...
"streamSettings": {
"sockopt": {
"mark": 0,
"tcpMaxSeg": 1440,
"tcpFastOpen": false,
"tproxy": "off",
"domainStrategy": "AsIs",
"happyEyeballs": {},
"dialerProxy": "",
"acceptProxyProtocol": false,
"tcpKeepAliveInterval": 0,
"tcpKeepAliveIdle": 300,
"tcpUserTimeout": 10000,
"tcpcongestion": "bbr",
"interface": "wg0",
"V6Only": false,
"tcpWindowClamp": 600,
"tcpMptcp": false,
"addressPortStrategy": "",
"customSockopt": []
}
}
}
]
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
mark: number
An integer. When non-zero, outbound connections are marked with this value through SO_MARK.
- Linux only.
- Requires
CAP_NET_ADMIN.
tcpMaxSeg: number
Used to set the maximum segment size of TCP packets.
tcpFastOpen: true | false | number
Whether to enable TCP Fast Open.
When set to true or a positive integer, TFO is enabled. When set to false or a negative value, TFO is forcibly disabled. When the field is absent or 0, the system default is used. This option is available for both inbound and outbound.
It is only available on the following operating systems or later:
- Linux 3.16: requires the kernel parameter
net.ipv4.tcp_fastopen. This parameter is a bitmap where0x1allows the client side and0x2allows the server side. The default is0x1. If the server must enable TFO, set it to0x3. Windows 10 (1607), but the implementation is incorrect- Mac OS 10.11 / iOS 9, needs testing
- FreeBSD 10.3 on server side / 12.0 on client side: requires
net.inet.tcp.fastopen.server_enabled=1andnet.inet.tcp.fastopen.client_enabled=1, needs testing
- Linux 3.16: requires the kernel parameter
For inbound, a positive integer here means the maximum number of pending TFO connection requests. Not every operating system supports setting this here:
- Linux / FreeBSD: the positive integer is used as the limit. The maximum accepted value is 2147483647. If set to
true, the value becomes256. On Linux,net.core.somaxconnalso caps it, so if you exceedsomaxconn, raise that as well. - Mac OS:
trueor a positive integer only means enabling TFO. The backlog must be configured separately vianet.inet.tcp.fastopen_backlog. - Windows:
trueor a positive integer only means enabling TFO.
- Linux / FreeBSD: the positive integer is used as the limit. The maximum accepted value is 2147483647. If set to
For outbound,
trueor a positive integer simply means enabling TFO on any supported OS.
tproxy: "redirect" | "tproxy" | "off"
Whether to enable transparent proxying. Linux only.
"redirect": transparent proxy in Redirect mode, supporting all IPv4 and IPv6 TCP connections"tproxy": transparent proxy in TProxy mode, supporting all IPv4 and IPv6 TCP and UDP connections"off": disable transparent proxying
Transparent proxying requires root or CAP_NET_ADMIN.
DANGER
When Dokodemo-door has followRedirect set to true, and tproxy is empty in Sockopt, the tproxy value is set to "redirect".
domainStrategy: "AsIs"
"UseIP" | "UseIPv6v4" | "UseIPv6" | "UseIPv4v6" | "UseIPv4"
"ForceIP" | "ForceIPv6v4" | "ForceIPv6" | "ForceIPv4v6" | "ForceIPv4"
The default value is "AsIs".
When the target address is a domain name, this field controls how outbound connections resolve and use that target:
- With
"AsIs", Xray does not specially handle the domain name. In the end it uses Go's built-in dialer directly. The priority is fixed to the RFC 6724 default and does not follow configurations such asgai.conf, so in practice IPv6 is usually preferred. - With any other value, Xray uses the Xray-core built-in DNS server for resolution. If there is no
DNSObject, system DNS is used. If multiple IP addresses match, the core randomly picks one target IP. "IPv4"means try IPv4 only."IPv4v6"means try IPv4 or IPv6, but for dual-stack domains prefer IPv4. The same logic applies to the IPv6-first variants.- When built-in DNS also sets
"queryStrategy", the actual behavior is the intersection of the two settings. Only IP types included in both are resolved. For example,"queryStrategy": "UseIPv4"together with"domainStrategy": "UseIP"behaves the same as"domainStrategy": "UseIPv4". - When using a
"Use"option, Xray falls back to"AsIs"if the resolution result does not match the requested family, such as a domain that only has IPv4 while usingUseIPv6. - When using a
"Force"option, the connection fails outright if the resolution result does not match the requested family.
TIP
When using "UseIP" or "ForceIP", and OutboundObject specifies sendThrough, the core automatically infers whether IPv4 or IPv6 is needed from the local address. If you manually force a single IP family, such as UseIPv4, but it conflicts with sendThrough, the connection fails.
DANGER
Improper use of this feature can create an infinite loop.
Short version: connecting to the server needs a DNS result, but completing the DNS query also needs to connect to the server.
Tony: which came first, the chicken or the egg?
Detailed explanation:
- Trigger condition: the proxy server is
proxy.com, and the built-in DNS server is enabled in non-Local mode. - Before Xray establishes a TCP connection to
proxy.com, it queriesproxy.comthrough the built-in DNS server. - The built-in DNS server connects to
dns.comand sends a query to obtain the IP ofproxy.com. - Bad routing rules cause the request sent in step 3 to be proxied through
proxy.com. - Xray now tries to establish another TCP connection to
proxy.com. - Before doing that, it again queries
proxy.comthrough the built-in DNS server. - The built-in DNS server reuses the connection from step 3 and sends the new query.
- The problem appears: the connection from step 3 is waiting for the query result from step 7, while step 7 cannot finish until the connection from step 3 is fully established.
- Good game.
Possible solutions:
- Fix the traffic split of the built-in DNS server.
- Use hosts.
If you still do not know how to solve it, do not use this feature.
So this feature is not recommended for inexperienced users unless they understand the routing implications.
dialerProxy: ""
An outbound identifier. When non-empty, the specified outbound is used to establish the connection. It can be used for chained forwarding that still respects transport configuration.
DANGER
This option is incompatible with ProxySettingsObject.Tag.
acceptProxyProtocol: true | false
Inbound-only. Controls whether PROXY protocol is accepted.
PROXY protocol is used to pass the real source IP and port. If you do not know what it is, ignore this option.
Common reverse proxies such as HAProxy and Nginx can be configured to send it, and VLESS fallback xver can also send it.
When set to true, the peer must send PROXY protocol v1 or v2 immediately after the underlying TCP connection is established, otherwise the connection is closed.
tcpKeepAliveIdle: number
TCP idle threshold in seconds. Once a TCP connection has been idle for this long, Keep-Alive probes begin.
For outbound, Xray uses Chrome's default values, where both idle and interval are 45 seconds. Setting either this field or tcpKeepAliveInterval to a negative value disables that default keepalive; a positive value overrides it.
For inbound, Keep-Alive is disabled by default. It becomes enabled when either this field or tcpKeepAliveInterval is non-zero. If only one is set, the other follows the operating-system default.
tcpKeepAliveInterval: number
Time interval in seconds between Keep-Alive probes after TCP enters Keep-Alive state. The rest of the behavior is described above.
tcpUserTimeout: number
In milliseconds. See: https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md
tcpcongestion: ""
TCP congestion-control algorithm. Linux only. When unset, the operating-system default is used.
Common algorithms
bbr(recommended)cubicreno
TIP
Run sysctl net.ipv4.tcp_congestion_control to see the current system default.
interface: ""
Bind the outbound connection to a specific network-interface name. Supported on Linux, iOS, Mac OS, and Windows.
V6Only: true | false
When set to true, listening on :: accepts only IPv6 connections. Linux only.
tcpWindowClamp: number
Bind the advertised TCP window size to this value. The kernel chooses the larger value between this and SOCK_MIN_RCVBUF / 2.
tcpMptcp: true | false
The default value is false. When set to true, Multipath TCP is enabled. This is client-only, because starting with Go 1.24 MPTCP is enabled by default when listening. It currently requires Linux kernel 5.6 or later.
tcpNoDelay: true | false
This field has been removed because Go enables TCP no delay by default. If you want to disable it, do so through customSockopt.
addressPortStrategy: "none" | "SrvPortOnly" | "SrvAddressOnly" | "SrvPortAndAddress" | "TxtPortOnly" | "TxtAddressOnly" | "TxtPortAndAddress"
Use SRV records or TXT records to specify the target address and or port used by outbound. The default value is none, which disables the feature.
These lookups go through system DNS rather than Xray's built-in DNS. The queried name is the outbound domain name. If the lookup fails, the request is sent using the original address and port.
Srv* means querying SRV records in their standard format. Txt* means querying TXT records in a format such as 127.0.0.1:80.
PortOnly resets only the port. AddressOnly resets only the address. PortAndAddress resets both.
This option takes effect before domainStrategy inside sockopt. After the address is rewritten, it is still resolved according to domainStrategy, if any. However, it takes effect after Freedom's own domainStrategy, so if that one already resolved the domain to an IP, this option no longer works.
As a practical consequence, if ordinary domain traffic is sent into a Freedom outbound with AsIs, enabling this field makes the core try to resolve and rewrite the address and port, for example by querying google.com for SRV records.
customSockopt: []
An array for advanced users to specify any needed socket option. In theory, all connection-related settings above can be expressed here, and you can also set other socket options that exist but are not exposed directly by the core. It currently supports Linux, Windows, and Darwin. The example below is equivalent to "tcpcongestion": "bbr".
Make sure you understand socket programming before using it.
"customSockopt": [
{
"system": "linux",
"type": "str",
"level": "6",
"opt": "13",
"value": "bbr"
}
]2
3
4
5
6
7
8
9
system: ""
Optional. Restricts the option to a specific operating system. If the current system does not match, the option is skipped. Supported values are linux, windows, and darwin, all in lowercase. If left empty, the option is applied directly.
type: ""
Required. The value type to set. Currently int and str are supported.
level: ""
Optional. Protocol level. The default is 6, which means TCP.
opt: ""
The option number to operate on, in decimal. In the example above, 13 is the decimal form of TCP_CONGESTION, whose hexadecimal value is 0xd.
value: ""
The value to set. In the example above, the value is bbr.
When type is int, the value must be a decimal number.
happyEyeballs: HappyEyeballsObject
An RFC 8305 Happy Eyeballs implementation, TCP only. When the target is a domain name, it races the resolved addresses and chooses the first successful one. It only works when Sockopt.domainStrategy is not AsIs.
Note that UseIPv4v6 and ForceIPv4v6 effectively reduce the usable list to IPv4 and only query IPv6 if IPv4 resolution fails. That is not recommended. Prefer UseIP or ForceIP together with HappyEyeballs.interleave.
WARNING
Do not use this together with the domainStrategy on a Freedom outbound, because then Sockopt only sees the final IP after replacement.
HappyEyeballsObject
"happyEyeballs": {
"tryDelayMs": 250,
"prioritizeIPv6": false,
"interleave": 1,
"maxConcurrentTry": 4
}2
3
4
5
6
tryDelayMs: number
Delay between each racing attempt, in milliseconds. The default is 0, which disables the feature. A recommended value is 250.
prioritizeIPv6: bool
Controls which IP family comes first after sorting. The default is false, meaning IPv4 comes first.
interleave: number
The RFC 8305 First Address Family Count. The default value is 1. It controls how IPv4 and IPv6 addresses are interleaved.
For example, the waiting dial queue may be ordered as 46464646 when this is 1, or 44664466 when it is 2, where 6 means an IPv6 address and 4 means an IPv4 address.
maxConcurrentTry: number
Maximum number of concurrent attempts. This prevents the core from launching too many connections when a domain resolves to many addresses and all of them fail. The default is 4. Setting it to 0 disables Happy Eyeballs.