From d348f6fa8ff2c4a8c164204299011192343c4397 Mon Sep 17 00:00:00 2001 From: Hiddify <114227601+hiddify-com@users.noreply.github.com> Date: Sat, 13 Jan 2024 14:47:24 +0000 Subject: [PATCH 1/4] refactor tls tricks --- common/tls/ech_client.go | 2 +- common/tls/std_client.go | 2 +- common/tls/utls_client.go | 12 +++++++++--- option/outbound.go | 2 +- option/tls.go | 3 +-- option/tls_tricks.go | 8 ++++++++ 6 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 option/tls_tricks.go diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index 0d9228273e..6c03c389aa 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -101,7 +101,7 @@ func NewECHClient(ctx context.Context, serverAddress string, options option.Outb if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { - if options.MixedCaseSNI { + if options.TLSTricks != nil && options.TLSTricks.MixedCaseSNI { tlsConfig.ServerName = randomizeCase(tlsConfig.ServerName) } else { tlsConfig.ServerName = serverName diff --git a/common/tls/std_client.go b/common/tls/std_client.go index 1a645cfc00..b66be96239 100644 --- a/common/tls/std_client.go +++ b/common/tls/std_client.go @@ -64,7 +64,7 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { - if options.MixedCaseSNI { + if options.TLSTricks != nil && options.TLSTricks.MixedCaseSNI { tlsConfig.ServerName = randomizeCase(tlsConfig.ServerName) } else { tlsConfig.ServerName = serverName diff --git a/common/tls/utls_client.go b/common/tls/utls_client.go index ce5b8083ae..6d80398ec3 100644 --- a/common/tls/utls_client.go +++ b/common/tls/utls_client.go @@ -139,7 +139,7 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out return nil, E.New("missing server_name or insecure=true") } - if options.MixedCaseSNI { + if options.TLSTricks.MixedCaseSNI { serverName = randomizeCase(serverName) } @@ -205,14 +205,20 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out if err != nil { return nil, err } - if options.PaddingSize != "" { - padding_size, err := option.ParseIntRange(options.PaddingSize) + if options.TLSTricks != nil && options.TLSTricks.PaddingMode == "random" { + padding_size, err := option.ParseIntRange(options.TLSTricks.PaddingSize) if err != nil { return nil, E.Cause(err, "invalid Padding Size supplied") } paddingSize2 := [2]int{int(padding_size[0]), int(padding_size[1])} return &UTLSClientConfig{config: &tlsConfig, paddingSize: paddingSize2, id: id}, nil + } + if options.TLSTricks.PaddingMode == "sni" { + + } + if options.TLSTricks.PaddingMode == "hello_client" { + } return &UTLSClientConfig{config: &tlsConfig, id: id}, nil } diff --git a/option/outbound.go b/option/outbound.go index 36ddd11ab5..f6adb3d3a4 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -140,7 +140,7 @@ type DialerOptions struct { ConnectTimeout Duration `json:"connect_timeout,omitempty"` TCPFastOpen bool `json:"tcp_fast_open,omitempty"` TCPMultiPath bool `json:"tcp_multi_path,omitempty"` - TLSFragment TLSFragmentOptions `json:"tls_fragment,omitempty"` + TLSFragment *TLSFragmentOptions `json:"tls_fragment,omitempty"` UDPFragment *bool `json:"udp_fragment,omitempty"` UDPFragmentDefault bool `json:"-"` DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` diff --git a/option/tls.go b/option/tls.go index 4f6bb2dc7d..396f3cae51 100644 --- a/option/tls.go +++ b/option/tls.go @@ -20,10 +20,8 @@ type InboundTLSOptions struct { type OutboundTLSOptions struct { Enabled bool `json:"enabled,omitempty"` DisableSNI bool `json:"disable_sni,omitempty"` - MixedCaseSNI bool `json:"mixedcase_sni,omitempty"` ServerName string `json:"server_name,omitempty"` Insecure bool `json:"insecure,omitempty"` - PaddingSize string `json:"padding_size,omitempty"` ALPN Listable[string] `json:"alpn,omitempty"` MinVersion string `json:"min_version,omitempty"` MaxVersion string `json:"max_version,omitempty"` @@ -33,6 +31,7 @@ type OutboundTLSOptions struct { ECH *OutboundECHOptions `json:"ech,omitempty"` UTLS *OutboundUTLSOptions `json:"utls,omitempty"` Reality *OutboundRealityOptions `json:"reality,omitempty"` + TLSTricks *TLSTricksOptions `json:"tls_tricks,omitempty"` } type InboundRealityOptions struct { diff --git a/option/tls_tricks.go b/option/tls_tricks.go new file mode 100644 index 0000000000..e1c88664a2 --- /dev/null +++ b/option/tls_tricks.go @@ -0,0 +1,8 @@ +package option + +type TLSTricksOptions struct { + MixedCaseSNI bool `json:"mixedcase_sni,omitempty"` + PaddingMode string `json:"padding_mode,omitempty"` + PaddingSize string `json:"padding_size,omitempty"` + PaddingSNI string `json:"padding_sni,omitempty"` +} From 458ca8290ae495f39969da0f151a2b5b572c7f4b Mon Sep 17 00:00:00 2001 From: Hiddify <114227601+hiddify-com@users.noreply.github.com> Date: Sun, 14 Jan 2024 23:40:25 +0000 Subject: [PATCH 2/4] fix: null tlsFragment --- common/dialer/default.go | 12 +++++++----- common/dialer/default_go1.20.go | 2 +- common/dialer/default_nongo1.20.go | 4 ++-- common/dialer/extended_tcp.go | 8 ++++---- common/dialer/extended_tcp_stub.go | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/common/dialer/default.go b/common/dialer/default.go index 799c1f407b..6dd9738495 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -98,11 +98,13 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi } setMultiPathTCP(&dialer4) } - if options.TLSFragment.Enabled && options.TCPFastOpen { - return nil, E.New("TLS Fragmentation is not compatible with TCP Fast Open, set `tcp_fast_open` to `false` in your outbound if you intend to enable TLS fragmentation.") - } - var tlsFragment TLSFragment - if options.TLSFragment.Enabled { + + var tlsFragment *TLSFragment=nil + if options.TLSFragment != nil && options.TLSFragment.Enabled { + tlsFragment = &TLSFragment{} + if options.TCPFastOpen { + return nil, E.New("TLS Fragmentation is not compatible with TCP Fast Open, set `tcp_fast_open` to `false` in your outbound if you intend to enable TLS fragmentation.") + } tlsFragment.Enabled = true sleep, err := option.ParseIntRange(options.TLSFragment.Sleep) diff --git a/common/dialer/default_go1.20.go b/common/dialer/default_go1.20.go index 26e14f6f8e..fc90299980 100644 --- a/common/dialer/default_go1.20.go +++ b/common/dialer/default_go1.20.go @@ -8,6 +8,6 @@ import ( type tcpDialer = ExtendedTCPDialer -func newTCPDialer(dialer net.Dialer, tfoEnabled bool, tlsFragment TLSFragment) (tcpDialer, error) { +func newTCPDialer(dialer net.Dialer, tfoEnabled bool, tlsFragment *TLSFragment) (tcpDialer, error) { return tcpDialer{Dialer: dialer, DisableTFO: !tfoEnabled, TLSFragment: tlsFragment}, nil } diff --git a/common/dialer/default_nongo1.20.go b/common/dialer/default_nongo1.20.go index e9eb4195e2..66c76a60fe 100644 --- a/common/dialer/default_nongo1.20.go +++ b/common/dialer/default_nongo1.20.go @@ -10,11 +10,11 @@ import ( type tcpDialer = net.Dialer -func newTCPDialer(dialer net.Dialer, tfoEnabled bool, tlsFragment TLSFragment) (tcpDialer, error) { +func newTCPDialer(dialer net.Dialer, tfoEnabled bool, tlsFragment *TLSFragment) (tcpDialer, error) { if tfoEnabled { return dialer, E.New("TCP Fast Open requires go1.20, please recompile your binary.") } - if tlsFragment.Enabled { + if tlsFragment != nil && tlsFragment.Enabled { return tcpDialer{Dialer: dialer, DisableTFO: true, TLSFragment: tlsFragment}, nil } return dialer, nil diff --git a/common/dialer/extended_tcp.go b/common/dialer/extended_tcp.go index 9cdb4e40c9..ddb50658d1 100644 --- a/common/dialer/extended_tcp.go +++ b/common/dialer/extended_tcp.go @@ -15,11 +15,11 @@ import ( type ExtendedTCPDialer struct { net.Dialer DisableTFO bool - TLSFragment TLSFragment + TLSFragment *TLSFragment } func (d *ExtendedTCPDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - if (d.DisableTFO && !d.TLSFragment.Enabled) || N.NetworkName(network) != N.NetworkTCP { + if (d.DisableTFO && !(d.TLSFragment != nil && d.TLSFragment.Enabled)) || N.NetworkName(network) != N.NetworkTCP { switch N.NetworkName(network) { case N.NetworkTCP, N.NetworkUDP: return d.Dialer.DialContext(ctx, network, destination.String()) @@ -28,10 +28,10 @@ func (d *ExtendedTCPDialer) DialContext(ctx context.Context, network string, des } } // Create a TLS-Fragmented dialer - if d.TLSFragment.Enabled { + if d.TLSFragment != nil && d.TLSFragment.Enabled { fragmentConn := &fragmentConn{ dialer: d.Dialer, - fragment: d.TLSFragment, + fragment: *d.TLSFragment, network: network, destination: destination, } diff --git a/common/dialer/extended_tcp_stub.go b/common/dialer/extended_tcp_stub.go index 44770e2d48..24e648ce7c 100644 --- a/common/dialer/extended_tcp_stub.go +++ b/common/dialer/extended_tcp_stub.go @@ -11,7 +11,7 @@ import ( ) func (d *ExtendedTCPDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - if !d.TLSFragment.Enabled || N.NetworkName(network) != N.NetworkTCP { + if d.TLSFragment == nil || !d.TLSFragment.Enabled || N.NetworkName(network) != N.NetworkTCP { switch N.NetworkName(network) { case N.NetworkTCP, N.NetworkUDP: return d.Dialer.DialContext(ctx, network, destination.String()) From 740afb0cb8b4ac645e4169e48284a143082ddc39 Mon Sep 17 00:00:00 2001 From: Hiddify <114227601+hiddify-com@users.noreply.github.com> Date: Sun, 14 Jan 2024 23:56:44 +0000 Subject: [PATCH 3/4] possibke fragment bug resolving --- common/dialer/fragment.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/dialer/fragment.go b/common/dialer/fragment.go index 0043ee6f2c..2f48b476cf 100644 --- a/common/dialer/fragment.go +++ b/common/dialer/fragment.go @@ -51,7 +51,7 @@ func (c *fragmentConn) Write(b []byte) (n int, err error) { return 0, c.err } // Do not fragment if it's not a TLS clientHello packet - if len(b) < 5 || b[0] != 22 { + if len(b) < 7 || b[0] != 22 { return c.conn.Write(b) } From 7864e2b96b562528de5e216126c980d78885a454 Mon Sep 17 00:00:00 2001 From: Hiddify <114227601+hiddify-com@users.noreply.github.com> Date: Tue, 16 Jan 2024 23:38:15 +0000 Subject: [PATCH 4/4] fix: unhandled nil --- common/tls/utls_client.go | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/common/tls/utls_client.go b/common/tls/utls_client.go index 6d80398ec3..267168003f 100644 --- a/common/tls/utls_client.go +++ b/common/tls/utls_client.go @@ -139,7 +139,7 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out return nil, E.New("missing server_name or insecure=true") } - if options.TLSTricks.MixedCaseSNI { + if options.TLSTricks != nil && options.TLSTricks.MixedCaseSNI { serverName = randomizeCase(serverName) } @@ -205,20 +205,23 @@ func NewUTLSClient(ctx context.Context, serverAddress string, options option.Out if err != nil { return nil, err } - if options.TLSTricks != nil && options.TLSTricks.PaddingMode == "random" { - padding_size, err := option.ParseIntRange(options.TLSTricks.PaddingSize) - if err != nil { - return nil, E.Cause(err, "invalid Padding Size supplied") - } - paddingSize2 := [2]int{int(padding_size[0]), int(padding_size[1])} + if options.TLSTricks != nil { + switch options.TLSTricks.PaddingMode { + case "random": + padding_size, err := option.ParseIntRange(options.TLSTricks.PaddingSize) + if err != nil { + return nil, E.Cause(err, "invalid Padding Size supplied") + } + paddingSize2 := [2]int{int(padding_size[0]), int(padding_size[1])} - return &UTLSClientConfig{config: &tlsConfig, paddingSize: paddingSize2, id: id}, nil - } - if options.TLSTricks.PaddingMode == "sni" { - - } - if options.TLSTricks.PaddingMode == "hello_client" { - + return &UTLSClientConfig{config: &tlsConfig, paddingSize: paddingSize2, id: id}, nil + case "sni": + + case "hello_client": + // TODO + default: + // TODO + } } return &UTLSClientConfig{config: &tlsConfig, id: id}, nil }