mirror of
https://github.com/MetaCubeX/Clash.Meta.git
synced 2025-04-19 08:40:57 +00:00
chore: cleanup trojan code
This commit is contained in:
parent
bad61f918f
commit
63e66f49ca
2 changed files with 56 additions and 155 deletions
|
@ -18,12 +18,13 @@ import (
|
|||
"github.com/metacubex/mihomo/transport/gun"
|
||||
"github.com/metacubex/mihomo/transport/shadowsocks/core"
|
||||
"github.com/metacubex/mihomo/transport/trojan"
|
||||
"github.com/metacubex/mihomo/transport/vmess"
|
||||
)
|
||||
|
||||
type Trojan struct {
|
||||
*Base
|
||||
instance *trojan.Trojan
|
||||
option *TrojanOption
|
||||
option *TrojanOption
|
||||
hexPassword [trojan.KeyLength]byte
|
||||
|
||||
// for gun mux
|
||||
gunTLSConfig *tls.Config
|
||||
|
@ -62,14 +63,20 @@ type TrojanSSOption struct {
|
|||
}
|
||||
|
||||
func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) {
|
||||
var err error
|
||||
|
||||
if t.option.Network == "ws" {
|
||||
host, port, _ := net.SplitHostPort(t.addr)
|
||||
wsOpts := &trojan.WebsocketOption{
|
||||
|
||||
wsOpts := &vmess.WebsocketConfig{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Path: t.option.WSOpts.Path,
|
||||
MaxEarlyData: t.option.WSOpts.MaxEarlyData,
|
||||
EarlyDataHeaderName: t.option.WSOpts.EarlyDataHeaderName,
|
||||
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
||||
ClientFingerprint: t.option.ClientFingerprint,
|
||||
Headers: http.Header{},
|
||||
}
|
||||
|
||||
|
@ -83,10 +90,39 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error)
|
|||
}
|
||||
}
|
||||
|
||||
return t.instance.StreamWebsocketConn(ctx, c, wsOpts)
|
||||
alpn := trojan.DefaultWebsocketALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
}
|
||||
|
||||
wsOpts.TLS = true
|
||||
tlsConfig := &tls.Config{
|
||||
NextProtos: alpn,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||
ServerName: t.option.SNI,
|
||||
}
|
||||
|
||||
wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vmess.StreamWebsocketConn(ctx, c, wsOpts)
|
||||
}
|
||||
|
||||
return t.instance.StreamConn(ctx, c)
|
||||
alpn := trojan.DefaultALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
}
|
||||
return vmess.StreamTLSConn(ctx, c, &vmess.TLSConfig{
|
||||
Host: t.option.SNI,
|
||||
SkipCertVerify: t.option.SkipCertVerify,
|
||||
FingerPrint: t.option.Fingerprint,
|
||||
ClientFingerprint: t.option.ClientFingerprint,
|
||||
NextProtos: alpn,
|
||||
Reality: t.realityConfig,
|
||||
})
|
||||
}
|
||||
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
|
@ -124,7 +160,7 @@ func (t *Trojan) writeHeaderContext(ctx context.Context, c net.Conn, metadata *C
|
|||
if metadata.NetWork == C.UDP {
|
||||
command = trojan.CommandUDP
|
||||
}
|
||||
err = t.instance.WriteHeader(c, command, serializesSocksAddr(metadata))
|
||||
err = trojan.WriteHeader(c, t.hexPassword, command, serializesSocksAddr(metadata))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -199,7 +235,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pc := t.instance.PacketConn(c)
|
||||
pc := trojan.NewPacketConn(c)
|
||||
return newPacketConn(pc, t), err
|
||||
}
|
||||
return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.Base.DialOptions(opts...)...), metadata)
|
||||
|
@ -234,7 +270,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pc := t.instance.PacketConn(c)
|
||||
pc := trojan.NewPacketConn(c)
|
||||
return newPacketConn(pc, t), err
|
||||
}
|
||||
|
||||
|
@ -245,7 +281,7 @@ func (t *Trojan) SupportWithDialer() C.NetWork {
|
|||
|
||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||
func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||
pc := t.instance.PacketConn(c)
|
||||
pc := trojan.NewPacketConn(c)
|
||||
return newPacketConn(pc, t), err
|
||||
}
|
||||
|
||||
|
@ -272,19 +308,6 @@ func (t *Trojan) Close() error {
|
|||
func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||
|
||||
tOption := &trojan.Option{
|
||||
Password: option.Password,
|
||||
ALPN: option.ALPN,
|
||||
ServerName: option.Server,
|
||||
SkipCertVerify: option.SkipCertVerify,
|
||||
Fingerprint: option.Fingerprint,
|
||||
ClientFingerprint: option.ClientFingerprint,
|
||||
}
|
||||
|
||||
if option.SNI != "" {
|
||||
tOption.ServerName = option.SNI
|
||||
}
|
||||
|
||||
t := &Trojan{
|
||||
Base: &Base{
|
||||
name: option.Name,
|
||||
|
@ -297,8 +320,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||
rmark: option.RoutingMark,
|
||||
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||
},
|
||||
instance: trojan.New(tOption),
|
||||
option: &option,
|
||||
option: &option,
|
||||
hexPassword: trojan.Key(option.Password),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -306,7 +329,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tOption.Reality = t.realityConfig
|
||||
|
||||
if option.SSOpts.Enabled {
|
||||
if option.SSOpts.Password == "" {
|
||||
|
@ -342,8 +364,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||
tlsConfig := &tls.Config{
|
||||
NextProtos: option.ALPN,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: tOption.SkipCertVerify,
|
||||
ServerName: tOption.ServerName,
|
||||
InsecureSkipVerify: option.SkipCertVerify,
|
||||
ServerName: option.SNI,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -352,13 +374,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig)
|
||||
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, option.ClientFingerprint, t.realityConfig)
|
||||
|
||||
t.gunTLSConfig = tlsConfig
|
||||
t.gunConfig = &gun.Config{
|
||||
ServiceName: option.GrpcOpts.GrpcServiceName,
|
||||
Host: tOption.ServerName,
|
||||
ClientFingerprint: tOption.ClientFingerprint,
|
||||
Host: option.SNI,
|
||||
ClientFingerprint: option.ClientFingerprint,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
package trojan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
N "github.com/metacubex/mihomo/common/net"
|
||||
"github.com/metacubex/mihomo/common/pool"
|
||||
"github.com/metacubex/mihomo/component/ca"
|
||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/transport/socks5"
|
||||
"github.com/metacubex/mihomo/transport/vmess"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -27,8 +20,8 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
defaultALPN = []string{"h2", "http/1.1"}
|
||||
defaultWebsocketALPN = []string{"http/1.1"}
|
||||
DefaultALPN = []string{"h2", "http/1.1"}
|
||||
DefaultWebsocketALPN = []string{"http/1.1"}
|
||||
|
||||
crlf = []byte{'\r', '\n'}
|
||||
)
|
||||
|
@ -43,115 +36,11 @@ const (
|
|||
KeyLength = 56
|
||||
)
|
||||
|
||||
type Option struct {
|
||||
Password string
|
||||
ALPN []string
|
||||
ServerName string
|
||||
SkipCertVerify bool
|
||||
Fingerprint string
|
||||
ClientFingerprint string
|
||||
Reality *tlsC.RealityConfig
|
||||
}
|
||||
|
||||
type WebsocketOption struct {
|
||||
Host string
|
||||
Port string
|
||||
Path string
|
||||
Headers http.Header
|
||||
V2rayHttpUpgrade bool
|
||||
V2rayHttpUpgradeFastOpen bool
|
||||
}
|
||||
|
||||
type Trojan struct {
|
||||
option *Option
|
||||
hexPassword [KeyLength]byte
|
||||
}
|
||||
|
||||
func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||
alpn := defaultALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
NextProtos: alpn,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||
ServerName: t.option.ServerName,
|
||||
}
|
||||
|
||||
var err error
|
||||
tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(t.option.ClientFingerprint) != 0 {
|
||||
if t.option.Reality == nil {
|
||||
utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
}
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality)
|
||||
}
|
||||
}
|
||||
if t.option.Reality != nil {
|
||||
return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint")
|
||||
}
|
||||
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
// fix tls handshake not timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err = tlsConn.HandshakeContext(ctx)
|
||||
return tlsConn, err
|
||||
}
|
||||
|
||||
func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
|
||||
alpn := defaultWebsocketALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
NextProtos: alpn,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: t.option.SkipCertVerify,
|
||||
ServerName: t.option.ServerName,
|
||||
}
|
||||
|
||||
var err error
|
||||
tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{
|
||||
Host: wsOptions.Host,
|
||||
Port: wsOptions.Port,
|
||||
Path: wsOptions.Path,
|
||||
Headers: wsOptions.Headers,
|
||||
V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade,
|
||||
V2rayHttpUpgradeFastOpen: wsOptions.V2rayHttpUpgradeFastOpen,
|
||||
TLS: true,
|
||||
TLSConfig: tlsConfig,
|
||||
ClientFingerprint: t.option.ClientFingerprint,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error {
|
||||
func WriteHeader(w io.Writer, hexPassword [KeyLength]byte, command Command, socks5Addr []byte) error {
|
||||
buf := pool.GetBuffer()
|
||||
defer pool.PutBuffer(buf)
|
||||
|
||||
buf.Write(t.hexPassword[:])
|
||||
buf.Write(hexPassword[:])
|
||||
buf.Write(crlf)
|
||||
|
||||
buf.WriteByte(command)
|
||||
|
@ -162,12 +51,6 @@ func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) er
|
|||
return err
|
||||
}
|
||||
|
||||
func (t *Trojan) PacketConn(conn net.Conn) net.PacketConn {
|
||||
return &PacketConn{
|
||||
Conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||
buf := pool.GetBuffer()
|
||||
defer pool.PutBuffer(buf)
|
||||
|
@ -243,10 +126,6 @@ func ReadPacket(r io.Reader, payload []byte) (net.Addr, int, int, error) {
|
|||
return uAddr, length, total - length, nil
|
||||
}
|
||||
|
||||
func New(option *Option) *Trojan {
|
||||
return &Trojan{option, Key(option.Password)}
|
||||
}
|
||||
|
||||
var _ N.EnhancePacketConn = (*PacketConn)(nil)
|
||||
|
||||
type PacketConn struct {
|
||||
|
|
Loading…
Add table
Reference in a new issue