Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
0a5dead
TLSSpoof: Add core package for fake ClientHello injection
codewithtamim Apr 25, 2026
97d6adf
TLSSpoof: Add raw socket spoofers for Linux, Darwin and FreeBSD
codewithtamim Apr 28, 2026
650a37f
TLSSpoof: Add Windows WinDivert spoofer
codewithtamim May 1, 2026
82b5808
TLS: Add spoof, spoof_method and spoof_count options
codewithtamim May 4, 2026
7ac0e9b
Transport: Integrate TLS spoof into dialers
codewithtamim May 7, 2026
a68197d
Transport: Integrate TLS spoof into dialers
codewithtamim May 7, 2026
bb19134
Rawpacket: Add tcpmask config, proto and conn wrapper with configurab…
codewithtamim May 9, 2026
25a14f9
Merge branch 'feature/tls-spoofing' of https://github.com/codewithtam…
codewithtamim May 9, 2026
0aed3e2
Rawpacket: Add raw socket spoofers for Linux, Darwin, FreeBSD and Win…
codewithtamim May 9, 2026
1e230bb
TLS: Remove spoof, spoof_method and spoof_count options
codewithtamim May 10, 2026
ee4dca3
Transport: Remove TLS spoof integration from dialers
codewithtamim May 10, 2026
84b0e27
Config: Add rawpacket tcpmask support
codewithtamim May 10, 2026
34233e3
Merge branch 'XTLS:main' into feature/tls-spoofing
codewithtamim May 10, 2026
f2557ab
Fix protoc version header in generated proto files
codewithtamim May 10, 2026
14fd936
Fix protoc version header in generated proto files
codewithtamim May 10, 2026
08290c6
Merge branch 'feature/tls-spoofing' of https://github.com/codewithtam…
codewithtamim May 10, 2026
1744bef
Rawpacket: Fix injection Write/Close order;; add sni field and fake-h…
codewithtamim May 28, 2026
0198cf2
Update config.pb.go
codewithtamim May 28, 2026
1d26028
TLSSpoof: Add core package for fake ClientHello injection
codewithtamim Apr 25, 2026
d1ec6d8
TLSSpoof: Add raw socket spoofers for Linux, Darwin and FreeBSD
codewithtamim Apr 28, 2026
21bc036
TLSSpoof: Add Windows WinDivert spoofer
codewithtamim May 1, 2026
0da25a9
TLS: Add spoof, spoof_method and spoof_count options
codewithtamim May 4, 2026
291b5f9
Transport: Integrate TLS spoof into dialers
codewithtamim May 7, 2026
e1616a4
Rawpacket: Add raw socket spoofers for Linux, Darwin, FreeBSD and Win…
codewithtamim May 9, 2026
bddac68
Rawpacket: Add tcpmask config, proto and conn wrapper with configurab…
codewithtamim May 9, 2026
480c2c7
TLS: Remove spoof, spoof_method and spoof_count options
codewithtamim May 10, 2026
6232543
Transport: Remove TLS spoof integration from dialers
codewithtamim May 10, 2026
3e45126
Config: Add rawpacket tcpmask support
codewithtamim May 10, 2026
7c83ef5
Fix protoc version header in generated proto files
codewithtamim May 10, 2026
7eb3848
Rawpacket: Fix injection Write/Close order;; add sni field and fake-h…
codewithtamim May 28, 2026
a6e8fae
Update config.pb.go
codewithtamim May 28, 2026
5c15e31
Merge branch 'main' into feature/tls-spoofing
codewithtamim Jun 3, 2026
13de1b0
Merge remote-tracking branch 'upstream/main' into feature/tls-spoofing
codewithtamim Jun 3, 2026
9453506
Remove stale imports for removed header sub-packages (dns/dtls/srtp/u…
codewithtamim Jun 3, 2026
cbede9a
Fix gofumpt formatting issues in rawpacket files
codewithtamim Jun 3, 2026
3f886a4
rawpacket: capture+modify spoofing with bidirectional WinDivert
codewithtamim Jun 4, 2026
4bcb59a
rawpacket: always use before-window seq for all methods
codewithtamim Jun 4, 2026
1ed2e39
rawpacket: use larger seq offset to ensure outside server window
codewithtamim Jun 4, 2026
ecf602f
rawpacket: add debug logging to Windows spoofer
codewithtamim Jun 4, 2026
f25c14f
rawpacket: use highest WinDivert priority to beat other handles
codewithtamim Jun 4, 2026
8827498
rawpacket: rewrite as stateless IP spoof tunnel transport
codewithtamim Jun 5, 2026
cd7f8e6
tls: remove cmdFakeHello (old ClientHello spoofer)
codewithtamim Jun 5, 2026
2d7aa77
Delete fakehello.go
codewithtamim Jun 5, 2026
e7e6284
Merge remote-tracking branch 'origin/main' into feature/tls-spoofing
codewithtamim Aug 19, 2026
482fba5
rawpacket: TCP sim, TLS spoof, masquerade
codewithtamim Aug 19, 2026
ae29358
rawpacket: fix inverted BPF filter jumps
codewithtamim Aug 19, 2026
40a2f3d
rawpacket: fix server-role ACK for data segments
codewithtamim Aug 19, 2026
b7dfde3
rawpacket: cover server ACK advance in tests
codewithtamim Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions infra/conf/transport_finalmask.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/header"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/original"
"github.com/xtls/xray-core/transport/internet/finalmask/noise"
"github.com/xtls/xray-core/transport/internet/finalmask/rawpacket"
"github.com/xtls/xray-core/transport/internet/finalmask/realm"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
Expand Down Expand Up @@ -70,6 +71,7 @@ var (
tcpmaskLoader = NewJSONConfigLoader(ConfigCreatorCache{
"header-custom": func() interface{} { return new(HeaderCustomTCP) },
"fragment": func() interface{} { return new(FragmentMask) },
"rawpacket": func() interface{} { return new(RawpacketMask) },
"sudoku": func() interface{} { return new(Sudoku) },
"xmc": func() interface{} { return new(XMC) },
}, "type", "settings")
Expand Down Expand Up @@ -231,6 +233,55 @@ func (c *HeaderCustomTCP) Build() (proto.Message, error) {
}, nil
}

type RawpacketMask struct {
Mode string `json:"mode"`
RemoteAddress string `json:"remoteAddress"`
RemotePort uint16 `json:"remotePort"`
RecvPort uint16 `json:"recvPort"`
SpoofIPs []string `json:"spoofIPs"`
Protocols []string `json:"protocols"`
MTU uint16 `json:"mtu"`
Target string `json:"target"`
TTL uint8 `json:"ttl"`
SendTransport string `json:"sendTransport"`
RecvTransport string `json:"recvTransport"`
RelayAddress string `json:"relayAddress"`
RelayPort uint16 `json:"relayPort"`
ClientIP string `json:"clientIP"`
ClientPort uint16 `json:"clientPort"`
PeerSpoofIP string `json:"peerSpoofIP"`
SpoofPort uint16 `json:"spoofPort"`
Auth string `json:"auth"`
SuppressRst bool `json:"suppressRst"`
Masquerade string `json:"masquerade"`
}

func (c *RawpacketMask) Build() (proto.Message, error) {
config := &rawpacket.Config{
Mode: c.Mode,
RemoteAddress: c.RemoteAddress,
RemotePort: uint32(c.RemotePort),
RecvPort: uint32(c.RecvPort),
SpoofIps: c.SpoofIPs,
Protocols: c.Protocols,
Mtu: uint32(c.MTU),
Target: c.Target,
Ttl: uint32(c.TTL),
SendTransport: c.SendTransport,
RecvTransport: c.RecvTransport,
RelayAddress: c.RelayAddress,
RelayPort: uint32(c.RelayPort),
ClientIp: c.ClientIP,
ClientPort: uint32(c.ClientPort),
PeerSpoofIp: c.PeerSpoofIP,
SpoofPort: uint32(c.SpoofPort),
Auth: c.Auth,
SuppressRst: c.SuppressRst,
Masquerade: c.Masquerade,
}
return config, nil
}

type FragmentMask struct {
Packets string `json:"packets"`
Length Int32Range `json:"length"`
Expand Down
13 changes: 13 additions & 0 deletions infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func (p TransportProtocol) Build() (string, error) {
switch strings.ToLower(string(p)) {
case "raw", "tcp":
return "tcp", nil
case "rawpacket":
return "rawpacket", nil
case "xhttp", "splithttp":
return "splithttp", nil
case "kcp", "mkcp":
Expand Down Expand Up @@ -48,6 +50,7 @@ type StreamConfig struct {
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
FinalMask *FinalMask `json:"finalmask"`
RawpacketSettings *RawpacketMask `json:"rawpacketSettings"`
TLSSettings *TLSConfig `json:"tlsSettings"`
REALITYSettings *REALITYConfig `json:"realitySettings"`
RAWSettings *TCPConfig `json:"rawSettings"`
Expand Down Expand Up @@ -182,6 +185,16 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
Settings: serial.ToTypedMessage(hs),
})
}
if c.RawpacketSettings != nil {
rs, err := c.RawpacketSettings.Build()
if err != nil {
return nil, errors.New("Failed to build rawpacket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "rawpacket",
Settings: serial.ToTypedMessage(rs),
})
}
if c.HysteriaSettings != nil {
hs, err := c.HysteriaSettings.Build()
if err != nil {
Expand Down
48 changes: 48 additions & 0 deletions main/commands/all/tls/fakehello.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tls

import (
"encoding/base64"
"fmt"
"os"

"github.com/xtls/xray-core/main/commands/base"
"github.com/xtls/xray-core/transport/internet/finalmask/rawpacket"
)

var cmdFakeHello = &base.Command{
UsageLine: "{{.Exec}} tls fake-hello [-hex] <sni>",
Short: "Generate a fake TLS ClientHello payload for rawpacket",
Long: `
Generate a fake TLS ClientHello for use in finalmask rawpacket settings.

Arguments:

-base64
Output base64-encoded payload (default).
-hex
Output hex-encoded payload instead of base64.
`,
}

func init() {
cmdFakeHello.Run = executeFakeHello
}

var fakeHelloHex = cmdFakeHello.Flag.Bool("hex", false, "")

func executeFakeHello(cmd *base.Command, args []string) {
if cmdFakeHello.Flag.NArg() < 1 {
base.Fatalf("sni not specified")
}
sni := cmdFakeHello.Flag.Arg(0)
payload, err := rawpacket.BuildFakeClientHello(sni)
if err != nil {
base.Fatalf("failed to build ClientHello: %s", err)
}
switch {
case *fakeHelloHex:
fmt.Fprintf(os.Stdout, "%x\n", payload)
default:
fmt.Fprintln(os.Stdout, base64.StdEncoding.EncodeToString(payload))
}
}
1 change: 1 addition & 0 deletions main/commands/all/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ var CmdTLS = &base.Command{
cmdPing,
cmdHash,
cmdECH,
cmdFakeHello,
},
}
51 changes: 51 additions & 0 deletions transport/internet/finalmask/rawpacket/client_hello.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package rawpacket

import (
"bytes"
"context"
"crypto/tls"
"errors"
"io"
"net"
"time"
)

// BuildFakeClientHello drives crypto/tls against a write-only in-memory conn
// to capture a generated ClientHello. CurvePreferences pins classical groups
// to suppress Go's default X25519MLKEM768 hybrid key share; without this the
// post-quantum public key alone (~1184 bytes) pushes the record past one MSS,
// and middleboxes do not reassemble fragmented ClientHellos. The handshake
// error is discarded because the stub conn's Read returns immediately.
func BuildFakeClientHello(sni string) ([]byte, error) {
if sni == "" {
return nil, errors.New("empty sni")
}
var buf bytes.Buffer
tlsConn := tls.Client(&writeOnlyConn{w: &buf}, &tls.Config{
ServerName: sni,
// Order matches what browsers advertised before post-quantum.
CurvePreferences: []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384},
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
NextProtos: []string{"h2", "http/1.1"},
InsecureSkipVerify: true,
})
_ = tlsConn.HandshakeContext(context.Background())
if buf.Len() == 0 {
return nil, errors.New("tls ClientHello not produced")
}
return buf.Bytes(), nil
}

type writeOnlyConn struct {
w io.Writer
}

func (c *writeOnlyConn) Read([]byte) (int, error) { return 0, io.EOF }
func (c *writeOnlyConn) Write(p []byte) (int, error) { return c.w.Write(p) }
func (c *writeOnlyConn) Close() error { return nil }
func (c *writeOnlyConn) LocalAddr() net.Addr { return nil }
func (c *writeOnlyConn) RemoteAddr() net.Addr { return nil }
func (c *writeOnlyConn) SetDeadline(time.Time) error { return nil }
func (c *writeOnlyConn) SetReadDeadline(time.Time) error { return nil }
func (c *writeOnlyConn) SetWriteDeadline(time.Time) error { return nil }
60 changes: 60 additions & 0 deletions transport/internet/finalmask/rawpacket/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package rawpacket

import (
"fmt"
"net/netip"
"strings"
)

const (
ProtocolTCP uint8 = 6
ProtocolICMP uint8 = 1
ProtocolICMPv6 uint8 = 58
ProtocolUDP uint8 = 17
)

func ParseProtocol(s string) (uint8, error) {
switch strings.ToLower(s) {
case "tcp":
return ProtocolTCP, nil
case "icmp":
return ProtocolICMP, nil
case "icmpv6":
return ProtocolICMPv6, nil
case "udp":
return ProtocolUDP, nil
default:
return 0, fmt.Errorf("rawpacket: unknown protocol: %s", s)
}
}

func ParseIPs(ss []string) ([]netip.Addr, error) {
var out []netip.Addr
for _, s := range ss {
ip, err := netip.ParseAddr(s)
if err != nil {
return nil, fmt.Errorf("rawpacket: invalid spoof IP %q: %w", s, err)
}
out = append(out, ip.Unmap())
}
return out, nil
}

type RelayConfig struct {
ListenPort uint16
ForwardAddr string
ForwardTransport string // "tcp" (Xray) or "udp" (reference, default)
ClientIP netip.Addr
ClientPort uint16
SpoofIP netip.Addr // single fallback
SpoofIPs []string
SpoofPort uint16
PeerSpoofIP netip.Addr
SendTransport string
RecvTransport string
Mtu uint32
SuppressRst bool
Masquerade string // "off" | "http" | "tls" | "dns"
Auth []byte
icmpSuppressed bool
}
Loading
Loading