Feature: support trojan websocket
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
@ -18,6 +19,7 @@ import (
|
||||
type Trojan struct {
|
||||
*Base
|
||||
instance *trojan.Trojan
|
||||
option *TrojanOption
|
||||
|
||||
// for gun mux
|
||||
gunTLSConfig *tls.Config
|
||||
@ -36,6 +38,34 @@ type TrojanOption struct {
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Network string `proxy:"network,omitempty"`
|
||||
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
|
||||
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
|
||||
}
|
||||
|
||||
func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
|
||||
if t.option.Network == "ws" {
|
||||
host, port, _ := net.SplitHostPort(t.addr)
|
||||
wsOpts := &trojan.WebsocketOption{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Path: t.option.WSOpts.Path,
|
||||
}
|
||||
|
||||
if t.option.SNI != "" {
|
||||
wsOpts.Host = t.option.SNI
|
||||
}
|
||||
|
||||
if len(t.option.WSOpts.Headers) != 0 {
|
||||
header := http.Header{}
|
||||
for key, value := range t.option.WSOpts.Headers {
|
||||
header.Add(key, value)
|
||||
}
|
||||
wsOpts.Headers = header
|
||||
}
|
||||
|
||||
return t.instance.StreamWebsocketConn(c, wsOpts)
|
||||
}
|
||||
|
||||
return t.instance.StreamConn(c)
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
@ -44,7 +74,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
|
||||
if t.transport != nil {
|
||||
c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig)
|
||||
} else {
|
||||
c, err = t.instance.StreamConn(c)
|
||||
c, err = t.plainStream(c)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -106,7 +136,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
||||
}
|
||||
defer safeConnClose(c, err)
|
||||
tcpKeepAlive(c)
|
||||
c, err = t.instance.StreamConn(c)
|
||||
c, err = t.plainStream(c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
||||
}
|
||||
@ -143,6 +173,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||
udp: option.UDP,
|
||||
},
|
||||
instance: trojan.New(tOption),
|
||||
option: &option,
|
||||
}
|
||||
|
||||
if option.Network == "grpc" {
|
||||
|
@ -105,8 +105,16 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
|
||||
if v.option.TLS {
|
||||
wsOpts.TLS = true
|
||||
wsOpts.SkipCertVerify = v.option.SkipCertVerify
|
||||
wsOpts.ServerName = v.option.ServerName
|
||||
wsOpts.TLSConfig = &tls.Config{
|
||||
ServerName: host,
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
NextProtos: []string{"http/1.1"},
|
||||
}
|
||||
if v.option.ServerName != "" {
|
||||
wsOpts.TLSConfig.ServerName = v.option.ServerName
|
||||
} else if host := wsOpts.Headers.Get("Host"); host != "" {
|
||||
wsOpts.TLSConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
||||
case "http":
|
||||
|
Reference in New Issue
Block a user