Merge from remote branch

This commit is contained in:
yaling888
2021-10-28 11:36:11 +08:00
86 changed files with 1065 additions and 461 deletions

View File

@ -1,6 +1,7 @@
package outbound
import (
"context"
"encoding/json"
"errors"
"net"
@ -30,8 +31,8 @@ func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
return c, errors.New("no support")
}
// DialUDP implements C.ProxyAdapter
func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
// ListenPacketContext implements C.ProxyAdapter
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("no support")
}

View File

@ -22,9 +22,9 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return NewConn(c, d), nil
}
// DialUDP implements C.ProxyAdapter
func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(context.Background(), "udp", "")
// ListenPacketContext implements C.ProxyAdapter
func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}

View File

@ -19,8 +19,8 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return NewConn(&NopConn{}, r), nil
}
// DialUDP implements C.ProxyAdapter
func (r *Reject) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
// ListenPacketContext implements C.ProxyAdapter
func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("match reject rule")
}

View File

@ -87,9 +87,9 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_
return NewConn(c, ss), err
}
// DialUDP implements C.ProxyAdapter
func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(context.Background(), "udp", "")
// ListenPacketContext implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}

View File

@ -72,9 +72,9 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata)
return NewConn(c, ssr), err
}
// DialUDP implements C.ProxyAdapter
func (ssr *ShadowSocksR) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(context.Background(), "udp", "")
// ListenPacketContext implements C.ProxyAdapter
func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return nil, err
}

View File

@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"strconv"
@ -77,10 +76,8 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Co
return NewConn(c, ss), nil
}
// DialUDP implements C.ProxyAdapter
func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
// ListenPacketContext implements C.ProxyAdapter
func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
c, err := dialer.DialContext(ctx, "tcp", ss.addr)
if err != nil {
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
@ -110,13 +107,13 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
return
}
pc, err := dialer.ListenPacket(context.Background(), "udp", "")
pc, err := dialer.ListenPacket(ctx, "udp", "")
if err != nil {
return
}
go func() {
io.Copy(ioutil.Discard, c)
io.Copy(io.Discard, c)
c.Close()
// A UDP association terminates when the TCP connection that the UDP
// ASSOCIATE request arrived on terminates. RFC1928

View File

@ -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 {
@ -88,8 +118,8 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
return NewConn(c, t), err
}
// DialUDP implements C.ProxyAdapter
func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
// ListenPacketContext implements C.ProxyAdapter
func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
var c net.Conn
// grpc transport
@ -100,15 +130,13 @@ func (t *Trojan) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
}
defer safeConnClose(c, err)
} else {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
c, err = dialer.DialContext(ctx, "tcp", t.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
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)
}
@ -145,6 +173,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
udp: option.UDP,
},
instance: trojan.New(tOption),
option: &option,
}
if option.Network == "grpc" {

View File

@ -79,8 +79,16 @@ func (v *Vless) 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":

View File

@ -31,23 +31,25 @@ type Vmess struct {
}
type VmessOption struct {
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
AlterID int `proxy:"alterId"`
Cipher string `proxy:"cipher"`
TLS bool `proxy:"tls,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
ServerName string `proxy:"servername,omitempty"`
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
AlterID int `proxy:"alterId"`
Cipher string `proxy:"cipher"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
TLS bool `proxy:"tls,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
ServerName string `proxy:"servername,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
// TODO: remove these until 2022
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
}
type HTTPOptions struct {
@ -103,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":
@ -213,8 +223,8 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn
return NewConn(c, v), err
}
// DialUDP implements C.ProxyAdapter
func (v *Vmess) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
// ListenPacketContext implements C.ProxyAdapter
func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
if !metadata.Resolved() {
ip, err := resolver.ResolveIP(metadata.Host)
@ -235,8 +245,6 @@ func (v *Vmess) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
} else {
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
c, err = dialer.DialContext(ctx, "tcp", v.addr)
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())