mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-01-05 17:13:32 +08:00
feat: impl restls
This commit is contained in:
parent
9cc7fdaca9
commit
e2d590ca12
@ -8,10 +8,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
restlsC "github.com/3andne/restls-client-go"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/structure"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/transport/restls"
|
||||
obfs "github.com/Dreamacro/clash/transport/simple-obfs"
|
||||
shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
@ -34,6 +36,7 @@ type ShadowSocks struct {
|
||||
obfsOption *simpleObfsOption
|
||||
v2rayOption *v2rayObfs.Option
|
||||
shadowTLSOption *shadowtls.ShadowTLSOption
|
||||
restlsConfig *restlsC.Config
|
||||
}
|
||||
|
||||
type ShadowSocksOption struct {
|
||||
@ -74,6 +77,14 @@ type shadowTLSOption struct {
|
||||
Version int `obfs:"version,omitempty"`
|
||||
}
|
||||
|
||||
type restlsOption struct {
|
||||
Password string `obfs:"password"`
|
||||
Host string `obfs:"host"`
|
||||
VersionHint string `obfs:"version-hint"`
|
||||
RestlsScript string `obfs:"restls-script,omitempty"`
|
||||
ClientID string `obfs:"client-id,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
switch ss.obfsMode {
|
||||
@ -86,6 +97,13 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case restls.Mode:
|
||||
var err error
|
||||
c, err = restls.NewRestls(c, ss.restlsConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s (restls) connect error: %w", ss.addr, err)
|
||||
}
|
||||
|
||||
}
|
||||
return ss.streamConn(c, metadata)
|
||||
}
|
||||
@ -143,7 +161,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale
|
||||
}
|
||||
}
|
||||
|
||||
c, err = ss.streamConn(c, metadata)
|
||||
c, err = ss.StreamConn(c, metadata)
|
||||
return NewConn(c, ss), err
|
||||
}
|
||||
|
||||
@ -202,6 +220,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
var v2rayOption *v2rayObfs.Option
|
||||
var obfsOption *simpleObfsOption
|
||||
var shadowTLSOpt *shadowtls.ShadowTLSOption
|
||||
var restlsConfig *restlsC.Config
|
||||
obfsMode := ""
|
||||
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true})
|
||||
@ -254,6 +273,19 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
SkipCertVerify: opt.SkipCertVerify,
|
||||
Version: opt.Version,
|
||||
}
|
||||
} else if option.Plugin == restls.Mode {
|
||||
obfsMode = restls.Mode
|
||||
restlsOpt := &restlsOption{}
|
||||
if err := decoder.Decode(option.PluginOpts, restlsOpt); err != nil {
|
||||
return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
|
||||
}
|
||||
|
||||
restlsConfig, err = restlsC.NewRestlsConfig(restlsOpt.Host, restlsOpt.Password, restlsOpt.VersionHint, restlsOpt.RestlsScript, restlsOpt.ClientID)
|
||||
restlsConfig.SessionTicketsDisabled = true
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &ShadowSocks{
|
||||
@ -274,6 +306,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
v2rayOption: v2rayOption,
|
||||
obfsOption: obfsOption,
|
||||
shadowTLSOption: shadowTLSOpt,
|
||||
restlsConfig: restlsConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -339,6 +339,43 @@ proxies: # socks5
|
||||
host: "cloud.tencent.com"
|
||||
password: "shadow_tls_password"
|
||||
version: 2 # support 1/2/3
|
||||
|
||||
- name: ss-restls-tls13
|
||||
type: ss
|
||||
server: [YOUR_SERVER_IP]
|
||||
port: 443
|
||||
cipher: chacha20-ietf-poly1305
|
||||
password: [YOUR_SS_PASSWORD]
|
||||
plugin: restls
|
||||
plugin-opts:
|
||||
host: "www.microsoft.com" # Must be a TLS 1.3 server
|
||||
# 应当是一个TLS 1.3 服务器
|
||||
password: [YOUR_RESTLS_PASSWORD]
|
||||
version-hint: "tls13"
|
||||
client-id: chrome # One of: chrome, ios, firefox or safari
|
||||
# 可以是chrome, ios, firefox, safari中的一个
|
||||
|
||||
# Control your post-handshake traffic through restls-script
|
||||
# Hide proxy behaviors like "tls in tls".
|
||||
# see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md
|
||||
# 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征
|
||||
# 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md
|
||||
restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100"
|
||||
- name: ss-restls-tls12
|
||||
type: ss
|
||||
server: [YOUR_SERVER_IP]
|
||||
port: 443
|
||||
cipher: chacha20-ietf-poly1305
|
||||
password: [YOUR_SS_PASSWORD]
|
||||
plugin: restls
|
||||
plugin-opts:
|
||||
host: "vscode.dev" # Must be a TLS 1.2 server
|
||||
# 应当是一个TLS 1.2 服务器
|
||||
password: [YOUR_RESTLS_PASSWORD]
|
||||
version-hint: "tls12"
|
||||
client-id: chrome # One of: chrome, ios, firefox or safari
|
||||
# 可以是chrome, ios, firefox, safari中的一个
|
||||
restls-script: "1000?100<1,500~100,350~100,600~100,400~200"
|
||||
|
||||
# vmess
|
||||
# cipher支持 auto/aes-128-gcm/chacha20-poly1305/none
|
||||
|
2
go.mod
2
go.mod
@ -51,6 +51,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/3andne/restls-client-go v0.1.1
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
@ -82,3 +83,4 @@ require (
|
||||
)
|
||||
|
||||
replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370
|
||||
replace github.com/3andne/restls-client-go v0.1.1 => ../go
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
||||
github.com/3andne/restls-client-go v0.1.1 h1:6BbtlaCct9yd2eEjeoELz/I8inXmYgBmLZ1zliXtvUo=
|
||||
github.com/3andne/restls-client-go v0.1.1/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
|
57
transport/restls/restls.go
Normal file
57
transport/restls/restls.go
Normal file
@ -0,0 +1,57 @@
|
||||
package restls
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
tls "github.com/3andne/restls-client-go"
|
||||
)
|
||||
|
||||
const (
|
||||
Mode string = "restls"
|
||||
)
|
||||
|
||||
// Restls
|
||||
type Restls struct {
|
||||
net.Conn
|
||||
firstPacketCache []byte
|
||||
firstPacket bool
|
||||
}
|
||||
|
||||
func (r *Restls) Read(b []byte) (int, error) {
|
||||
if err := r.Conn.(*tls.UConn).Handshake(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err := r.Conn.(*tls.UConn).Read(b)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *Restls) Write(b []byte) (int, error) {
|
||||
if r.firstPacket {
|
||||
r.firstPacketCache = append([]byte(nil), b...)
|
||||
r.firstPacket = false
|
||||
return len(b), nil
|
||||
}
|
||||
if len(r.firstPacketCache) != 0 {
|
||||
b = append(r.firstPacketCache, b...)
|
||||
r.firstPacketCache = nil
|
||||
}
|
||||
n, err := r.Conn.(*tls.UConn).Write(b)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// NewRestls return a Restls Connection
|
||||
func NewRestls(conn net.Conn, config *tls.Config) (net.Conn, error) {
|
||||
if config != nil {
|
||||
clientIDPtr := config.ClientID.Load()
|
||||
if clientIDPtr != nil {
|
||||
return &Restls{
|
||||
Conn: tls.UClient(conn, config, *clientIDPtr),
|
||||
firstPacket: true,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return &Restls{
|
||||
Conn: tls.UClient(conn, config, tls.HelloChrome_Auto),
|
||||
firstPacket: true,
|
||||
}, nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user