TLS : tls spoofing#6103
Conversation
…im/Xray-core into feature/tls-spoofing
|
应当加到 finalmask |
|
将它添加为一个tcpmask(以避免需要修改其他传输) |
|
|
|
|
@Fangliding @RPRX new changes are ready |
|
@Fangliding any update? |
|
@codewithtamim 下个月合并 |
|
this should be merged, in iran TLS spoofing is back (it got blocked before, its alive again!) |
can you try building from my branch and try it? and then give some feedback :) |
من خیلی تلاش کردم با تغییرات شما در هسته xray و روشهای مختلفی که اینجا گفتید در سیستم عامل ویندوز وصل بشم ولی ننتونستم. کانفیگی که استفاده کردم: |
Try now. https://github.com/codewithtamim/Xray-core/actions/runs/26607198630 also made a small change, now you can specify sni and it will auto generate the payload, or you can do just by running xray tls fake-hello domain.com YOU NEED TO RUN IT AS SUDO |
Thanks for your efforts! I tried running this new version with sudo, but unfortunately, it's still not working for me. For reference, I’m using the same configuration (with slight necessary changes to fit this method and with different ttl and method values as you suggested), which works perfectly with Patterniha's method. |
It shows any error? or like the internet is blocked something? do you have some logs? |
|
@codewithtamim 我看了下这是直接加了个 rawpacket 的 finalmask,那可以直接合并毕竟不影响其它东西 需要 rebase 一下,更新下 PR 正文的 example,另外这个东西能给 UDP 也用上吗 |
I got some report from IRAN it's not working for them. So need a bit more time for it. |
# Conflicts: # infra/conf/transport_internet.go
…tp/wechat/wireguard)
@Fangliding @RPRX , Added the pr body with clear details and example. Please review and let me know if you need anything else. And about your question, no it can't be done with udp as the whole mechanism relies on tcp state (seq num, ack windows, tcp options ) but for UDP its connectionless, so there is nothing in meaningful way to corrupt. and no ClientHello equivalent to spoof, so this is TCP only by its design. |
|
@codewithtamim {
"log": {
"loglevel": "debug"
},
"dns": {
"hosts": {
"dns.google": [
"8.8.8.8",
"8.8.4.4",
"2001:4860:4860::8888",
"2001:4860:4860::8844"
],
"dns.alidns.com": [
"223.5.5.5",
"223.6.6.6",
"2400:3200::1",
"2400:3200:baba::1"
],
"one.one.one.one": [
"1.1.1.1",
"1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001"
],
"1dot1dot1dot1.cloudflare-dns.com": [
"1.1.1.1",
"1.0.0.1",
"2606:4700:4700::1111",
"2606:4700:4700::1001"
],
"cloudflare-dns.com": [
"104.16.249.249",
"104.16.248.249",
"2606:4700::6810:f8f9",
"2606:4700::6810:f9f9"
],
"dns.cloudflare.com": [
"104.16.132.229",
"104.16.133.229",
"2606:4700::6810:84e5",
"2606:4700::6810:85e5"
],
"dot.pub": [
"1.12.12.12",
"120.53.53.53"
],
"doh.pub": [
"1.12.12.12",
"120.53.53.53"
],
"dns.quad9.net": [
"9.9.9.9",
"149.112.112.112",
"2620:fe::fe",
"2620:fe::9"
],
"dns.yandex.net": [
"77.88.8.8",
"77.88.8.1",
"2a02:6b8::feed:0ff",
"2a02:6b8:0:1::feed:0ff"
],
"dns.sb": [
"185.222.222.222",
"2a09::"
],
"dns.umbrella.com": [
"208.67.220.220",
"208.67.222.222",
"2620:119:35::35",
"2620:119:53::53"
],
"dns.sse.cisco.com": [
"208.67.220.220",
"208.67.222.222",
"2620:119:35::35",
"2620:119:53::53"
],
"engage.cloudflareclient.com": [
"162.159.192.1"
]
},
"servers": [
{
"address": "localhost",
"domains": [
"ir"
],
"skipFallback": true,
"tag": "direct-dns-1"
},
{
"address": "223.5.5.5",
"domains": [
"full:dns.cloudflare.com"
],
"skipFallback": true
},
"https://dns.cloudflare.com/dns-query"
],
"tag": "dns-module"
},
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "mixed",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "104.19.229.21",
"port": 443,
"users": [
{
"id": "ID",
"email": "t@t.tt",
"security": "auto",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"finalmask": {
"tcp": [
{
"type": "rawpacket",
"settings": {
"payload": "FgMBASMBAAEfAwNQSRTVQcrdgTJ18wpMBzpJUiYKbqQEA0AWaYcRXY0WSSCLT7JFRB8wEyr4ONd2fq1MV0ywyi0i/ggJFGKHsj3aXAAawCvAL8AswDDMqcyowAnAE8AKwBQTARMCEwMBAAC8AAAAEwARAAAOY2xvdWRmbGFyZS5jb20ACwACAQD/AQABAAAXAAAAEgAAAAUABQEAAAAAAAoACAAGAB0AFwAYAA0AFgAUCAQEAwgHCAUIBgQBBQEGAQUDBgMAMgAaABgIBAQDCAcIBQgGBAEFAQYBBQMGAwIBAgMAEAAOAAwCaDIIaHR0cC8xLjEAKwAFBAMEAwMAMwAmACQAHQAgjWOKaOkAdprI+VdRkwt3twGgGJx1ZXngBoNbn11rc3E=", // xray tls fake-hello cloudflare.com
"method": "wrong-sequence", // other methods are tested as well
"ttl": 11,
"count": 1
}
}
]
},
"network": "ws",
"security": "tls",
"tlsSettings": {
"allowInsecure": false,
"serverName": "example.com",
"fingerprint": "chrome"
},
"wsSettings": {
"path": "/path",
"host": "example.com"
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": [
"api"
],
"outboundTag": "api"
},
{
"type": "field",
"outboundTag": "direct",
"domain": [
"ir"
]
},
{
"type": "field",
"inboundTag": [
"direct-dns-1"
],
"outboundTag": "direct"
},
{
"type": "field",
"inboundTag": [
"dns-module"
],
"outboundTag": "proxy"
}
]
}
}here are some logs : Xray 26.6.1 (Xray, Penetrates Everything.) cbede9a-dirty (go1.26.0 windows/amd64)
A unified platform for anti-censorship.
2026/06/04 16:49:50.525374 [Info] infra/conf/serial: Reading config: &{Name:config.json Format:json}
2026/06/04 16:49:50.527105 [Warning] common/errors: The feature WebSocket transport (with ALPN http/1.1, etc.) is deprecated, not recommended for using and might be removed. Please migrate to XHTTP H2 & H3 as soon as possible.
2026/06/04 16:49:50.527105 [Debug] app/log: Logger started
2026/06/04 16:49:50.529836 [Info] app/dns: DNS: created localhost client
2026/06/04 16:49:50.529836 [Info] app/dns: DNS: created UDP client initialized for 223.5.5.5:53
2026/06/04 16:49:50.529836 [Info] app/dns: DNS: created DOH client for https://dns.cloudflare.com/dns-query, with h2c false
2026/06/04 16:49:50.532962 [Debug] app/proxyman/inbound: creating stream worker on 127.0.0.1:10808
2026/06/04 16:49:50.533982 [Info] transport/internet/tcp: listening TCP on 127.0.0.1:10808
2026/06/04 16:49:50.533982 [Warning] core: Xray 26.6.1 started
2026/06/04 16:50:09.124770 [Debug] [2620548628] proxy/socks: Not Socks request, try to parse as HTTP request
2026/06/04 16:50:09.124770 [Info] [2620548628] proxy/http: request to Method [CONNECT] Host [www.youtube.com:443] with URL [//www.youtube.com:443]
2026/06/04 16:50:09.125806 [Info] [2620548628] app/dispatcher: sniffed domain: www.youtube.com
2026/06/04 16:50:09.125815 [Info] [2620548628] app/dispatcher: default route for tcp:www.youtube.com:443
2026/06/04 16:50:09.125815 [Info] [2620548628] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:09.125815 [Debug] [2620548628] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:09.125815 from 127.0.0.1:21620 accepted //www.youtube.com:443 [socks >> proxy]
2026/06/04 16:50:09.324241 [Error] [2620548628] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21621->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:09.324803 [Info] [2620548628] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:09.324803 [Debug] [2620548628] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:09.492776 [Error] [2620548628] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21622->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:09.704340 [Info] [2620548628] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:09.704555 [Debug] [2620548628] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:09.905114 [Error] [2620548628] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21623->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:10.305286 [Info] [2620548628] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:10.305410 [Debug] [2620548628] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:10.490815 [Error] [2620548628] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21625->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:11.091239 [Info] [2620548628] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:11.091456 [Debug] [2620548628] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:11.302958 [Error] [2620548628] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21627->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:12.103545 [Info] [2620548628] app/proxyman/outbound: app/proxyman/outbound: failed to process outbound traffic > proxy/vless/outbound: failed to find an available destination > common/retry: [transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21621->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21622->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21623->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21625->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21627->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.] > common/retry: all retry attempts failed
2026/06/04 16:50:12.104520 [Debug] [484192671] proxy/socks: Not Socks request, try to parse as HTTP request
2026/06/04 16:50:12.105264 [Info] [484192671] proxy/http: request to Method [CONNECT] Host [www.youtube.com:443] with URL [//www.youtube.com:443]
2026/06/04 16:50:12.105816 [Info] [484192671] app/dispatcher: sniffed domain: www.youtube.com
2026/06/04 16:50:12.105816 [Info] [484192671] app/dispatcher: default route for tcp:www.youtube.com:443
2026/06/04 16:50:12.106348 [Info] [484192671] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:12.106348 [Debug] [484192671] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:12.105111 from 127.0.0.1:21628 accepted //www.youtube.com:443 [socks >> proxy]
2026/06/04 16:50:12.270323 [Error] [484192671] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21629->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:12.270323 [Info] [484192671] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:12.271289 [Debug] [484192671] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:12.430042 [Error] [484192671] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21630->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:12.630325 [Info] [484192671] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:12.630472 [Debug] [484192671] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:12.823680 [Error] [484192671] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21632->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:13.214460 [Info] [484192671] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:13.214685 [Debug] [484192671] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:13.405304 [Error] [484192671] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21633->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:14.005625 [Info] [484192671] transport/internet/websocket: creating connection to tcp:104.19.229.21:443
2026/06/04 16:50:14.005840 [Debug] [484192671] transport/internet: dialing to tcp:104.19.229.21:443
2026/06/04 16:50:14.190617 [Error] [484192671] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:21634->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 16:50:14.978842 [Info] [484192671] app/proxyman/outbound: app/proxyman/outbound: failed to process outbound traffic > proxy/vless/outbound: failed to find an available destination > common/retry: [transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21629->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21630->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21632->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21633->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. transport/internet/websocket: failed to dial WebSocket > transport/internet/websocket: failed to dial to (wss://104.19.229.21/path): > read tcp 10.244.46.253:21634->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.] > common/retry: all retry attempts failed |
|
@Ahmad-2213 Can you test with reality? and with a different machine? Also try with the format I gave for raw packet in example try to use the same sort of configuration and reduce the ttl |
unfortunately i don't have a server that i could configure reality for, however, i can redirect to an Open proxy via freedom + final mask if solves the problem. (e.g. "redirect":"IP:443" , TCP + TLS ) I meassured the TTL of IP before Setting TTL . updated configuration : {
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"settings": {
"auth": "noauth"
}
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "104.19.229.21",
"port": 443,
"users": [
{
"id": "ID",
"email": "t@t.tt",
"security": "auto",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "example.com",
"fingerprint": "chrome"
},
"wsSettings": {
"path": "/path",
"host": "example.com"
},
"finalmask": {
"tcp": [
{
"type": "rawpacket",
"settings": {
"sni": "cloudflare.com",
"method": "wrong-sequence"
}
}
]
}
}
}
]
}
logs: Xray 26.6.1 (Xray, Penetrates Everything.) cbede9a-dirty (go1.26.0 windows/amd64)
A unified platform for anti-censorship.
2026/06/04 17:31:40.187134 [Info] infra/conf/serial: Reading config: &{Name:config.json Format:json}
2026/06/04 17:31:40.187673 [Warning] common/errors: The feature WebSocket transport (with ALPN http/1.1, etc.) is deprecated, not recommended for using and might be removed. Please migrate to XHTTP H2 & H3 as soon as possible.
2026/06/04 17:31:40.189222 [Warning] core: Xray 26.6.1 started
2026/06/04 17:31:40.639721 from 127.0.0.1:22786 accepted //fonts.gstatic.com:443 [socks >> proxy]
2026/06/04 17:31:40.654932 from 127.0.0.1:22787 accepted //unpkg.com:443 [socks >> proxy]
2026/06/04 17:31:40.654932 from 127.0.0.1:22785 accepted //iplocation.com:443 [socks >> proxy]
2026/06/04 17:31:40.861233 [Error] [170264619] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:22789->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 17:31:40.861233 [Error] [2059557928] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:22788->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 17:31:40.861975 [Error] [1363289195] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:22790->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 17:31:41.046264 [Error] [1363289195] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:22792->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host.
2026/06/04 17:31:41.052596 [Error] [2059557928] transport/internet/websocket: failed to dial to 104.19.229.21:443 > read tcp 10.244.46.253:22791->104.19.229.21:443: wsarecv: An existing connection was forcibly closed by the remote host. |
I have a few, dm me on tg(same username) I will give you multiple variations of the config, just test and give me feedback |


fix #5964
RawPacket aka TLS Spoofing
So first lets talk about the idea,
when you connect to a xray server, the censors can see your TLS ClientHello, read the SNI, and figure out what you are doing and block :)
The RawPacket aka TLS spoofing fixes that by injecting a fake TLS ClientHello before the real one Hits.
The fake one carries like a decoy domain (ex. baidu.com) and then the real one carries your actual destination (ex. www.example.com).
A sensor that captures the first packet sees baidu.com and think that you are just browsing, and everything is okay with that, but in reality your connection goes through :)
It can be configured in the
finalmask.tcpokay? and its only for client side.How everything works
When Xray dials a TCP connection and the first
Write()happens (which also triggers the real TLS handshake) , our Raw Packet setup does the following.1.builds a fake Tls ClientHello with whatever SNI you want or you have option to provide the raw bytes (b64).
2.Then we. wrap it in a raw TCP/ip packet.
3.Then deliberately we corrupt the TCP header using whatever method is selected okay?
Then we shoot it out via a raw socket
Then immediately let the real
Write()go through normallyIn short : two packets arrive at the server back to back and the fake one gets dropped by the servers TCP stack because of the corruption and then the real handshake proceeds like nothing happened.
Config Example
{ "streamSettings": { "finalmask": { "tcp": [ { "type": "rawpacket", "settings": { "sni": "baidu.com", "payload": "", "method": "wrong-sequence", "ttl": 3, "count": 1 } } ] } } }Available Fields
sni: The domain to put in the fake ClientHello. If you set this, it will auto generate a valid TLS ClientHello for you automatically. If you setpayloadandsnisame time , sni wins here.payload: If you don't want an auto gnrated ClientHello, then just encode your raw bytes that you want into base64 and put them here. I have added an option to do it from command line also. Do like thisIt will out the thing and then just copy paste.
Note : If
sniand payload are empty or not set , the raw packet does nothing and the connection goes through normally.method: It defines how we corrupt the fake packet so the server drops it.wrong-sequence: It duplicates the sequence number (looks like a retransmission so server drops it)So we grab the kernels
snd_nxt( the next sequence number the kernel expects to send), then subtract the length of the fake payload and then use that as the sequence number of the injected packet. The results then is a duplicate of the. last segment, so the receivers TCP stack sees it as a retransmit at best, or like out of window at worst and then drops it.wrong-checksum: It flips all the bits in the TCP checksum (so server sees a bad checksum and drops it)We build the packet with a correct checksum and then flip every bit(^0xFFFF). The receiver then validates the checksum and its wrong, so the packet goes in trash.
wrong-ack: It sets ACK number way outside the receive window (so server sends dup ACK then drops it)It sets the ACK number to
rcv_nxt - window/2and that's way outside of the receivers window, and the kernel responds with a dup ACK containing the correct sequence number, then drops it.wrong-md5: This adds a fake TCP MD5 signature option and server without MD5 drops itHere we append a TCP option with kind=19 and length=18 to the TCP header. The kind 19 is the MD5 signature option (RFC 2385), if the receiver doesn't use TCP MD5 (which is basically everything except some BGP routers), it sees an unknown option and drops the packet.
wrong-timestamp: Backdates the tcp timestamp by 1 hour (paws detects regression and then drops)Just backdate the TCP timestamp option value by 3600000 MS (1 HR), The receivers paws mechanism checks if the timestamp went backwards, If it did the packet is then dropped.
Note :
wrong-timestampmethod only works on Linux, it doesn't work on MacOS and Free BSD because kernel doesn't expose the per connection timestamp offset, so we can't really tell what to value undercut.ttl: it defines the IP time to live for the fake packet. Default is 3 but the idea is to keep it lower so the packet dies before reaching the server or can but still reaches the probe, you can change it if needed.count: Defines how many writes should trigger an injection. Default is set to 1 means that only the first write gets fake packet treatment, after that the raw socket closes itself and all the subsequent writes goes directly to the TCP connection with zero overhead.Platform Support
How to run it
Linux :
Macos/FreeBSD :
Windows : Run a terminal with Admin rights .
If you miss that , you will get the following error.
transport/internet/tcp: mask err > open AF_INET SOCK_RAW: operation not permitted Hint: run as root, or grant capabilities: sudo setcap cap_net_raw,cap_net_admin+ep /path/to/xrayA Sample Client Example
TESTING I DID
I tested the implementation myself on an Ubuntu 24.0.4 and it works. Here is the process I followed.
First ran xray on the server normally with my config,
Example (that's what I used) :
Then run the server
Client Example :
Cases :
Output
With capabilities everything works. I tested all 5 methods and it worked.
Proof from wire capture, I ran a tcpdump on loopback and saw both packets :
Packet 1 (fake one , the one we injected)
Here look at
0x0090:... 0000 0962 6169 6475 2e63 6f 6d 62 61 69 64 75 2e 63 6f 6d= baidu.com and that's the decoy SNI in the fake ClientHelloPacket 2 (real one, a normal TCP socket) :
Now look at
0x0240:7777 772e 6d69 6372 6f73 6f66 742e 636f 6d= www.microsoft.com, that's the real SNI the server processes.So a probe that only grabs packet 1 sees Baidu.com and moves on. Packet 2 with real SNI goes through the server and the connection works fine.
So that's basically All. Feel free to ask any questions I will try to give ans, Thanks