mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-12 21:18:03 +08:00
chore: cleanup trojan code
This commit is contained in:
parent
bad61f918f
commit
63e66f49ca
@ -18,12 +18,13 @@ import (
|
|||||||
"github.com/metacubex/mihomo/transport/gun"
|
"github.com/metacubex/mihomo/transport/gun"
|
||||||
"github.com/metacubex/mihomo/transport/shadowsocks/core"
|
"github.com/metacubex/mihomo/transport/shadowsocks/core"
|
||||||
"github.com/metacubex/mihomo/transport/trojan"
|
"github.com/metacubex/mihomo/transport/trojan"
|
||||||
|
"github.com/metacubex/mihomo/transport/vmess"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Trojan struct {
|
type Trojan struct {
|
||||||
*Base
|
*Base
|
||||||
instance *trojan.Trojan
|
option *TrojanOption
|
||||||
option *TrojanOption
|
hexPassword [trojan.KeyLength]byte
|
||||||
|
|
||||||
// for gun mux
|
// for gun mux
|
||||||
gunTLSConfig *tls.Config
|
gunTLSConfig *tls.Config
|
||||||
@ -62,14 +63,20 @@ type TrojanSSOption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) {
|
func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
if t.option.Network == "ws" {
|
if t.option.Network == "ws" {
|
||||||
host, port, _ := net.SplitHostPort(t.addr)
|
host, port, _ := net.SplitHostPort(t.addr)
|
||||||
wsOpts := &trojan.WebsocketOption{
|
|
||||||
|
wsOpts := &vmess.WebsocketConfig{
|
||||||
Host: host,
|
Host: host,
|
||||||
Port: port,
|
Port: port,
|
||||||
Path: t.option.WSOpts.Path,
|
Path: t.option.WSOpts.Path,
|
||||||
|
MaxEarlyData: t.option.WSOpts.MaxEarlyData,
|
||||||
|
EarlyDataHeaderName: t.option.WSOpts.EarlyDataHeaderName,
|
||||||
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
|
V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade,
|
||||||
V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen,
|
||||||
|
ClientFingerprint: t.option.ClientFingerprint,
|
||||||
Headers: http.Header{},
|
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
|
// 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 {
|
if metadata.NetWork == C.UDP {
|
||||||
command = trojan.CommandUDP
|
command = trojan.CommandUDP
|
||||||
}
|
}
|
||||||
err = t.instance.WriteHeader(c, command, serializesSocksAddr(metadata))
|
err = trojan.WriteHeader(c, t.hexPassword, command, serializesSocksAddr(metadata))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +235,7 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := t.instance.PacketConn(c)
|
pc := trojan.NewPacketConn(c)
|
||||||
return newPacketConn(pc, t), err
|
return newPacketConn(pc, t), err
|
||||||
}
|
}
|
||||||
return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.Base.DialOptions(opts...)...), metadata)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := t.instance.PacketConn(c)
|
pc := trojan.NewPacketConn(c)
|
||||||
return newPacketConn(pc, t), err
|
return newPacketConn(pc, t), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +281,7 @@ func (t *Trojan) SupportWithDialer() C.NetWork {
|
|||||||
|
|
||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||||
func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
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
|
return newPacketConn(pc, t), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,19 +308,6 @@ func (t *Trojan) Close() error {
|
|||||||
func NewTrojan(option TrojanOption) (*Trojan, error) {
|
func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
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{
|
t := &Trojan{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: option.Name,
|
name: option.Name,
|
||||||
@ -297,8 +320,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
prefer: C.NewDNSPrefer(option.IPVersion),
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
},
|
},
|
||||||
instance: trojan.New(tOption),
|
option: &option,
|
||||||
option: &option,
|
hexPassword: trojan.Key(option.Password),
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -306,7 +329,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tOption.Reality = t.realityConfig
|
|
||||||
|
|
||||||
if option.SSOpts.Enabled {
|
if option.SSOpts.Enabled {
|
||||||
if option.SSOpts.Password == "" {
|
if option.SSOpts.Password == "" {
|
||||||
@ -342,8 +364,8 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
NextProtos: option.ALPN,
|
NextProtos: option.ALPN,
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
InsecureSkipVerify: tOption.SkipCertVerify,
|
InsecureSkipVerify: option.SkipCertVerify,
|
||||||
ServerName: tOption.ServerName,
|
ServerName: option.SNI,
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -352,13 +374,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
|||||||
return nil, err
|
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.gunTLSConfig = tlsConfig
|
||||||
t.gunConfig = &gun.Config{
|
t.gunConfig = &gun.Config{
|
||||||
ServiceName: option.GrpcOpts.GrpcServiceName,
|
ServiceName: option.GrpcOpts.GrpcServiceName,
|
||||||
Host: tOption.ServerName,
|
Host: option.SNI,
|
||||||
ClientFingerprint: tOption.ClientFingerprint,
|
ClientFingerprint: option.ClientFingerprint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
package trojan
|
package trojan
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/common/pool"
|
"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/socks5"
|
||||||
"github.com/metacubex/mihomo/transport/vmess"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -27,8 +20,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultALPN = []string{"h2", "http/1.1"}
|
DefaultALPN = []string{"h2", "http/1.1"}
|
||||||
defaultWebsocketALPN = []string{"http/1.1"}
|
DefaultWebsocketALPN = []string{"http/1.1"}
|
||||||
|
|
||||||
crlf = []byte{'\r', '\n'}
|
crlf = []byte{'\r', '\n'}
|
||||||
)
|
)
|
||||||
@ -43,115 +36,11 @@ const (
|
|||||||
KeyLength = 56
|
KeyLength = 56
|
||||||
)
|
)
|
||||||
|
|
||||||
type Option struct {
|
func WriteHeader(w io.Writer, hexPassword [KeyLength]byte, command Command, socks5Addr []byte) error {
|
||||||
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 {
|
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
buf.Write(t.hexPassword[:])
|
buf.Write(hexPassword[:])
|
||||||
buf.Write(crlf)
|
buf.Write(crlf)
|
||||||
|
|
||||||
buf.WriteByte(command)
|
buf.WriteByte(command)
|
||||||
@ -162,12 +51,6 @@ func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) er
|
|||||||
return err
|
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) {
|
func writePacket(w io.Writer, socks5Addr, payload []byte) (int, error) {
|
||||||
buf := pool.GetBuffer()
|
buf := pool.GetBuffer()
|
||||||
defer pool.PutBuffer(buf)
|
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
|
return uAddr, length, total - length, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(option *Option) *Trojan {
|
|
||||||
return &Trojan{option, Key(option.Password)}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ N.EnhancePacketConn = (*PacketConn)(nil)
|
var _ N.EnhancePacketConn = (*PacketConn)(nil)
|
||||||
|
|
||||||
type PacketConn struct {
|
type PacketConn struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user