mirror of
https://github.com/MetaCubeX/Clash.Meta.git
synced 2025-04-11 04:50:56 +00:00
feat: add gost-plugin which currently only ws and mws are tested
This commit is contained in:
parent
8be0ad90cc
commit
1a3403d4e1
2 changed files with 133 additions and 0 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/metacubex/mihomo/component/proxydialer"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
gost "github.com/metacubex/mihomo/transport/gost-plugin"
|
||||
"github.com/metacubex/mihomo/transport/restls"
|
||||
obfs "github.com/metacubex/mihomo/transport/simple-obfs"
|
||||
shadowtls "github.com/metacubex/mihomo/transport/sing-shadowtls"
|
||||
|
@ -34,6 +35,7 @@ type ShadowSocks struct {
|
|||
obfsMode string
|
||||
obfsOption *simpleObfsOption
|
||||
v2rayOption *v2rayObfs.Option
|
||||
gostOption *gost.Option
|
||||
shadowTLSOption *shadowtls.ShadowTLSOption
|
||||
restlsConfig *restlsC.Config
|
||||
}
|
||||
|
@ -71,6 +73,19 @@ type v2rayObfsOption struct {
|
|||
V2rayHttpUpgradeFastOpen bool `obfs:"v2ray-http-upgrade-fast-open,omitempty"`
|
||||
}
|
||||
|
||||
type gostObfsOption struct {
|
||||
Mode string `obfs:"mode"`
|
||||
Host string `obfs:"host,omitempty"`
|
||||
Path string `obfs:"path,omitempty"`
|
||||
TLS bool `obfs:"tls,omitempty"`
|
||||
Fingerprint string `obfs:"fingerprint,omitempty"`
|
||||
Headers map[string]string `obfs:"headers,omitempty"`
|
||||
SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"`
|
||||
Mux bool `obfs:"mux,omitempty"`
|
||||
V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"`
|
||||
V2rayHttpUpgradeFastOpen bool `obfs:"v2ray-http-upgrade-fast-open,omitempty"`
|
||||
}
|
||||
|
||||
type shadowTLSOption struct {
|
||||
Password string `obfs:"password"`
|
||||
Host string `obfs:"host"`
|
||||
|
@ -101,6 +116,12 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
|
||||
}
|
||||
case gost.ModeWebsocket:
|
||||
var err error
|
||||
c, err = gost.NewGostWebsocket(ctx, c, ss.gostOption)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
|
||||
}
|
||||
case shadowtls.Mode:
|
||||
var err error
|
||||
c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption)
|
||||
|
@ -240,6 +261,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
}
|
||||
|
||||
var v2rayOption *v2rayObfs.Option
|
||||
var gostOption *gost.Option
|
||||
var obfsOption *simpleObfsOption
|
||||
var shadowTLSOpt *shadowtls.ShadowTLSOption
|
||||
var restlsConfig *restlsC.Config
|
||||
|
@ -281,6 +303,30 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
v2rayOption.SkipCertVerify = opts.SkipCertVerify
|
||||
v2rayOption.Fingerprint = opts.Fingerprint
|
||||
}
|
||||
} else if option.Plugin == "gost-plugin" {
|
||||
opts := gostObfsOption{Host: "bing.com", Mux: true}
|
||||
if err := decoder.Decode(option.PluginOpts, &opts); err != nil {
|
||||
return nil, fmt.Errorf("ss %s initialize gost-plugin error: %w", addr, err)
|
||||
}
|
||||
|
||||
if opts.Mode != gost.ModeWebsocket {
|
||||
return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode)
|
||||
}
|
||||
obfsMode = opts.Mode
|
||||
gostOption = &gost.Option{
|
||||
Host: opts.Host,
|
||||
Path: opts.Path,
|
||||
Headers: opts.Headers,
|
||||
Mux: opts.Mux,
|
||||
V2rayHttpUpgrade: opts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: opts.V2rayHttpUpgradeFastOpen,
|
||||
}
|
||||
|
||||
if opts.TLS {
|
||||
gostOption.TLS = true
|
||||
gostOption.SkipCertVerify = opts.SkipCertVerify
|
||||
gostOption.Fingerprint = opts.Fingerprint
|
||||
}
|
||||
} else if option.Plugin == shadowtls.Mode {
|
||||
obfsMode = shadowtls.Mode
|
||||
opt := &shadowTLSOption{
|
||||
|
@ -336,6 +382,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
option: &option,
|
||||
obfsMode: obfsMode,
|
||||
v2rayOption: v2rayOption,
|
||||
gostOption: gostOption,
|
||||
obfsOption: obfsOption,
|
||||
shadowTLSOption: shadowTLSOpt,
|
||||
restlsConfig: restlsConfig,
|
||||
|
|
86
transport/gost-plugin/websocket.go
Normal file
86
transport/gost-plugin/websocket.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
package gost
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
"github.com/metacubex/mihomo/transport/vmess"
|
||||
smux "github.com/sagernet/smux"
|
||||
)
|
||||
|
||||
const (
|
||||
ModeWebsocket string = "gost-websocket"
|
||||
)
|
||||
|
||||
// Option is options of gost websocket
|
||||
type Option struct {
|
||||
Host string
|
||||
Port string
|
||||
Path string
|
||||
Headers map[string]string
|
||||
TLS bool
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
Mux bool
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
}
|
||||
|
||||
// NewGostWebsocket return a gost websocket
|
||||
func NewGostWebsocket(ctx context.Context, conn net.Conn, option *Option) (net.Conn, error) {
|
||||
header := http.Header{}
|
||||
for k, v := range option.Headers {
|
||||
header.Add(k, v)
|
||||
}
|
||||
|
||||
config := &vmess.WebsocketConfig{
|
||||
Host: option.Host,
|
||||
Port: option.Port,
|
||||
Path: option.Path,
|
||||
V2rayHttpUpgrade: option.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: option.V2rayHttpUpgradeFastOpen,
|
||||
Headers: header,
|
||||
}
|
||||
|
||||
if option.TLS {
|
||||
config.TLS = true
|
||||
tlsConfig := &tls.Config{
|
||||
ServerName: option.Host,
|
||||
InsecureSkipVerify: option.SkipCertVerify,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
}
|
||||
var err error
|
||||
config.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if host := config.Headers.Get("Host"); host != "" {
|
||||
config.TLSConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
conn, err = vmess.StreamWebsocketConn(ctx, conn, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if option.Mux {
|
||||
session, err := smux.Client(conn, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stream, err := session.OpenStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn = stream
|
||||
}
|
||||
return conn, nil
|
||||
}
|
Loading…
Add table
Reference in a new issue