Skip to content

👻 freedom: TLS fragmentation and socket options

Since v1.19.33-r2 there is a proxy type freedom. It is DIRECT, the connection goes straight to the site, plus the fragment and sockopt settings of the Xray-core freedom outbound. Two fragmentation modes are taken from sing-box (tls_fragment, tls_record_fragment).

Fragmentation splits the TLS ClientHello so that the site name (SNI) never travels in one piece. It helps against DPI that matches the ClientHello as a whole. Use freedom through rules or groups only for the sites that need it.

proxies:
- name: FRAGMENT
type: freedom
fragment:
packets: tlshello
length: "1-1"
interval: "0"
sockopt:
tcp-congestion: bbr
tcp-keep-alive-idle: 300
tcp-keep-alive-interval: 60
tcp-user-timeout: 10000
custom-sockopt:
- { opt: "1", type: int, value: "1" }
rules:
- DOMAIN-SUFFIX,example.com,FRAGMENT

This is the same as the Xray outbound below:

{
"protocol": "freedom",
"settings": { "fragment": { "packets": "tlshello", "length": "1-1", "interval": "0" } },
"streamSettings": {
"sockopt": {
"customSockopt": [{ "opt": "1", "type": "int", "value": "1" }],
"tcpcongestion": "bbr",
"tcpKeepAliveIdle": 300,
"tcpKeepAliveInterval": 60,
"tcpUserTimeout": 10000
}
},
"tag": "FRAGMENT"
}

The usual DIRECT options also work: interface-name, routing-mark, ip-version, tfo, mptcp. UDP goes out as with DIRECT.

ParameterValuesWhat it does
packetstlshello, "N-M" or emptytlshello rewrites the first ClientHello into several TLS records. "1-3" cuts the first three writes of the connection into TCP segments, empty cuts every write
length"N" or "N-M", bytesSize of a piece. Required with split: length
interval"N" or "N-M", msPause between pieces. With tlshello and 0 all records go out in one write
max-split"N" or "N-M"At most this many pieces, the last one takes the rest. Empty or 0 means no limit
splitlength (default) or snisni: one random cut inside every label of the site name but the top-level one, as in sing-box; length is not needed then
waitinterval (default) or ackack: every piece goes in its own TCP segment and the next one waits until the server acknowledged it, as in sing-box
fallback-delayms, 500 by defaultThe pause for wait: ack where the acknowledgement can’t be seen
  • Ranges work as in Xray: the upper bound is not included, so "100-200" gives 100 to 199.
  • A large ClientHello (with post-quantum keys) often comes in several writes. freedom holds it until the record is complete and only then cuts it. Xray in this case sends it uncut.
  • After the fragmented part the connection works at full speed: data is copied between the sockets directly again.
  • With wait: ack the acknowledgement is read on Linux, Android, macOS and iOS. On Windows and other systems fallback-delay is used. An acknowledgement that comes back faster than 20 ms is taken for one from a middlebox, not from the server, and fallback-delay is waited too. For nearby servers lower it, otherwise every piece costs 500 ms.
ParameterValuesWhat it does
tcp-congestionbbr, cubic, …TCP congestion control. Linux and Android only
tcp-user-timeoutmsHow long sent data may stay unacknowledged before the connection is closed. Linux and Android only
tcp-keep-alive-idlesecondsIdle time before the first keep-alive probe. A negative value turns keep-alive off
tcp-keep-alive-intervalsecondsInterval between keep-alive probes
custom-sockoptlistAny socket option, as customSockopt in Xray

custom-sockopt fields:

  • opt: option number;
  • value: its value;
  • type: int (default) or str;
  • level: 6 (TCP) by default;
  • system: linux, windows, darwin or empty for every system; linux also applies on Android;
  • network: tcp, tcp4, tcp6 or empty.

Numbers can be decimal or 0x…. On Windows only int values work.

An option the system or the kernel does not support, for example bbr on many Android phones, is skipped with one warning in the log. The connection works without it.