Merge remote-tracking branch 'Pro-Plus/with-tun' into Alpha

# Conflicts:
#	README.md
#	adapter/outbound/trojan.go
#	adapter/outbound/vless.go
#	transport/trojan/trojan.go
This commit is contained in:
MetaCubeX
2022-03-30 13:15:45 +08:00
33 changed files with 569 additions and 327 deletions

View File

@ -14,6 +14,7 @@ type Direct struct {
// DialContext implements C.ProxyAdapter
func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
opts = append(opts, dialer.WithDirect())
c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...)
if err != nil {
return nil, err
@ -24,6 +25,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
// ListenPacketContext implements C.ProxyAdapter
func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
opts = append(opts, dialer.WithDirect())
pc, err := dialer.ListenPacket(ctx, "udp", "", d.Base.DialOptions(opts...)...)
if err != nil {
return nil, err

View File

@ -4,7 +4,6 @@ import (
"context"
"crypto/tls"
"fmt"
xtls "github.com/xtls/go"
"net"
"net/http"
"strconv"
@ -13,6 +12,7 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/gun"
"github.com/Dreamacro/clash/transport/trojan"
"github.com/Dreamacro/clash/transport/vless"
"golang.org/x/net/http2"
)
@ -34,7 +34,6 @@ type TrojanOption struct {
Server string `proxy:"server"`
Port int `proxy:"port"`
Password string `proxy:"password"`
Flow string `proxy:"flow,omitempty"`
ALPN []string `proxy:"alpn,omitempty"`
SNI string `proxy:"sni,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
@ -42,6 +41,8 @@ type TrojanOption struct {
Network string `proxy:"network,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
}
func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
@ -83,19 +84,13 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
var tc trojan.Command
if xtlsConn, ok := c.(*xtls.Conn); ok {
xtlsConn.RPRX = true
if t.instance.GetFlow() == trojan.XRD {
xtlsConn.DirectMode = true
tc = trojan.CommandXRD
} else {
tc = trojan.CommandXRO
}
} else {
tc = trojan.CommandTCP
c, err = t.instance.PresetXTLSConn(c)
if err != nil {
return nil, err
}
err = t.instance.WriteHeader(c, tc, serializesSocksAddr(metadata))
err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata))
return c, err
}
@ -108,6 +103,12 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
return nil, err
}
c, err = t.instance.PresetXTLSConn(c)
if err != nil {
c.Close()
return nil, err
}
if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil {
c.Close()
return nil, err
@ -169,13 +170,21 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
tOption := &trojan.Option{
Password: option.Password,
Flow: option.Flow,
ALPN: option.ALPN,
ServerName: option.Server,
SkipCertVerify: option.SkipCertVerify,
ClientSessionCache: getClientSessionCache(),
ClientXSessionCache: getClientXSessionCache(),
Password: option.Password,
ALPN: option.ALPN,
ServerName: option.Server,
SkipCertVerify: option.SkipCertVerify,
FlowShow: option.FlowShow,
}
if option.Network != "ws" && len(option.Flow) >= 16 {
option.Flow = option.Flow[:16]
switch option.Flow {
case vless.XRO, vless.XRD, vless.XRS:
tOption.Flow = option.Flow
default:
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
}
}
if option.SNI != "" {
@ -212,7 +221,12 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
ServerName: tOption.ServerName,
}
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig)
if t.option.Flow != "" {
t.transport = gun.NewHTTP2XTLSClient(dialFn, tlsConfig)
} else {
t.transport = gun.NewHTTP2Client(dialFn, tlsConfig)
}
t.gunTLSConfig = tlsConfig
t.gunConfig = &gun.Config{
ServiceName: option.GrpcOpts.GrpcServiceName,

View File

@ -67,7 +67,7 @@ func resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
return nil, err
}
ip, err := resolver.ResolveIP(host)
ip, err := resolver.ResolveProxyServerHost(host)
if err != nil {
return nil, err
}

View File

@ -6,6 +6,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"net/http"
"strconv"
@ -23,7 +24,7 @@ import (
const (
// max packet length
maxLength = 8192
maxLength = 1024 << 3
)
type Vless struct {
@ -39,21 +40,22 @@ type Vless struct {
type VlessOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
UUID string `proxy:"uuid"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
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"`
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"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,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"`
}
func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
@ -62,7 +64,6 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
case "ws":
host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &vmess.WebsocketConfig{
Host: host,
Port: port,
@ -79,18 +80,17 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
wsOpts.Headers = header
}
if v.option.TLS {
wsOpts.TLS = true
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
}
wsOpts.TLS = true
wsOpts.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
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":
@ -128,6 +128,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig)
}
default:
// default tcp network
// handle TLS And XTLS
c, err = v.streamTLSOrXTLSConn(c, false)
}
@ -158,7 +159,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
return vless.StreamXTLSConn(conn, &xtlsOpts)
} else if v.option.TLS {
} else {
tlsOpts := vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
@ -174,8 +175,6 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
return vmess.StreamTLSConn(conn, &tlsOpts)
}
return conn, nil
}
func (v *Vless) isXTLSEnabled() bool {
@ -213,7 +212,7 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
// ListenPacketContext implements C.ProxyAdapter
func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
// vless use stream-oriented udp with a special address, so we needs a net.UDPAddr
if !metadata.Resolved() {
ip, err := resolver.ResolveIP(metadata.Host)
if err != nil {
@ -269,7 +268,7 @@ func parseVlessAddr(metadata *C.Metadata) *vless.DstAddr {
copy(addr[1:], []byte(metadata.Host))
}
port, _ := strconv.Atoi(metadata.DstPort)
port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
return &vless.DstAddr{
UDP: metadata.NetWork == C.UDP,
AddrType: addrType,
@ -283,43 +282,46 @@ type vlessPacketConn struct {
rAddr net.Addr
remain int
mux sync.Mutex
cache []byte
cache [2]byte
}
func (c *vlessPacketConn) writePacket(b []byte, addr net.Addr) (int, error) {
length := len(b)
defer func() {
c.cache = c.cache[:0]
}()
c.cache = append(c.cache, byte(length>>8), byte(length))
c.cache = append(c.cache, b...)
n, err := c.Conn.Write(c.cache)
if n > 2 {
return n - 2, err
func (c *vlessPacketConn) writePacket(payload []byte) (int, error) {
binary.BigEndian.PutUint16(c.cache[:], uint16(len(payload)))
if _, err := c.Conn.Write(c.cache[:]); err != nil {
return 0, err
}
return 0, err
return c.Conn.Write(payload)
}
func (c *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
if len(b) <= maxLength {
return c.writePacket(b, addr)
total := len(b)
if total == 0 {
return 0, nil
}
if total <= maxLength {
return c.writePacket(b)
}
offset := 0
total := len(b)
for offset < total {
cursor := offset + maxLength
if cursor > total {
cursor = total
}
n, err := c.writePacket(b[offset:cursor], addr)
n, err := c.writePacket(b[offset:cursor])
if err != nil {
return offset + n, err
}
offset = cursor
if offset == total {
break
}
}
return total, nil
@ -329,40 +331,45 @@ func (c *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
c.mux.Lock()
defer c.mux.Unlock()
length := len(b)
if c.remain > 0 {
length := len(b)
if c.remain < length {
length = c.remain
}
n, err := c.Conn.Read(b[:length])
if err != nil {
return 0, nil, err
return 0, c.rAddr, err
}
c.remain -= n
return n, c.rAddr, nil
}
var packetLength uint16
if err := binary.Read(c.Conn, binary.BigEndian, &packetLength); err != nil {
return 0, nil, err
if _, err := c.Conn.Read(b[:2]); err != nil {
return 0, c.rAddr, err
}
remain := int(packetLength)
n, err := c.Conn.Read(b[:length])
remain -= n
if remain > 0 {
c.remain = remain
total := int(binary.BigEndian.Uint16(b[:2]))
if total == 0 {
return 0, c.rAddr, nil
}
return n, c.rAddr, err
length := len(b)
if length > total {
length = total
}
if _, err := io.ReadFull(c.Conn, b[:length]); err != nil {
return 0, c.rAddr, errors.New("read packet error")
}
c.remain = total - length
return length, c.rAddr, nil
}
func NewVless(option VlessOption) (*Vless, error) {
if !option.TLS && option.Network == "grpc" {
return nil, fmt.Errorf("TLS must be true with vless-grpc")
}
var addons *vless.Addons
if option.Network != "ws" && len(option.Flow) >= 16 {
option.Flow = option.Flow[:16]
@ -372,7 +379,7 @@ func NewVless(option VlessOption) (*Vless, error) {
Flow: option.Flow,
}
default:
return nil, fmt.Errorf("unsupported vless flow type: %s", option.Flow)
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
}
}

View File

@ -31,7 +31,13 @@ type HealthCheck struct {
func (hc *HealthCheck) process() {
ticker := time.NewTicker(time.Duration(hc.interval) * time.Second)
go hc.check()
go func() {
t := time.NewTicker(30 * time.Second)
<-t.C
t.Stop()
hc.check()
}()
for {
select {
case <-ticker.C: