Skip to content

Commit

Permalink
add ss-opts for trojan outbound like trojan-go's shadowsocks config
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed May 22, 2024
1 parent 5f7fbab commit 1afc250
Showing 1 changed file with 55 additions and 12 deletions.
67 changes: 55 additions & 12 deletions adapter/outbound/trojan.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package outbound
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
Expand All @@ -14,6 +15,7 @@ import (
"github.com/metacubex/mihomo/component/proxydialer"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/gun"
"github.com/metacubex/mihomo/transport/shadowsocks/core"
"github.com/metacubex/mihomo/transport/trojan"

"golang.org/x/net/http2"
Expand All @@ -28,22 +30,32 @@ type Trojan struct {
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *http2.Transport

ssCipher core.Cipher
}

type TrojanOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Password string `proxy:"password"`
ALPN []string `proxy:"alpn,omitempty"`
SNI string `proxy:"sni,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Password string `proxy:"password"`
ALPN []string `proxy:"alpn,omitempty"`
SNI string `proxy:"sni,omitempty"`
Fingerprint string `proxy:"fingerprint,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
SSOpts TrojanSSOption `proxy:"ss-opts,omitempty"`
}

// TrojanSSOption from https://github.com/p4gefau1t/trojan-go/blob/v0.10.6/tunnel/shadowsocks/config.go#L5
type TrojanSSOption struct {
Enabled bool `proxy:"enabled,omitempty"`
Method string `proxy:"method,omitempty"`
Password string `proxy:"password,omitempty"`
}

func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) {
Expand Down Expand Up @@ -89,6 +101,10 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}

if t.ssCipher != nil {
c = t.ssCipher.StreamConn(c)
}

if metadata.NetWork == C.UDP {
err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
return c, err
Expand All @@ -106,6 +122,10 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
return nil, err
}

if t.ssCipher != nil {
c = t.ssCipher.StreamConn(c)
}

if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil {
c.Close()
return nil, err
Expand Down Expand Up @@ -155,6 +175,11 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)

if t.ssCipher != nil {
c = t.ssCipher.StreamConn(c)
}

err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
if err != nil {
return nil, err
Expand Down Expand Up @@ -187,6 +212,10 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}

if t.ssCipher != nil {
c = t.ssCipher.StreamConn(c)
}

err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
if err != nil {
return nil, err
Expand Down Expand Up @@ -242,6 +271,20 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
option: &option,
}

if option.SSOpts.Enabled {
if option.SSOpts.Password == "" {
return nil, errors.New("empty password")
}
if option.SSOpts.Method == "" {
option.SSOpts.Method = "AES-128-GCM"
}
ciph, err := core.PickCipher(option.SSOpts.Method, nil, option.SSOpts.Password)
if err != nil {
return nil, err
}
t.ssCipher = ciph
}

if option.Network == "grpc" {
dialFn := func(network, addr string) (net.Conn, error) {
var err error
Expand Down

0 comments on commit 1afc250

Please sign in to comment.