From 804cff8c5566a257add0a37babc6ac94ae9b0377 Mon Sep 17 00:00:00 2001 From: 3andero <31029660+3andero@users.noreply.github.com> Date: Thu, 12 Jan 2023 17:55:01 -0800 Subject: [PATCH 001/126] fix: skip-cert-verify is true by default (#333) * fix: skip-cert-verify is true by default * fix: format * fix: typo Co-authored-by: 3andero <3andero@github.com> Co-authored-by: Hellojack <106379370+H1JK@users.noreply.github.com> --- adapter/outbound/http.go | 4 ++-- adapter/outbound/hysteria.go | 2 +- adapter/outbound/shadowsocks.go | 2 +- adapter/outbound/socks5.go | 4 ++-- adapter/outbound/trojan.go | 2 +- adapter/outbound/tuic.go | 2 +- adapter/outbound/vless.go | 4 ++-- adapter/outbound/vmess.go | 7 ++++--- component/tls/config.go | 24 +++++++++++++++--------- dns/client.go | 7 ++++--- dns/doh.go | 2 +- dns/doq.go | 2 +- transport/trojan/trojan.go | 4 ++-- transport/v2ray-plugin/websocket.go | 4 ++-- transport/vless/xtls.go | 4 ++-- transport/vmess/tls.go | 4 ++-- 16 files changed, 43 insertions(+), 35 deletions(-) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index b734290a..088dd8ff 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -7,7 +7,6 @@ import ( "encoding/base64" "errors" "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" "io" "net" "net/http" @@ -15,6 +14,7 @@ import ( "strconv" "github.com/Dreamacro/clash/component/dialer" + tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" ) @@ -150,7 +150,7 @@ func NewHttp(option HttpOption) (*Http, error) { sni = option.SNI } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(&tls.Config{ + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(&tls.Config{ InsecureSkipVerify: option.SkipCertVerify, ServerName: sni, }) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index a1276415..9d32cb33 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -178,7 +178,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { return nil, err } } else { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 8df84c7c..3e04b6ef 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -223,7 +223,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } if len(shadowTLSOpt.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, shadowTLSOpt.Fingerprint); err != nil { return nil, err diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 28d41180..c76707c3 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -5,12 +5,12 @@ import ( "crypto/tls" "errors" "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" "io" "net" "strconv" "github.com/Dreamacro/clash/component/dialer" + tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -167,7 +167,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index e7928b50..99c49345 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -268,7 +268,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index fa24ae39..3bd750c1 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -143,7 +143,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { return nil, err } } else { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index e9e382c4..a0d711cb 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -98,7 +98,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) } @@ -522,7 +522,7 @@ func NewVless(option VlessOption) (*Vless, error) { ServiceName: v.option.GrpcOpts.GrpcServiceName, Host: v.option.ServerName, } - tlsConfig := tlsC.GetGlobalFingerprintTLCConfig(&tls.Config{ + tlsConfig := tlsC.GetGlobalFingerprintTLSConfig(&tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, ServerName: v.option.ServerName, }) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 4d3bb3d7..26ed400e 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -5,14 +5,15 @@ import ( "crypto/tls" "errors" "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" - vmess "github.com/sagernet/sing-vmess" "net" "net/http" "strconv" "strings" "sync" + tlsC "github.com/Dreamacro/clash/component/tls" + vmess "github.com/sagernet/sing-vmess" + "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" @@ -114,7 +115,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { if wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint); err != nil { return nil, err diff --git a/component/tls/config.go b/component/tls/config.go index 4470658f..6f5b1107 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -7,12 +7,13 @@ import ( "crypto/x509" "encoding/hex" "fmt" - xtls "github.com/xtls/go" "sync" "time" + + xtls "github.com/xtls/go" ) -var globalFingerprints = make([][32]byte, 0, 0) +var globalFingerprints = make([][32]byte, 0) var mutex sync.Mutex func verifyPeerCertificateAndFingerprints(fingerprints *[][32]byte, insecureSkipVerify bool) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { @@ -74,7 +75,7 @@ func convertFingerprint(fingerprint string) (*[32]byte, error) { } func GetDefaultTLSConfig() *tls.Config { - return GetGlobalFingerprintTLCConfig(nil) + return GetGlobalFingerprintTLSConfig(nil) } // GetSpecifiedFingerprintTLSConfig specified fingerprint @@ -95,16 +96,20 @@ func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) } } -func GetGlobalFingerprintTLCConfig(tlsConfig *tls.Config) *tls.Config { +func GetGlobalFingerprintTLSConfig(tlsConfig *tls.Config) *tls.Config { + // If there's at least one fingerprint then we could skip the general check + // If there's no fingerprints but the config insists then we should skip. + // Otherwise we should do a general verification. + shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify if tlsConfig == nil { return &tls.Config{ - InsecureSkipVerify: true, + InsecureSkipVerify: shouldSkipVerify, VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false), } } tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify) - tlsConfig.InsecureSkipVerify = true + tlsConfig.InsecureSkipVerify = shouldSkipVerify return tlsConfig } @@ -126,15 +131,16 @@ func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint strin } } -func GetGlobalFingerprintXTLCConfig(tlsConfig *xtls.Config) *xtls.Config { +func GetGlobalFingerprintXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { + shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify if tlsConfig == nil { return &xtls.Config{ - InsecureSkipVerify: true, + InsecureSkipVerify: shouldSkipVerify, VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false), } } tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify) - tlsConfig.InsecureSkipVerify = true + tlsConfig.InsecureSkipVerify = shouldSkipVerify return tlsConfig } diff --git a/dns/client.go b/dns/client.go index a7bf5eb3..30fd25c8 100644 --- a/dns/client.go +++ b/dns/client.go @@ -4,13 +4,14 @@ import ( "context" "crypto/tls" "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" - "go.uber.org/atomic" "math/rand" "net" "net/netip" "strings" + tlsC "github.com/Dreamacro/clash/component/tls" + "go.uber.org/atomic" + "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" @@ -77,7 +78,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) ch := make(chan result, 1) go func() { if strings.HasSuffix(c.Client.Net, "tls") { - conn = tls.Client(conn, tlsC.GetGlobalFingerprintTLCConfig(c.Client.TLSConfig)) + conn = tls.Client(conn, tlsC.GetGlobalFingerprintTLSConfig(c.Client.TLSConfig)) } msg, _, err := c.Client.ExchangeWithConn(m, &D.Conn{ diff --git a/dns/doh.go b/dns/doh.go index 34685578..ca694fb9 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -374,7 +374,7 @@ func (doh *dnsOverHTTPS) createClient(ctx context.Context) (*http.Client, error) // HTTP3 is enabled in the upstream options). If this attempt is successful, // it returns an HTTP3 transport, otherwise it returns the H1/H2 transport. func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripper, err error) { - tlsConfig := tlsC.GetGlobalFingerprintTLCConfig( + tlsConfig := tlsC.GetGlobalFingerprintTLSConfig( &tls.Config{ InsecureSkipVerify: false, MinVersion: tls.VersionTLS12, diff --git a/dns/doq.go b/dns/doq.go index 1c5956af..85c3a85c 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -298,7 +298,7 @@ func (doq *dnsOverQUIC) openStream(ctx context.Context, conn quic.Connection) (q // openConnection opens a new QUIC connection. func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connection, err error) { - tlsConfig := tlsC.GetGlobalFingerprintTLCConfig( + tlsConfig := tlsC.GetGlobalFingerprintTLSConfig( &tls.Config{ InsecureSkipVerify: false, NextProtos: []string{ diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 86de2f65..561f8765 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -82,7 +82,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } if len(t.option.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalFingerprintXTLCConfig(xtlsConfig) + xtlsConfig = tlsC.GetGlobalFingerprintXTLSConfig(xtlsConfig) } else { var err error if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, t.option.Fingerprint); err != nil { @@ -107,7 +107,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } if len(t.option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); err != nil { diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 2a052888..56b0e481 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -2,10 +2,10 @@ package obfs import ( "crypto/tls" - tlsC "github.com/Dreamacro/clash/component/tls" "net" "net/http" + tlsC "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/transport/vmess" ) @@ -43,7 +43,7 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { NextProtos: []string{"http/1.1"}, } if len(option.Fingerprint) == 0 { - config.TLSConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + config.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { var err error if config.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index ab8248af..0b461c56 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -2,9 +2,9 @@ package vless import ( "context" - tlsC "github.com/Dreamacro/clash/component/tls" "net" + tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" xtls "github.com/xtls/go" ) @@ -23,7 +23,7 @@ func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { NextProtos: cfg.NextProtos, } if len(cfg.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalFingerprintXTLCConfig(xtlsConfig) + xtlsConfig = tlsC.GetGlobalFingerprintXTLSConfig(xtlsConfig) } else { var err error if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, cfg.Fingerprint); err != nil { diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 75434095..8ac80ce6 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -3,9 +3,9 @@ package vmess import ( "context" "crypto/tls" - tlsC "github.com/Dreamacro/clash/component/tls" "net" + tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" ) @@ -24,7 +24,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { } if len(cfg.FingerPrint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLCConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, cfg.FingerPrint); err != nil { From f96bf655573b7eb2d86df041fcfab09d484e5e2f Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 14 Jan 2023 02:23:30 +0800 Subject: [PATCH 002/126] chore: Refine process code --- component/process/process.go | 10 +-------- component/process/process_darwin.go | 16 +++++-------- component/process/process_freebsd_amd64.go | 16 +++++-------- component/process/process_linux.go | 10 ++++----- component/process/process_other.go | 4 ++-- component/process/process_windows.go | 10 ++++----- constant/metadata.go | 15 +++++++------ rules/common/uid.go | 26 +++++++--------------- 8 files changed, 41 insertions(+), 66 deletions(-) diff --git a/component/process/process.go b/component/process/process.go index fe4c5d2a..76ec2c45 100644 --- a/component/process/process.go +++ b/component/process/process.go @@ -16,14 +16,6 @@ const ( UDP = "udp" ) -func FindProcessName(network string, srcIP netip.Addr, srcPort int) (*uint32, string, error) { +func FindProcessName(network string, srcIP netip.Addr, srcPort int) (uint32, string, error) { return findProcessName(network, srcIP, srcPort) } - -func FindUid(network string, srcIP netip.Addr, srcPort int) (*uint32, error) { - _, uid, err := resolveSocketByNetlink(network, srcIP, srcPort) - if err != nil { - return nil, err - } - return &uid, nil -} diff --git a/component/process/process_darwin.go b/component/process/process_darwin.go index 39e56dd2..67d2e833 100644 --- a/component/process/process_darwin.go +++ b/component/process/process_darwin.go @@ -33,11 +33,7 @@ var structSize = func() int { } }() -func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uint32, uint32, error) { - return 0, 0, ErrPlatformNotSupport -} - -func findProcessName(network string, ip netip.Addr, port int) (*uint32, string, error) { +func findProcessName(network string, ip netip.Addr, port int) (uint32, string, error) { var spath string switch network { case TCP: @@ -45,14 +41,14 @@ func findProcessName(network string, ip netip.Addr, port int) (*uint32, string, case UDP: spath = "net.inet.udp.pcblist_n" default: - return nil, "", ErrInvalidNetwork + return 0, "", ErrInvalidNetwork } isIPv4 := ip.Is4() value, err := syscall.Sysctl(spath) if err != nil { - return nil, "", err + return 0, "", err } buf := []byte(value) @@ -96,7 +92,7 @@ func findProcessName(network string, ip netip.Addr, port int) (*uint32, string, // xsocket_n.so_last_pid pid := readNativeUint32(buf[so+68 : so+72]) pp, err := getExecPathFromPID(pid) - return nil, pp, err + return 0, pp, err } // udp packet connection may be not equal with srcIP @@ -106,10 +102,10 @@ func findProcessName(network string, ip netip.Addr, port int) (*uint32, string, } if network == UDP && fallbackUDPProcess != "" { - return nil, fallbackUDPProcess, nil + return 0, fallbackUDPProcess, nil } - return nil, "", ErrNotFound + return 0, "", ErrNotFound } func getExecPathFromPID(pid uint32) (string, error) { diff --git a/component/process/process_freebsd_amd64.go b/component/process/process_freebsd_amd64.go index ffbe1515..709ade3b 100644 --- a/component/process/process_freebsd_amd64.go +++ b/component/process/process_freebsd_amd64.go @@ -21,11 +21,7 @@ var ( once sync.Once ) -func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uint32, uint32, error) { - return 0, 0, ErrPlatformNotSupport -} - -func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string, error) { once.Do(func() { if err := initSearcher(); err != nil { log.Errorln("Initialize PROCESS-NAME failed: %s", err.Error()) @@ -35,7 +31,7 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, strin }) if defaultSearcher == nil { - return nil, "", ErrPlatformNotSupport + return 0, "", ErrPlatformNotSupport } var spath string @@ -46,22 +42,22 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, strin case UDP: spath = "net.inet.udp.pcblist" default: - return nil, "", ErrInvalidNetwork + return 0, "", ErrInvalidNetwork } value, err := syscall.Sysctl(spath) if err != nil { - return nil, "", err + return 0, "", err } buf := []byte(value) pid, err := defaultSearcher.Search(buf, ip, uint16(srcPort), isTCP) if err != nil { - return nil, "", err + return 0, "", err } pp, err := getExecPathFromPID(pid) - return nil, pp, err + return 0, pp, err } func getExecPathFromPID(pid uint32) (string, error) { diff --git a/component/process/process_linux.go b/component/process/process_linux.go index 9b1a4844..f8174495 100644 --- a/component/process/process_linux.go +++ b/component/process/process_linux.go @@ -59,14 +59,14 @@ type inetDiagResponse struct { INode uint32 } -func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, string, error) { - inode, uid, err := resolveSocketByNetlink(network, ip, srcPort) +func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string, error) { + uid, inode, err := resolveSocketByNetlink(network, ip, srcPort) if err != nil { - return nil, "", err + return 0, "", err } pp, err := resolveProcessNameByProcSearch(inode, uid) - return &uid, pp, err + return uid, pp, err } func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uint32, uint32, error) { @@ -119,7 +119,7 @@ func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uint32, response := (*inetDiagResponse)(unsafe.Pointer(&msg.Data[0])) - return response.INode, response.UID, nil + return response.UID, response.INode, nil } return 0, 0, ErrNotFound diff --git a/component/process/process_other.go b/component/process/process_other.go index 32614b26..eea6e5fd 100644 --- a/component/process/process_other.go +++ b/component/process/process_other.go @@ -4,8 +4,8 @@ package process import "net/netip" -func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, string, error) { - return nil, "", ErrPlatformNotSupport +func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string, error) { + return 0, "", ErrPlatformNotSupport } func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (uint32, uint32, error) { diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 7e073c8e..cce08e30 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -62,7 +62,7 @@ func initWin32API() error { return nil } -func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string, error) { once.Do(func() { err := initWin32API() if err != nil { @@ -86,22 +86,22 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (*uint32, strin fn = getExUDPTable class = udpTablePid default: - return nil, "", ErrInvalidNetwork + return 0, "", ErrInvalidNetwork } buf, err := getTransportTable(fn, family, class) if err != nil { - return nil, "", err + return 0, "", err } s := newSearcher(family == windows.AF_INET, network == TCP) pid, err := s.Search(buf, ip, uint16(srcPort)) if err != nil { - return nil, "", err + return 0, "", err } pp, err := getExecPathFromPID(pid) - return nil, pp, err + return 0, pp, err } type searcher struct { diff --git a/constant/metadata.go b/constant/metadata.go index 359329f9..4605a146 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -128,7 +128,7 @@ type Metadata struct { InName string `json:"inboundName"` Host string `json:"host"` DNSMode DNSMode `json:"dnsMode"` - Uid *uint32 `json:"uid"` + Uid uint32 `json:"uid"` Process string `json:"process"` ProcessPath string `json:"processPath"` SpecialProxy string `json:"specialProxy"` @@ -149,13 +149,14 @@ func (m *Metadata) SourceDetail() string { return fmt.Sprintf("[%s]", ClashName) } - if m.Process != "" && m.Uid != nil { - return fmt.Sprintf("%s(%s, uid=%d)", m.SourceAddress(), m.Process, *m.Uid) - } else if m.Uid != nil { - return fmt.Sprintf("%s(uid=%d)", m.SourceAddress(), *m.Uid) - } else if m.Process != "" { + switch { + case m.Process != "" && m.Uid != 0: + return fmt.Sprintf("%s(%s, uid=%d)", m.SourceAddress(), m.Process, m.Uid) + case m.Uid != 0: + return fmt.Sprintf("%s(uid=%d)", m.SourceAddress(), m.Uid) + case m.Process != "": return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process) - } else { + default: return fmt.Sprintf("%s", m.SourceAddress()) } } diff --git a/rules/common/uid.go b/rules/common/uid.go index 1457a3d0..ea275c28 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -3,7 +3,6 @@ package common import ( "fmt" "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/process" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "runtime" @@ -72,27 +71,14 @@ func (u *Uid) RuleType() C.RuleType { } func (u *Uid) Match(metadata *C.Metadata) (bool, string) { - srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16) - if err != nil { - return false, "" - } - var uid *uint32 - if metadata.Uid != nil { - uid = metadata.Uid - } else if uid, err = process.FindUid(metadata.NetWork.String(), metadata.SrcIP, int(srcPort)); err == nil { - metadata.Uid = uid - } else { - log.Warnln("[UID] could not get uid from %s", metadata.String()) - return false, "" - } - - if uid != nil { - for _, _uid := range u.uids { - if _uid.Contains(*uid) { + if metadata.Uid != 0 { + for _, uid := range u.uids { + if uid.Contains(metadata.Uid) { return true, u.adapter } } } + log.Warnln("[UID] could not get uid from %s", metadata.String()) return false, "" } @@ -103,3 +89,7 @@ func (u *Uid) Adapter() string { func (u *Uid) Payload() string { return u.oUid } + +func (u *Uid) ShouldFindProcess() bool { + return true +} From 3b6fc1c49694f40c69db549130a759ee31b6f206 Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 14 Jan 2023 02:27:44 +0800 Subject: [PATCH 003/126] chore: adjust the case of Program names and HttpRequest UA --- component/http/http.go | 2 +- constant/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/component/http/http.go b/component/http/http.go index 5f7968f6..54a3daa9 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -13,7 +13,7 @@ import ( ) const ( - UA = "Clash" + UA = "clash.meta" ) func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { diff --git a/constant/version.go b/constant/version.go index 8bc7e2f7..cbb7ab61 100644 --- a/constant/version.go +++ b/constant/version.go @@ -4,5 +4,5 @@ var ( Meta = true Version = "1.10.0" BuildTime = "unknown time" - ClashName = "Clash.Meta" + ClashName = "clash.meta" ) From 606e8948c0dd1f72757bbfd0c9339ab9982510ef Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 14 Jan 2023 16:20:58 +0800 Subject: [PATCH 004/126] Fix: TLS defaults to true for h2/grpc networks --- adapter/outbound/vmess.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 26ed400e..54e5f865 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -367,7 +367,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { switch option.Network { case "h2", "grpc": if !option.TLS { - return nil, fmt.Errorf("TLS must be true with h2/grpc network") + option.TLS = true } } From 2095f4f6709ac928614ed5812b5a1cfbffd0b731 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 14 Jan 2023 18:10:22 +0800 Subject: [PATCH 005/126] chore: update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e7ee7ab9..d8801262 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ vendor # test suite test/config/cache* /output -/.vscode \ No newline at end of file +.vscode/ +.fleet/ \ No newline at end of file From b6b6413d0406d18692d70a72aed2d81621346e53 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 14 Jan 2023 21:08:06 +0800 Subject: [PATCH 006/126] refactor: replace experimental.fingerprints with custom-certificates and Change the fingerprint verification logic to SSL pinning --- adapter/outbound/http.go | 2 +- adapter/outbound/hysteria.go | 2 +- adapter/outbound/shadowsocks.go | 2 +- adapter/outbound/socks5.go | 2 +- adapter/outbound/trojan.go | 2 +- adapter/outbound/tuic.go | 2 +- adapter/outbound/vless.go | 4 +- adapter/outbound/vmess.go | 2 +- component/tls/config.go | 133 +++++++++++++--------------- config/config.go | 8 +- dns/client.go | 2 +- dns/doh.go | 2 +- dns/doq.go | 2 +- hub/executor/executor.go | 9 +- hub/hub.go | 4 +- transport/trojan/trojan.go | 4 +- transport/v2ray-plugin/websocket.go | 2 +- transport/vless/xtls.go | 2 +- transport/vmess/tls.go | 2 +- 19 files changed, 91 insertions(+), 97 deletions(-) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 088dd8ff..720dc3e1 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -150,7 +150,7 @@ func NewHttp(option HttpOption) (*Http, error) { sni = option.SNI } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(&tls.Config{ + tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ InsecureSkipVerify: option.SkipCertVerify, ServerName: sni, }) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 9d32cb33..bd75cc3c 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -178,7 +178,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { return nil, err } } else { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 3e04b6ef..54566666 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -223,7 +223,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } if len(shadowTLSOpt.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, shadowTLSOpt.Fingerprint); err != nil { return nil, err diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index c76707c3..d40a6bff 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -167,7 +167,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 99c49345..c401999f 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -268,7 +268,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 3bd750c1..417339be 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -143,7 +143,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { return nil, err } } else { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index a0d711cb..449663f7 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -98,7 +98,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + wsOpts.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) } @@ -522,7 +522,7 @@ func NewVless(option VlessOption) (*Vless, error) { ServiceName: v.option.GrpcOpts.GrpcServiceName, Host: v.option.ServerName, } - tlsConfig := tlsC.GetGlobalFingerprintTLSConfig(&tls.Config{ + tlsConfig := tlsC.GetGlobalTLSConfig(&tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, ServerName: v.option.ServerName, }) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 54e5f865..999e1283 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -115,7 +115,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + wsOpts.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { if wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint); err != nil { return nil, err diff --git a/component/tls/config.go b/component/tls/config.go index 6f5b1107..14e5b20d 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -6,63 +6,57 @@ import ( "crypto/tls" "crypto/x509" "encoding/hex" + "errors" "fmt" + "strings" "sync" - "time" + + CN "github.com/Dreamacro/clash/common/net" xtls "github.com/xtls/go" ) -var globalFingerprints = make([][32]byte, 0) -var mutex sync.Mutex +var tlsCertificates = make([]tls.Certificate, 0) -func verifyPeerCertificateAndFingerprints(fingerprints *[][32]byte, insecureSkipVerify bool) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { +var mutex sync.RWMutex +var errNotMacth error = errors.New("certificate fingerprints do not match") + +func AddCertificate(privateKey, certificate string) error { + mutex.Lock() + defer mutex.Unlock() + if cert, err := CN.ParseCert(certificate, privateKey); err != nil { + return err + } else { + tlsCertificates = append(tlsCertificates, cert) + } + return nil +} + +func GetCertificates() []tls.Certificate { + mutex.RLock() + defer mutex.RUnlock() + return tlsCertificates +} + +func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { - if insecureSkipVerify { - return nil - } - - var preErr error + // ssl pining for i := range rawCerts { rawCert := rawCerts[i] cert, err := x509.ParseCertificate(rawCert) if err == nil { - opts := x509.VerifyOptions{ - CurrentTime: time.Now(), - } - - if _, err := cert.Verify(opts); err == nil { + hash := sha256.Sum256(cert.Raw) + if bytes.Equal(fingerprint[:], hash[:]) { return nil - } else { - fingerprint := sha256.Sum256(cert.Raw) - for _, fp := range *fingerprints { - if bytes.Equal(fingerprint[:], fp[:]) { - return nil - } - } - - preErr = err } } } - - return preErr + return errNotMacth } } -func AddCertFingerprint(fingerprint string) error { - fpByte, err2 := convertFingerprint(fingerprint) - if err2 != nil { - return err2 - } - - mutex.Lock() - globalFingerprints = append(globalFingerprints, *fpByte) - mutex.Unlock() - return nil -} - func convertFingerprint(fingerprint string) (*[32]byte, error) { + fingerprint = strings.TrimSpace(strings.Replace(fingerprint, ":", "", -1)) fpByte, err := hex.DecodeString(fingerprint) if err != nil { return nil, err @@ -75,7 +69,7 @@ func convertFingerprint(fingerprint string) (*[32]byte, error) { } func GetDefaultTLSConfig() *tls.Config { - return GetGlobalFingerprintTLSConfig(nil) + return GetGlobalTLSConfig(nil) } // GetSpecifiedFingerprintTLSConfig specified fingerprint @@ -83,33 +77,20 @@ func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { return nil, err } else { - if tlsConfig == nil { - return &tls.Config{ - InsecureSkipVerify: true, - VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, false), - }, nil - } else { - tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, tlsConfig.InsecureSkipVerify) - tlsConfig.InsecureSkipVerify = true - return tlsConfig, nil - } + tlsConfig = GetGlobalTLSConfig(tlsConfig) + tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) + tlsConfig.InsecureSkipVerify = true + return tlsConfig, nil } } -func GetGlobalFingerprintTLSConfig(tlsConfig *tls.Config) *tls.Config { - // If there's at least one fingerprint then we could skip the general check - // If there's no fingerprints but the config insists then we should skip. - // Otherwise we should do a general verification. - shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify +func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { if tlsConfig == nil { return &tls.Config{ - InsecureSkipVerify: shouldSkipVerify, - VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false), + Certificates: tlsCertificates, } } - - tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify) - tlsConfig.InsecureSkipVerify = shouldSkipVerify + tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCertificates...) return tlsConfig } @@ -118,29 +99,37 @@ func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint strin if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { return nil, err } else { - if tlsConfig == nil { - return &xtls.Config{ - InsecureSkipVerify: true, - VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, false), - }, nil - } else { - tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, tlsConfig.InsecureSkipVerify) + tlsConfig=GetGlobalXTLSConfig(tlsConfig) + tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) tlsConfig.InsecureSkipVerify = true return tlsConfig, nil - } } } -func GetGlobalFingerprintXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { - shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify +func GetGlobalXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { + xtlsCerts := make([]xtls.Certificate, len(tlsCertificates)) + for _, cert := range tlsCertificates { + tlsSsaList := make([]xtls.SignatureScheme, len(cert.SupportedSignatureAlgorithms)) + for _, ssa := range cert.SupportedSignatureAlgorithms { + tlsSsa := xtls.SignatureScheme(ssa) + tlsSsaList = append(tlsSsaList, tlsSsa) + } + xtlsCert := xtls.Certificate{ + Certificate: cert.Certificate, + PrivateKey: cert.PrivateKey, + OCSPStaple: cert.OCSPStaple, + SignedCertificateTimestamps: cert.SignedCertificateTimestamps, + Leaf: cert.Leaf, + SupportedSignatureAlgorithms: tlsSsaList, + } + xtlsCerts = append(xtlsCerts, xtlsCert) + } if tlsConfig == nil { return &xtls.Config{ - InsecureSkipVerify: shouldSkipVerify, - VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false), + Certificates: xtlsCerts, } } - tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify) - tlsConfig.InsecureSkipVerify = shouldSkipVerify + tlsConfig.Certificates = xtlsCerts return tlsConfig } diff --git a/config/config.go b/config/config.go index e2250e8a..43ff5872 100644 --- a/config/config.go +++ b/config/config.go @@ -4,7 +4,6 @@ import ( "container/list" "errors" "fmt" - P "github.com/Dreamacro/clash/component/process" "net" "net/netip" "net/url" @@ -14,6 +13,8 @@ import ( "strings" "time" + P "github.com/Dreamacro/clash/component/process" + "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outboundgroup" @@ -116,6 +117,11 @@ type Profile struct { } type TLS struct { + RawCert + CustomTrustCert []RawCert `yaml:"custom-certifactes"` +} + +type RawCert struct { Certificate string `yaml:"certificate"` PrivateKey string `yaml:"private-key"` } diff --git a/dns/client.go b/dns/client.go index 30fd25c8..fe9362bb 100644 --- a/dns/client.go +++ b/dns/client.go @@ -78,7 +78,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) ch := make(chan result, 1) go func() { if strings.HasSuffix(c.Client.Net, "tls") { - conn = tls.Client(conn, tlsC.GetGlobalFingerprintTLSConfig(c.Client.TLSConfig)) + conn = tls.Client(conn, tlsC.GetGlobalTLSConfig(c.Client.TLSConfig)) } msg, _, err := c.Client.ExchangeWithConn(m, &D.Conn{ diff --git a/dns/doh.go b/dns/doh.go index ca694fb9..5abd0479 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -374,7 +374,7 @@ func (doh *dnsOverHTTPS) createClient(ctx context.Context) (*http.Client, error) // HTTP3 is enabled in the upstream options). If this attempt is successful, // it returns an HTTP3 transport, otherwise it returns the H1/H2 transport. func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripper, err error) { - tlsConfig := tlsC.GetGlobalFingerprintTLSConfig( + tlsConfig := tlsC.GetGlobalTLSConfig( &tls.Config{ InsecureSkipVerify: false, MinVersion: tls.VersionTLS12, diff --git a/dns/doq.go b/dns/doq.go index 85c3a85c..1097b500 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -298,7 +298,7 @@ func (doq *dnsOverQUIC) openStream(ctx context.Context, conn quic.Connection) (q // openConnection opens a new QUIC connection. func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connection, err error) { - tlsConfig := tlsC.GetGlobalFingerprintTLSConfig( + tlsConfig := tlsC.GetGlobalTLSConfig( &tls.Config{ InsecureSkipVerify: false, NextProtos: []string{ diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 55786864..be682f36 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -18,7 +18,7 @@ import ( "github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/resolver" SNI "github.com/Dreamacro/clash/component/sniffer" - "github.com/Dreamacro/clash/component/tls" + CTLS "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" @@ -146,10 +146,9 @@ func updateExperimental(c *config.Config) { } func preUpdateExperimental(c *config.Config) { - for _, fingerprint := range c.Experimental.Fingerprints { - if err := tls.AddCertFingerprint(fingerprint); err != nil { - log.Warnln("fingerprint[%s] is err, %s", fingerprint, err.Error()) - } + CTLS.AddCertificate(c.TLS.PrivateKey, c.TLS.Certificate) + for _, c := range c.TLS.CustomTrustCert { + CTLS.AddCertificate(c.PrivateKey, c.Certificate) } } diff --git a/hub/hub.go b/hub/hub.go index ee18e70a..1e925bfe 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -42,8 +42,8 @@ func Parse(options ...Option) error { } if cfg.General.ExternalController != "" { - go route.Start(cfg.General.ExternalController,cfg.General.ExternalControllerTLS, - cfg.General.Secret,cfg.TLS.Certificate,cfg.TLS.PrivateKey) + go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS, + cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey) } executor.ApplyConfig(cfg, true) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 561f8765..ca7b9425 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -82,7 +82,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } if len(t.option.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalFingerprintXTLSConfig(xtlsConfig) + xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) } else { var err error if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, t.option.Fingerprint); err != nil { @@ -107,7 +107,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } if len(t.option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); err != nil { diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 56b0e481..7c2c8a88 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -43,7 +43,7 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { NextProtos: []string{"http/1.1"}, } if len(option.Fingerprint) == 0 { - config.TLSConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + config.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { var err error if config.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index 0b461c56..a1aea44f 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -23,7 +23,7 @@ func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { NextProtos: cfg.NextProtos, } if len(cfg.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalFingerprintXTLSConfig(xtlsConfig) + xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) } else { var err error if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, cfg.Fingerprint); err != nil { diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 8ac80ce6..02442771 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -24,7 +24,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { } if len(cfg.FingerPrint) == 0 { - tlsConfig = tlsC.GetGlobalFingerprintTLSConfig(tlsConfig) + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { var err error if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, cfg.FingerPrint); err != nil { From 27ceae580a9eb85147858bca2d000549845191df Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 14 Jan 2023 21:34:26 +0800 Subject: [PATCH 007/126] chore: update config.yaml --- docs/config.yaml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 27be2ce7..a55aa9b2 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -26,11 +26,7 @@ external-ui: /path/to/ui/folder # 配置WEB UI目录,使用http://{{external-c # routing-mark: 6666 # 配置 fwmark 仅用于Linux experimental: - # 具体配置待定 - # 证书指纹,SHA256格式,补充校验TLS证书 - # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 - fingerprints: - - "8F111FA9AD3CD8E917A118522CAC39EA33741B3BBE73F91CECE548D5CCB0E5E8" # 忽略大小写 + # 类似于 /etc/hosts, 仅支持配置单个 IP hosts: # '*.clash.dev': 127.0.0.1 @@ -121,7 +117,7 @@ tunnels: - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn # full yaml config - - network: [ tcp, udp ] + - network: [tcp, udp] address: 127.0.0.1:7777 target: target.com proxy: proxy @@ -250,6 +246,8 @@ proxies: plugin-opts: mode: websocket # no QUIC now # tls: true # wss + # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 + # 配置指纹将实现 SSL Pining 效果 # fingerprint: xxxx # skip-cert-verify: true # host: bing.com @@ -673,6 +671,11 @@ sub-rules: tls: certificate: string # 证书 PEM 格式,或者 证书的路径 private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 + # 自定义证书验证,将加入 Clash 证书验证中,绝大多数 TLS 相关支持,如:DNS + # 可用于自定义证书的验证 + custom-certificates: + - certificate: string # 证书 PEM 格式,或者 证书的路径 + private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 # 流量入站 listeners: @@ -757,7 +760,7 @@ listeners: listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - network: [ tcp, udp ] + network: [tcp, udp] target: target.com - name: tun-in-1 @@ -801,4 +804,3 @@ listeners: # - com.android.chrome # exclude_package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin - From 5dd691aa959ba98bbc8b1076d3088ec440acf7d3 Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 14 Jan 2023 21:37:06 +0800 Subject: [PATCH 008/126] fix: ss converter cipher missing --- common/convert/converter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/convert/converter.go b/common/convert/converter.go index 89b4d95f..891f43bb 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -272,7 +272,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { cipher string password string ) - + cipher = cipherRaw if password, found = urlSS.User.Password(); !found { dcBuf, _ := enc.DecodeString(cipherRaw) cipher, password, found = strings.Cut(string(dcBuf), ":") From 8a9b3b3d59e41d64e04cd5e4de6e5629252a44bb Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 14 Jan 2023 22:34:54 +0800 Subject: [PATCH 009/126] fix: config parse error --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 43ff5872..e20c8540 100644 --- a/config/config.go +++ b/config/config.go @@ -117,7 +117,7 @@ type Profile struct { } type TLS struct { - RawCert + RawCert `yaml:",inline"` CustomTrustCert []RawCert `yaml:"custom-certifactes"` } From 2c80155c6f68b5be211267d62a71d123869e2b82 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 15 Jan 2023 01:46:30 +0800 Subject: [PATCH 010/126] Update Makefile add CGO support for release build add release.sh --- .github/workflows/prerelease.yml | 57 ++++++++++++++++++++++++++++---- Makefile | 21 ++++++++++-- release.sh | 37 +++++++++++++++++++++ 3 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 release.sh diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 4a792eaa..b5cbb781 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -10,12 +10,36 @@ on: - Alpha - Beta jobs: - Build: - runs-on: ubuntu-latest + Build-Prerelease: + permissions: write-all + runs-on: ubuntu-22.04 + steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 + - name: Set variables + if: ${{ github.ref_name }} == Alpha + run: echo "VERSION=master" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{ github.ref_name }} == Beta + run: echo "VERSION=alpha" >> $GITHUB_ENV + shell: bash + + - name: Set ENV + run: | + echo "NAME=clash.meta" >> $GITHUB_ENV + echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV + echo "REPO=${{ github.repository }}" >> $GITHUB_ENV + echo "TARGET=windows/*,linux/*,darwin-10.16/*" >> $GITHUB_ENV + echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV + echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV + echo "$ShortSHA" + echo "$REPO" + shell: bash + - name: Setup Go uses: actions/setup-go@v3 with: @@ -23,17 +47,38 @@ jobs: check-latest: true cache: true - - name: Test + - uses: nttld/setup-ndk@v1 + id: setup-ndk + with: + ndk-version: r25b + add-to-path: false + + - name: Go Test if: ${{github.ref_name=='Beta'}} run: | go test ./... + - name: Set up xgo + run: | + docker pull techknowlogick/xgo:latest + go install src.techknowlogick.com/xgo@latest + - name: Build if: success() env: - NAME: Clash.Meta - BINDIR: bin - run: make -j$(($(nproc) + 1)) releases + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + run: | + mkdir bin + make android-arm64 + make xgoall + cp release.sh ./bin/ + cd bin + ls -la + chmod +x * + bash ./release.sh + rm ./release.sh + ls -la + cd .. - name: Delete current release assets uses: andreaswilli/delete-release-assets-action@v2.0.0 diff --git a/Makefile b/Makefile index e23fa2d3..78e4cd4f 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,23 @@ all:linux-amd64 linux-arm64\ darwin-amd64 darwin-arm64\ windows-amd64 windows-arm64\ +xgoTarget = windows/*,linux/*,darwin-10.16/* +xgoTags = with_gvisor,with_lwip +Ldflags =-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" -w -s -buildid= + +xgoall: SHELL:=/bin/bash +xgoall: + xgo --branch $(BRANCH) --out=$(BINDIR)/$(NAME) --targets='$(xgoTarget)' --tags='$(xgoTags)' -ldflags='$(Ldflags)' github.com/$(REPO) + + +darwin-all: darwin-amd64 darwin-arm64 + +GOBUILDCGO = CGO_ENABLED=1 go build -tags with_gvisor,with_lwip -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \ + -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ + -w -s -buildid=' + +CCAndroid=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang + docker: GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ @@ -99,7 +116,7 @@ linux-mips64le: GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ android-arm64: - GOARCH=arm64 GOOS=android $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + CC=$(CCAndroid) GOARCH=arm64 GOOS=android $(GOBUILDCGO) -o $(BINDIR)/$(NAME)-$@ freebsd-386: GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ @@ -154,4 +171,4 @@ CFLAGS := -O2 -g -Wall -Werror $(CFLAGS) ebpf: export BPF_CLANG := $(CLANG) ebpf: export BPF_CFLAGS := $(CFLAGS) ebpf: - cd component/ebpf/ && go generate ./... \ No newline at end of file + cd component/ebpf/ && go generate ./... diff --git a/release.sh b/release.sh new file mode 100644 index 00000000..6422207f --- /dev/null +++ b/release.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ $FILENAME =~ "darwin-10.16-arm64" ]];then + echo "rename darwin-10.16-arm64 $FILENAME" + mv $FILENAME clash.meta-darwin-arm64-${VERSION}-${ShortSHA} + elif [[ $FILENAME =~ "darwin-10.16-amd64" ]];then + echo "rename darwin-10.16-amd64 $FILENAME" + mv $FILENAME clash.meta-darwin-amd64-${VERSION}-${ShortSHA} + elif [[ $FILENAME =~ "windows-4.0-386" ]];then + echo "rename windows 386 $FILENAME" + mv $FILENAME clash.meta-windows-386-${VERSION}-${ShortSHA}.exe + elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then + echo "rename windows amd64 $FILENAME" + mv $FILENAME clash.meta-windows-amd64-${VERSION}-${ShortSHA}.exe + elif [[ $FILENAME =~ "linux" ]];then + echo "rename linux $FILENAME" + mv $FILENAME $FILENAME-${VERSION}-${ShortSHA} + elif [[ $FILENAME =~ "android" ]];then + echo "rename android $FILENAME" + mv $FILENAME $FILENAME-${VERSION}-${ShortSHA} + else echo "skip $FILENAME" + fi +done + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then + gzip -S ".gz" $FILENAME + elif [[ $FILENAME =~ ".exe" ]];then + zip -m $FILENAME.zip $FILENAME + else echo "skip $FILENAME" + fi +done \ No newline at end of file From 3b53f5bca32aea81816dbe76803c25dd254e6a6f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 15 Jan 2023 15:04:27 +0800 Subject: [PATCH 011/126] chore: better workflow --- .github/release-cgo-android.sh | 17 +++ .github/release-cgo.sh | 18 +++ release.sh => .github/rename-cgo.sh | 12 +- .github/workflows/prerelease.yml | 174 +++++++++++++++++++++++----- Makefile | 16 +-- 5 files changed, 187 insertions(+), 50 deletions(-) create mode 100644 .github/release-cgo-android.sh create mode 100644 .github/release-cgo.sh rename release.sh => .github/rename-cgo.sh (69%) diff --git a/.github/release-cgo-android.sh b/.github/release-cgo-android.sh new file mode 100644 index 00000000..447efd6e --- /dev/null +++ b/.github/release-cgo-android.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +BRANCH=$(git branch --show-current) +if [ "$BRANCH" = "Alpha" ];then + VERSION=alpha-$(git rev-parse --short HEAD) +elif [ "$BRANCH" = "Beta" ]; then + VERSION=beta-$(git rev-parse --short HEAD) +elif [ "$BRANCH" = "" ]; then + VERSION=$(git describe --tags) +else + VERSION=$(git rev-parse --short HEAD) +fi + +CC=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang +Ldflags="-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" + +CGO_ENABLED=1 go build -tags with_gvisor,with_lwip -trimpath -ldflags "${Ldflags}" -o bin/clash.meta-android-arm64 \ No newline at end of file diff --git a/.github/release-cgo.sh b/.github/release-cgo.sh new file mode 100644 index 00000000..6ceff700 --- /dev/null +++ b/.github/release-cgo.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +BRANCH=$(git branch --show-current) +if [ "$BRANCH" = "Alpha" ];then + VERSION=alpha-$(git rev-parse --short HEAD) +elif [ "$BRANCH" = "Beta" ]; then +VERSION=beta-$(git rev-parse --short HEAD) +elif [ "$BRANCH" = "" ]; then +VERSION=$(git describe --tags) +else +VERSION=$(git rev-parse --short HEAD) +fi + +xgoTarget=windows/*,linux/*,darwin-10.16/* +xgoTags=with_gvisor,with_lwip +Ldflags="-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" + +xgo --branch ${BRANCH} --out=${BINDIR}/${NAME} --targets="${xgoTarget}" --tags="${xgoTags}" -ldflags="${Ldflags}" github.com/${REPO} \ No newline at end of file diff --git a/release.sh b/.github/rename-cgo.sh similarity index 69% rename from release.sh rename to .github/rename-cgo.sh index 6422207f..283f485e 100644 --- a/release.sh +++ b/.github/rename-cgo.sh @@ -5,22 +5,22 @@ for FILENAME in $FILENAMES do if [[ $FILENAME =~ "darwin-10.16-arm64" ]];then echo "rename darwin-10.16-arm64 $FILENAME" - mv $FILENAME clash.meta-darwin-arm64-${VERSION}-${ShortSHA} + mv $FILENAME clash.meta-darwin-arm64-cgo-${VERSION}-${ShortSHA} elif [[ $FILENAME =~ "darwin-10.16-amd64" ]];then echo "rename darwin-10.16-amd64 $FILENAME" - mv $FILENAME clash.meta-darwin-amd64-${VERSION}-${ShortSHA} + mv $FILENAME clash.meta-darwin-amd64-cgo-${VERSION}-${ShortSHA} elif [[ $FILENAME =~ "windows-4.0-386" ]];then echo "rename windows 386 $FILENAME" - mv $FILENAME clash.meta-windows-386-${VERSION}-${ShortSHA}.exe + mv $FILENAME clash.meta-windows-386-cgo-${VERSION}-${ShortSHA}.exe elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then echo "rename windows amd64 $FILENAME" - mv $FILENAME clash.meta-windows-amd64-${VERSION}-${ShortSHA}.exe + mv $FILENAME clash.meta-windows-amd64-cgo-${VERSION}-${ShortSHA}.exe elif [[ $FILENAME =~ "linux" ]];then echo "rename linux $FILENAME" - mv $FILENAME $FILENAME-${VERSION}-${ShortSHA} + mv $FILENAME $FILENAME-cgo-${VERSION}-${ShortSHA} elif [[ $FILENAME =~ "android" ]];then echo "rename android $FILENAME" - mv $FILENAME $FILENAME-${VERSION}-${ShortSHA} + mv $FILENAME $FILENAME-cgo-${VERSION}-${ShortSHA} else echo "skip $FILENAME" fi done diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index b5cbb781..d7357cb6 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -10,7 +10,49 @@ on: - Alpha - Beta jobs: - Build-Prerelease: + Build-Prerelease-WithoutCGO: + runs-on: ubuntu-latest + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: '1.19' + check-latest: true + + - name: Cache go module + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-WithoutCGO-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-WithoutCGO- + ${{ runner.os }}-go- + + - name: Test + if: ${{github.ref_name=='Beta'}} + run: | + go test ./... + + - name: Build + if: success() + env: + NAME: Clash.Meta + BINDIR: bin + run: make -j$(($(nproc) + 1)) releases + + - name: Delete current release assets + uses: andreaswilli/delete-release-assets-action@v2.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + tag: Prerelease-${{ github.ref_name }} + deleteOnlyFromDrafts: false + + Build-Prerelease-WithCGO: permissions: write-all runs-on: ubuntu-22.04 @@ -19,13 +61,13 @@ jobs: uses: actions/checkout@v3 - name: Set variables - if: ${{ github.ref_name }} == Alpha - run: echo "VERSION=master" >> $GITHUB_ENV + if: ${{github.ref_name=='Alpha'}} + run: echo "VERSION=alpha" >> $GITHUB_ENV shell: bash - name: Set variables - if: ${{ github.ref_name }} == Beta - run: echo "VERSION=alpha" >> $GITHUB_ENV + if: ${{github.ref_name=='Beta'}} + run: echo "VERSION=beta" >> $GITHUB_ENV shell: bash - name: Set ENV @@ -33,8 +75,6 @@ jobs: echo "NAME=clash.meta" >> $GITHUB_ENV echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV - echo "TARGET=windows/*,linux/*,darwin-10.16/*" >> $GITHUB_ENV - echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "$ShortSHA" echo "$REPO" @@ -45,18 +85,6 @@ jobs: with: go-version: '1.19' check-latest: true - cache: true - - - uses: nttld/setup-ndk@v1 - id: setup-ndk - with: - ndk-version: r25b - add-to-path: false - - - name: Go Test - if: ${{github.ref_name=='Beta'}} - run: | - go test ./... - name: Set up xgo run: | @@ -69,23 +97,111 @@ jobs: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | mkdir bin - make android-arm64 - make xgoall - cp release.sh ./bin/ + cp .github/release-cgo.sh ./bin/ + cp .github/rename-cgo.sh ./bin/ cd bin ls -la chmod +x * - bash ./release.sh - rm ./release.sh + bash ./release-cgo.sh + rm ./release-cgo.sh + bash ./rename-cgo.sh + rm ./rename-cgo.sh ls -la cd .. - - name: Delete current release assets - uses: andreaswilli/delete-release-assets-action@v2.0.0 + - uses: actions/upload-artifact@v3 + if: ${{ success() }} with: - github_token: ${{ secrets.GITHUB_TOKEN }} - tag: Prerelease-${{ github.ref_name }} - deleteOnlyFromDrafts: false + name: artifact + path: bin/ + + Build-Prerelease-WithCGO-Android: + permissions: write-all + runs-on: ubuntu-22.04 + + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: Set variables + if: ${{github.ref_name=='Alpha'}} + run: echo "VERSION=alpha" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name=='Beta'}} + run: echo "VERSION=beta" >> $GITHUB_ENV + shell: bash + + - name: Set ENV + run: | + echo "NAME=clash.meta" >> $GITHUB_ENV + echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV + echo "REPO=${{ github.repository }}" >> $GITHUB_ENV + echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV + echo "$ShortSHA" + echo "$REPO" + shell: bash + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: '1.19' + check-latest: true + + - name: Cache go module + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-WithCGO-Android-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-WithCGO-Android- + ${{ runner.os }}-go- + + - uses: nttld/setup-ndk@v1 + id: setup-ndk + with: + ndk-version: r25b + add-to-path: false + + - name: Build + if: success() + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + run: | + mkdir bin + cp .github/release-cgo-android.sh ./ + bash ./release-cgo-android.sh + rm ./release-cgo-android.sh + cp .github/rename-cgo.sh ./bin/ + cd bin + ls -la + chmod +x * + bash ./rename-cgo.sh + rm ./rename-cgo.sh + ls -la + cd .. + + - uses: actions/upload-artifact@v3 + if: ${{ success() }} + with: + name: artifact + path: bin/ + + Upload-Prerelease: + needs: [ Build-Prerelease-WithoutCGO, Build-Prerelease-WithCGO, Build-Prerelease-WithCGO-Android ] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: bin/ + + - name: Display structure of downloaded files + run: ls -R + working-directory: bin - name: Tag Repo uses: richardsimko/update-tag@v1 diff --git a/Makefile b/Makefile index 78e4cd4f..9427be29 100644 --- a/Makefile +++ b/Makefile @@ -47,23 +47,9 @@ all:linux-amd64 linux-arm64\ darwin-amd64 darwin-arm64\ windows-amd64 windows-arm64\ -xgoTarget = windows/*,linux/*,darwin-10.16/* -xgoTags = with_gvisor,with_lwip -Ldflags =-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" -w -s -buildid= - -xgoall: SHELL:=/bin/bash -xgoall: - xgo --branch $(BRANCH) --out=$(BINDIR)/$(NAME) --targets='$(xgoTarget)' --tags='$(xgoTags)' -ldflags='$(Ldflags)' github.com/$(REPO) - darwin-all: darwin-amd64 darwin-arm64 -GOBUILDCGO = CGO_ENABLED=1 go build -tags with_gvisor,with_lwip -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \ - -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ - -w -s -buildid=' - -CCAndroid=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang - docker: GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ @@ -116,7 +102,7 @@ linux-mips64le: GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ android-arm64: - CC=$(CCAndroid) GOARCH=arm64 GOOS=android $(GOBUILDCGO) -o $(BINDIR)/$(NAME)-$@ + GOARCH=arm64 GOOS=android $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ freebsd-386: GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ From c0ffa06b951278234f456c5509c75bc3f7036afd Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 15 Jan 2023 14:00:48 +0800 Subject: [PATCH 012/126] chore: Update dependencies --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 3eb1fd91..a0f95e20 100644 --- a/go.mod +++ b/go.mod @@ -26,9 +26,9 @@ require ( github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.0 - github.com/sagernet/sing-vmess v0.1.0 - github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c + github.com/sagernet/sing v0.1.5 + github.com/sagernet/sing-vmess v0.1.1 + github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.35.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 @@ -36,11 +36,11 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a + golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 - golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e + golang.org/x/net v0.3.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 + golang.org/x/sys v0.4.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 @@ -69,7 +69,7 @@ require ( github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/text v0.4.0 // indirect + golang.org/x/text v0.5.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.1.12 // indirect gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect diff --git a/go.sum b/go.sum index cc305000..262b98c1 100644 --- a/go.sum +++ b/go.sum @@ -121,12 +121,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.0 h1:FGmaP2BVPYO2IyC/3R1DaQa/zr+kOKHRgWqrmOF+Gu8= -github.com/sagernet/sing v0.1.0/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4= -github.com/sagernet/sing-vmess v0.1.0 h1:x0tYBJRbVi7zVXpMEW45eApGpXIDs9ub3raglouAKMo= -github.com/sagernet/sing-vmess v0.1.0/go.mod h1:4lwj6EHrUlgRnKhbmtboGbt+wtl5+tHMv96Ez8LZArw= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c h1:qP3ZOHnjZalvqbjundbXiv/YrNlo3HOgrKc+S1QGs0U= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= +github.com/sagernet/sing v0.1.5 h1:1ZHE4cqqds8559RPqzmHiXkOYWyXkNDiULFr00+LxG8= +github.com/sagernet/sing v0.1.5/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing-vmess v0.1.1 h1:WMdkJcc3icIqpDQZGQ7X+jfLilooIZ0zAaC0qeQTWFU= +github.com/sagernet/sing-vmess v0.1.1/go.mod h1:COSSEmy19vMWOTEKIUSDiTEyx6yBfTYIzekDlCMow+Q= +github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= +github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= @@ -160,8 +160,8 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= +golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -181,8 +181,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -211,14 +211,14 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 8fa66c13a9d2470536d8f011ec92eb566a8adc17 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 15 Jan 2023 21:51:33 +0800 Subject: [PATCH 013/126] chore: better workflow --- .github/release-cgo-android.sh | 17 --- .github/release-cgo.sh | 18 --- .github/release.sh | 26 ++++ .github/rename-cgo.sh | 23 +--- .github/workflows/prerelease.yml | 204 ++++++++++++++++--------------- 5 files changed, 139 insertions(+), 149 deletions(-) delete mode 100644 .github/release-cgo-android.sh delete mode 100644 .github/release-cgo.sh create mode 100644 .github/release.sh diff --git a/.github/release-cgo-android.sh b/.github/release-cgo-android.sh deleted file mode 100644 index 447efd6e..00000000 --- a/.github/release-cgo-android.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -BRANCH=$(git branch --show-current) -if [ "$BRANCH" = "Alpha" ];then - VERSION=alpha-$(git rev-parse --short HEAD) -elif [ "$BRANCH" = "Beta" ]; then - VERSION=beta-$(git rev-parse --short HEAD) -elif [ "$BRANCH" = "" ]; then - VERSION=$(git describe --tags) -else - VERSION=$(git rev-parse --short HEAD) -fi - -CC=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang -Ldflags="-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" - -CGO_ENABLED=1 go build -tags with_gvisor,with_lwip -trimpath -ldflags "${Ldflags}" -o bin/clash.meta-android-arm64 \ No newline at end of file diff --git a/.github/release-cgo.sh b/.github/release-cgo.sh deleted file mode 100644 index 6ceff700..00000000 --- a/.github/release-cgo.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -BRANCH=$(git branch --show-current) -if [ "$BRANCH" = "Alpha" ];then - VERSION=alpha-$(git rev-parse --short HEAD) -elif [ "$BRANCH" = "Beta" ]; then -VERSION=beta-$(git rev-parse --short HEAD) -elif [ "$BRANCH" = "" ]; then -VERSION=$(git describe --tags) -else -VERSION=$(git rev-parse --short HEAD) -fi - -xgoTarget=windows/*,linux/*,darwin-10.16/* -xgoTags=with_gvisor,with_lwip -Ldflags="-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" - -xgo --branch ${BRANCH} --out=${BINDIR}/${NAME} --targets="${xgoTarget}" --tags="${xgoTags}" -ldflags="${Ldflags}" github.com/${REPO} \ No newline at end of file diff --git a/.github/release.sh b/.github/release.sh new file mode 100644 index 00000000..4757cdbe --- /dev/null +++ b/.github/release.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then + gzip -S ".gz" $FILENAME + elif [[ $FILENAME =~ ".exe" ]];then + zip -m ${FILENAME%.*}.zip $FILENAME + else echo "skip $FILENAME" + fi +done + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ $FILENAME =~ ".zip" ]];then + echo "rename $FILENAME" + mv $FILENAME ${FILENAME%.*}-${VERSION}.zip + elif [[ $FILENAME =~ ".gz" ]];then + echo "rename $FILENAME" + mv $FILENAME ${FILENAME%.*}-${VERSION}.gz + else + echo "skip $FILENAME" + fi +done \ No newline at end of file diff --git a/.github/rename-cgo.sh b/.github/rename-cgo.sh index 283f485e..54841712 100644 --- a/.github/rename-cgo.sh +++ b/.github/rename-cgo.sh @@ -5,33 +5,22 @@ for FILENAME in $FILENAMES do if [[ $FILENAME =~ "darwin-10.16-arm64" ]];then echo "rename darwin-10.16-arm64 $FILENAME" - mv $FILENAME clash.meta-darwin-arm64-cgo-${VERSION}-${ShortSHA} + mv $FILENAME clash.meta-darwin-arm64-cgo elif [[ $FILENAME =~ "darwin-10.16-amd64" ]];then echo "rename darwin-10.16-amd64 $FILENAME" - mv $FILENAME clash.meta-darwin-amd64-cgo-${VERSION}-${ShortSHA} + mv $FILENAME clash.meta-darwin-amd64-cgo elif [[ $FILENAME =~ "windows-4.0-386" ]];then echo "rename windows 386 $FILENAME" - mv $FILENAME clash.meta-windows-386-cgo-${VERSION}-${ShortSHA}.exe + mv $FILENAME clash.meta-windows-386-cgo.exe elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then echo "rename windows amd64 $FILENAME" - mv $FILENAME clash.meta-windows-amd64-cgo-${VERSION}-${ShortSHA}.exe + mv $FILENAME clash.meta-windows-amd64-cgo.exe elif [[ $FILENAME =~ "linux" ]];then echo "rename linux $FILENAME" - mv $FILENAME $FILENAME-cgo-${VERSION}-${ShortSHA} + mv $FILENAME $FILENAME-cgo elif [[ $FILENAME =~ "android" ]];then echo "rename android $FILENAME" - mv $FILENAME $FILENAME-cgo-${VERSION}-${ShortSHA} - else echo "skip $FILENAME" - fi -done - -FILENAMES=$(ls) -for FILENAME in $FILENAMES -do - if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then - gzip -S ".gz" $FILENAME - elif [[ $FILENAME =~ ".exe" ]];then - zip -m $FILENAME.zip $FILENAME + mv $FILENAME $FILENAME-cgo else echo "skip $FILENAME" fi done \ No newline at end of file diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index d7357cb6..25630f35 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -5,36 +5,54 @@ on: branches: - Alpha - Beta - pull_request: + pull_request_target: branches: - Alpha - Beta jobs: Build-Prerelease-WithoutCGO: + permissions: write-all runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + job: + - { target: "linux-amd64 linux-amd64-compatible linux-arm64 linux-armv5 linux-armv6 linux-armv7", id: "1" } + - { target: "linux-mips64 linux-mips64le linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "2" } + - { target: "android-arm64 freebsd-386 freebsd-amd64 freebsd-arm64", id: "3" } + - { target: "windows-amd64-compatible windows-amd64 windows-arm64 windows-arm32v7 windows-386", id: "4" } + - { target: "darwin-amd64 darwin-arm64", id: "5" } steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 + - name: Set variables + run: echo "VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name=='Alpha'}} + run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name=='Beta'}} + run: echo "VERSION=beta-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name==''}} + run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV + shell: bash + - name: Setup Go uses: actions/setup-go@v3 with: go-version: '1.19' check-latest: true - - name: Cache go module - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-WithoutCGO-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-WithoutCGO- - ${{ runner.os }}-go- - - name: Test - if: ${{github.ref_name=='Beta'}} + if: ${{ github.ref_name=='Beta' && matrix.job.id=='5' }} run: | go test ./... @@ -43,69 +61,14 @@ jobs: env: NAME: Clash.Meta BINDIR: bin - run: make -j$(($(nproc) + 1)) releases - - - name: Delete current release assets - uses: andreaswilli/delete-release-assets-action@v2.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - tag: Prerelease-${{ github.ref_name }} - deleteOnlyFromDrafts: false - - Build-Prerelease-WithCGO: - permissions: write-all - runs-on: ubuntu-22.04 - - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v3 - - - name: Set variables - if: ${{github.ref_name=='Alpha'}} - run: echo "VERSION=alpha" >> $GITHUB_ENV - shell: bash - - - name: Set variables - if: ${{github.ref_name=='Beta'}} - run: echo "VERSION=beta" >> $GITHUB_ENV - shell: bash - - - name: Set ENV run: | - echo "NAME=clash.meta" >> $GITHUB_ENV - echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV - echo "REPO=${{ github.repository }}" >> $GITHUB_ENV - echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV - echo "$ShortSHA" - echo "$REPO" - shell: bash - - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.19' - check-latest: true - - - name: Set up xgo - run: | - docker pull techknowlogick/xgo:latest - go install src.techknowlogick.com/xgo@latest - - - name: Build - if: success() - env: - ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - run: | - mkdir bin - cp .github/release-cgo.sh ./bin/ - cp .github/rename-cgo.sh ./bin/ + make -j$(($(nproc) + 1)) ${{ matrix.job.target }} cd bin ls -la chmod +x * - bash ./release-cgo.sh - rm ./release-cgo.sh - bash ./rename-cgo.sh - rm ./rename-cgo.sh + cp ../.github/release.sh ./ + bash ./release.sh + rm ./release.sh ls -la cd .. @@ -115,22 +78,41 @@ jobs: name: artifact path: bin/ - Build-Prerelease-WithCGO-Android: + Build-Prerelease-WithCGO: permissions: write-all runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + job: + - { target: windows/* } + - { target: linux/386,linux/amd64,linux/arm64 } + - { target: linux/arm,linux/arm-6,linux/arm-7,linux/riscv64 } + - { target: linux/mips,linux/mipsle,linux/mips64,linux/mips64le } + - { target: darwin-10.16/* } + - { target: android } steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 + - name: Set variables + run: echo "VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + - name: Set variables if: ${{github.ref_name=='Alpha'}} - run: echo "VERSION=alpha" >> $GITHUB_ENV + run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV shell: bash - name: Set variables if: ${{github.ref_name=='Beta'}} - run: echo "VERSION=beta" >> $GITHUB_ENV + run: echo "VERSION=beta-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name==''}} + run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV shell: bash - name: Set ENV @@ -139,8 +121,13 @@ jobs: echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV - echo "$ShortSHA" - echo "$REPO" + echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV + shell: bash + + - name: Set ENV + run: | + echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV + echo "LDFLAGS=-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV shell: bash - name: Setup Go @@ -149,36 +136,50 @@ jobs: go-version: '1.19' check-latest: true - - name: Cache go module - uses: actions/cache@v3 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-WithCGO-Android-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go-WithCGO-Android- - ${{ runner.os }}-go- - - uses: nttld/setup-ndk@v1 + if: ${{matrix.job.target=='android'}} id: setup-ndk with: ndk-version: r25b add-to-path: false - - name: Build - if: success() + - name: Build Android + if: ${{matrix.job.target=='android'}} env: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | mkdir bin - cp .github/release-cgo-android.sh ./ - bash ./release-cgo-android.sh - rm ./release-cgo-android.sh - cp .github/rename-cgo.sh ./bin/ + CC=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang + CGO_ENABLED=1 CC=${CC} GOARCH=arm64 GOOS=android go build -tags ${TAGS} -trimpath -ldflags "${LDFLAGS}" -o bin/${NAME}-android-arm64 cd bin ls -la chmod +x * + cp ../.github/rename-cgo.sh ./ + bash ./rename-cgo.sh + rm ./rename-cgo.sh + cp ../.github/release.sh ./ + bash ./release.sh + rm ./release.sh + ls -la + cd .. + + - name: Set up xgo + if: ${{matrix.job.target!='android'}} + run: | + docker pull techknowlogick/xgo:latest + go install src.techknowlogick.com/xgo@latest + + - name: Build by xgo + if: ${{matrix.job.target!='android'}} + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + run: | + mkdir bin + xgo --branch ${{ github.ref_name }} --targets="${{ matrix.job.target }}" --tags="${TAGS}" -ldflags="${LDFLAGS}" --out bin/${NAME} github.com/${{ github.repository }} + cd bin + ls -la + chmod +x * + cp ../.github/rename-cgo.sh ./ bash ./rename-cgo.sh rm ./rename-cgo.sh ls -la @@ -190,8 +191,10 @@ jobs: name: artifact path: bin/ + Upload-Prerelease: - needs: [ Build-Prerelease-WithoutCGO, Build-Prerelease-WithCGO, Build-Prerelease-WithCGO-Android ] + permissions: write-all + needs: [ Build-Prerelease-WithoutCGO, Build-Prerelease-WithCGO ] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 @@ -203,8 +206,15 @@ jobs: run: ls -R working-directory: bin + - name: Delete current release assets + uses: andreaswilli/delete-release-assets-action@v2.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + tag: Prerelease-${{ github.ref_name }} + deleteOnlyFromDrafts: false + - name: Tag Repo - uses: richardsimko/update-tag@v1 + uses: richardsimko/update-tag@v1.0.6 with: tag_name: Prerelease-${{ github.ref_name }} env: @@ -218,4 +228,4 @@ jobs: tag_name: Prerelease-${{ github.ref_name }} files: bin/* prerelease: true - generate_release_notes: true + generate_release_notes: true \ No newline at end of file From d1565bb46f903e2a4223071f6191cba9e674d410 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 16 Jan 2023 09:42:03 +0800 Subject: [PATCH 014/126] refactor: Implement extended IO --- adapter/outbound/base.go | 16 ++++-- adapter/outbound/trojan.go | 4 +- common/net/bufconn.go | 25 +++++++++- transport/vless/conn.go | 95 ++++++++++++++++++++++++------------ transport/vmess/websocket.go | 80 ++++++++++++++++++++++++++++++ tunnel/connection.go | 6 ++- tunnel/statistic/tracker.go | 32 +++++++++++- 7 files changed, 219 insertions(+), 39 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index d7ffec5a..03e9e6ca 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -4,12 +4,15 @@ import ( "context" "encoding/json" "errors" - "github.com/gofrs/uuid" "net" "strings" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" + + "github.com/gofrs/uuid" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" ) type Base struct { @@ -166,7 +169,7 @@ func NewBase(opt BaseOption) *Base { } type conn struct { - net.Conn + network.ExtendedConn chain C.Chain actualRemoteDestination string } @@ -185,8 +188,15 @@ func (c *conn) AppendToChains(a C.ProxyAdapter) { c.chain = append(c.chain, a.Name()) } +func (c *conn) Upstream() any { + if wrapper, ok := c.ExtendedConn.(*bufio.ExtendedConnWrapper); ok { + return wrapper.Conn + } + return c.ExtendedConn +} + func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { - return &conn{c, []string{a.Name()}, parseRemoteDestination(a.Addr())} + return &conn{bufio.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} } type packetConn struct { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index c401999f..a36f5f57 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -14,6 +14,8 @@ import ( "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" "github.com/Dreamacro/clash/transport/vless" + + "github.com/sagernet/sing/common/bufio" ) type Trojan struct { @@ -95,7 +97,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) return c, err } err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)) - return c, err + return bufio.NewExtendedConn(c), err } // DialContext implements C.ProxyAdapter diff --git a/common/net/bufconn.go b/common/net/bufconn.go index a50c7f03..bcac11d3 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -3,18 +3,24 @@ package net import ( "bufio" "net" + + "github.com/sagernet/sing/common/buf" + sing_bufio "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" ) +var _ network.ExtendedConn = (*BufferedConn)(nil) + type BufferedConn struct { r *bufio.Reader - net.Conn + network.ExtendedConn } func NewBufferedConn(c net.Conn) *BufferedConn { if bc, ok := c.(*BufferedConn); ok { return bc } - return &BufferedConn{bufio.NewReader(c), c} + return &BufferedConn{bufio.NewReader(c), sing_bufio.NewExtendedConn(c)} } // Reader returns the internal bufio.Reader. @@ -42,3 +48,18 @@ func (c *BufferedConn) UnreadByte() error { func (c *BufferedConn) Buffered() int { return c.r.Buffered() } + +func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { + if c.r.Buffered() > 0 { + _, err = buffer.ReadOnceFrom(c.r) + return + } + return c.ExtendedConn.ReadBuffer(buffer) +} + +func (c *BufferedConn) Upstream() any { + if wrapper, ok := c.ExtendedConn.(*sing_bufio.ExtendedConnWrapper); ok { + return wrapper.Conn + } + return c.ExtendedConn +} diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 5ee69611..72d14d0c 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -1,7 +1,6 @@ package vless import ( - "bytes" "encoding/binary" "errors" "fmt" @@ -9,12 +8,16 @@ import ( "net" "github.com/gofrs/uuid" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) type Conn struct { - net.Conn + network.ExtendedConn dst *DstAddr id *uuid.UUID addons *Addons @@ -23,57 +26,82 @@ type Conn struct { func (vc *Conn) Read(b []byte) (int, error) { if vc.received { - return vc.Conn.Read(b) + return vc.ExtendedConn.Read(b) } if err := vc.recvResponse(); err != nil { return 0, err } vc.received = true - return vc.Conn.Read(b) + return vc.ExtendedConn.Read(b) } -func (vc *Conn) sendRequest() error { - buf := &bytes.Buffer{} +func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { + if vc.received { + return vc.ExtendedConn.ReadBuffer(buffer) + } - buf.WriteByte(Version) // protocol version - buf.Write(vc.id.Bytes()) // 16 bytes of uuid + if err := vc.recvResponse(); err != nil { + return err + } + vc.received = true + return vc.ExtendedConn.ReadBuffer(buffer) +} +func (vc *Conn) sendRequest() (err error) { + requestLen := 1 // protocol version + requestLen += 16 // UUID + requestLen += 1 // addons length + var addonsBytes []byte if vc.addons != nil { - bytes, err := proto.Marshal(vc.addons) + addonsBytes, err = proto.Marshal(vc.addons) if err != nil { return err } - - buf.WriteByte(byte(len(bytes))) - buf.Write(bytes) - } else { - buf.WriteByte(0) // addon data length. 0 means no addon data } + requestLen += len(addonsBytes) + requestLen += 1 // command + if !vc.dst.Mux { + requestLen += 2 // port + requestLen += 1 // addr type + requestLen += len(vc.dst.Addr) + } + _buffer := buf.StackNewSize(requestLen) + defer common.KeepAlive(_buffer) + buffer := common.Dup(_buffer) + defer buffer.Release() + + common.Must( + buffer.WriteByte(Version), // protocol version + common.Error(buffer.Write(vc.id.Bytes())), // 16 bytes of uuid + buffer.WriteByte(byte(len(addonsBytes))), + common.Error(buffer.Write(addonsBytes)), + ) if vc.dst.Mux { - buf.WriteByte(CommandMux) + common.Must(buffer.WriteByte(CommandMux)) } else { if vc.dst.UDP { - buf.WriteByte(CommandUDP) + common.Must(buffer.WriteByte(CommandUDP)) } else { - buf.WriteByte(CommandTCP) + common.Must(buffer.WriteByte(CommandTCP)) } - // Port AddrType Addr - binary.Write(buf, binary.BigEndian, vc.dst.Port) - buf.WriteByte(vc.dst.AddrType) - buf.Write(vc.dst.Addr) + binary.BigEndian.PutUint16(buffer.Extend(2), vc.dst.Port) + common.Must( + buffer.WriteByte(vc.dst.AddrType), + common.Error(buffer.Write(vc.dst.Addr)), + ) } - _, err := vc.Conn.Write(buf.Bytes()) - return err + _, err = vc.ExtendedConn.Write(buffer.Bytes()) + return } func (vc *Conn) recvResponse() error { var err error - buf := make([]byte, 1) - _, err = io.ReadFull(vc.Conn, buf) + var buf [1]byte + _, err = io.ReadFull(vc.ExtendedConn, buf[:]) if err != nil { return err } @@ -82,25 +110,32 @@ func (vc *Conn) recvResponse() error { return errors.New("unexpected response version") } - _, err = io.ReadFull(vc.Conn, buf) + _, err = io.ReadFull(vc.ExtendedConn, buf[:]) if err != nil { return err } length := int64(buf[0]) if length != 0 { // addon data length > 0 - io.CopyN(io.Discard, vc.Conn, length) // just discard + io.CopyN(io.Discard, vc.ExtendedConn, length) // just discard } return nil } +func (vc *Conn) Upstream() any { + if wrapper, ok := vc.ExtendedConn.(*bufio.ExtendedConnWrapper); ok { + return wrapper.Conn + } + return vc.ExtendedConn +} + // newConn return a Conn instance func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { c := &Conn{ - Conn: conn, - id: client.uuid, - dst: dst, + ExtendedConn: bufio.NewExtendedConn(conn), + id: client.uuid, + dst: dst, } if !dst.UDP && client.Addons != nil { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index b7b369fd..735ea7f2 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -5,9 +5,11 @@ import ( "context" "crypto/tls" "encoding/base64" + "encoding/binary" "errors" "fmt" "io" + "math/rand" "net" "net/http" "net/url" @@ -15,15 +17,24 @@ import ( "strings" "sync" "time" + _ "unsafe" "github.com/gorilla/websocket" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" ) +//go:linkname maskBytes github.com/gorilla/websocket.maskBytes +func maskBytes(key [4]byte, pos int, b []byte) int + type websocketConn struct { conn *websocket.Conn reader io.Reader remoteAddr net.Addr + rawWriter network.ExtendedWriter + // https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency rMux sync.Mutex wMux sync.Mutex @@ -31,6 +42,7 @@ type websocketConn struct { type websocketWithEarlyDataConn struct { net.Conn + wsWriter network.ExtendedWriter underlay net.Conn closed bool dialed chan bool @@ -79,6 +91,54 @@ func (wsc *websocketConn) Write(b []byte) (int, error) { return len(b), nil } +func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { + var payloadBitLength int + dataLen := buffer.Len() + data := buffer.Bytes() + if dataLen < 126 { + payloadBitLength = 1 + } else if dataLen < 65536 { + payloadBitLength = 3 + } else { + payloadBitLength = 9 + } + + var headerLen int + headerLen += 1 // FIN / RSV / OPCODE + headerLen += payloadBitLength + headerLen += 4 // MASK KEY + + header := buffer.ExtendHeader(headerLen) + header[0] = websocket.BinaryMessage | 1<<7 + header[1] = 1 << 7 + + if dataLen < 126 { + header[1] |= byte(dataLen) + } else if dataLen < 65536 { + header[1] |= 126 + binary.BigEndian.PutUint16(header[2:], uint16(dataLen)) + } else { + header[1] |= 127 + binary.BigEndian.PutUint64(header[2:], uint64(dataLen)) + } + + maskKey := rand.Uint32() + binary.BigEndian.PutUint32(header[1+payloadBitLength:], maskKey) + maskBytes(*(*[4]byte)(header[1+payloadBitLength:]), 0, data) + + wsc.wMux.Lock() + defer wsc.wMux.Unlock() + return wsc.rawWriter.WriteBuffer(buffer) +} + +func (wsc *websocketConn) FrontHeadroom() int { + return 14 +} + +func (wsc *websocketConn) Upstream() any { + return wsc.conn.UnderlyingConn() +} + func (wsc *websocketConn) Close() error { var errors []string if err := wsc.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5)); err != nil { @@ -149,6 +209,7 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { } wsedc.dialed <- true + wsedc.wsWriter = bufio.NewExtendedWriter(wsedc.Conn) if earlyDataBuf.Len() != 0 { _, err = wsedc.Conn.Write(earlyDataBuf.Bytes()) } @@ -170,6 +231,20 @@ func (wsedc *websocketWithEarlyDataConn) Write(b []byte) (int, error) { return wsedc.Conn.Write(b) } +func (wsedc *websocketWithEarlyDataConn) WriteBuffer(buffer *buf.Buffer) error { + if wsedc.closed { + return io.ErrClosedPipe + } + if wsedc.Conn == nil { + if err := wsedc.Dial(buffer.Bytes()); err != nil { + return err + } + return nil + } + + return wsedc.wsWriter.WriteBuffer(buffer) +} + func (wsedc *websocketWithEarlyDataConn) Read(b []byte) (int, error) { if wsedc.closed { return 0, io.ErrClosedPipe @@ -228,6 +303,10 @@ func (wsedc *websocketWithEarlyDataConn) SetWriteDeadline(t time.Time) error { return wsedc.Conn.SetWriteDeadline(t) } +func (wsedc *websocketWithEarlyDataConn) Upstream() any { + return wsedc.Conn +} + func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { ctx, cancel := context.WithCancel(context.Background()) conn = &websocketWithEarlyDataConn{ @@ -294,6 +373,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf return &websocketConn{ conn: wsConn, + rawWriter: bufio.NewExtendedWriter(wsConn.UnderlyingConn()), remoteAddr: conn.RemoteAddr(), }, nil } diff --git a/tunnel/connection.go b/tunnel/connection.go index c63bab78..1747597e 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -1,14 +1,16 @@ package tunnel import ( + "context" "errors" "net" "net/netip" "time" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" + + "github.com/sagernet/sing/common/bufio" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { @@ -60,5 +62,5 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } func handleSocket(ctx C.ConnContext, outbound net.Conn) { - N.Relay(ctx.Conn(), outbound) + bufio.CopyConn(context.TODO(), ctx.Conn(), outbound) } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index fc627297..32d44f0c 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -7,6 +7,9 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" "go.uber.org/atomic" ) @@ -29,7 +32,9 @@ type trackerInfo struct { type tcpTracker struct { C.Conn `json:"-"` *trackerInfo - manager *Manager + manager *Manager + extendedReader network.ExtendedReader + extendedWriter network.ExtendedWriter } func (tt *tcpTracker) ID() string { @@ -44,6 +49,14 @@ func (tt *tcpTracker) Read(b []byte) (int, error) { return n, err } +func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) { + err = tt.extendedReader.ReadBuffer(buffer) + download := int64(buffer.Len()) + tt.manager.PushDownloaded(download) + tt.DownloadTotal.Add(download) + return +} + func (tt *tcpTracker) Write(b []byte) (int, error) { n, err := tt.Conn.Write(b) upload := int64(n) @@ -52,11 +65,26 @@ func (tt *tcpTracker) Write(b []byte) (int, error) { return n, err } +func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) { + err = tt.extendedWriter.WriteBuffer(buffer) + var upload int64 + if err != nil { + upload = int64(buffer.Len()) + } + tt.manager.PushUploaded(upload) + tt.UploadTotal.Add(upload) + return +} + func (tt *tcpTracker) Close() error { tt.manager.Leave(tt) return tt.Conn.Close() } +func (tt *tcpTracker) Upstream() any { + return tt.Conn +} + func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) *tcpTracker { uuid, _ := uuid.NewV4() if conn != nil { @@ -79,6 +107,8 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R UploadTotal: atomic.NewInt64(0), DownloadTotal: atomic.NewInt64(0), }, + extendedReader: bufio.NewExtendedReader(conn), + extendedWriter: bufio.NewExtendedWriter(conn), } if rule != nil { From 643fdd0bce632229e99e42c4ff0389fecaf28d74 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 09:54:52 +0800 Subject: [PATCH 015/126] chore: tuic decrease unneeded copy --- transport/tuic/protocol.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index ab696e79..a54c8e54 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -454,12 +454,10 @@ func NewAddress(metadata *C.Metadata) Address { switch metadata.AddrType() { case socks5.AtypIPv4: addrType = AtypIPv4 - addr = make([]byte, net.IPv4len) - copy(addr[:], metadata.DstIP.AsSlice()) + addr = metadata.DstIP.AsSlice() case socks5.AtypIPv6: addrType = AtypIPv6 - addr = make([]byte, net.IPv6len) - copy(addr[:], metadata.DstIP.AsSlice()) + addr = metadata.DstIP.AsSlice() case socks5.AtypDomainName: addrType = AtypDomainName addr = make([]byte, len(metadata.Host)+1) @@ -478,18 +476,14 @@ func NewAddress(metadata *C.Metadata) Address { func NewAddressAddrPort(addrPort netip.AddrPort) Address { var addrType byte - var addr []byte if addrPort.Addr().Is4() { addrType = AtypIPv4 - addr = make([]byte, net.IPv4len) } else { addrType = AtypIPv6 - addr = make([]byte, net.IPv6len) } - copy(addr[:], addrPort.Addr().AsSlice()) return Address{ TYPE: addrType, - ADDR: addr, + ADDR: addrPort.Addr().AsSlice(), PORT: addrPort.Port(), } } From 50832aab47ba9cebf37d48f0ada3a9f451a6b646 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 10:50:31 +0800 Subject: [PATCH 016/126] chore: decrease direct depend on the sing package --- adapter/outbound/base.go | 9 ++++---- adapter/outbound/trojan.go | 5 ++-- common/buf/sing.go | 19 ++++++++++++++++ common/net/bufconn.go | 12 ++++------ common/net/relay.go | 44 ++++++++++++++++++------------------ common/net/sing.go | 24 ++++++++++++++++++++ transport/vless/conn.go | 35 ++++++++++++++-------------- transport/vmess/websocket.go | 14 ++++++------ tunnel/connection.go | 6 ++--- tunnel/statistic/tracker.go | 13 +++++------ 10 files changed, 108 insertions(+), 73 deletions(-) create mode 100644 common/buf/sing.go create mode 100644 common/net/sing.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 03e9e6ca..e0efe595 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -7,12 +7,11 @@ import ( "net" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid" - "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/network" ) type Base struct { @@ -169,7 +168,7 @@ func NewBase(opt BaseOption) *Base { } type conn struct { - network.ExtendedConn + N.ExtendedConn chain C.Chain actualRemoteDestination string } @@ -189,14 +188,14 @@ func (c *conn) AppendToChains(a C.ProxyAdapter) { } func (c *conn) Upstream() any { - if wrapper, ok := c.ExtendedConn.(*bufio.ExtendedConnWrapper); ok { + if wrapper, ok := c.ExtendedConn.(*N.ExtendedConnWrapper); ok { return wrapper.Conn } return c.ExtendedConn } func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { - return &conn{bufio.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} + return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} } type packetConn struct { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index a36f5f57..c90ee377 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -8,14 +8,13 @@ import ( "net/http" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" "github.com/Dreamacro/clash/transport/vless" - - "github.com/sagernet/sing/common/bufio" ) type Trojan struct { @@ -97,7 +96,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) return c, err } err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)) - return bufio.NewExtendedConn(c), err + return N.NewExtendedConn(c), err } // DialContext implements C.ProxyAdapter diff --git a/common/buf/sing.go b/common/buf/sing.go new file mode 100644 index 00000000..b5e015f5 --- /dev/null +++ b/common/buf/sing.go @@ -0,0 +1,19 @@ +package buf + +import ( + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" +) + +type Buffer = buf.Buffer + +var StackNewSize = buf.StackNewSize +var KeepAlive = common.KeepAlive + +//go:norace +func Dup[T any](obj T) T { + return common.Dup(obj) +} + +var Must = common.Must +var Error = common.Error diff --git a/common/net/bufconn.go b/common/net/bufconn.go index bcac11d3..b3e3d1f3 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -4,23 +4,21 @@ import ( "bufio" "net" - "github.com/sagernet/sing/common/buf" - sing_bufio "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/network" + "github.com/Dreamacro/clash/common/buf" ) -var _ network.ExtendedConn = (*BufferedConn)(nil) +var _ ExtendedConn = (*BufferedConn)(nil) type BufferedConn struct { r *bufio.Reader - network.ExtendedConn + ExtendedConn } func NewBufferedConn(c net.Conn) *BufferedConn { if bc, ok := c.(*BufferedConn); ok { return bc } - return &BufferedConn{bufio.NewReader(c), sing_bufio.NewExtendedConn(c)} + return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c)} } // Reader returns the internal bufio.Reader. @@ -58,7 +56,7 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { } func (c *BufferedConn) Upstream() any { - if wrapper, ok := c.ExtendedConn.(*sing_bufio.ExtendedConnWrapper); ok { + if wrapper, ok := c.ExtendedConn.(*ExtendedConnWrapper); ok { return wrapper.Conn } return c.ExtendedConn diff --git a/common/net/relay.go b/common/net/relay.go index d4edede2..6191e76b 100644 --- a/common/net/relay.go +++ b/common/net/relay.go @@ -1,24 +1,24 @@ package net -import ( - "io" - "net" - "time" -) - -// Relay copies between left and right bidirectionally. -func Relay(leftConn, rightConn net.Conn) { - ch := make(chan error) - - go func() { - // Wrapping to avoid using *net.TCPConn.(ReadFrom) - // See also https://github.com/Dreamacro/clash/pull/1209 - _, err := io.Copy(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}) - leftConn.SetReadDeadline(time.Now()) - ch <- err - }() - - _, _ = io.Copy(WriteOnlyWriter{Writer: rightConn}, ReadOnlyReader{Reader: leftConn}) - rightConn.SetReadDeadline(time.Now()) - <-ch -} +//import ( +// "io" +// "net" +// "time" +//) +// +//// Relay copies between left and right bidirectionally. +//func Relay(leftConn, rightConn net.Conn) { +// ch := make(chan error) +// +// go func() { +// // Wrapping to avoid using *net.TCPConn.(ReadFrom) +// // See also https://github.com/Dreamacro/clash/pull/1209 +// _, err := io.Copy(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}) +// leftConn.SetReadDeadline(time.Now()) +// ch <- err +// }() +// +// _, _ = io.Copy(WriteOnlyWriter{Writer: rightConn}, ReadOnlyReader{Reader: leftConn}) +// rightConn.SetReadDeadline(time.Now()) +// <-ch +//} diff --git a/common/net/sing.go b/common/net/sing.go new file mode 100644 index 00000000..37ba3f0c --- /dev/null +++ b/common/net/sing.go @@ -0,0 +1,24 @@ +package net + +import ( + "context" + "net" + + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" +) + +type ExtendedConnWrapper = bufio.ExtendedConnWrapper + +var NewExtendedConn = bufio.NewExtendedConn +var NewExtendedWriter = bufio.NewExtendedWriter +var NewExtendedReader = bufio.NewExtendedReader + +type ExtendedConn = network.ExtendedConn +type ExtendedWriter = network.ExtendedWriter +type ExtendedReader = network.ExtendedReader + +// Relay copies between left and right bidirectionally. +func Relay(leftConn, rightConn net.Conn) { + _ = bufio.CopyConn(context.TODO(), leftConn, rightConn) +} diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 72d14d0c..d57f3ae1 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -7,17 +7,16 @@ import ( "io" "net" + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" + "github.com/gofrs/uuid" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/network" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) type Conn struct { - network.ExtendedConn + N.ExtendedConn dst *DstAddr id *uuid.UUID addons *Addons @@ -67,30 +66,30 @@ func (vc *Conn) sendRequest() (err error) { requestLen += len(vc.dst.Addr) } _buffer := buf.StackNewSize(requestLen) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) + defer buf.KeepAlive(_buffer) + buffer := buf.Dup(_buffer) defer buffer.Release() - common.Must( - buffer.WriteByte(Version), // protocol version - common.Error(buffer.Write(vc.id.Bytes())), // 16 bytes of uuid + buf.Must( + buffer.WriteByte(Version), // protocol version + buf.Error(buffer.Write(vc.id.Bytes())), // 16 bytes of uuid buffer.WriteByte(byte(len(addonsBytes))), - common.Error(buffer.Write(addonsBytes)), + buf.Error(buffer.Write(addonsBytes)), ) if vc.dst.Mux { - common.Must(buffer.WriteByte(CommandMux)) + buf.Must(buffer.WriteByte(CommandMux)) } else { if vc.dst.UDP { - common.Must(buffer.WriteByte(CommandUDP)) + buf.Must(buffer.WriteByte(CommandUDP)) } else { - common.Must(buffer.WriteByte(CommandTCP)) + buf.Must(buffer.WriteByte(CommandTCP)) } binary.BigEndian.PutUint16(buffer.Extend(2), vc.dst.Port) - common.Must( + buf.Must( buffer.WriteByte(vc.dst.AddrType), - common.Error(buffer.Write(vc.dst.Addr)), + buf.Error(buffer.Write(vc.dst.Addr)), ) } @@ -124,7 +123,7 @@ func (vc *Conn) recvResponse() error { } func (vc *Conn) Upstream() any { - if wrapper, ok := vc.ExtendedConn.(*bufio.ExtendedConnWrapper); ok { + if wrapper, ok := vc.ExtendedConn.(*N.ExtendedConnWrapper); ok { return wrapper.Conn } return vc.ExtendedConn @@ -133,7 +132,7 @@ func (vc *Conn) Upstream() any { // newConn return a Conn instance func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { c := &Conn{ - ExtendedConn: bufio.NewExtendedConn(conn), + ExtendedConn: N.NewExtendedConn(conn), id: client.uuid, dst: dst, } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 735ea7f2..ce5615d5 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -19,10 +19,10 @@ import ( "time" _ "unsafe" + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" + "github.com/gorilla/websocket" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/network" ) //go:linkname maskBytes github.com/gorilla/websocket.maskBytes @@ -33,7 +33,7 @@ type websocketConn struct { reader io.Reader remoteAddr net.Addr - rawWriter network.ExtendedWriter + rawWriter N.ExtendedWriter // https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency rMux sync.Mutex @@ -42,7 +42,7 @@ type websocketConn struct { type websocketWithEarlyDataConn struct { net.Conn - wsWriter network.ExtendedWriter + wsWriter N.ExtendedWriter underlay net.Conn closed bool dialed chan bool @@ -209,7 +209,7 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { } wsedc.dialed <- true - wsedc.wsWriter = bufio.NewExtendedWriter(wsedc.Conn) + wsedc.wsWriter = N.NewExtendedWriter(wsedc.Conn) if earlyDataBuf.Len() != 0 { _, err = wsedc.Conn.Write(earlyDataBuf.Bytes()) } @@ -373,7 +373,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf return &websocketConn{ conn: wsConn, - rawWriter: bufio.NewExtendedWriter(wsConn.UnderlyingConn()), + rawWriter: N.NewExtendedWriter(wsConn.UnderlyingConn()), remoteAddr: conn.RemoteAddr(), }, nil } diff --git a/tunnel/connection.go b/tunnel/connection.go index 1747597e..c63bab78 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -1,16 +1,14 @@ package tunnel import ( - "context" "errors" "net" "net/netip" "time" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" - - "github.com/sagernet/sing/common/bufio" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { @@ -62,5 +60,5 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } func handleSocket(ctx C.ConnContext, outbound net.Conn) { - bufio.CopyConn(context.TODO(), ctx.Conn(), outbound) + N.Relay(ctx.Conn(), outbound) } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 32d44f0c..c034d75d 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -4,12 +4,11 @@ import ( "net" "time" + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/network" "go.uber.org/atomic" ) @@ -33,8 +32,8 @@ type tcpTracker struct { C.Conn `json:"-"` *trackerInfo manager *Manager - extendedReader network.ExtendedReader - extendedWriter network.ExtendedWriter + extendedReader N.ExtendedReader + extendedWriter N.ExtendedWriter } func (tt *tcpTracker) ID() string { @@ -107,8 +106,8 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R UploadTotal: atomic.NewInt64(0), DownloadTotal: atomic.NewInt64(0), }, - extendedReader: bufio.NewExtendedReader(conn), - extendedWriter: bufio.NewExtendedWriter(conn), + extendedReader: N.NewExtendedReader(conn), + extendedWriter: N.NewExtendedWriter(conn), } if rule != nil { From bec66e9e69fe483a66ecfa5ad8189ebabaad1a9a Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 16 Jan 2023 11:42:10 +0800 Subject: [PATCH 017/126] adjust: Improve WebSocket mask --- common/net/websocket.go | 131 +++++++++++++++++++++++++++++++++++ transport/vmess/websocket.go | 4 +- 2 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 common/net/websocket.go diff --git a/common/net/websocket.go b/common/net/websocket.go new file mode 100644 index 00000000..b002310a --- /dev/null +++ b/common/net/websocket.go @@ -0,0 +1,131 @@ +package net + +import ( + "encoding/binary" + "math/bits" +) + +// kanged from https://github.com/nhooyr/websocket/blob/master/frame.go +// License: MIT + +// MaskWebSocket applies the WebSocket masking algorithm to p +// with the given key. +// See https://tools.ietf.org/html/rfc6455#section-5.3 +// +// The returned value is the correctly rotated key to +// to continue to mask/unmask the message. +// +// It is optimized for LittleEndian and expects the key +// to be in little endian. +// +// See https://github.com/golang/go/issues/31586 +func MaskWebSocket(key uint32, b []byte) uint32 { + if len(b) >= 8 { + key64 := uint64(key)<<32 | uint64(key) + + // At some point in the future we can clean these unrolled loops up. + // See https://github.com/golang/go/issues/31586#issuecomment-487436401 + + // Then we xor until b is less than 128 bytes. + for len(b) >= 128 { + v := binary.LittleEndian.Uint64(b) + binary.LittleEndian.PutUint64(b, v^key64) + v = binary.LittleEndian.Uint64(b[8:16]) + binary.LittleEndian.PutUint64(b[8:16], v^key64) + v = binary.LittleEndian.Uint64(b[16:24]) + binary.LittleEndian.PutUint64(b[16:24], v^key64) + v = binary.LittleEndian.Uint64(b[24:32]) + binary.LittleEndian.PutUint64(b[24:32], v^key64) + v = binary.LittleEndian.Uint64(b[32:40]) + binary.LittleEndian.PutUint64(b[32:40], v^key64) + v = binary.LittleEndian.Uint64(b[40:48]) + binary.LittleEndian.PutUint64(b[40:48], v^key64) + v = binary.LittleEndian.Uint64(b[48:56]) + binary.LittleEndian.PutUint64(b[48:56], v^key64) + v = binary.LittleEndian.Uint64(b[56:64]) + binary.LittleEndian.PutUint64(b[56:64], v^key64) + v = binary.LittleEndian.Uint64(b[64:72]) + binary.LittleEndian.PutUint64(b[64:72], v^key64) + v = binary.LittleEndian.Uint64(b[72:80]) + binary.LittleEndian.PutUint64(b[72:80], v^key64) + v = binary.LittleEndian.Uint64(b[80:88]) + binary.LittleEndian.PutUint64(b[80:88], v^key64) + v = binary.LittleEndian.Uint64(b[88:96]) + binary.LittleEndian.PutUint64(b[88:96], v^key64) + v = binary.LittleEndian.Uint64(b[96:104]) + binary.LittleEndian.PutUint64(b[96:104], v^key64) + v = binary.LittleEndian.Uint64(b[104:112]) + binary.LittleEndian.PutUint64(b[104:112], v^key64) + v = binary.LittleEndian.Uint64(b[112:120]) + binary.LittleEndian.PutUint64(b[112:120], v^key64) + v = binary.LittleEndian.Uint64(b[120:128]) + binary.LittleEndian.PutUint64(b[120:128], v^key64) + b = b[128:] + } + + // Then we xor until b is less than 64 bytes. + for len(b) >= 64 { + v := binary.LittleEndian.Uint64(b) + binary.LittleEndian.PutUint64(b, v^key64) + v = binary.LittleEndian.Uint64(b[8:16]) + binary.LittleEndian.PutUint64(b[8:16], v^key64) + v = binary.LittleEndian.Uint64(b[16:24]) + binary.LittleEndian.PutUint64(b[16:24], v^key64) + v = binary.LittleEndian.Uint64(b[24:32]) + binary.LittleEndian.PutUint64(b[24:32], v^key64) + v = binary.LittleEndian.Uint64(b[32:40]) + binary.LittleEndian.PutUint64(b[32:40], v^key64) + v = binary.LittleEndian.Uint64(b[40:48]) + binary.LittleEndian.PutUint64(b[40:48], v^key64) + v = binary.LittleEndian.Uint64(b[48:56]) + binary.LittleEndian.PutUint64(b[48:56], v^key64) + v = binary.LittleEndian.Uint64(b[56:64]) + binary.LittleEndian.PutUint64(b[56:64], v^key64) + b = b[64:] + } + + // Then we xor until b is less than 32 bytes. + for len(b) >= 32 { + v := binary.LittleEndian.Uint64(b) + binary.LittleEndian.PutUint64(b, v^key64) + v = binary.LittleEndian.Uint64(b[8:16]) + binary.LittleEndian.PutUint64(b[8:16], v^key64) + v = binary.LittleEndian.Uint64(b[16:24]) + binary.LittleEndian.PutUint64(b[16:24], v^key64) + v = binary.LittleEndian.Uint64(b[24:32]) + binary.LittleEndian.PutUint64(b[24:32], v^key64) + b = b[32:] + } + + // Then we xor until b is less than 16 bytes. + for len(b) >= 16 { + v := binary.LittleEndian.Uint64(b) + binary.LittleEndian.PutUint64(b, v^key64) + v = binary.LittleEndian.Uint64(b[8:16]) + binary.LittleEndian.PutUint64(b[8:16], v^key64) + b = b[16:] + } + + // Then we xor until b is less than 8 bytes. + for len(b) >= 8 { + v := binary.LittleEndian.Uint64(b) + binary.LittleEndian.PutUint64(b, v^key64) + b = b[8:] + } + } + + // Then we xor until b is less than 4 bytes. + for len(b) >= 4 { + v := binary.LittleEndian.Uint32(b) + binary.LittleEndian.PutUint32(b, v^key) + b = b[4:] + } + + // xor remaining bytes. + for i := range b { + b[i] ^= byte(key) + key = bits.RotateLeft32(key, -8) + } + + return key +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index ce5615d5..90cd7772 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -123,8 +123,8 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { } maskKey := rand.Uint32() - binary.BigEndian.PutUint32(header[1+payloadBitLength:], maskKey) - maskBytes(*(*[4]byte)(header[1+payloadBitLength:]), 0, data) + binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) + N.MaskWebSocket(maskKey, data) wsc.wMux.Lock() defer wsc.wMux.Unlock() From 4e4d741075e336c500dbe199159b4171291cdd81 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 12:11:34 +0800 Subject: [PATCH 018/126] chore: code cleanup --- adapter/outbound/base.go | 3 --- common/net/bufconn.go | 3 --- common/net/sing.go | 2 -- transport/vless/conn.go | 3 --- transport/vmess/websocket.go | 4 ---- 5 files changed, 15 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index e0efe595..dc339969 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -188,9 +188,6 @@ func (c *conn) AppendToChains(a C.ProxyAdapter) { } func (c *conn) Upstream() any { - if wrapper, ok := c.ExtendedConn.(*N.ExtendedConnWrapper); ok { - return wrapper.Conn - } return c.ExtendedConn } diff --git a/common/net/bufconn.go b/common/net/bufconn.go index b3e3d1f3..9f1dda2b 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -56,8 +56,5 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { } func (c *BufferedConn) Upstream() any { - if wrapper, ok := c.ExtendedConn.(*ExtendedConnWrapper); ok { - return wrapper.Conn - } return c.ExtendedConn } diff --git a/common/net/sing.go b/common/net/sing.go index 37ba3f0c..342f2e95 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -8,8 +8,6 @@ import ( "github.com/sagernet/sing/common/network" ) -type ExtendedConnWrapper = bufio.ExtendedConnWrapper - var NewExtendedConn = bufio.NewExtendedConn var NewExtendedWriter = bufio.NewExtendedWriter var NewExtendedReader = bufio.NewExtendedReader diff --git a/transport/vless/conn.go b/transport/vless/conn.go index d57f3ae1..75eef495 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -123,9 +123,6 @@ func (vc *Conn) recvResponse() error { } func (vc *Conn) Upstream() any { - if wrapper, ok := vc.ExtendedConn.(*N.ExtendedConnWrapper); ok { - return wrapper.Conn - } return vc.ExtendedConn } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 90cd7772..b38c0006 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -17,7 +17,6 @@ import ( "strings" "sync" "time" - _ "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" @@ -25,9 +24,6 @@ import ( "github.com/gorilla/websocket" ) -//go:linkname maskBytes github.com/gorilla/websocket.maskBytes -func maskBytes(key [4]byte, pos int, b []byte) int - type websocketConn struct { conn *websocket.Conn reader io.Reader From a5821e5785cb6a67fe93d60ce2c82e2c9af6701c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 12:28:30 +0800 Subject: [PATCH 019/126] fix: add ReaderReplaceable to BufferedConn, avoid buffered data lost --- common/net/bufconn.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 9f1dda2b..ba0ca026 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -58,3 +58,10 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { func (c *BufferedConn) Upstream() any { return c.ExtendedConn } + +func (c *BufferedConn) ReaderReplaceable() bool { + if c.r.Buffered() > 0 { + return false + } + return true +} From e88bddc24ffa56244875e953adc6e67e1d4f2ae3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 12:47:22 +0800 Subject: [PATCH 020/126] fix: addr panic --- go.mod | 2 +- go.sum | 4 ++-- listener/sing/sing.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index a0f95e20..199f3e9c 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.5 + github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182 github.com/sagernet/sing-vmess v0.1.1 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.35.0 diff --git a/go.sum b/go.sum index 262b98c1..176d7f95 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.5 h1:1ZHE4cqqds8559RPqzmHiXkOYWyXkNDiULFr00+LxG8= -github.com/sagernet/sing v0.1.5/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182 h1:TsLXlVXH7ql2yHOYczF6hfHrrAiMiS6itVG0HMJKJ08= +github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= github.com/sagernet/sing-vmess v0.1.1 h1:WMdkJcc3icIqpDQZGQ7X+jfLilooIZ0zAaC0qeQTWFU= github.com/sagernet/sing-vmess v0.1.1/go.mod h1:COSSEmy19vMWOTEKIUSDiTEyx6yBfTYIzekDlCMow+Q= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index e8aafa39..2780e275 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -146,7 +146,7 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { err = errors.New("writeBack to closed connection") return } - err = conn.WritePacket(buff, M.ParseSocksaddr(addr.String())) + err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) return } From 49a26023299e0a11b4ab41b63d5552927708c86a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 13:26:30 +0800 Subject: [PATCH 021/126] fix: add Upstream to refconn --- common/net/refconn.go | 4 ++++ listener/sing/sing.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/common/net/refconn.go b/common/net/refconn.go index 6d28a2bf..324e6474 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -51,6 +51,10 @@ func (c *refConn) SetWriteDeadline(t time.Time) error { return c.conn.SetWriteDeadline(t) } +func (c *refConn) Upstream() any { + return c.conn +} + func NewRefConn(conn net.Conn, ref any) net.Conn { return &refConn{conn: conn, ref: ref} } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2780e275..27a9d6ac 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -48,6 +48,10 @@ func (c *waitCloseConn) RemoteAddr() net.Addr { return c.rAddr } +func (c *waitCloseConn) Upstream() any { + return c.Conn +} + func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { additions := h.Additions if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { From ead21f37d7c79da066fcf2187a6aaf83e4320c26 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 15:09:25 +0800 Subject: [PATCH 022/126] chore: better workflow --- .github/workflows/prerelease.yml | 49 +++++++++++++++++--------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 25630f35..eaebecaf 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -17,11 +17,14 @@ jobs: fail-fast: false matrix: job: - - { target: "linux-amd64 linux-amd64-compatible linux-arm64 linux-armv5 linux-armv6 linux-armv7", id: "1" } - - { target: "linux-mips64 linux-mips64le linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "2" } - - { target: "android-arm64 freebsd-386 freebsd-amd64 freebsd-arm64", id: "3" } - - { target: "windows-amd64-compatible windows-amd64 windows-arm64 windows-arm32v7 windows-386", id: "4" } - - { target: "darwin-amd64 darwin-arm64", id: "5" } + - { target: "linux-amd64 linux-amd64-compatible", id: "1" } + - { target: "linux-armv5 linux-armv6 linux-armv7", id: "2" } + - { target: "linux-arm64 linux-mips64 linux-mips64le", id: "3" } + - { target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "4" } + - { target: "freebsd-386 freebsd-amd64 freebsd-arm64", id: "5" } + - { target: "windows-amd64-compatible windows-amd64 windows-386", id: "6" } + - { target: "windows-arm64 windows-arm32v7", id: "7" } + - { target: "darwin-amd64 darwin-arm64 android-arm64", id: "8" } steps: - name: Check out code into the Go module directory uses: actions/checkout@v3 @@ -52,7 +55,7 @@ jobs: check-latest: true - name: Test - if: ${{ github.ref_name=='Beta' && matrix.job.id=='5' }} + if: ${{ github.ref_name=='Beta' && matrix.job.id=='1' }} run: | go test ./... @@ -85,12 +88,14 @@ jobs: fail-fast: false matrix: job: - - { target: windows/* } - - { target: linux/386,linux/amd64,linux/arm64 } - - { target: linux/arm,linux/arm-6,linux/arm-7,linux/riscv64 } - - { target: linux/mips,linux/mipsle,linux/mips64,linux/mips64le } - - { target: darwin-10.16/* } - - { target: android } + - { target: "windows/*", id: "1" } + - { target: "linux/386,linux/amd64", id: "2" } + - { target: "linux/arm64,linux/riscv64", id: "3" } + - { target: "linux/arm,linux/arm-6,linux/arm-7", id: "4" } + - { target: "linux/mips,linux/mipsle", id: "5" } + - { target: "linux/mips64,linux/mips64le", id: "6" } + - { target: "darwin-10.16/*", id: "7" } + - { target: "android", id: "8" } steps: - name: Check out code into the Go module directory @@ -151,17 +156,6 @@ jobs: mkdir bin CC=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android33-clang CGO_ENABLED=1 CC=${CC} GOARCH=arm64 GOOS=android go build -tags ${TAGS} -trimpath -ldflags "${LDFLAGS}" -o bin/${NAME}-android-arm64 - cd bin - ls -la - chmod +x * - cp ../.github/rename-cgo.sh ./ - bash ./rename-cgo.sh - rm ./rename-cgo.sh - cp ../.github/release.sh ./ - bash ./release.sh - rm ./release.sh - ls -la - cd .. - name: Set up xgo if: ${{matrix.job.target!='android'}} @@ -176,12 +170,21 @@ jobs: run: | mkdir bin xgo --branch ${{ github.ref_name }} --targets="${{ matrix.job.target }}" --tags="${TAGS}" -ldflags="${LDFLAGS}" --out bin/${NAME} github.com/${{ github.repository }} + + - name: Rename and zip + if: ${{ success() }} + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + run: | cd bin ls -la chmod +x * cp ../.github/rename-cgo.sh ./ bash ./rename-cgo.sh rm ./rename-cgo.sh + cp ../.github/release.sh ./ + bash ./release.sh + rm ./release.sh ls -la cd .. From 926ef9e33d4b68b53485a009a6c8aa6a3a2e134e Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 16 Jan 2023 15:54:20 +0800 Subject: [PATCH 023/126] feat: gRPC gun implement extended writer --- transport/gun/gun.go | 27 +++++++++++++++++++++++++-- transport/gun/utils.go | 10 ++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 transport/gun/utils.go diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 66b95517..0ff68fca 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -17,6 +17,7 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" "go.uber.org/atomic" @@ -121,13 +122,13 @@ func (g *Conn) Read(b []byte) (n int, err error) { func (g *Conn) Write(b []byte) (n int, err error) { protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A} varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b))) - grpcHeader := make([]byte, 5) + var grpcHeader [5]byte grpcPayloadLen := uint32(varuintSize + 1 + len(b)) binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen) buf := pool.GetBuffer() defer pool.PutBuffer(buf) - buf.Write(grpcHeader) + buf.Write(grpcHeader[:]) buf.Write(protobufHeader[:varuintSize+1]) buf.Write(b) @@ -139,6 +140,28 @@ func (g *Conn) Write(b []byte) (n int, err error) { return len(b), err } +func (g *Conn) WriteBuffer(buffer *buf.Buffer) error { + defer buffer.Release() + dataLen := buffer.Len() + varLen := UVarintLen(uint64(dataLen)) + header := buffer.ExtendHeader(6 + varLen) + header[0] = 0x00 + binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen)) + header[5] = 0x0A + binary.PutUvarint(header[6:], uint64(dataLen)) + _, err := g.writer.Write(buffer.Bytes()) + + if err == io.ErrClosedPipe && g.err != nil { + err = g.err + } + + return err +} + +func (g *Conn) FrontHeadroom() int { + return 6 + binary.MaxVarintLen64 +} + func (g *Conn) Close() error { g.close.Store(true) if r := g.response; r != nil { diff --git a/transport/gun/utils.go b/transport/gun/utils.go new file mode 100644 index 00000000..e5f6e019 --- /dev/null +++ b/transport/gun/utils.go @@ -0,0 +1,10 @@ +package gun + +func UVarintLen(x uint64) int { + i := 0 + for x >= 0x80 { + x >>= 7 + i++ + } + return i + 1 +} From bb79272020e38b1f08efa955fd35c98b11d03029 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Jan 2023 16:44:31 +0800 Subject: [PATCH 024/126] chore: better workflow --- .github/workflows/prerelease.yml | 140 +++++++++++-------------------- 1 file changed, 47 insertions(+), 93 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index eaebecaf..79ab159c 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -10,92 +10,29 @@ on: - Alpha - Beta jobs: - Build-Prerelease-WithoutCGO: + Build: permissions: write-all runs-on: ubuntu-latest strategy: fail-fast: false matrix: job: - - { target: "linux-amd64 linux-amd64-compatible", id: "1" } - - { target: "linux-armv5 linux-armv6 linux-armv7", id: "2" } - - { target: "linux-arm64 linux-mips64 linux-mips64le", id: "3" } - - { target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "4" } - - { target: "freebsd-386 freebsd-amd64 freebsd-arm64", id: "5" } - - { target: "windows-amd64-compatible windows-amd64 windows-386", id: "6" } - - { target: "windows-arm64 windows-arm32v7", id: "7" } - - { target: "darwin-amd64 darwin-arm64 android-arm64", id: "8" } - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v3 - - - name: Set variables - run: echo "VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - shell: bash - - - name: Set variables - if: ${{github.ref_name=='Alpha'}} - run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV - shell: bash - - - name: Set variables - if: ${{github.ref_name=='Beta'}} - run: echo "VERSION=beta-$(git rev-parse --short HEAD)" >> $GITHUB_ENV - shell: bash - - - name: Set variables - if: ${{github.ref_name==''}} - run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV - shell: bash - - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.19' - check-latest: true - - - name: Test - if: ${{ github.ref_name=='Beta' && matrix.job.id=='1' }} - run: | - go test ./... - - - name: Build - if: success() - env: - NAME: Clash.Meta - BINDIR: bin - run: | - make -j$(($(nproc) + 1)) ${{ matrix.job.target }} - cd bin - ls -la - chmod +x * - cp ../.github/release.sh ./ - bash ./release.sh - rm ./release.sh - ls -la - cd .. - - - uses: actions/upload-artifact@v3 - if: ${{ success() }} - with: - name: artifact - path: bin/ - - Build-Prerelease-WithCGO: - permissions: write-all - runs-on: ubuntu-22.04 - strategy: - fail-fast: false - matrix: - job: - - { target: "windows/*", id: "1" } - - { target: "linux/386,linux/amd64", id: "2" } - - { target: "linux/arm64,linux/riscv64", id: "3" } - - { target: "linux/arm,linux/arm-6,linux/arm-7", id: "4" } - - { target: "linux/mips,linux/mipsle", id: "5" } - - { target: "linux/mips64,linux/mips64le", id: "6" } - - { target: "darwin-10.16/*", id: "7" } - - { target: "android", id: "8" } + - { type: "WithoutCGO", target: "linux-amd64 linux-amd64-compatible", id: "1" } + - { type: "WithoutCGO", target: "linux-armv5 linux-armv6 linux-armv7", id: "2" } + - { type: "WithoutCGO", target: "linux-arm64 linux-mips64 linux-mips64le", id: "3" } + - { type: "WithoutCGO", target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "4" } + - { type: "WithoutCGO", target: "freebsd-386 freebsd-amd64 freebsd-arm64", id: "5" } + - { type: "WithoutCGO", target: "windows-amd64-compatible windows-amd64 windows-386", id: "6" } + - { type: "WithoutCGO", target: "windows-arm64 windows-arm32v7", id: "7" } + - { type: "WithoutCGO", target: "darwin-amd64 darwin-arm64 android-arm64", id: "8" } + - { type: "WithCGO", target: "windows/*", id: "1" } + - { type: "WithCGO", target: "linux/386,linux/amd64", id: "2" } + - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "3" } + - { type: "WithCGO", target: "linux/arm,linux/arm-6,linux/arm-7", id: "4" } + - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "5" } + - { type: "WithCGO", target: "linux/mips64,linux/mips64le", id: "6" } + - { type: "WithCGO", target: "darwin-10.16/*", id: "7" } + - { type: "WithCGO", target: "android", id: "8" } steps: - name: Check out code into the Go module directory @@ -123,7 +60,6 @@ jobs: - name: Set ENV run: | echo "NAME=clash.meta" >> $GITHUB_ENV - echo "BUILD_TIME=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV @@ -141,15 +77,27 @@ jobs: go-version: '1.19' check-latest: true + - name: Test + if: ${{ github.ref_name=='Beta' && matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} + run: | + go test ./... + + - name: Build WithoutCGO + if: ${{ matrix.job.type=='WithoutCGO' }} + env: + NAME: Clash.Meta + BINDIR: bin + run: make -j$(($(nproc) + 1)) ${{ matrix.job.target }} + - uses: nttld/setup-ndk@v1 - if: ${{matrix.job.target=='android'}} + if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} id: setup-ndk with: ndk-version: r25b add-to-path: false - name: Build Android - if: ${{matrix.job.target=='android'}} + if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} env: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | @@ -158,30 +106,36 @@ jobs: CGO_ENABLED=1 CC=${CC} GOARCH=arm64 GOOS=android go build -tags ${TAGS} -trimpath -ldflags "${LDFLAGS}" -o bin/${NAME}-android-arm64 - name: Set up xgo - if: ${{matrix.job.target!='android'}} + if: ${{ matrix.job.type=='WithCGO' && matrix.job.target!='android' }} run: | docker pull techknowlogick/xgo:latest go install src.techknowlogick.com/xgo@latest - name: Build by xgo - if: ${{matrix.job.target!='android'}} + if: ${{ matrix.job.type=='WithCGO' && matrix.job.target!='android' }} env: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | mkdir bin xgo --branch ${{ github.ref_name }} --targets="${{ matrix.job.target }}" --tags="${TAGS}" -ldflags="${LDFLAGS}" --out bin/${NAME} github.com/${{ github.repository }} - - name: Rename and zip + - name: Rename + if: ${{ matrix.job.type=='WithCGO' }} + run: | + cd bin + ls -la + cp ../.github/rename-cgo.sh ./ + bash ./rename-cgo.sh + rm ./rename-cgo.sh + ls -la + cd .. + + - name: Zip if: ${{ success() }} - env: - ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | cd bin ls -la chmod +x * - cp ../.github/rename-cgo.sh ./ - bash ./rename-cgo.sh - rm ./rename-cgo.sh cp ../.github/release.sh ./ bash ./release.sh rm ./release.sh @@ -195,9 +149,9 @@ jobs: path: bin/ - Upload-Prerelease: + Upload: permissions: write-all - needs: [ Build-Prerelease-WithoutCGO, Build-Prerelease-WithCGO ] + needs: [ Build ] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 From f3b76df13b870810d71bcf256902d496a91e0630 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 16 Jan 2023 14:53:19 +0800 Subject: [PATCH 025/126] chore: Update BBR config chore: Adjust workflow --- .github/workflows/prerelease.yml | 1 + transport/tuic/congestion/bbr_sender.go | 109 ++++++++++++------------ transport/tuic/conn.go | 11 ++- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 79ab159c..e32cdce0 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -95,6 +95,7 @@ jobs: with: ndk-version: r25b add-to-path: false + local-cache: true - name: Build Android if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 1706956b..6c862b80 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -13,16 +13,21 @@ import ( ) const ( - MaxDatagramSize = 1252 - DefaultBBRMaxCongestionWindow congestion.ByteCount = 2000 * MaxDatagramSize - InitialCongestionWindow congestion.ByteCount = 10 * MaxDatagramSize - MinInitialPacketSize = 1200 + // InitialMaxDatagramSize is the default maximum packet size used in QUIC for congestion window computations in bytes. + InitialMaxDatagramSize = 1252 + InitialCongestionWindow congestion.ByteCount = 10 InitialPacketSizeIPv4 = 1252 InitialPacketSizeIPv6 = 1232 + DefaultBBRMaxCongestionWindow congestion.ByteCount = 10000 ) -func GetMaxPacketSize(addr net.Addr) congestion.ByteCount { - maxSize := congestion.ByteCount(MinInitialPacketSize) +const ( + initialMinCongestionWindow = 4 + minInitialPacketSize = 1200 +) + +func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { + maxSize := congestion.ByteCount(minInitialPacketSize) // If this is not a UDP address, we don't know anything about the MTU. // Use the minimum size of an Initial packet as the max packet size. if udpAddr, ok := addr.(*net.UDPAddr); ok { @@ -35,41 +40,11 @@ func GetMaxPacketSize(addr net.Addr) congestion.ByteCount { return maxSize } -func GetMaxOutgoingPacketSize(addr net.Addr) congestion.ByteCount { - maxSize := congestion.ByteCount(MinInitialPacketSize) - // If this is not a UDP address, we don't know anything about the MTU. - // Use the minimum size of an Initial packet as the max packet size. - if udpAddr, ok := addr.(*net.UDPAddr); ok { - - if udpAddr.IP.To4() != nil { - //The maximum packet size of any QUIC packet over IPv4. 1500(Ethernet) - 20(IPv4 header) - 8(UDP header) = 1472. - maxSize = congestion.ByteCount(1472) - } else { - // The maximum outgoing packet size allowed. - // The maximum packet size of any QUIC packet over IPv6, based on ethernet's max - // size, minus the IP and UDP headers. IPv6 has a 40 byte header, UDP adds an - // additional 8 bytes. This is a total overhead of 48 bytes. Ethernet's - // max packet size is 1500 bytes, 1500 - 48 = 1452. - maxSize = congestion.ByteCount(1452) - } - } - return maxSize -} - var ( - // Default maximum packet size used in the Linux TCP implementation. - // Used in QUIC for congestion window computations in bytes. - MaxSegmentSize = MaxDatagramSize - // Default initial rtt used before any samples are received. InitialRtt = 100 * time.Millisecond - // Constants based on TCP defaults. - // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. - // Does not inflate the pacing rate. - DefaultMinimumCongestionWindow = 4 * MaxDatagramSize - // The gain used for the STARTUP, equal to 2/ln(2). DefaultHighGain = 2.89 @@ -174,9 +149,9 @@ type bbrSender struct { // The initial value of the |congestion_window_|. initialCongestionWindow congestion.ByteCount // The largest value the |congestion_window_| can achieve. - maxCongestionWindow congestion.ByteCount + initialMaxCongestionWindow congestion.ByteCount // The smallest value the |congestion_window_| can achieve. - minCongestionWindow congestion.ByteCount + //minCongestionWindow congestion.ByteCount // The pacing gain applied during the STARTUP phase. highGain float64 // The CWND gain applied during the STARTUP phase. @@ -269,11 +244,14 @@ type bbrSender struct { pacer *pacer maxDatagramSize congestion.ByteCount - - MaxOutgoingPacketSize congestion.ByteCount } -func NewBBRSender(clock Clock, initialMaxDatagramSize, initialCongestionWindow, initialMaxOutgoingPacketSize, maxCongestionWindow congestion.ByteCount) *bbrSender { +func NewBBRSender( + clock Clock, + initialMaxDatagramSize, + initialCongestionWindow, + initialMaxCongestionWindow congestion.ByteCount, +) *bbrSender { b := &bbrSender{ mode: STARTUP, clock: clock, @@ -282,8 +260,6 @@ func NewBBRSender(clock Clock, initialMaxDatagramSize, initialCongestionWindow, maxAckHeight: NewWindowedFilter(int64(BandwidthWindowSize), MaxFilter), congestionWindow: initialCongestionWindow, initialCongestionWindow: initialCongestionWindow, - maxCongestionWindow: maxCongestionWindow, - minCongestionWindow: congestion.ByteCount(DefaultMinimumCongestionWindow), highGain: DefaultHighGain, highCwndGain: DefaultHighGain, drainGain: 1.0 / DefaultHighGain, @@ -292,15 +268,22 @@ func NewBBRSender(clock Clock, initialMaxDatagramSize, initialCongestionWindow, congestionWindowGainConst: DefaultCongestionWindowGainConst, numStartupRtts: RoundTripsWithoutGrowthBeforeExitingStartup, recoveryState: NOT_IN_RECOVERY, - recoveryWindow: maxCongestionWindow, + recoveryWindow: initialMaxCongestionWindow, minRttSinceLastProbeRtt: InfiniteRTT, - MaxOutgoingPacketSize: initialMaxOutgoingPacketSize, maxDatagramSize: initialMaxDatagramSize, } b.pacer = newPacer(b.BandwidthEstimate) return b } +func (b *bbrSender) maxCongestionWindow() congestion.ByteCount { + return b.maxDatagramSize * DefaultBBRMaxCongestionWindow +} + +func (b *bbrSender) minCongestionWindow() congestion.ByteCount { + return b.maxDatagramSize * initialMinCongestionWindow +} + func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { b.rttStats = provider } @@ -323,10 +306,10 @@ func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { if s < b.maxDatagramSize { panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s)) } - cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow + cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow() b.maxDatagramSize = s if cwndIsMinCwnd { - b.congestionWindow = b.minCongestionWindow + b.congestionWindow = b.minCongestionWindow() } b.pacer.SetMaxDatagramSize(s) } @@ -393,6 +376,7 @@ func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes con b.CalculatePacingRate() b.CalculateCongestionWindow(bytesAcked, excessAcked) b.CalculateRecoveryWindow(bytesAcked, congestion.ByteCount(0)) + } func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { @@ -491,8 +475,21 @@ func (b *bbrSender) OnRetransmissionTimeout(packetsRetransmitted bool) { // //} +//func (b *bbrSender) BandwidthEstimate() Bandwidth { +// return Bandwidth(b.maxBandwidth.GetBest()) +//} + +// BandwidthEstimate returns the current bandwidth estimate func (b *bbrSender) BandwidthEstimate() Bandwidth { - return Bandwidth(b.maxBandwidth.GetBest()) + if b.rttStats == nil { + return infBandwidth + } + srtt := b.rttStats.SmoothedRTT() + if srtt == 0 { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return infBandwidth + } + return BandwidthFromDelta(b.GetCongestionWindow(), srtt) } //func (b *bbrSender) HybridSlowStart() *HybridSlowStart { @@ -740,7 +737,7 @@ func (b *bbrSender) GetTargetCongestionWindow(gain float64) congestion.ByteCount congestionWindow = congestion.ByteCount(gain * float64(b.initialCongestionWindow)) } - return maxByteCount(congestionWindow, b.minCongestionWindow) + return maxByteCount(congestionWindow, b.minCongestionWindow()) } func (b *bbrSender) CheckIfFullBandwidthReached() { @@ -811,7 +808,7 @@ func (b *bbrSender) MaybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRtt // PROBE_RTT. The CWND during PROBE_RTT is kMinimumCongestionWindow, but // we allow an extra packet since QUIC checks CWND before sending a // packet. - if b.GetBytesInFlight() < b.ProbeRttCongestionWindow()+b.MaxOutgoingPacketSize { + if b.GetBytesInFlight() < b.ProbeRttCongestionWindow()+b.maxDatagramSize { b.exitProbeRttAt = now.Add(ProbeRttTime) b.probeRttRoundPassed = false } @@ -836,7 +833,7 @@ func (b *bbrSender) ProbeRttCongestionWindow() congestion.ByteCount { if b.probeRttBasedOnBdp { return b.GetTargetCongestionWindow(ModerateProbeRttMultiplier) } else { - return b.minCongestionWindow + return b.minCongestionWindow() } } @@ -921,8 +918,8 @@ func (b *bbrSender) CalculateCongestionWindow(ackedBytes, excessAcked congestion } // Enforce the limits on the congestion window. - b.congestionWindow = maxByteCount(b.congestionWindow, b.minCongestionWindow) - b.congestionWindow = minByteCount(b.congestionWindow, b.maxCongestionWindow) + b.congestionWindow = maxByteCount(b.congestionWindow, b.minCongestionWindow()) + b.congestionWindow = minByteCount(b.congestionWindow, b.maxCongestionWindow()) } func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.ByteCount) { @@ -936,7 +933,7 @@ func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.Byt // Set up the initial recovery window. if b.recoveryWindow == 0 { - b.recoveryWindow = maxByteCount(b.GetBytesInFlight()+ackedBytes, b.minCongestionWindow) + b.recoveryWindow = maxByteCount(b.GetBytesInFlight()+ackedBytes, b.minCongestionWindow()) return } @@ -945,7 +942,7 @@ func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.Byt if b.recoveryWindow >= lostBytes { b.recoveryWindow -= lostBytes } else { - b.recoveryWindow = congestion.ByteCount(MaxSegmentSize) + b.recoveryWindow = congestion.ByteCount(b.maxDatagramSize) } // In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH, // release additional |bytes_acked| to achieve a slow-start-like behavior. @@ -955,7 +952,7 @@ func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.Byt // Sanity checks. Ensure that we always allow to send at least an MSS or // |bytes_acked| in response, whichever is larger. b.recoveryWindow = maxByteCount(b.recoveryWindow, b.GetBytesInFlight()+ackedBytes) - b.recoveryWindow = maxByteCount(b.recoveryWindow, b.minCongestionWindow) + b.recoveryWindow = maxByteCount(b.recoveryWindow, b.minCongestionWindow()) } var _ congestion.CongestionControl = &bbrSender{} diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index 8e6722c0..a6baf451 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -26,7 +26,7 @@ func SetCongestionController(quicConn quic.Connection, cc string) { quicConn.SetCongestionControl( congestion.NewCubicSender( congestion.DefaultClock{}, - congestion.GetMaxPacketSize(quicConn.RemoteAddr()), + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), false, nil, ), @@ -35,7 +35,7 @@ func SetCongestionController(quicConn quic.Connection, cc string) { quicConn.SetCongestionControl( congestion.NewCubicSender( congestion.DefaultClock{}, - congestion.GetMaxPacketSize(quicConn.RemoteAddr()), + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), true, nil, ), @@ -44,10 +44,9 @@ func SetCongestionController(quicConn quic.Connection, cc string) { quicConn.SetCongestionControl( congestion.NewBBRSender( congestion.DefaultClock{}, - congestion.GetMaxPacketSize(quicConn.RemoteAddr()), - congestion.GetMaxOutgoingPacketSize(quicConn.RemoteAddr()), - congestion.InitialCongestionWindow, - congestion.DefaultBBRMaxCongestionWindow, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + congestion.InitialCongestionWindow*congestion.InitialMaxDatagramSize, + congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, ), ) } From db4f3eda5512a2e76cd6b2515ef43b1cd696eb68 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 17 Jan 2023 01:07:28 +0800 Subject: [PATCH 026/126] fix: Add CC for TUIC server --- listener/parse.go | 1 + transport/tuic/server.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/listener/parse.go b/listener/parse.go index 9459b9e1..aa9e39ac 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -92,6 +92,7 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) { AuthenticationTimeout: 1000, ALPN: []string{"h3"}, MaxUdpRelayPacketSize: 1500, + CongestionController: "bbr", } err = decoder.Decode(mapping, tuicOption) if err != nil { diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 3f459fd6..77d99322 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -73,6 +73,7 @@ func (s *Server) Close() error { } type serverHandler struct { + serverOption ServerOption *Server quicConn quic.Connection uuid uuid.UUID @@ -166,7 +167,7 @@ func (s *serverHandler) handleStream() (err error) { if err != nil { return err } - + SetCongestionController(s.quicConn, s.CongestionController) go func() (err error) { stream := &quicStreamConn{ Stream: quicStream, @@ -214,6 +215,7 @@ func (s *serverHandler) handleUniStream() (err error) { if err != nil { return err } + SetCongestionController(s.quicConn, s.CongestionController) go func() (err error) { defer func() { stream.CancelRead(0) From f4414566d347fa006996b864fe5af35a96e1935c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 10:41:51 +0800 Subject: [PATCH 027/126] fix: tuic server's SetCongestionController --- transport/tuic/server.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 77d99322..5968e3e1 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -54,6 +54,7 @@ func (s *Server) Serve() error { if err != nil { return err } + SetCongestionController(conn, s.CongestionController) uuid, err := uuid.NewV4() if err != nil { return err @@ -73,7 +74,6 @@ func (s *Server) Close() error { } type serverHandler struct { - serverOption ServerOption *Server quicConn quic.Connection uuid uuid.UUID @@ -167,7 +167,6 @@ func (s *serverHandler) handleStream() (err error) { if err != nil { return err } - SetCongestionController(s.quicConn, s.CongestionController) go func() (err error) { stream := &quicStreamConn{ Stream: quicStream, @@ -215,7 +214,6 @@ func (s *serverHandler) handleUniStream() (err error) { if err != nil { return err } - SetCongestionController(s.quicConn, s.CongestionController) go func() (err error) { defer func() { stream.CancelRead(0) From 5b1de296af800af4c7fe896fc544f8eab8a52921 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 12:26:31 +0800 Subject: [PATCH 028/126] chore: Update dependencies --- go.mod | 20 ++++++++++---------- go.sum | 47 +++++++++++++++++++++++------------------------ 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/go.mod b/go.mod index 199f3e9c..56532f53 100644 --- a/go.mod +++ b/go.mod @@ -8,17 +8,17 @@ require ( github.com/coreos/go-iptables v0.6.0 github.com/database64128/tfo-go/v2 v2.0.2 github.com/dlclark/regexp2 v1.7.0 - github.com/go-chi/chi/v5 v5.0.7 + github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 github.com/gofrs/uuid v4.3.1+incompatible github.com/google/gopacket v1.1.19 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 - github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c + github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 - github.com/mdlayher/netlink v1.7.0 + github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e github.com/metacubex/sing-shadowsocks v0.1.0 github.com/metacubex/sing-tun v0.1.0 @@ -26,19 +26,19 @@ require ( github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182 + github.com/sagernet/sing v0.1.6 github.com/sagernet/sing-vmess v0.1.1 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c - github.com/samber/lo v1.35.0 + github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.4.0 + golang.org/x/crypto v0.5.0 golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 - golang.org/x/net v0.3.0 + golang.org/x/net v0.5.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.4.0 google.golang.org/protobuf v1.28.1 @@ -55,7 +55,7 @@ require ( github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/josharian/native v1.0.0 // indirect + github.com/josharian/native v1.1.0 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/marten-seemann/qpack v0.3.0 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect @@ -66,10 +66,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect + github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.1.12 // indirect gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect diff --git a/go.sum b/go.sum index 176d7f95..87f9cdaa 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:Pjfxu github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= @@ -55,10 +55,11 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c h1:OCFM4+DXTWfNlyeoddrTwdup/ztkGSyAMR2UGcPckNQ= -github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 h1:Z72DOke2yOK0Ms4Z2LK1E1OrRJXOxSj5DllTz2FYTRg= +github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8/go.mod h1:m5WMe03WCvWcXjRnhvaAbAAXdCnu20J5P+mmH44ZzpE= +github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -84,8 +85,8 @@ github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI= -github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= +github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4= +github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= @@ -102,7 +103,6 @@ github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c h1:VHtXDn github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c/go.mod h1:fULJ451x1/XlpIhl+Oo+EPGKla9tFZaqT5dKLrZ+NvM= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= @@ -121,14 +121,14 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182 h1:TsLXlVXH7ql2yHOYczF6hfHrrAiMiS6itVG0HMJKJ08= -github.com/sagernet/sing v0.1.6-0.20230114115804-bc788b027182/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing v0.1.6 h1:Qy63OUfKpcqKjfd5rPmUlj0RGjHZSK/PJn0duyCCsRg= +github.com/sagernet/sing v0.1.6/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= github.com/sagernet/sing-vmess v0.1.1 h1:WMdkJcc3icIqpDQZGQ7X+jfLilooIZ0zAaC0qeQTWFU= github.com/sagernet/sing-vmess v0.1.1/go.mod h1:COSSEmy19vMWOTEKIUSDiTEyx6yBfTYIzekDlCMow+Q= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= -github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= -github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= +github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= +github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -143,9 +143,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/u-root/uio v0.0.0-20221213070652-c3537552635f h1:dpx1PHxYqAnXzbryJrWP1NQLzEjwcVgFLhkknuFQ7ww= +github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M= @@ -160,8 +159,8 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= -golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -181,8 +180,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -206,8 +205,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -217,8 +216,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -237,7 +236,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From c90bf1c6e246f580953a5db887aa9839bffc1b79 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 17 Jan 2023 12:33:15 +0800 Subject: [PATCH 029/126] chore: Update const type --- transport/tuic/congestion/bbr_sender.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 6c862b80..5adbd0b7 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -14,11 +14,11 @@ import ( const ( // InitialMaxDatagramSize is the default maximum packet size used in QUIC for congestion window computations in bytes. - InitialMaxDatagramSize = 1252 - InitialCongestionWindow congestion.ByteCount = 10 - InitialPacketSizeIPv4 = 1252 - InitialPacketSizeIPv6 = 1232 - DefaultBBRMaxCongestionWindow congestion.ByteCount = 10000 + InitialMaxDatagramSize = 1252 + InitialPacketSizeIPv4 = 1252 + InitialPacketSizeIPv6 = 1232 + InitialCongestionWindow = 10 + DefaultBBRMaxCongestionWindow = 10000 ) const ( From 421c91a58c5d2c0c244e5d202380fe2a0e221436 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 17 Jan 2023 12:43:51 +0800 Subject: [PATCH 030/126] chore: update docker.yaml and Makefile docker --- .github/workflows/docker.yaml | 1 + Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index e02d5d01..0d5747a1 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -4,6 +4,7 @@ on: push: branches: - Beta + - Alpha tags: - "v*" env: diff --git a/Makefile b/Makefile index 9427be29..b1ee532f 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ all:linux-amd64 linux-arm64\ darwin-all: darwin-amd64 darwin-arm64 docker: - GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ darwin-amd64: GOARCH=amd64 GOOS=darwin GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ From 37eca8af242c0dd865c0b8b2a0f82b7312715f39 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 14:25:19 +0800 Subject: [PATCH 031/126] fix: tuic server's MaxIncomingStreams --- listener/tuic/server.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 8b928637..724d7418 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -18,6 +18,8 @@ import ( "github.com/Dreamacro/clash/transport/tuic" ) +const ServerMaxIncomingStreams = (1 << 32) - 1 + type Listener struct { closed bool config LC.TuicServer @@ -47,8 +49,8 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet } quicConfig := &quic.Config{ MaxIdleTimeout: time.Duration(config.MaxIdleTime) * time.Millisecond, - MaxIncomingStreams: 1 >> 32, - MaxIncomingUniStreams: 1 >> 32, + MaxIncomingStreams: ServerMaxIncomingStreams, + MaxIncomingUniStreams: ServerMaxIncomingStreams, EnableDatagrams: true, } quicConfig.InitialStreamReceiveWindow = tuic.DefaultStreamReceiveWindow / 10 From ba6163574ecc6d425ac5ed81ec95513fd28760d7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 15:41:51 +0800 Subject: [PATCH 032/126] chore: better parseAddr --- adapter/inbound/http.go | 4 ++-- adapter/inbound/https.go | 4 ++-- adapter/inbound/packet.go | 4 ++-- adapter/inbound/socket.go | 21 ++++++--------------- adapter/inbound/util.go | 18 +++++++++++++++--- transport/tuic/client.go | 1 - transport/tuic/conn.go | 3 +-- transport/tuic/server.go | 18 ++++++++++++------ 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 94040078..b1b881ce 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -16,11 +16,11 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(source.String()); err == nil { + if ip, port, err := parseAddr(source); err == nil { metadata.SrcIP = ip metadata.SrcPort = port } - if ip, port, err := parseAddr(conn.LocalAddr().String()); err == nil { + if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { metadata.InIP = ip metadata.InPort = port } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 3fff2371..485e72bb 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -15,11 +15,11 @@ func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) *cont for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil { + if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { metadata.SrcIP = ip metadata.SrcPort = port } - if ip, port, err := parseAddr(conn.LocalAddr().String()); err == nil { + if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { metadata.InIP = ip metadata.InPort = port } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index d1fcb05d..44e5e1a7 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -24,12 +24,12 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil { + if ip, port, err := parseAddr(packet.LocalAddr()); err == nil { metadata.SrcIP = ip metadata.SrcPort = port } if p, ok := packet.(C.UDPPacketInAddr); ok { - if ip, port, err := parseAddr(p.InAddr().String()); err == nil { + if ip, port, err := parseAddr(p.InAddr()); err == nil { metadata.InIP = ip metadata.InPort = port } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 557b22ab..590f64d7 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -18,22 +18,13 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad addition.Apply(metadata) } - remoteAddr := conn.RemoteAddr() - - // Filter when net.Addr interface is nil - if remoteAddr != nil { - if ip, port, err := parseAddr(remoteAddr.String()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } + if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { + metadata.SrcIP = ip + metadata.SrcPort = port } - localAddr := conn.LocalAddr() - // Filter when net.Addr interface is nil - if localAddr != nil { - if ip, port, err := parseAddr(localAddr.String()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } + if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { + metadata.InIP = ip + metadata.InPort = port } return context.NewConnContext(conn, metadata) diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index cddbcf1f..88e989f9 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -1,13 +1,14 @@ package inbound import ( - "github.com/Dreamacro/clash/common/nnip" + "errors" "net" "net/http" "net/netip" "strconv" "strings" + "github.com/Dreamacro/clash/common/nnip" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -57,8 +58,19 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr string) (netip.Addr, string, error) { - host, port, err := net.SplitHostPort(addr) +func parseAddr(addr net.Addr) (netip.Addr, string, error) { + // Filter when net.Addr interface is nil + if addr == nil { + return netip.Addr{}, "", errors.New("nil addr") + } + if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { + ip, port, err := parseAddr(rawAddr.RawAddr()) + if err == nil { + return ip, port, err + } + } + addrStr := addr.String() + host, port, err := net.SplitHostPort(addrStr) if err != nil { return netip.Addr{}, "", err } diff --git a/transport/tuic/client.go b/transport/tuic/client.go index 1d1c3d15..d3f511df 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -361,7 +361,6 @@ func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Met pc := &quicStreamPacketConn{ connId: connId, quicConn: quicConn, - lAddr: quicConn.LocalAddr(), inputConn: N.NewBufferedConn(pipe2), udpRelayMode: t.UdpRelayMode, maxUdpRelayPacketSize: t.MaxUdpRelayPacketSize, diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index a6baf451..7ecc3f0d 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -109,7 +109,6 @@ var _ net.Conn = &quicStreamConn{} type quicStreamPacketConn struct { connId uint32 quicConn quic.Connection - lAddr net.Addr inputConn *N.BufferedConn udpRelayMode string @@ -251,7 +250,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } func (q *quicStreamPacketConn) LocalAddr() net.Addr { - return q.lAddr + return q.quicConn.LocalAddr() } var _ net.PacketConn = &quicStreamPacketConn{} diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 5968e3e1..2830b324 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -140,7 +140,6 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err pc := &quicStreamPacketConn{ connId: assocId, quicConn: s.quicConn, - lAddr: s.quicConn.LocalAddr(), inputConn: nil, udpRelayMode: udpRelayMode, maxUdpRelayPacketSize: s.MaxUdpRelayPacketSize, @@ -152,12 +151,12 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{ pc: pc, packet: &packet, - rAddr: s.genServerAssocIdAddr(assocId), + rAddr: s.genServerAssocIdAddr(assocId, s.quicConn.RemoteAddr()), }) } -func (s *serverHandler) genServerAssocIdAddr(assocId uint32) net.Addr { - return ServerAssocIdAddr(fmt.Sprintf("tuic-%s-%d", s.uuid.String(), assocId)) +func (s *serverHandler) genServerAssocIdAddr(assocId uint32, addr net.Addr) net.Addr { + return &ServerAssocIdAddr{assocId: fmt.Sprintf("tuic-%s-%d", s.uuid.String(), assocId), addr: addr} } func (s *serverHandler) handleStream() (err error) { @@ -274,14 +273,21 @@ func (s *serverHandler) handleUniStream() (err error) { } } -type ServerAssocIdAddr string +type ServerAssocIdAddr struct { + assocId string + addr net.Addr +} func (a ServerAssocIdAddr) Network() string { return "ServerAssocIdAddr" } func (a ServerAssocIdAddr) String() string { - return string(a) + return a.assocId +} + +func (a ServerAssocIdAddr) RawAddr() net.Addr { + return a.addr } type serverUDPPacket struct { From fa5b5ca02d3620ddfb3d1b59dc3fbebe801692b5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 21:36:16 +0800 Subject: [PATCH 033/126] fix: tcpTracker's upload --- tunnel/statistic/tracker.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index c034d75d..97dd7316 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -65,11 +65,8 @@ func (tt *tcpTracker) Write(b []byte) (int, error) { } func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) { + upload := int64(buffer.Len()) err = tt.extendedWriter.WriteBuffer(buffer) - var upload int64 - if err != nil { - upload = int64(buffer.Len()) - } tt.manager.PushUploaded(upload) tt.UploadTotal.Add(upload) return From 106a58779dc2caac17c9a3ccc76f1352da7a6560 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Jan 2023 22:06:21 +0800 Subject: [PATCH 034/126] chore: update quic-go --- go.mod | 2 +- go.sum | 4 ++-- transport/hysteria/core/client.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 56532f53..6aaf9b6b 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e + github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 github.com/metacubex/sing-shadowsocks v0.1.0 github.com/metacubex/sing-tun v0.1.0 github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c diff --git a/go.sum b/go.sum index 87f9cdaa..b965c336 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20221217030112-bdcd835fd60e h1:3PHqNvIAwYbv9cOQbRFIUgzJ+K6fhV1HHj+Vpg8U7g8= github.com/metacubex/gvisor v0.0.0-20221217030112-bdcd835fd60e/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= -github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e h1:RnfC6+sShJ3biU2Q2wuh4FxZ8/3fp1QG+1zAfswVehA= -github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e/go.mod h1:7NPWVTLiX2Ss9q9gBNZaNHsPqZ3Tg/ApyrXxxUYbl78= +github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 h1:CGn1ku3QZ/OjJjnRH4eO9jtXegdPQZUJ7y1Y6CppLd0= +github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91/go.mod h1:8VvqBlJaARNcwAE9zrbhKI/I1R5Lu4gqmt3CSGrJl7s= github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A= github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= github.com/metacubex/sing-tun v0.1.0 h1:iQj0+0WjJynSKAtfv87wOZlVKWl3w9RvkOSkVe9zuMg= diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index 5465e3d2..1df14242 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -406,7 +406,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { _ = struc.Pack(&msgBuf, &msg) err = c.Session.SendMessage(msgBuf.Bytes()) if err != nil { - if errSize, ok := err.(quic.ErrMessageToLarge); ok { + if errSize, ok := err.(quic.ErrMessageTooLarge); ok { // need to frag msg.MsgID = uint16(rand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 fragMsgs := fragUDPMessage(msg, int(errSize)) From 5bbf73e3b553810184496a0159b7c65e13415719 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 18 Jan 2023 12:06:36 +0800 Subject: [PATCH 035/126] chore: new Random TLS KeyPair when empty input --- common/net/tls.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/common/net/tls.go b/common/net/tls.go index 4f5263b8..5e1c81f2 100644 --- a/common/net/tls.go +++ b/common/net/tls.go @@ -1,11 +1,19 @@ package net import ( + "crypto/rand" + "crypto/rsa" "crypto/tls" + "crypto/x509" + "encoding/pem" "fmt" + "math/big" ) func ParseCert(certificate, privateKey string) (tls.Certificate, error) { + if certificate == "" || privateKey == "" { + return newRandomTLSKeyPair() + } cert, painTextErr := tls.X509KeyPair([]byte(certificate), []byte(privateKey)) if painTextErr == nil { return cert, nil @@ -17,3 +25,28 @@ func ParseCert(certificate, privateKey string) (tls.Certificate, error) { } return cert, nil } + +func newRandomTLSKeyPair() (tls.Certificate, error) { + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return tls.Certificate{}, err + } + template := x509.Certificate{SerialNumber: big.NewInt(1)} + certDER, err := x509.CreateCertificate( + rand.Reader, + &template, + &template, + &key.PublicKey, + key) + if err != nil { + return tls.Certificate{}, err + } + keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + + tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) + if err != nil { + return tls.Certificate{}, err + } + return tlsCert, nil +} From 8a7027e8d6ae9dab8ddd77d657fe8d4eae4a8c24 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 20 Jan 2023 16:29:08 +0800 Subject: [PATCH 036/126] Fix: Remove EnableProcess from config.go and enable-process from config.yaml. Fix: FindProcess is now enabled by default when the rule set contains process-name rules. --- config/config.go | 6 +----- constant/provider/interface.go | 1 + docs/config.yaml | 7 +++++++ hub/executor/executor.go | 2 +- rules/provider/classical_strategy.go | 5 +++++ rules/provider/domain_strategy.go | 4 ++++ rules/provider/ipcidr_strategy.go | 4 ++++ rules/provider/provider.go | 5 +++++ rules/provider/rule_set.go | 11 ++++++----- tunnel/tunnel.go | 8 ++------ 10 files changed, 36 insertions(+), 17 deletions(-) diff --git a/config/config.go b/config/config.go index e20c8540..c5ba80fc 100644 --- a/config/config.go +++ b/config/config.go @@ -53,7 +53,6 @@ type General struct { GeodataMode bool `json:"geodata-mode"` GeodataLoader string `json:"geodata-loader"` TCPConcurrent bool `json:"tcp-concurrent"` - EnableProcess bool `json:"enable-process"` FindProcessMode P.FindProcessMode `json:"find-process-mode"` Sniffing bool `json:"sniffing"` EBpf EBpf `json:"-"` @@ -117,7 +116,7 @@ type Profile struct { } type TLS struct { - RawCert `yaml:",inline"` + RawCert `yaml:",inline"` CustomTrustCert []RawCert `yaml:"custom-certifactes"` } @@ -259,7 +258,6 @@ type RawConfig struct { GeodataMode bool `yaml:"geodata-mode"` GeodataLoader string `yaml:"geodata-loader"` TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` - EnableProcess bool `yaml:"enable-process" json:"enable-process"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` Sniffer RawSniffer `yaml:"sniffer"` @@ -337,7 +335,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { Proxy: []map[string]any{}, ProxyGroup: []map[string]any{}, TCPConcurrent: false, - EnableProcess: false, FindProcessMode: P.FindProcessStrict, Tun: RawTun{ Enable: false, @@ -555,7 +552,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) { GeodataMode: cfg.GeodataMode, GeodataLoader: cfg.GeodataLoader, TCPConcurrent: cfg.TCPConcurrent, - EnableProcess: cfg.EnableProcess, FindProcessMode: cfg.FindProcessMode, EBpf: cfg.EBpf, }, nil diff --git a/constant/provider/interface.go b/constant/provider/interface.go index 8bc3c0fe..b42bbe71 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -102,5 +102,6 @@ type RuleProvider interface { Behavior() RuleType Match(*constant.Metadata) bool ShouldResolveIP() bool + ShouldFindProcess() bool AsRule(adaptor string) constant.Rule } diff --git a/docs/config.yaml b/docs/config.yaml index a55aa9b2..206548b2 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -9,6 +9,13 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为 true,'*'表示所有地址 + +# find-process-mode has 3 values: always, strict, off +# - always, 开启,强制匹配所有进程 +# - strict, 默认,由clash判断是否开启 +# - off, 不匹配进程,推荐在路由器上使用此模式 +find-process-mode: strict + mode: rule log-level: debug # 日志等级 silent/error/warning/info/debug diff --git a/hub/executor/executor.go b/hub/executor/executor.go index be682f36..94398db1 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -308,7 +308,7 @@ func updateTunnels(tunnels []LC.Tunnel) { func updateGeneral(general *config.General, force bool) { tunnel.SetMode(general.Mode) - tunnel.SetFindProcessMode(general.EnableProcess, general.FindProcessMode) + tunnel.SetFindProcessMode(general.FindProcessMode) dialer.DisableIPv6 = !general.IPv6 if !dialer.DisableIPv6 { log.Infoln("Use IPv6") diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 73426e85..25360ec7 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -42,6 +42,11 @@ func (c *classicalStrategy) OnUpdate(rules []string) { shouldResolveIP := false for _, rawRule := range rules { ruleType, rule, params := ruleParse(rawRule) + + if ruleType == "PROCESS-NAME" { + c.shouldFindProcess = true + } + r, err := c.parse(ruleType, rule, "", params) if err != nil { log.Warnln("parse rule error:[%s]", err.Error()) diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index 61fe93a6..85528f40 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -12,6 +12,10 @@ type domainStrategy struct { domainRules *trie.DomainTrie[struct{}] } +func (d *domainStrategy) ShouldFindProcess() bool { + return false +} + func (d *domainStrategy) Match(metadata *C.Metadata) bool { return d.domainRules != nil && d.domainRules.Search(metadata.Host) != nil } diff --git a/rules/provider/ipcidr_strategy.go b/rules/provider/ipcidr_strategy.go index bba9ddc5..88228301 100644 --- a/rules/provider/ipcidr_strategy.go +++ b/rules/provider/ipcidr_strategy.go @@ -12,6 +12,10 @@ type ipcidrStrategy struct { trie *trie.IpCidrTrie } +func (i *ipcidrStrategy) ShouldFindProcess() bool { + return false +} + func (i *ipcidrStrategy) Match(metadata *C.Metadata) bool { return i.trie != nil && i.trie.IsContain(metadata.DstIP.AsSlice()) } diff --git a/rules/provider/provider.go b/rules/provider/provider.go index 347bebaa..175917c2 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -37,6 +37,7 @@ type ruleStrategy interface { Match(metadata *C.Metadata) bool Count() int ShouldResolveIP() bool + ShouldFindProcess() bool OnUpdate(rules []string) } @@ -86,6 +87,10 @@ func (rp *ruleSetProvider) ShouldResolveIP() bool { return rp.strategy.ShouldResolveIP() } +func (rp *ruleSetProvider) ShouldFindProcess() bool { + return rp.strategy.ShouldFindProcess() +} + func (rp *ruleSetProvider) AsRule(adaptor string) C.Rule { panic("implement me") } diff --git a/rules/provider/rule_set.go b/rules/provider/rule_set.go index 326e3b0d..4a49ad41 100644 --- a/rules/provider/rule_set.go +++ b/rules/provider/rule_set.go @@ -9,14 +9,15 @@ import ( type RuleSet struct { *common.Base - ruleProviderName string - adapter string - ruleProvider P.RuleProvider - noResolveIP bool + ruleProviderName string + adapter string + ruleProvider P.RuleProvider + noResolveIP bool + shouldFindProcess bool } func (rs *RuleSet) ShouldFindProcess() bool { - return false + return !rs.shouldFindProcess && rs.getProviders().ShouldFindProcess() } func (rs *RuleSet) RuleType() C.RuleType { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c5534062..0cc045c3 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -148,12 +148,8 @@ func SetMode(m TunnelMode) { // SetFindProcessMode replace SetAlwaysFindProcess // always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory -func SetFindProcessMode(legacyAlways bool, mode P.FindProcessMode) { - if legacyAlways { - findProcessMode = P.FindProcessAlways - } else { - findProcessMode = mode - } +func SetFindProcessMode(mode P.FindProcessMode) { + findProcessMode = mode } // processUDP starts a loop to handle udp packet From 8cd1e40fb3b6d1463b09e5cb8bc928bf06a774ac Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 20 Jan 2023 17:13:32 +0800 Subject: [PATCH 037/126] Update README.md --- .github/workflows/prerelease.yml | 5 ++++- README.md | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index e32cdce0..456039df 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -2,6 +2,9 @@ name: Prerelease on: workflow_dispatch: push: + paths: + - '!README.md' + - '!docs/**' branches: - Alpha - Beta @@ -186,4 +189,4 @@ jobs: tag_name: Prerelease-${{ github.ref_name }} files: bin/* prerelease: true - generate_release_notes: true \ No newline at end of file + generate_release_notes: true diff --git a/README.md b/README.md index 321ce97e..f1f10151 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ - Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`. - Comprehensive HTTP RESTful API controller -## Getting Started -Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash/wiki). +## Wiki +Documentation is available on [Clash.Meta Wiki](https://docs.metacubex.one/). ## Advanced usage for this branch @@ -49,11 +49,16 @@ If you can't visit github,you should set proxy first: go env -w GOPROXY=https://goproxy.io,direct ``` -So now you can build it: +Now you can build it: ```shell go build ``` +If you need gvisor for tun stack, build with: +```shell +go build -tags with_gvisor +``` + ### DNS configuration Support `geosite` with `fallback-filter`. @@ -110,7 +115,7 @@ Built-in [Wintun](https://www.wintun.net) driver. # Enable the TUN listener tun: enable: true - stack: gvisor # only gvisor + stack: system # system/gvisor dns-hijack: - 0.0.0.0:53 # additional dns server listen on TUN auto-route: true # auto set global route From 4f641ce12da74c7688015d2f177db55c127bc9a0 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 20 Jan 2023 17:35:49 +0800 Subject: [PATCH 038/126] fix: ShadowTLS header use array instead --- transport/shadowtls/shadowtls.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/transport/shadowtls/shadowtls.go b/transport/shadowtls/shadowtls.go index 86a23779..2c0c5946 100644 --- a/transport/shadowtls/shadowtls.go +++ b/transport/shadowtls/shadowtls.go @@ -54,8 +54,8 @@ func (h HashedConn) Read(b []byte) (n int, err error) { } func (s *ShadowTLS) read(b []byte) (int, error) { - buf := pool.Get(tlsHeaderLen) - _, err := io.ReadFull(s.Conn, buf) + var buf [tlsHeaderLen]byte + _, err := io.ReadFull(s.Conn, buf[:]) if err != nil { return 0, fmt.Errorf("shadowtls read failed %w", err) } @@ -63,7 +63,6 @@ func (s *ShadowTLS) read(b []byte) (int, error) { return 0, fmt.Errorf("invalid shadowtls header %v", buf) } length := int(binary.BigEndian.Uint16(buf[3:])) - pool.Put(buf) if length > len(b) { n, err := s.Conn.Read(b) From fb623c09298eb2fa3c856e8e72ba5d7c219d268a Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:23:51 +0800 Subject: [PATCH 039/126] chore: Correct the decision of enabling find process --- rules/provider/rule_set.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/provider/rule_set.go b/rules/provider/rule_set.go index 4a49ad41..45cddf6c 100644 --- a/rules/provider/rule_set.go +++ b/rules/provider/rule_set.go @@ -17,7 +17,7 @@ type RuleSet struct { } func (rs *RuleSet) ShouldFindProcess() bool { - return !rs.shouldFindProcess && rs.getProviders().ShouldFindProcess() + return rs.shouldFindProcess || rs.getProviders().ShouldFindProcess() } func (rs *RuleSet) RuleType() C.RuleType { From 24e31d0a400764ac0b93ec522210a35425a16a29 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:42:48 +0800 Subject: [PATCH 040/126] Chore: Update paths-ignore --- .github/workflows/prerelease.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 456039df..41558baf 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -2,9 +2,9 @@ name: Prerelease on: workflow_dispatch: push: - paths: - - '!README.md' - - '!docs/**' + paths-ignore: + - 'docs/**' + - 'README.md' branches: - Alpha - Beta From 3bace079488070a1fa5454d2f3b9aadd310101f4 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 21 Jan 2023 22:31:07 +0800 Subject: [PATCH 041/126] fix: ipv6 logic --- hub/executor/executor.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 94398db1..16a194c2 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -154,20 +154,17 @@ func preUpdateExperimental(c *config.Config) { func updateDNS(c *config.DNS, generalIPv6 bool) { if !c.Enable { - resolver.DisableIPv6 = !generalIPv6 resolver.DefaultResolver = nil resolver.DefaultHostMapper = nil resolver.DefaultLocalServer = nil dns.ReCreateServer("", nil, nil) return - } else { - resolver.DisableIPv6 = !c.IPv6 } cfg := dns.Config{ Main: c.NameServer, Fallback: c.Fallback, - IPv6: c.IPv6, + IPv6: c.IPv6 && generalIPv6, EnhancedMode: c.EnhancedMode, Pool: c.FakeIPRange, Hosts: c.Hosts, @@ -312,9 +309,8 @@ func updateGeneral(general *config.General, force bool) { dialer.DisableIPv6 = !general.IPv6 if !dialer.DisableIPv6 { log.Infoln("Use IPv6") - } else { - resolver.DisableIPv6 = true } + resolver.DisableIPv6 = dialer.DisableIPv6 if general.TCPConcurrent { dialer.SetDial(general.TCPConcurrent) From d426db43ec97aefb02b3f4b44a500be60ce8bd16 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 11:14:45 +0800 Subject: [PATCH 042/126] chore: adjust log --- component/resource/fetcher.go | 4 ++-- hub/executor/executor.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index df8e9a54..4b905c7f 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -57,7 +57,7 @@ func (f *Fetcher[V]) Initial() (V, error) { f.UpdatedAt = &modTime isLocal = true if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { - log.Infoln("[Provider] %s not updated for a long time, force refresh", f.Name()) + log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name()) forceUpdate = true } } else { @@ -162,7 +162,7 @@ func (f *Fetcher[V]) pullLoop() { case <-f.ticker.C: elm, same, err := f.Update() if err != nil { - log.Warnln("[Provider] %s pull error: %s", f.Name(), err.Error()) + log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error()) continue } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 16a194c2..9082f856 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -223,11 +223,11 @@ func loadProvider(pv provider.Provider) { switch pv.Type() { case provider.Proxy: { - log.Warnln("initial proxy provider %s error: %v", (pv).Name(), err) + log.Errorln("initial proxy provider %s error: %v", (pv).Name(), err) } case provider.Rule: { - log.Warnln("initial rule provider %s error: %v", (pv).Name(), err) + log.Errorln("initial rule provider %s error: %v", (pv).Name(), err) } } From d1f5bef25d46f882a66b7bb7b2e313c73953f745 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 11:17:30 +0800 Subject: [PATCH 043/126] chore: better log --- component/sniffer/dispatcher.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index fd4fe98e..759e1043 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -101,13 +101,13 @@ func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) { } originHost := metadata.Host if originHost != host { - log.Infoln("[Sniffer] Sniff TCP [%s:%s]-->[%s:%s] success, replace domain [%s]-->[%s]", - metadata.SrcIP, metadata.SrcPort, + log.Infoln("[Sniffer] Sniff TCP [%s]-->[%s:%s] success, replace domain [%s]-->[%s]", + metadata.SourceDetail(), dstIP, metadata.DstPort, metadata.Host, host) } else { - log.Debugln("[Sniffer] Sniff TCP [%s:%s]-->[%s:%s] success, replace domain [%s]-->[%s]", - metadata.SrcIP, metadata.SrcPort, + log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s:%s] success, replace domain [%s]-->[%s]", + metadata.SourceDetail(), dstIP, metadata.DstPort, metadata.Host, host) } From df1f6e2b991fb148a9bbf000696088d7559e3854 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 13:16:25 +0800 Subject: [PATCH 044/126] feat: better config for sniffer --- component/sniffer/base_sniffer.go | 52 ++++++++++++ component/sniffer/dispatcher.go | 27 +++---- component/sniffer/http_sniffer.go | 17 ++++ component/sniffer/tls_sniffer.go | 17 ++++ config/config.go | 127 ++++++++++++++++++------------ constant/sniffer/sniffer.go | 1 + hub/executor/executor.go | 2 +- 7 files changed, 179 insertions(+), 64 deletions(-) create mode 100644 component/sniffer/base_sniffer.go diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go new file mode 100644 index 00000000..6d076b59 --- /dev/null +++ b/component/sniffer/base_sniffer.go @@ -0,0 +1,52 @@ +package sniffer + +import ( + "errors" + + "github.com/Dreamacro/clash/common/utils" + "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/constant/sniffer" +) + +type SnifferConfig struct { + Ports []utils.Range[uint16] +} + +type BaseSniffer struct { + ports []utils.Range[uint16] + supportNetworkType constant.NetWork +} + +// Protocol implements sniffer.Sniffer +func (*BaseSniffer) Protocol() string { + return "unknown" +} + +// SniffTCP implements sniffer.Sniffer +func (*BaseSniffer) SniffTCP(bytes []byte) (string, error) { + return "", errors.New("TODO") +} + +// SupportNetwork implements sniffer.Sniffer +func (bs *BaseSniffer) SupportNetwork() constant.NetWork { + return bs.supportNetworkType +} + +// SupportPort implements sniffer.Sniffer +func (bs *BaseSniffer) SupportPort(port uint16) bool { + for _, portRange := range bs.ports { + if portRange.Contains(port) { + return true + } + } + return false +} + +func NewBaseSniffer(ports []utils.Range[uint16], networkType constant.NetWork) *BaseSniffer { + return &BaseSniffer{ + ports: ports, + supportNetworkType: networkType, + } +} + +var _ sniffer.Sniffer = (*BaseSniffer)(nil) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 759e1043..a450693b 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -11,7 +11,6 @@ import ( "github.com/Dreamacro/clash/common/cache" N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/sniffer" @@ -33,7 +32,6 @@ type SnifferDispatcher struct { forceDomain *trie.DomainTrie[struct{}] skipSNI *trie.DomainTrie[struct{}] - portRanges *[]utils.Range[uint16] skipList *cache.LruCache[string, uint8] rwMux sync.RWMutex @@ -55,10 +53,12 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { } inWhitelist := false - for _, portRange := range *sd.portRanges { - if portRange.Contains(uint16(port)) { - inWhitelist = true - break + for _, sniffer := range sd.sniffers { + if sniffer.SupportNetwork() == C.TCP || sniffer.SupportNetwork() == C.ALLNet { + inWhitelist = sniffer.SupportPort(uint16(port)) + if inWhitelist { + break + } } } @@ -182,21 +182,20 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) { return &dispatcher, nil } -func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTrie[struct{}], - skipSNI *trie.DomainTrie[struct{}], ports *[]utils.Range[uint16], +func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, forceDomain *trie.DomainTrie[struct{}], + skipSNI *trie.DomainTrie[struct{}], forceDnsMapping bool, parsePureIp bool) (*SnifferDispatcher, error) { dispatcher := SnifferDispatcher{ enable: true, forceDomain: forceDomain, skipSNI: skipSNI, - portRanges: ports, skipList: cache.New[string, uint8](cache.WithSize[string, uint8](128), cache.WithAge[string, uint8](600)), forceDnsMapping: forceDnsMapping, parsePureIp: parsePureIp, } - for _, snifferName := range needSniffer { - s, err := NewSniffer(snifferName) + for snifferName, config := range snifferConfig { + s, err := NewSniffer(snifferName, config) if err != nil { log.Errorln("Sniffer name[%s] is error", snifferName) return &SnifferDispatcher{enable: false}, err @@ -208,12 +207,12 @@ func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTr return &dispatcher, nil } -func NewSniffer(name sniffer.Type) (sniffer.Sniffer, error) { +func NewSniffer(name sniffer.Type, snifferConfig SnifferConfig) (sniffer.Sniffer, error) { switch name { case sniffer.TLS: - return &TLSSniffer{}, nil + return NewTLSSniffer(snifferConfig) case sniffer.HTTP: - return &HTTPSniffer{}, nil + return NewHTTPSniffer(snifferConfig) default: return nil, ErrorUnsupportedSniffer } diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index 551b20c8..bfa7ca6e 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -7,7 +7,9 @@ import ( "net" "strings" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/constant/sniffer" ) var ( @@ -24,10 +26,25 @@ const ( ) type HTTPSniffer struct { + *BaseSniffer version version host string } +var _ sniffer.Sniffer = (*HTTPSniffer)(nil) + +func NewHTTPSniffer(snifferConfig SnifferConfig) (*HTTPSniffer, error) { + ports := make([]utils.Range[uint16], 0) + if len(snifferConfig.Ports) == 0 { + ports = append(ports, *utils.NewRange[uint16](80, 80)) + } else { + ports = append(ports, snifferConfig.Ports...) + } + return &HTTPSniffer{ + BaseSniffer: NewBaseSniffer(ports, C.TCP), + }, nil +} + func (http *HTTPSniffer) Protocol() string { switch http.version { case HTTP1: diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index f5a8fd99..0867d0f0 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -5,7 +5,9 @@ import ( "errors" "strings" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/constant/sniffer" ) var ( @@ -13,7 +15,22 @@ var ( errNotClientHello = errors.New("not client hello") ) +var _ sniffer.Sniffer = (*TLSSniffer)(nil) + type TLSSniffer struct { + *BaseSniffer +} + +func NewTLSSniffer(snifferConfig SnifferConfig) (*TLSSniffer, error) { + ports := make([]utils.Range[uint16], 0) + if len(snifferConfig.Ports) == 0 { + ports = append(ports, *utils.NewRange[uint16](443, 443)) + } else { + ports = append(ports, snifferConfig.Ports...) + } + return &TLSSniffer{ + BaseSniffer: NewBaseSniffer(ports, C.TCP), + }, nil } func (tls *TLSSniffer) Protocol() string { diff --git a/config/config.go b/config/config.go index c5ba80fc..f4a991a9 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ import ( "time" P "github.com/Dreamacro/clash/component/process" + SNIFF "github.com/Dreamacro/clash/component/sniffer" "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/outbound" @@ -134,11 +135,10 @@ type IPTables struct { type Sniffer struct { Enable bool - Sniffers []snifferTypes.Type + Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig Reverses *trie.DomainTrie[struct{}] ForceDomain *trie.DomainTrie[struct{}] SkipDomain *trie.DomainTrie[struct{}] - Ports *[]utils.Range[uint16] ForceDnsMapping bool ParsePureIp bool } @@ -287,13 +287,18 @@ type RawGeoXUrl struct { } type RawSniffer struct { - Enable bool `yaml:"enable" json:"enable"` - Sniffing []string `yaml:"sniffing" json:"sniffing"` - ForceDomain []string `yaml:"force-domain" json:"force-domain"` - SkipDomain []string `yaml:"skip-domain" json:"skip-domain"` - Ports []string `yaml:"port-whitelist" json:"port-whitelist"` - ForceDnsMapping bool `yaml:"force-dns-mapping" json:"force-dns-mapping"` - ParsePureIp bool `yaml:"parse-pure-ip" json:"parse-pure-ip"` + Enable bool `yaml:"enable" json:"enable"` + Sniffing []string `yaml:"sniffing" json:"sniffing"` + ForceDomain []string `yaml:"force-domain" json:"force-domain"` + SkipDomain []string `yaml:"skip-domain" json:"skip-domain"` + Ports []string `yaml:"port-whitelist" json:"port-whitelist"` + ForceDnsMapping bool `yaml:"force-dns-mapping" json:"force-dns-mapping"` + ParsePureIp bool `yaml:"parse-pure-ip" json:"parse-pure-ip"` + Sniff map[string]RawSniffingConfig `yaml:"sniff" json:"sniff"` +} + +type RawSniffingConfig struct { + Ports []string `yaml:"ports" json:"ports"` } // EBpf config @@ -1187,55 +1192,54 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { ForceDnsMapping: snifferRaw.ForceDnsMapping, ParsePureIp: snifferRaw.ParsePureIp, } + loadSniffer := make(map[snifferTypes.Type]SNIFF.SnifferConfig) - var ports []utils.Range[uint16] - if len(snifferRaw.Ports) == 0 { - ports = append(ports, *utils.NewRange[uint16](80, 80)) - ports = append(ports, *utils.NewRange[uint16](443, 443)) - } else { - for _, portRange := range snifferRaw.Ports { - portRaws := strings.Split(portRange, "-") - p, err := strconv.ParseUint(portRaws[0], 10, 16) + if len(snifferRaw.Sniff) != 0 { + for sniffType, sniffConfig := range snifferRaw.Sniff { + find := false + ports, err := parsePortRange(sniffConfig.Ports) if err != nil { - return nil, fmt.Errorf("%s format error", portRange) + return nil, err } - - start := uint16(p) - if len(portRaws) > 1 { - p, err = strconv.ParseUint(portRaws[1], 10, 16) - if err != nil { - return nil, fmt.Errorf("%s format error", portRange) + for _, snifferType := range snifferTypes.List { + if snifferType.String() == strings.ToUpper(sniffType) { + find = true + loadSniffer[snifferType] = SNIFF.SnifferConfig{ + Ports: ports, + } } + } - end := uint16(p) - ports = append(ports, *utils.NewRange(start, end)) - } else { - ports = append(ports, *utils.NewRange(start, start)) + if !find { + return nil, fmt.Errorf("not find the sniffer[%s]", sniffType) + } + } + } else { + // Deprecated: Use Sniff instead + log.Warnln("Deprecated: Use Sniff instead") + globalPorts, err := parsePortRange(snifferRaw.Ports) + if err != nil { + return nil, err + } + + for _, snifferName := range snifferRaw.Sniffing { + find := false + for _, snifferType := range snifferTypes.List { + if snifferType.String() == strings.ToUpper(snifferName) { + find = true + loadSniffer[snifferType] = SNIFF.SnifferConfig{ + Ports: globalPorts, + } + } + } + + if !find { + return nil, fmt.Errorf("not find the sniffer[%s]", snifferName) } } } - sniffer.Ports = &ports - - loadSniffer := make(map[snifferTypes.Type]struct{}) - - for _, snifferName := range snifferRaw.Sniffing { - find := false - for _, snifferType := range snifferTypes.List { - if snifferType.String() == strings.ToUpper(snifferName) { - find = true - loadSniffer[snifferType] = struct{}{} - } - } - - if !find { - return nil, fmt.Errorf("not find the sniffer[%s]", snifferName) - } - } - - for st := range loadSniffer { - sniffer.Sniffers = append(sniffer.Sniffers, st) - } + sniffer.Sniffers = loadSniffer sniffer.ForceDomain = trie.New[struct{}]() for _, domain := range snifferRaw.ForceDomain { err := sniffer.ForceDomain.Insert(domain, struct{}{}) @@ -1256,3 +1260,28 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { return sniffer, nil } + +func parsePortRange(portRanges []string) ([]utils.Range[uint16], error) { + ports := make([]utils.Range[uint16], 0) + for _, portRange := range portRanges { + portRaws := strings.Split(portRange, "-") + p, err := strconv.ParseUint(portRaws[0], 10, 16) + if err != nil { + return nil, fmt.Errorf("%s format error", portRange) + } + + start := uint16(p) + if len(portRaws) > 1 { + p, err = strconv.ParseUint(portRaws[1], 10, 16) + if err != nil { + return nil, fmt.Errorf("%s format error", portRange) + } + + end := uint16(p) + ports = append(ports, *utils.NewRange(start, end)) + } else { + ports = append(ports, *utils.NewRange(start, start)) + } + } + return ports, nil +} diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index 8ab2d496..6b20b3f6 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -6,6 +6,7 @@ type Sniffer interface { SupportNetwork() constant.NetWork SniffTCP(bytes []byte) (string, error) Protocol() string + SupportPort(port uint16) bool } const ( diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 9082f856..d88e91dc 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -279,7 +279,7 @@ func updateTun(general *config.General) { func updateSniffer(sniffer *config.Sniffer) { if sniffer.Enable { dispatcher, err := SNI.NewSnifferDispatcher( - sniffer.Sniffers, sniffer.ForceDomain, sniffer.SkipDomain, sniffer.Ports, + sniffer.Sniffers, sniffer.ForceDomain, sniffer.SkipDomain, sniffer.ForceDnsMapping, sniffer.ParsePureIp, ) if err != nil { From 096bb8d4391e6792aa7ff33773aa2bb68875a54c Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 14:08:11 +0800 Subject: [PATCH 045/126] feat: add override-destination for sniffer --- component/sniffer/base_sniffer.go | 3 ++- component/sniffer/dispatcher.go | 37 +++++++++++++++++-------------- config/config.go | 14 +++++++++--- constant/metadata.go | 10 +++++++++ rules/common/domain.go | 2 +- rules/common/domain_keyword.go | 2 +- rules/common/domain_suffix.go | 2 +- rules/common/geosite.go | 2 +- rules/provider/domain_strategy.go | 2 +- 9 files changed, 48 insertions(+), 26 deletions(-) diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index 6d076b59..c2958cc6 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -9,7 +9,8 @@ import ( ) type SnifferConfig struct { - Ports []utils.Range[uint16] + OverrideDest bool + Ports []utils.Range[uint16] } type BaseSniffer struct { diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index a450693b..0d6badf5 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -26,15 +26,12 @@ var ( var Dispatcher *SnifferDispatcher type SnifferDispatcher struct { - enable bool - - sniffers []sniffer.Sniffer - - forceDomain *trie.DomainTrie[struct{}] - skipSNI *trie.DomainTrie[struct{}] - skipList *cache.LruCache[string, uint8] - rwMux sync.RWMutex - + enable bool + sniffers map[sniffer.Sniffer]SnifferConfig + forceDomain *trie.DomainTrie[struct{}] + skipSNI *trie.DomainTrie[struct{}] + skipList *cache.LruCache[string, uint8] + rwMux sync.RWMutex forceDnsMapping bool parsePureIp bool } @@ -53,10 +50,12 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { } inWhitelist := false - for _, sniffer := range sd.sniffers { + overrideDest := false + for sniffer, config := range sd.sniffers { if sniffer.SupportNetwork() == C.TCP || sniffer.SupportNetwork() == C.ALLNet { inWhitelist = sniffer.SupportPort(uint16(port)) if inWhitelist { + overrideDest = config.OverrideDest break } } @@ -89,12 +88,12 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { sd.skipList.Delete(dst) sd.rwMux.RUnlock() - sd.replaceDomain(metadata, host) + sd.replaceDomain(metadata, host, overrideDest) } } } -func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) { +func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { dstIP := "" if metadata.DstIP.IsValid() { dstIP = metadata.DstIP.String() @@ -112,7 +111,11 @@ func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) { metadata.Host, host) } - metadata.Host = host + if overrideDest { + metadata.Host = host + } else { + metadata.SniffHost = host + } metadata.DNSMode = C.DNSNormal } @@ -121,7 +124,7 @@ func (sd *SnifferDispatcher) Enable() bool { } func (sd *SnifferDispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metadata) (string, error) { - for _, s := range sd.sniffers { + for s := range sd.sniffers { if s.SupportNetwork() == C.TCP { _ = conn.SetReadDeadline(time.Now().Add(1 * time.Second)) _, err := conn.Peek(1) @@ -189,9 +192,10 @@ func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, forceDom enable: true, forceDomain: forceDomain, skipSNI: skipSNI, - skipList: cache.New[string, uint8](cache.WithSize[string, uint8](128), cache.WithAge[string, uint8](600)), + skipList: cache.New(cache.WithSize[string, uint8](128), cache.WithAge[string, uint8](600)), forceDnsMapping: forceDnsMapping, parsePureIp: parsePureIp, + sniffers: make(map[sniffer.Sniffer]SnifferConfig, 0), } for snifferName, config := range snifferConfig { @@ -200,8 +204,7 @@ func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, forceDom log.Errorln("Sniffer name[%s] is error", snifferName) return &SnifferDispatcher{enable: false}, err } - - dispatcher.sniffers = append(dispatcher.sniffers, s) + dispatcher.sniffers[s] = config } return &dispatcher, nil diff --git a/config/config.go b/config/config.go index f4a991a9..c5ff0577 100644 --- a/config/config.go +++ b/config/config.go @@ -288,6 +288,7 @@ type RawGeoXUrl struct { type RawSniffer struct { Enable bool `yaml:"enable" json:"enable"` + OverrideDest bool `yaml:"override-destination" json:"override-destination"` Sniffing []string `yaml:"sniffing" json:"sniffing"` ForceDomain []string `yaml:"force-domain" json:"force-domain"` SkipDomain []string `yaml:"skip-domain" json:"skip-domain"` @@ -298,7 +299,8 @@ type RawSniffer struct { } type RawSniffingConfig struct { - Ports []string `yaml:"ports" json:"ports"` + Ports []string `yaml:"ports" json:"ports"` + OverrideDest *bool `yaml:"override-destination" json:"override-destination"` } // EBpf config @@ -1201,11 +1203,16 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { if err != nil { return nil, err } + overrideDest := snifferRaw.OverrideDest + if sniffConfig.OverrideDest != nil { + overrideDest = *sniffConfig.OverrideDest + } for _, snifferType := range snifferTypes.List { if snifferType.String() == strings.ToUpper(sniffType) { find = true loadSniffer[snifferType] = SNIFF.SnifferConfig{ - Ports: ports, + Ports: ports, + OverrideDest: overrideDest, } } } @@ -1228,7 +1235,8 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { if snifferType.String() == strings.ToUpper(snifferName) { find = true loadSniffer[snifferType] = SNIFF.SnifferConfig{ - Ports: globalPorts, + Ports: globalPorts, + OverrideDest: snifferRaw.OverrideDest, } } } diff --git a/constant/metadata.go b/constant/metadata.go index 4605a146..d57c21b6 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -134,6 +134,8 @@ type Metadata struct { SpecialProxy string `json:"specialProxy"` SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` + // Only domain rule + SniffHost string } func (m *Metadata) RemoteAddress() string { @@ -176,6 +178,14 @@ func (m *Metadata) Resolved() bool { return m.DstIP.IsValid() } +func (m *Metadata) RuleHost() string { + if len(m.SniffHost) == 0 { + return m.Host + } else { + return m.SniffHost + } +} + // Pure is used to solve unexpected behavior // when dialing proxy connection in DNSMapping mode. func (m *Metadata) Pure() *Metadata { diff --git a/rules/common/domain.go b/rules/common/domain.go index 1dc6b250..6b3eba22 100644 --- a/rules/common/domain.go +++ b/rules/common/domain.go @@ -19,7 +19,7 @@ func (d *Domain) RuleType() C.RuleType { } func (d *Domain) Match(metadata *C.Metadata) (bool, string) { - return metadata.Host == d.domain, d.adapter + return metadata.RuleHost() == d.domain, d.adapter } func (d *Domain) Adapter() string { diff --git a/rules/common/domain_keyword.go b/rules/common/domain_keyword.go index 4fff673e..94d2a949 100644 --- a/rules/common/domain_keyword.go +++ b/rules/common/domain_keyword.go @@ -19,7 +19,7 @@ func (dk *DomainKeyword) RuleType() C.RuleType { } func (dk *DomainKeyword) Match(metadata *C.Metadata) (bool, string) { - domain := metadata.Host + domain := metadata.RuleHost() return strings.Contains(domain, dk.keyword), dk.adapter } diff --git a/rules/common/domain_suffix.go b/rules/common/domain_suffix.go index 1e48a236..4bdc2e2e 100644 --- a/rules/common/domain_suffix.go +++ b/rules/common/domain_suffix.go @@ -19,7 +19,7 @@ func (ds *DomainSuffix) RuleType() C.RuleType { } func (ds *DomainSuffix) Match(metadata *C.Metadata) (bool, string) { - domain := metadata.Host + domain := metadata.RuleHost() return strings.HasSuffix(domain, "."+ds.suffix) || domain == ds.suffix, ds.adapter } diff --git a/rules/common/geosite.go b/rules/common/geosite.go index 865b0b1b..c0a3a1da 100644 --- a/rules/common/geosite.go +++ b/rules/common/geosite.go @@ -29,7 +29,7 @@ func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) { return false, "" } - domain := metadata.Host + domain := metadata.RuleHost() return gs.matcher.ApplyDomain(domain), gs.adapter } diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index 85528f40..add64e76 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -17,7 +17,7 @@ func (d *domainStrategy) ShouldFindProcess() bool { } func (d *domainStrategy) Match(metadata *C.Metadata) bool { - return d.domainRules != nil && d.domainRules.Search(metadata.Host) != nil + return d.domainRules != nil && d.domainRules.Search(metadata.RuleHost()) != nil } func (d *domainStrategy) Count() int { From 1225173a43e13db4cb970964ed1e616b6382478d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 14:12:53 +0800 Subject: [PATCH 046/126] chore: update config.yaml --- docs/config.yaml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 206548b2..1da21c74 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -9,7 +9,6 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为 true,'*'表示所有地址 - # find-process-mode has 3 values: always, strict, off # - always, 开启,强制匹配所有进程 # - strict, 默认,由clash判断是否开启 @@ -87,14 +86,31 @@ ebpf: # 嗅探域名 可选配置 sniffer: enable: false + # 是否适用嗅探结果作为实际访问,默认 false + override-destination: false + sniff: + # TLS 默认如果不配置 ports 默认嗅探 443 + TLS: + # ports: [443, 8443] + + # 默认嗅探 80 + HTTP: + # 需要嗅探的端口 + + ports: [80, 8080-8880] + # 可覆盖 sniffer.override-destination + override-destination: true + force-domain: + - +.v2ex.com # 需要嗅探协议 + # 已废弃 sniffing: - tls - http # 强制对此域名进行嗅探 - force-domain: - - +.v2ex.com + # 仅对白名单中的端口进行嗅探,默认为 443,80 + # 已废弃 port-whitelist: - "80" - "443" From 97537bd1854bd89573cc2e7863c5a194d1ec83c6 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 14:14:18 +0800 Subject: [PATCH 047/126] chore: update config.yaml --- docs/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 1da21c74..76c76f02 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -103,14 +103,14 @@ sniffer: force-domain: - +.v2ex.com # 需要嗅探协议 - # 已废弃 + # 已废弃,若 sniffer.sniff 配置则此项无效 sniffing: - tls - http # 强制对此域名进行嗅探 # 仅对白名单中的端口进行嗅探,默认为 443,80 - # 已废弃 + # 已废弃,若 sniffer.sniff 配置则此项无效 port-whitelist: - "80" - "443" From b54ddc3aa9a26e771bd0ee2cf78bd174231327cc Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 14:19:13 +0800 Subject: [PATCH 048/126] chore: update config.yaml --- docs/config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 76c76f02..a677ca35 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -86,7 +86,8 @@ ebpf: # 嗅探域名 可选配置 sniffer: enable: false - # 是否适用嗅探结果作为实际访问,默认 false + # 是否使用嗅探结果作为实际访问,默认 false + # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false sniff: # TLS 默认如果不配置 ports 默认嗅探 443 From 39394e49ae833b7a4387de4b5fb5947b40a63891 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 23 Jan 2023 14:51:25 +0800 Subject: [PATCH 049/126] chore: update config.yaml --- docs/config.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/config.yaml b/docs/config.yaml index a677ca35..2ef06023 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -86,6 +86,11 @@ ebpf: # 嗅探域名 可选配置 sniffer: enable: false + ## 对 redir-host 类型识别的流量进行强制嗅探 + ## 如:Tun、Redir 和 TProxy 并 DNS 为 redir-host 皆属于 + # force-dns-mapping: false + ## 对所有未获取到域名的流量进行强制嗅探 + # parse-pure-ip: false # 是否使用嗅探结果作为实际访问,默认 false # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false @@ -103,6 +108,9 @@ sniffer: override-destination: true force-domain: - +.v2ex.com + ## 对嗅探结果进行跳过 + # skip-domain: + # - Mijia Cloud # 需要嗅探协议 # 已废弃,若 sniffer.sniff 配置则此项无效 sniffing: From 023a96a6d3424f84693d45dc7ba6ef0f612de3f7 Mon Sep 17 00:00:00 2001 From: ag2s20150909 Date: Tue, 24 Jan 2023 16:34:52 +0800 Subject: [PATCH 050/126] make ConvertsV2Ray more robust (#349) * make ConvertsV2Ray more robust * add log * fix --- adapter/outboundgroup/groupbase.go | 1 + adapter/provider/provider.go | 1 + common/convert/converter.go | 13 +++++++++++-- common/convert/v.go | 10 +++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index fee24bd6..0a421793 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -165,6 +165,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { for i := range gb.excludeTypeArray { if strings.EqualFold(mType, gb.excludeTypeArray[i]) { flag = true + break } } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 7d7ba977..e8bd7ed1 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -301,6 +301,7 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray for i := range excludeTypeArray { if strings.EqualFold(pType, excludeTypeArray[i]) { flag = true + break } } diff --git a/common/convert/converter.go b/common/convert/converter.go index 891f43bb..d58e0bab 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/Dreamacro/clash/log" "net/url" "strconv" "strings" @@ -120,7 +121,11 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { } query := urlVLess.Query() vless := make(map[string]any, 20) - handleVShareLink(names, urlVLess, scheme, vless) + err = handleVShareLink(names, urlVLess, scheme, vless) + if err != nil { + log.Warnln("error:%s line:%s", err.Error(), line) + continue + } if flow := query.Get("flow"); flow != "" { vless["flow"] = strings.ToLower(flow) } @@ -138,7 +143,11 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { } query := urlVMess.Query() vmess := make(map[string]any, 20) - handleVShareLink(names, urlVMess, scheme, vmess) + err = handleVShareLink(names, urlVMess, scheme, vmess) + if err != nil { + log.Warnln("error:%s line:%s", err.Error(), line) + continue + } vmess["alterId"] = 0 vmess["cipher"] = "auto" if encryption := query.Get("encryption"); encryption != "" { diff --git a/common/convert/v.go b/common/convert/v.go index 29be4a9f..02c7b707 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -1,15 +1,22 @@ package convert import ( + "errors" "net/url" "strings" ) -func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy map[string]any) { +func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy map[string]any) error { // Xray VMessAEAD / VLESS share link standard // https://github.com/XTLS/Xray-core/discussions/716 query := url.Query() proxy["name"] = uniqueName(names, url.Fragment) + if url.Hostname() == "" { + return errors.New("url.Hostname() is empty") + } + if url.Port() == "" { + return errors.New("url.Port() is empty") + } proxy["type"] = scheme proxy["server"] = url.Hostname() proxy["port"] = url.Port() @@ -94,4 +101,5 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m grpcOpts["grpc-service-name"] = query.Get("serviceName") proxy["grpc-opts"] = grpcOpts } + return nil } From 16c4b55e31a233cd97a87eff6790bb93eb9a78bf Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:48:15 +0800 Subject: [PATCH 051/126] Chore: Decrease the default MaxUdpRelayPacketSize to 1252 to avoid the relay UDP exceeding the size of the QUIC's datagram. ClientMaxOpenStreams now follows the config.yaml option. --- adapter/outbound/tuic.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 417339be..0ca13670 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -165,7 +165,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { } if option.MaxUdpRelayPacketSize == 0 { - option.MaxUdpRelayPacketSize = 1500 + option.MaxUdpRelayPacketSize = 1252 } if option.MaxOpenStreams == 0 { @@ -216,9 +216,14 @@ func NewTuic(option TuicOption) (*Tuic, error) { prefer: C.NewDNSPrefer(option.IPVersion), }, } - // to avoid tuic's "too many open streams", decrease to 0.9x + clientMaxOpenStreams := int64(option.MaxOpenStreams) - clientMaxOpenStreams = clientMaxOpenStreams - int64(math.Ceil(float64(clientMaxOpenStreams)/10.0)) + + // to avoid tuic's "too many open streams", decrease to 0.9x + if clientMaxOpenStreams == 100 { + clientMaxOpenStreams = clientMaxOpenStreams - int64(math.Ceil(float64(clientMaxOpenStreams)/10.0)) + } + if clientMaxOpenStreams < 1 { clientMaxOpenStreams = 1 } From 80f48518ca367564e9dacebb3b5357cb31cfda23 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:50:21 +0800 Subject: [PATCH 052/126] Chore: Update config.yaml --- docs/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.yaml b/docs/config.yaml index 2ef06023..f8ab2e1b 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -544,6 +544,7 @@ proxies: # max-udp-relay-packet-size: 1500 # fast-open: true # skip-cert-verify: true + max-open-streams: 16 # default 100, too many open streams may hurt performance # ShadowsocksR # The supported ciphers (encryption methods): all stream ciphers in ss From 9a4be1fbec74b00faebd911203c86e64b6a90597 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 24 Jan 2023 21:56:17 +0800 Subject: [PATCH 053/126] Chore: Action ignore docs/**,README.md when push. --- .github/workflows/docker.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 0d5747a1..fc05376f 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -2,6 +2,9 @@ name: Docker on: push: + paths-ignore: + - 'docs/**' + - 'README.md' branches: - Beta - Alpha From a563e9375e18ad85e3a92aac1e56f3eaff6d78b4 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 25 Jan 2023 13:00:18 +0800 Subject: [PATCH 054/126] chore: better source address --- tunnel/tunnel.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 0cc045c3..9c6c155f 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -304,12 +304,12 @@ func handleUDPConn(packet C.PacketAdapter) { log.Warnln( "[UDP] dial %s %s --> %s error: %s", proxy.Name(), - metadata.SourceAddress(), + metadata.SourceDetail(), metadata.RemoteAddress(), err.Error(), ) } else { - log.Warnln("[UDP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceAddress(), metadata.RemoteAddress(), err.Error()) + log.Warnln("[UDP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) } }) if err != nil { @@ -321,7 +321,7 @@ func handleUDPConn(packet C.PacketAdapter) { switch true { case metadata.SpecialProxy != "": - log.Infoln("[UDP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy) + log.Infoln("[UDP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) case rule != nil: if rule.Payload() != "" { log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), rawPc.Chains().String()) @@ -390,12 +390,12 @@ func handleTCPConn(connCtx C.ConnContext) { log.Warnln( "[TCP] dial %s %s --> %s error: %s", proxy.Name(), - metadata.SourceAddress(), + metadata.SourceDetail(), metadata.RemoteAddress(), err.Error(), ) } else { - log.Warnln("[TCP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceAddress(), metadata.RemoteAddress(), err.Error()) + log.Warnln("[TCP] dial %s (match %s/%s) %s --> %s error: %s", proxy.Name(), rule.RuleType().String(), rule.Payload(), metadata.SourceDetail(), metadata.RemoteAddress(), err.Error()) } }) if err != nil { @@ -409,7 +409,7 @@ func handleTCPConn(connCtx C.ConnContext) { switch true { case metadata.SpecialProxy != "": - log.Infoln("[TCP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy) + log.Infoln("[TCP] %s --> %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), metadata.SpecialProxy) case rule != nil: if rule.Payload() != "" { log.Infoln("[TCP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), remoteConn.Chains().String()) @@ -423,7 +423,7 @@ func handleTCPConn(connCtx C.ConnContext) { default: log.Infoln( "[TCP] %s --> %s doesn't match any rule using DIRECT", - metadata.SourceAddress(), + metadata.SourceDetail(), metadata.RemoteAddress(), ) } From a2aa267e43a2d6cc927ad06dbd909bf583439048 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 25 Jan 2023 20:53:39 +0800 Subject: [PATCH 055/126] chore: update workflows docker --- .github/workflows/docker.yaml | 65 ---------------- .github/workflows/prerelease.yml | 126 +++++++++++++++++++++++++++---- Dockerfile | 19 +++-- docker/file-name.sh | 26 +++++++ 4 files changed, 147 insertions(+), 89 deletions(-) delete mode 100644 .github/workflows/docker.yaml create mode 100644 docker/file-name.sh diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml deleted file mode 100644 index fc05376f..00000000 --- a/.github/workflows/docker.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: Docker - -on: - push: - paths-ignore: - - 'docs/**' - - 'README.md' - branches: - - Beta - - Alpha - tags: - - "v*" -env: - REGISTRY: docker.io -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Setup Docker buildx - uses: docker/setup-buildx-action@v1 - with: - version: latest - - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v3 - with: - images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}} - - - name: Log into registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v2 - with: - context: . - file: ./Dockerfile - push: ${{ github.event_name != 'pull_request' }} - platforms: | - linux/386 - linux/amd64 - linux/arm64/v8 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 41558baf..5d1e0e25 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -3,8 +3,8 @@ on: workflow_dispatch: push: paths-ignore: - - 'docs/**' - - 'README.md' + - "docs/**" + - "README.md" branches: - Alpha - Beta @@ -12,6 +12,8 @@ on: branches: - Alpha - Beta +env: + REGISTRY: docker.io jobs: Build: permissions: write-all @@ -20,18 +22,54 @@ jobs: fail-fast: false matrix: job: - - { type: "WithoutCGO", target: "linux-amd64 linux-amd64-compatible", id: "1" } - - { type: "WithoutCGO", target: "linux-armv5 linux-armv6 linux-armv7", id: "2" } - - { type: "WithoutCGO", target: "linux-arm64 linux-mips64 linux-mips64le", id: "3" } - - { type: "WithoutCGO", target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "4" } - - { type: "WithoutCGO", target: "freebsd-386 freebsd-amd64 freebsd-arm64", id: "5" } - - { type: "WithoutCGO", target: "windows-amd64-compatible windows-amd64 windows-386", id: "6" } - - { type: "WithoutCGO", target: "windows-arm64 windows-arm32v7", id: "7" } - - { type: "WithoutCGO", target: "darwin-amd64 darwin-arm64 android-arm64", id: "8" } + - { + type: "WithoutCGO", + target: "linux-amd64 linux-amd64-compatible", + id: "1", + } + - { + type: "WithoutCGO", + target: "linux-armv5 linux-armv6 linux-armv7", + id: "2", + } + - { + type: "WithoutCGO", + target: "linux-arm64 linux-mips64 linux-mips64le", + id: "3", + } + - { + type: "WithoutCGO", + target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", + id: "4", + } + - { + type: "WithoutCGO", + target: "freebsd-386 freebsd-amd64 freebsd-arm64", + id: "5", + } + - { + type: "WithoutCGO", + target: "windows-amd64-compatible windows-amd64 windows-386", + id: "6", + } + - { + type: "WithoutCGO", + target: "windows-arm64 windows-arm32v7", + id: "7", + } + - { + type: "WithoutCGO", + target: "darwin-amd64 darwin-arm64 android-arm64", + id: "8", + } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386,linux/amd64", id: "2" } - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "3" } - - { type: "WithCGO", target: "linux/arm,linux/arm-6,linux/arm-7", id: "4" } + - { + type: "WithCGO", + target: "linux/arm,linux/arm-6,linux/arm-7", + id: "4", + } - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "5" } - { type: "WithCGO", target: "linux/mips64,linux/mips64le", id: "6" } - { type: "WithCGO", target: "darwin-10.16/*", id: "7" } @@ -77,7 +115,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: "1.19" check-latest: true - name: Test @@ -152,10 +190,9 @@ jobs: name: artifact path: bin/ - Upload: permissions: write-all - needs: [ Build ] + needs: [Build] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 @@ -190,3 +227,64 @@ jobs: files: bin/* prerelease: true generate_release_notes: true + Docker: + permissions: write-all + needs: [Build] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/download-artifact@v3 + with: + name: artifact + path: bin/ + + - name: Display structure of downloaded files + run: ls -R + working-directory: bin + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v1 + with: + version: latest + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v3 + with: + images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}} + - name: Show files + run: | + ls . + ls bin/ + - name: Log into registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + platforms: | + linux/386 + linux/amd64 + linux/arm64/v8 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 10f961a3..9c2e44c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,17 @@ -FROM golang:alpine as builder +FROM alpine:latest as builder -RUN apk add --no-cache make git && \ +RUN apk add --no-cache gzip && \ mkdir /clash-config && \ wget -O /clash-config/Country.mmdb https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb && \ wget -O /clash-config/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat && \ wget -O /clash-config/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat - -COPY . /clash-src -WORKDIR /clash-src -RUN go mod download &&\ - make docker &&\ - mv ./bin/clash.meta-docker /clash - +COPY docker/file-name.sh /clash/file-name.sh +WORKDIR /clash +COPY bin/ bin/ +RUN FILE_NAME=`sh file-name.sh` && echo $FILE_NAME && \ + FILE_NAME=`ls bin/ | egrep "$FILE_NAME.*"|awk NR==1` && \ + mv bin/$FILE_NAME clash.gz && gzip -d clash.gz && echo "$FILE_NAME" > /clash-config/test FROM alpine:latest LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta" @@ -21,6 +20,6 @@ RUN apk add --no-cache ca-certificates tzdata iptables VOLUME ["/root/.config/clash/"] COPY --from=builder /clash-config/ /root/.config/clash/ -COPY --from=builder /clash /clash +COPY --from=builder /clash/clash /clash RUN chmod +x /clash ENTRYPOINT [ "/clash" ] diff --git a/docker/file-name.sh b/docker/file-name.sh new file mode 100644 index 00000000..fb87cad0 --- /dev/null +++ b/docker/file-name.sh @@ -0,0 +1,26 @@ +#!/bin/sh +os="clash.meta-linux-" +arch=`uname -m` +case $arch in + "x86_64") + arch="amd64-compatible" + ;; + "x86") + arch="386-cgo" + ;; + "aarch64") + arch="arm64" + ;; + "armv7l") + arch="armv7" + ;; + "riscv64") + arch="riscv64-cgo" + ;; + *) + echo "Unknown architecture" + exit 1 + ;; +esac +file_name="$os$arch" +echo $file_name \ No newline at end of file From 87553c6aa0e70817aed74a1350acc85af8e1d3bc Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 26 Jan 2023 23:19:33 +0800 Subject: [PATCH 056/126] Update config.yaml --- docs/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index f8ab2e1b..a57c3e86 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -544,7 +544,7 @@ proxies: # max-udp-relay-packet-size: 1500 # fast-open: true # skip-cert-verify: true - max-open-streams: 16 # default 100, too many open streams may hurt performance + # max-open-streams: 20 # default 100, too many open streams may hurt performance # ShadowsocksR # The supported ciphers (encryption methods): all stream ciphers in ss From 248578086fc82a86b005f809f29235310a000cc5 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 27 Jan 2023 11:31:58 +0800 Subject: [PATCH 057/126] feat: Converter support WS early data parameters --- common/convert/v.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/convert/v.go b/common/convert/v.go index 02c7b707..eb2073c3 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -2,7 +2,9 @@ package convert import ( "errors" + "fmt" "net/url" + "strconv" "strings" ) @@ -94,6 +96,17 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m wsOpts["path"] = query.Get("path") wsOpts["headers"] = headers + if earlyData := query.Get("ed"); earlyData != "" { + med, err := strconv.Atoi(earlyData) + if err != nil { + return fmt.Errorf("bad WebSocket max early data size: %v", err) + } + wsOpts["max-early-data"] = med + } + if earlyDataHeader := query.Get("eh"); earlyDataHeader != "" { + wsOpts["early-data-header-name"] = earlyDataHeader + } + proxy["ws-opts"] = wsOpts case "grpc": From 6decaef050941c94547dd837a6d844e51bb80964 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 27 Jan 2023 12:38:15 +0800 Subject: [PATCH 058/126] fix: sub-rule condition don't work --- rules/logic/logic.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rules/logic/logic.go b/rules/logic/logic.go index 4a0bd7e8..a53503df 100644 --- a/rules/logic/logic.go +++ b/rules/logic/logic.go @@ -247,7 +247,10 @@ func matchSubRules(metadata *C.Metadata, name string, subRules map[string][]C.Ru func (logic *Logic) Match(metadata *C.Metadata) (bool, string) { switch logic.ruleType { case C.SubRules: - return matchSubRules(metadata, logic.adapter, logic.subRules) + if m, _ := logic.rules[0].Match(metadata); m { + return matchSubRules(metadata, logic.adapter, logic.subRules) + } + return false, "" case C.NOT: if m, _ := logic.rules[0].Match(metadata); !m { return true, logic.adapter From 5bcea37d59df0badb860204c56ac02f469f89731 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 27 Jan 2023 13:07:52 +0800 Subject: [PATCH 059/126] chore: better parse udp dns --- config/config.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index c5ff0577..66c3a989 100644 --- a/config/config.go +++ b/config/config.go @@ -860,10 +860,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) var nameservers []dns.NameServer for idx, server := range servers { - // parse without scheme .e.g 8.8.8.8:53 - if !strings.Contains(server, "://") { - server = "udp://" + server - } + server, _ = parsePureDNSServer(server) u, err := url.Parse(server) if err != nil { return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error()) @@ -939,6 +936,25 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) return nameservers, nil } +func parsePureDNSServer(server string) (string, bool) { + addPre := func(server string) string { + return "udp://" + server + } + if ip := net.ParseIP(server); ip == nil { + // parse without scheme .e.g 8.8.8.8:53 + + if strings.Contains(server,"://") { + return server, true + } + if addr, err := net.ResolveUDPAddr("", server); err == nil { + return addPre(addr.String()), true + } else { + return addPre(server), false + } + } else { + return addPre(net.JoinHostPort(ip.String(), "53")), true + } +} func parseNameServerPolicy(nsPolicy map[string]string, preferH3 bool) (map[string]dns.NameServer, error) { policy := map[string]dns.NameServer{} From 4629ecb8ee4a68cd2c73118332a8f2209466a704 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:27:39 +0800 Subject: [PATCH 060/126] Chore: Add GEO data url configuration. --- docs/config.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index a57c3e86..ef3fbd1d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -17,6 +17,13 @@ find-process-mode: strict mode: rule +#自定义 geox-url +geox-url: + geoip: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat" + geosite: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat" + mmdb: "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb" + + log-level: debug # 日志等级 silent/error/warning/info/debug ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录 @@ -252,10 +259,10 @@ proxies: # udp: true # udp-over-tcp: false # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual - # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 - # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, - # UDP 则为双栈解析,获取结果中的第一个 IPv4 - # ipv6-prefer 同 ipv4-prefer + # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 + # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, + # UDP 则为双栈解析,获取结果中的第一个 IPv4 + # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 - name: "ss2" type: ss From f7538568c081316ec66869aa00d6961831ab98b0 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:41:23 +0800 Subject: [PATCH 061/126] Chore: Change default latency test url to HTTPS. --- adapter/outboundgroup/parser.go | 2 +- docs/config.yaml | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index ebae562a..05976c89 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -78,7 +78,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide providersMap[groupName] = pd } else { if groupOption.URL == "" { - groupOption.URL = "http://www.gstatic.com/generate_204" + groupOption.URL = "https://cp.cloudflare.com/generate_204" } if groupOption.Interval == 0 { diff --git a/docs/config.yaml b/docs/config.yaml index ef3fbd1d..a3e12939 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -110,7 +110,7 @@ sniffer: HTTP: # 需要嗅探的端口 - ports: [80, 8080-8880] + ports: [ 80, 8080-8880 ] # 可覆盖 sniffer.override-destination override-destination: true force-domain: @@ -156,7 +156,7 @@ tunnels: - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn # full yaml config - - network: [tcp, udp] + - network: [ tcp, udp ] address: 127.0.0.1:7777 target: target.com proxy: proxy @@ -257,8 +257,8 @@ proxies: password: "password" # udp: true - # udp-over-tcp: false - # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual + # udp-over-tcp: false + # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 # ipv4-prefer:优先使用 IPv4 对于 TCP 会进行双栈解析,并发链接但是优先使用 IPv4 链接, # UDP 则为双栈解析,获取结果中的第一个 IPv4 @@ -534,6 +534,8 @@ proxies: private-key: eCtXsJZ27+4PbhDkHnB923tkUn2Gj59wZw5wFA75MnU= public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= udp: true +# reserved: 'U4An' + - name: tuic server: www.example.com @@ -593,7 +595,7 @@ proxy-groups: - vmess1 # tolerance: 150 # lazy: true - url: "http://www.gstatic.com/generate_204" + url: "https://cp.cloudflare.com/generate_204" interval: 300 # fallback 将按照 url 测试结果按照节点顺序选择 @@ -603,7 +605,7 @@ proxy-groups: - ss1 - ss2 - vmess1 - url: "http://www.gstatic.com/generate_204" + url: "https://cp.cloudflare.com/generate_204" interval: 300 # load-balance 将按照算法随机选择节点 @@ -613,7 +615,7 @@ proxy-groups: - ss1 - ss2 - vmess1 - url: "http://www.gstatic.com/generate_204" + url: "https://cp.cloudflare.com/generate_204" interval: 300 # strategy: consistent-hashing # 可选 round-robin 和 sticky-sessions @@ -655,14 +657,14 @@ proxy-providers: enable: true interval: 600 # lazy: true - url: http://www.gstatic.com/generate_204 + url: https://cp.cloudflare.com/generate_204 test: type: file path: /test.yaml health-check: enable: true interval: 36000 - url: http://www.gstatic.com/generate_204 + url: https://cp.cloudflare.com/generate_204 rule-providers: rule1: behavior: classical # domain ipcidr @@ -800,7 +802,7 @@ listeners: listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - network: [tcp, udp] + network: [ tcp, udp ] target: target.com - name: tun-in-1 From d3193cf8b73a6069a6a9c5cc5383b711815c1c2c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:08:05 +0800 Subject: [PATCH 062/126] Chore: Better parsing pure IPv6 UDP DNS --- config/config.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 66c3a989..8935f6c8 100644 --- a/config/config.go +++ b/config/config.go @@ -940,10 +940,15 @@ func parsePureDNSServer(server string) (string, bool) { addPre := func(server string) string { return "udp://" + server } + + //IPv6 server without "[" and "]" e.g., "2400:3200:baba::1" + if strings.Count(server, ":") >= 2 && strings.Count(server, "[") == 0 && strings.Count(server, "]") == 0 { + server = "[" + server + "]:53" + } + if ip := net.ParseIP(server); ip == nil { // parse without scheme .e.g 8.8.8.8:53 - - if strings.Contains(server,"://") { + if strings.Contains(server, "://") { return server, true } if addr, err := net.ResolveUDPAddr("", server); err == nil { @@ -952,7 +957,7 @@ func parsePureDNSServer(server string) (string, bool) { return addPre(server), false } } else { - return addPre(net.JoinHostPort(ip.String(), "53")), true + return addPre(server), true } } func parseNameServerPolicy(nsPolicy map[string]string, preferH3 bool) (map[string]dns.NameServer, error) { From 0d62e42c50a0e5f5824aad0e9971e69570253cf3 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 27 Jan 2023 17:02:58 +0800 Subject: [PATCH 063/126] chore: better parsing pure UDP DNS --- config/config.go | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/config/config.go b/config/config.go index 8935f6c8..489087b5 100644 --- a/config/config.go +++ b/config/config.go @@ -936,28 +936,22 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) return nameservers, nil } -func parsePureDNSServer(server string) (string, bool) { +func parsePureDNSServer(server string) string { addPre := func(server string) string { return "udp://" + server } - //IPv6 server without "[" and "]" e.g., "2400:3200:baba::1" - if strings.Count(server, ":") >= 2 && strings.Count(server, "[") == 0 && strings.Count(server, "]") == 0 { - server = "[" + server + "]:53" - } - - if ip := net.ParseIP(server); ip == nil { - // parse without scheme .e.g 8.8.8.8:53 + if ip,err := netip.ParseAddr(server); err != nil { if strings.Contains(server, "://") { - return server, true - } - if addr, err := net.ResolveUDPAddr("", server); err == nil { - return addPre(addr.String()), true - } else { - return addPre(server), false + return server } + return addPre(server) } else { - return addPre(server), true + if ip.Is4(){ + return addPre(server) + }else{ + return addPre("["+server+"]") + } } } func parseNameServerPolicy(nsPolicy map[string]string, preferH3 bool) (map[string]dns.NameServer, error) { From 1924b308fdaf88a55b03774a400361a31a0c1560 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 27 Jan 2023 17:10:15 +0800 Subject: [PATCH 064/126] chore: clear code --- config/config.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 489087b5..923daa12 100644 --- a/config/config.go +++ b/config/config.go @@ -4,7 +4,7 @@ import ( "container/list" "errors" "fmt" - "net" + "net" "net/netip" "net/url" "os" @@ -840,18 +840,17 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) { } func hostWithDefaultPort(host string, defPort string) (string, error) { - if !strings.Contains(host, ":") { - host += ":" - } - hostname, port, err := net.SplitHostPort(host) - if err != nil { + if err != nil&&!strings.Contains(err.Error(),"missing port in address") { return "", err } if port == "" { port = defPort } + if hostname==""{ + hostname=host + } return net.JoinHostPort(hostname, port), nil } @@ -860,7 +859,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) var nameservers []dns.NameServer for idx, server := range servers { - server, _ = parsePureDNSServer(server) + server = parsePureDNSServer(server) u, err := url.Parse(server) if err != nil { return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error()) From 02684a868f32ca05af9aa49d61a77fac7580a897 Mon Sep 17 00:00:00 2001 From: i40e <120920147+i40e@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:40:36 +0800 Subject: [PATCH 065/126] feature: geosite-based nameserver policy --- dns/filters.go | 11 +++++++++++ dns/resolver.go | 47 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/dns/filters.go b/dns/filters.go index 0dbfa317..b51e6402 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -91,6 +91,17 @@ type geoSiteFilter struct { matchers []*router.DomainMatcher } +func NewGeoSite(group string) (fallbackDomainFilter, error) { + matcher, _, err := geodata.LoadGeoSiteMatcher(group) + if err != nil { + return nil, err + } + filter := &geoSiteFilter{ + matchers: []*router.DomainMatcher{matcher}, + } + return filter, nil +} + func (gsf *geoSiteFilter) Match(domain string) bool { for _, matcher := range gsf.matchers { if matcher.ApplyDomain(domain) { diff --git a/dns/resolver.go b/dns/resolver.go index d99a465d..65bcd6d3 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -4,17 +4,20 @@ import ( "context" "errors" "fmt" - "go.uber.org/atomic" "math/rand" "net/netip" + "strings" "time" + "go.uber.org/atomic" + "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" "golang.org/x/sync/singleflight" @@ -30,6 +33,12 @@ type result struct { Error error } +type geositePolicyRecord struct { + matcher fallbackDomainFilter + policy *Policy + inversedMatching bool +} + type Resolver struct { ipv6 bool hosts *trie.DomainTrie[netip.Addr] @@ -40,6 +49,7 @@ type Resolver struct { group singleflight.Group lruCache *cache.LruCache[string, *D.Msg] policy *trie.DomainTrie[*Policy] + geositePolicy []geositePolicyRecord proxyServer []dnsClient } @@ -272,12 +282,18 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient { } record := r.policy.Search(domain) - if record == nil { - return nil + if record != nil { + p := record.Data() + return p.GetData() } - p := record.Data() - return p.GetData() + for _, geositeRecord := range r.geositePolicy { + matched := geositeRecord.matcher.Match(domain) + if matched != geositeRecord.inversedMatching { + return geositeRecord.policy.GetData() + } + } + return nil } func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool { @@ -433,7 +449,26 @@ func NewResolver(config Config) *Resolver { if len(config.Policy) != 0 { r.policy = trie.New[*Policy]() for domain, nameserver := range config.Policy { - _ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) + if strings.HasPrefix(strings.ToLower(domain), "@geosite:") { + groupname := domain[9:] + inverse := false + if strings.HasPrefix(groupname, "!") { + inverse = true + groupname = groupname[1:] + } + log.Debugln("adding geosite policy: %s inversed %s", groupname, inverse) + matcher, err := NewGeoSite(groupname) + if err != nil { + continue + } + r.geositePolicy = append(r.geositePolicy, geositePolicyRecord{ + matcher: matcher, + policy: NewPolicy(transform([]NameServer{nameserver}, defaultResolver)), + inversedMatching: inverse, + }) + } else { + _ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) + } } r.policy.Optimize() } From 2b2644a76fcc75bc1a540b1f3d7d5493c3b966b2 Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 28 Jan 2023 00:07:20 +0800 Subject: [PATCH 066/126] chore: restful api display xudp for VLESS and VMess --- adapter/adapter.go | 1 + adapter/outbound/base.go | 8 ++++++++ adapter/outbound/vless.go | 21 +++++++++++---------- adapter/outbound/vmess.go | 1 + constant/adapters.go | 1 + 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index feef72be..ffb5ced0 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -92,6 +92,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { mapping["history"] = p.DelayHistory() mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() + mapping["xudp"] = p.SupportXUDP() mapping["tfo"] = p.SupportTFO() return json.Marshal(mapping) } diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index dc339969..24de7d94 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -20,6 +20,7 @@ type Base struct { iface string tp C.AdapterType udp bool + xudp bool tfo bool rmark int id string @@ -89,6 +90,11 @@ func (b *Base) SupportUDP() bool { return b.udp } +// SupportXUDP implements C.ProxyAdapter +func (b *Base) SupportXUDP() bool { + return b.xudp +} + // SupportTFO implements C.ProxyAdapter func (b *Base) SupportTFO() bool { return b.tfo @@ -148,6 +154,7 @@ type BaseOption struct { Addr string Type C.AdapterType UDP bool + XUDP bool TFO bool Interface string RoutingMark int @@ -160,6 +167,7 @@ func NewBase(opt BaseOption) *Base { addr: opt.Addr, tp: opt.Type, udp: opt.UDP, + xudp: opt.XUDP, tfo: opt.TFO, iface: opt.Interface, rmark: opt.RoutingMark, diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 449663f7..0bd56ff4 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -474,6 +474,16 @@ func NewVless(option VlessOption) (*Vless, error) { } } + switch option.PacketEncoding { + case "packetaddr", "packet": + option.PacketAddr = true + case "xudp": + option.XUDP = true + } + if option.XUDP { + option.PacketAddr = false + } + client, err := vless.NewClient(option.UUID, addons, option.FlowShow) if err != nil { return nil, err @@ -485,6 +495,7 @@ func NewVless(option VlessOption) (*Vless, error) { addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Vless, udp: option.UDP, + xudp: option.XUDP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), @@ -493,16 +504,6 @@ func NewVless(option VlessOption) (*Vless, error) { option: &option, } - switch option.PacketEncoding { - case "packetaddr", "packet": - option.PacketAddr = true - case "xudp": - option.XUDP = true - } - if option.XUDP { - option.PacketAddr = false - } - switch option.Network { case "h2": if len(option.HTTP2Opts.Host) == 0 { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 999e1283..727da2ee 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -377,6 +377,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Vmess, udp: option.UDP, + xudp: option.XUDP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/constant/adapters.go b/constant/adapters.go index c13a85c4..4480a953 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -92,6 +92,7 @@ type ProxyAdapter interface { Type() AdapterType Addr() string SupportUDP() bool + SupportXUDP() bool SupportTFO() bool MarshalJSON() ([]byte, error) From 596bf32caabd8356a0fa1c6a9e2540e0fd41f068 Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 28 Jan 2023 00:19:58 +0800 Subject: [PATCH 067/126] chore: adjust keyword for geosite-based nameserver policy --- dns/resolver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 65bcd6d3..8784dd78 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -449,8 +449,8 @@ func NewResolver(config Config) *Resolver { if len(config.Policy) != 0 { r.policy = trie.New[*Policy]() for domain, nameserver := range config.Policy { - if strings.HasPrefix(strings.ToLower(domain), "@geosite:") { - groupname := domain[9:] + if strings.HasPrefix(strings.ToLower(domain), "geosite:") { + groupname := domain[8:] inverse := false if strings.HasPrefix(groupname, "!") { inverse = true From 85db58aeb54171cbf45ea57224d96119ce71ea6d Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 28 Jan 2023 00:32:17 +0800 Subject: [PATCH 068/126] chore: update config.yaml --- docs/config.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index a3e12939..1215b21d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -236,9 +236,10 @@ dns: # - '+.youtube.com' # 配置查询域名使用的 DNS 服务器 - # nameserver-policy: + nameserver-policy: # 'www.baidu.com': '114.114.114.114' # '+.internal.crop.com': '10.0.0.1' + 'geosite:cn': 'https://doh.pub/dns-query' proxies: # Shadowsocks From a6a72a5b546a2af0ed558af2975db080d393631e Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+dreamacro@users.noreply.github.com> Date: Mon, 16 Jan 2023 15:20:39 +0800 Subject: [PATCH 069/126] Feature: add dns query json api --- component/resolver/resolver.go | 3 ++ hub/route/configs.go | 13 +++--- hub/route/dns.go | 76 ++++++++++++++++++++++++++++++++++ hub/route/proxies.go | 8 ++-- hub/route/server.go | 1 + 5 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 hub/route/dns.go diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 55f98d3c..fa1e7c02 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -11,6 +11,8 @@ import ( "time" "github.com/Dreamacro/clash/component/trie" + + "github.com/miekg/dns" ) var ( @@ -44,6 +46,7 @@ type Resolver interface { ResolveIP(ctx context.Context, host string) (ip netip.Addr, err error) ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, err error) ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, err error) + ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error) } // LookupIPv4WithResolver same as LookupIPv4, but with a resolver diff --git a/hub/route/configs.go b/hub/route/configs.go index 37acac5e..5047c6d6 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -104,7 +104,6 @@ func pointerOrDefault(p *int, def int) int { if p != nil { return *p } - return def } @@ -210,7 +209,7 @@ func pointerOrDefaultTuicServer(p *tuicServerSchema, def LC.TuicServer) LC.TuicS func patchConfigs(w http.ResponseWriter, r *http.Request) { general := &configSchema{} - if err := render.DecodeJSON(r.Body, general); err != nil { + if err := render.DecodeJSON(r.Body, &general); err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) return @@ -266,13 +265,11 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { render.NoContent(w, r) } -type updateConfigRequest struct { - Path string `json:"path"` - Payload string `json:"payload"` -} - func updateConfigs(w http.ResponseWriter, r *http.Request) { - req := updateConfigRequest{} + req := struct { + Path string `json:"path"` + Payload string `json:"payload"` + }{} if err := render.DecodeJSON(r.Body, &req); err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) diff --git a/hub/route/dns.go b/hub/route/dns.go new file mode 100644 index 00000000..c02db022 --- /dev/null +++ b/hub/route/dns.go @@ -0,0 +1,76 @@ +package route + +import ( + "context" + "math" + "net/http" + + "github.com/Dreamacro/clash/component/resolver" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" + "github.com/miekg/dns" + "github.com/samber/lo" +) + +func dnsRouter() http.Handler { + r := chi.NewRouter() + r.Get("/query", queryDNS) + return r +} + +func queryDNS(w http.ResponseWriter, r *http.Request) { + name := r.URL.Query().Get("name") + qTypeStr, _ := lo.Coalesce(r.URL.Query().Get("type"), "A") + + qType, exist := dns.StringToType[qTypeStr] + if !exist { + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, newError("invalid query type")) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) + defer cancel() + + msg := dns.Msg{} + msg.SetQuestion(dns.Fqdn(name), qType) + resp, err := resolver.DefaultResolver.ExchangeContext(ctx, &msg) + if err != nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(err.Error())) + return + } + + responseData := render.M{ + "Status": resp.Rcode, + "Question": resp.Question, + "TC": resp.Truncated, + "RD": resp.RecursionDesired, + "RA": resp.RecursionAvailable, + "AD": resp.AuthenticatedData, + "CD": resp.CheckingDisabled, + } + + rr2Json := func(rr dns.RR, _ int) render.M { + header := rr.Header() + return render.M{ + "name": header.Name, + "type": header.Rrtype, + "TTL": header.Ttl, + "data": lo.Substring(rr.String(), len(header.String()), math.MaxUint), + } + } + + if len(resp.Answer) > 0 { + responseData["Answer"] = lo.Map(resp.Answer, rr2Json) + } + if len(resp.Ns) > 0 { + responseData["Authority"] = lo.Map(resp.Ns, rr2Json) + } + if len(resp.Extra) > 0 { + responseData["Additional"] = lo.Map(resp.Extra, rr2Json) + } + + render.JSON(w, r, responseData) +} diff --git a/hub/route/proxies.go b/hub/route/proxies.go index baffb1f5..5bf6eb9c 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -70,12 +70,10 @@ func getProxy(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, proxy) } -type UpdateProxyRequest struct { - Name string `json:"name"` -} - func updateProxy(w http.ResponseWriter, r *http.Request) { - req := UpdateProxyRequest{} + req := struct { + Name string `json:"name"` + }{} if err := render.DecodeJSON(r.Body, &req); err != nil { render.Status(r, http.StatusBadRequest) render.JSON(w, r, ErrBadRequest) diff --git a/hub/route/server.go b/hub/route/server.go index 2bef92c1..0d6a47ac 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -73,6 +73,7 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/providers/proxies", proxyProviderRouter()) r.Mount("/providers/rules", ruleProviderRouter()) r.Mount("/cache", cacheRouter()) + r.Mount("/dns", dnsRouter()) }) if uiPath != "" { From 03520e0d6faeeba60d852033bb9232454912f9ca Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Wed, 18 Jan 2023 16:58:03 +0800 Subject: [PATCH 070/126] Fix: dns api panic on disable dns section (#2498) --- hub/route/dns.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hub/route/dns.go b/hub/route/dns.go index c02db022..2918b059 100644 --- a/hub/route/dns.go +++ b/hub/route/dns.go @@ -20,6 +20,12 @@ func dnsRouter() http.Handler { } func queryDNS(w http.ResponseWriter, r *http.Request) { + if resolver.DefaultResolver == nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError("DNS section is disabled")) + return + } + name := r.URL.Query().Get("name") qTypeStr, _ := lo.Coalesce(r.URL.Query().Get("type"), "A") From a06b387accfdd71640b672ce71f96589402973d3 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 28 Jan 2023 14:58:52 +0800 Subject: [PATCH 071/126] adjust: VLESS enable XUDP by default --- adapter/outbound/vless.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 0bd56ff4..dd6e0f23 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -477,11 +477,11 @@ func NewVless(option VlessOption) (*Vless, error) { switch option.PacketEncoding { case "packetaddr", "packet": option.PacketAddr = true - case "xudp": - option.XUDP = true - } - if option.XUDP { - option.PacketAddr = false + option.XUDP = false + default: // https://github.com/XTLS/Xray-core/pull/1567#issuecomment-1407305458 + if !option.PacketAddr { + option.XUDP = true + } } client, err := vless.NewClient(option.UUID, addons, option.FlowShow) From 2cf66f41cbdcc305144e83d749f4c325ad3c5249 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 28 Jan 2023 16:09:14 +0800 Subject: [PATCH 072/126] fix: parse error --- config/config.go | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/config/config.go b/config/config.go index 923daa12..78f4eecb 100644 --- a/config/config.go +++ b/config/config.go @@ -4,7 +4,7 @@ import ( "container/list" "errors" "fmt" - "net" + "net" "net/netip" "net/url" "os" @@ -841,17 +841,16 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) { func hostWithDefaultPort(host string, defPort string) (string, error) { hostname, port, err := net.SplitHostPort(host) - if err != nil&&!strings.Contains(err.Error(),"missing port in address") { - return "", err + if err != nil { + if !strings.Contains(err.Error(), "missing port in address") { + return "", err + } + host = host + ":" + defPort + if hostname, port, err = net.SplitHostPort(host); err != nil { + return "", err + } } - if port == "" { - port = defPort - } - if hostname==""{ - hostname=host - } - return net.JoinHostPort(hostname, port), nil } @@ -940,17 +939,17 @@ func parsePureDNSServer(server string) string { return "udp://" + server } - if ip,err := netip.ParseAddr(server); err != nil { + if ip, err := netip.ParseAddr(server); err != nil { if strings.Contains(server, "://") { return server } - return addPre(server) + return addPre(server) } else { - if ip.Is4(){ - return addPre(server) - }else{ - return addPre("["+server+"]") - } + if ip.Is4() { + return addPre(server) + } else { + return addPre("[" + server + "]") + } } } func parseNameServerPolicy(nsPolicy map[string]string, preferH3 bool) (map[string]dns.NameServer, error) { From e52d5993266ca169bed07995f42e91be7f7500ba Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 28 Jan 2023 22:33:03 +0800 Subject: [PATCH 073/126] chore: better dns log --- dns/client.go | 20 ++++++++++++++++++++ dns/dhcp.go | 15 ++++++++++++++- dns/doh.go | 6 +++++- dns/middleware.go | 1 - dns/resolver.go | 1 + dns/util.go | 4 +++- 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/dns/client.go b/dns/client.go index fe9362bb..211eb91f 100644 --- a/dns/client.go +++ b/dns/client.go @@ -25,6 +25,26 @@ type client struct { host string iface *atomic.String proxyAdapter string + addr string +} + +var _ dnsClient = (*client)(nil) + +// Address implements dnsClient +func (c *client) Address() string { + if len(c.addr) != 0 { + return c.addr + } + schema := "udp" + if strings.HasPrefix(c.Client.Net, "tcp") { + schema = "tcp" + if strings.HasSuffix(c.Client.Net, "tls") { + schema = "tls" + } + } + + c.addr = fmt.Sprintf("%s//:%s", schema, net.JoinHostPort(c.host, c.port)) + return c.addr } func (c *client) Exchange(m *D.Msg) (*D.Msg, error) { diff --git a/dns/dhcp.go b/dns/dhcp.go index 1efa3bd1..151e4421 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -2,12 +2,14 @@ package dns import ( "context" - "go.uber.org/atomic" "net" "net/netip" + "strings" "sync" "time" + "go.uber.org/atomic" + "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/resolver" @@ -34,6 +36,17 @@ type dhcpClient struct { err error } +var _ dnsClient = (*dhcpClient)(nil) + +// Address implements dnsClient +func (d *dhcpClient) Address() string { + addrs := make([]string, 0) + for _, c := range d.clients { + addrs = append(addrs, c.Address()) + } + return strings.Join(addrs, ",") +} + func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) defer cancel() diff --git a/dns/doh.go b/dns/doh.go index 5abd0479..df3df6b4 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -64,6 +64,7 @@ type dnsOverHTTPS struct { r *Resolver httpVersions []C.HTTPVersion proxyAdapter string + addr string } // type check @@ -83,6 +84,7 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin doh := &dnsOverHTTPS{ url: u, + addr: u.String(), r: r, proxyAdapter: proxyAdapter, quicConfig: &quic.Config{ @@ -98,7 +100,9 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin } // Address implements the Upstream interface for *dnsOverHTTPS. -func (doh *dnsOverHTTPS) Address() string { return doh.url.String() } +func (doh *dnsOverHTTPS) Address() string { + return doh.addr +} func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { // Quote from https://www.rfc-editor.org/rfc/rfc8484.html: // In order to maximize HTTP cache friendliness, DoH clients using media diff --git a/dns/middleware.go b/dns/middleware.go index 28ced849..7dc9622d 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -164,7 +164,6 @@ func withResolver(resolver *Resolver) handler { msg.SetRcode(r, msg.Rcode) msg.Authoritative = true - log.Debugln("[DNS] %s --> %s", msgToDomain(r), msgToIP(msg)) return msg, nil } } diff --git a/dns/resolver.go b/dns/resolver.go index 8784dd78..895b7393 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -26,6 +26,7 @@ import ( type dnsClient interface { Exchange(m *D.Msg) (msg *D.Msg, err error) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) + Address() string } type result struct { diff --git a/dns/util.go b/dns/util.go index e53abab0..203ab615 100644 --- a/dns/util.go +++ b/dns/util.go @@ -235,15 +235,18 @@ func listenPacket(ctx context.Context, proxyAdapter string, network string, addr func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) + domain := msgToDomain(m) for _, client := range clients { r := client fast.Go(func() (*D.Msg, error) { + log.Debugln("[DNS] resolve %s from %s", domain, r.Address()) m, err := r.ExchangeContext(ctx, m) if err != nil { return nil, err } else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused { return nil, errors.New("server failure") } + log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), r.Address()) return m, nil }) } @@ -256,7 +259,6 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M } return nil, err } - msg = elm return } From 2ce193877bcc3ca65732c435d2b763412b54b870 Mon Sep 17 00:00:00 2001 From: kunish Date: Sun, 29 Jan 2023 00:17:01 +0800 Subject: [PATCH 074/126] docs(README.md): remove missing image link, mention Yacd-meta --- README.md | 83 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index f1f10151..aac16751 100644 --- a/README.md +++ b/README.md @@ -30,35 +30,40 @@ - Comprehensive HTTP RESTful API controller ## Wiki -Documentation is available on [Clash.Meta Wiki](https://docs.metacubex.one/). -## Advanced usage for this branch +Documentation is available on [Clash.Meta Wiki](https://docs.metacubex.one/). ## Build You should install [golang](https://go.dev) first. Then get the source code of Clash.Meta: + ```shell git clone https://github.com/MetaCubeX/Clash.Meta.git cd Clash.Meta && go mod download ``` If you can't visit github,you should set proxy first: + ```shell go env -w GOPROXY=https://goproxy.io,direct ``` Now you can build it: + ```shell go build ``` If you need gvisor for tun stack, build with: + ```shell go build -tags with_gvisor ``` +## Advanced usage of this fork + ### DNS configuration Support `geosite` with `fallback-filter`. @@ -69,7 +74,6 @@ Support resolve ip with a `Proxy Tunnel`. ```yaml proxy-groups: - - name: DNS type: url-test use: @@ -78,6 +82,7 @@ proxy-groups: interval: 180 lazy: true ``` + ```yaml dns: enable: true @@ -93,12 +98,12 @@ dns: - https://doh.pub/dns-query - tls://223.5.5.5:853 fallback: - - 'https://1.0.0.1/dns-query#DNS' # append the proxy adapter name or group name to the end of DNS URL with '#' prefix. - - 'tls://8.8.4.4:853#DNS' + - "https://1.0.0.1/dns-query#DNS" # append the proxy adapter name or group name to the end of DNS URL with '#' prefix. + - "tls://8.8.4.4:853#DNS" fallback-filter: geoip: false geosite: - - gfw # `geosite` filter only use fallback server to resolve ip, prevent DNS leaks to unsafe DNS providers. + - gfw # `geosite` filter only use fallback server to resolve ip, prevent DNS leaks to unsafe DNS providers. domain: - +.example.com ipcidr: @@ -116,27 +121,29 @@ Built-in [Wintun](https://www.wintun.net) driver. tun: enable: true stack: system # system/gvisor - dns-hijack: + dns-hijack: - 0.0.0.0:53 # additional dns server listen on TUN auto-route: true # auto set global route ``` + ### Rules configuration + - Support rule `GEOSITE`. - Support rule-providers `RULE-SET`. - Support `multiport` condition for rule `SRC-PORT` and `DST-PORT`. - Support `network` condition for all rules. - Support source IPCIDR condition for all rules, just append to the end. - The `GEOSITE` databases via https://github.com/Loyalsoldier/v2ray-rules-dat. + ```yaml rules: - # network(tcp/udp) condition for all rules - DOMAIN-SUFFIX,bilibili.com,DIRECT,tcp - DOMAIN-SUFFIX,bilibili.com,REJECT,udp - + # multiport condition for rules SRC-PORT and DST-PORT - DST-PORT,123/136/137-139,DIRECT,udp - + # rule GEOSITE - GEOSITE,category-ads-all,REJECT - GEOSITE,icloud@cn,DIRECT @@ -147,18 +154,17 @@ rules: - GEOSITE,youtube,PROXY - GEOSITE,geolocation-cn,DIRECT - GEOSITE,geolocation-!cn,PROXY - + # source IPCIDR condition for all rules in gateway proxy #- GEOSITE,geolocation-!cn,REJECT,192.168.1.88/32,192.168.1.99/32 - GEOIP,telegram,PROXY,no-resolve - GEOIP,private,DIRECT,no-resolve - GEOIP,cn,DIRECT - + - MATCH,PROXY ``` - ### Proxies configuration Active health detection `urltest / fallback` (based on tcp handshake, multiple failures within a limited time will actively trigger health detection to use the node) @@ -167,18 +173,17 @@ Support `Policy Group Filter` ```yaml proxy-groups: - - name: 🚀 HK Group type: select use: - ALL - filter: 'HK' + filter: "HK" - name: 🚀 US Group type: select use: - ALL - filter: 'US' + filter: "US" proxy-providers: ALL: @@ -190,14 +195,12 @@ proxy-providers: enable: true interval: 600 url: http://www.gstatic.com/generate_204 - ``` - - Support outbound transport protocol `VLESS`. The XTLS support (TCP/UDP) transport by the XRAY-CORE. + ```yaml proxies: - name: "vless" @@ -208,7 +211,7 @@ proxies: servername: example.com # AKA SNI # flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS # skip-cert-verify: true - + - name: "vless-ws" type: vless server: server @@ -233,12 +236,12 @@ proxies: network: grpc servername: example.com # priority over wss host # skip-cert-verify: true - grpc-opts: + grpc-opts: grpc-service-name: grpcname ``` - Support outbound transport protocol `Wireguard` + ```yaml proxies: - name: "wg" @@ -253,6 +256,7 @@ proxies: ``` Support outbound transport protocol `Tuic` + ```yaml proxies: - name: "tuic" @@ -271,10 +275,10 @@ proxies: # max-udp-relay-packet-size: 1500 # fast-open: true # skip-cert-verify: true - ``` ### IPTABLES configuration + Work on Linux OS who's supported `iptables` ```yaml @@ -286,17 +290,15 @@ iptables: inbound-interface: eth0 # detect the inbound interface, default is 'lo' ``` +### General installation guide for Linux -### General installation guide for Linux -+ Create user given name `clash-meta` +- Create user given name `clash-meta` -+ Download and decompress pre-built binaries from [releases](https://github.com/MetaCubeX/Clash.Meta/releases) - -+ Rename executable file to `Clash-Meta` and move to `/usr/local/bin/` - -+ Create folder `/etc/Clash-Meta/` as working directory +- Download and decompress pre-built binaries from [releases](https://github.com/MetaCubeX/Clash.Meta/releases) +- Rename executable file to `Clash-Meta` and move to `/usr/local/bin/` +- Create folder `/etc/Clash-Meta/` as working directory Run Meta Kernel by user `clash-meta` as a daemon. @@ -322,10 +324,13 @@ ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta [Install] WantedBy=multi-user.target ``` + Launch clashd on system startup with: + ```shell $ systemctl enable Clash-Meta ``` + Launch clashd immediately with: ```shell @@ -336,9 +341,11 @@ $ systemctl start Clash-Meta Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`. -To display process name in GUI please use [Dashboard For Meta](https://github.com/MetaCubeX/clash-dashboard). +To display process name in GUI please use [Razord-meta](https://github.com/MetaCubeX/Razord-meta). -![img.png](https://github.com/Clash-Mini/Dashboard/raw/master/View/Dashboard-Process.png) +### Dashboard + +We also made a custom fork of yacd provide better support for this project, check it out at [Yacd-meta](https://github.com/MetaCubeX/Yacd-meta) ## Development @@ -347,12 +354,12 @@ the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library ## Credits -* [Dreamacro/clash](https://github.com/Dreamacro/clash) -* [SagerNet/sing-box](https://github.com/SagerNet/sing-box) -* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2) -* [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core) -* [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go) -* [yaling888/clash-plus-pro](https://github.com/yaling888/clash) +- [Dreamacro/clash](https://github.com/Dreamacro/clash) +- [SagerNet/sing-box](https://github.com/SagerNet/sing-box) +- [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2) +- [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core) +- [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go) +- [yaling888/clash-plus-pro](https://github.com/yaling888/clash) ## License From 32c53b9584229f8a7b19a6306533758218bbe368 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 29 Jan 2023 11:03:39 +0800 Subject: [PATCH 075/126] chore: dns log error --- dns/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dns/client.go b/dns/client.go index 211eb91f..c5a52281 100644 --- a/dns/client.go +++ b/dns/client.go @@ -43,7 +43,7 @@ func (c *client) Address() string { } } - c.addr = fmt.Sprintf("%s//:%s", schema, net.JoinHostPort(c.host, c.port)) + c.addr = fmt.Sprintf("%s://%s", schema, net.JoinHostPort(c.host, c.port)) return c.addr } From ee21b7bc378e318a1850e0595dca8f9cb60f4020 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 29 Jan 2023 22:30:40 +0800 Subject: [PATCH 076/126] chore: update gvisor --- go.mod | 8 ++++---- go.sum | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 6aaf9b6b..bccc2135 100644 --- a/go.mod +++ b/go.mod @@ -21,8 +21,8 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 github.com/metacubex/sing-shadowsocks v0.1.0 - github.com/metacubex/sing-tun v0.1.0 - github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c + github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b + github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 @@ -72,7 +72,7 @@ require ( golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.1.12 // indirect - gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect + gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b // indirect ) -replace gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c => github.com/metacubex/gvisor v0.0.0-20221217030112-bdcd835fd60e +replace gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b => github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8 diff --git a/go.sum b/go.sum index b965c336..b850cce9 100644 --- a/go.sum +++ b/go.sum @@ -91,16 +91,16 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20221217030112-bdcd835fd60e h1:3PHqNvIAwYbv9cOQbRFIUgzJ+K6fhV1HHj+Vpg8U7g8= -github.com/metacubex/gvisor v0.0.0-20221217030112-bdcd835fd60e/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= +github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8 h1:CrAPNUP06BvFDmzt+Bluqw9SqFK/q7VuGBUB7Cx3Bic= +github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8/go.mod h1:94x/o/BlxPAbw4phqHRac0/IzpcQRUP7ZQldDWV3TKU= github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 h1:CGn1ku3QZ/OjJjnRH4eO9jtXegdPQZUJ7y1Y6CppLd0= github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91/go.mod h1:8VvqBlJaARNcwAE9zrbhKI/I1R5Lu4gqmt3CSGrJl7s= github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A= github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= -github.com/metacubex/sing-tun v0.1.0 h1:iQj0+0WjJynSKAtfv87wOZlVKWl3w9RvkOSkVe9zuMg= -github.com/metacubex/sing-tun v0.1.0/go.mod h1:l4JyI6RTrlHLQz5vSakg+wxA+LwGVI0Mz5ZtlOv67dA= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c h1:VHtXDny/TNOF7YDT9d9Qkr+x6K1O4cejXLlyPUXDeXQ= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c/go.mod h1:fULJ451x1/XlpIhl+Oo+EPGKla9tFZaqT5dKLrZ+NvM= +github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b h1:k0Wnbfp7lsdBVVJY4YNbg0OxBiKWZSir8k10g0TuOlI= +github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b/go.mod h1:lJWUpVKefklkLUL3ukp9Iapz+zSxS/fvfbevoUL2Vwg= +github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e h1:ZpzW8ymNjU2Gi7ieJexUV8BDrIuBfCBaZdgAyB1RsYs= +github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e/go.mod h1:hF5lqFsfWeDrImIQ5XkOTS8aucCWvK4GOoCUNYKTrPU= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= From 884db8a8b53d556263823025f0778c7ae33df27f Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:00:02 +0800 Subject: [PATCH 077/126] chore: add patch for debug api,better workflow. --- .github/workflows/prerelease.yml | 23 +++++++------- patch/add_debug_api.patch | 53 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 patch/add_debug_api.patch diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 5d1e0e25..3b97691f 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -63,17 +63,16 @@ jobs: id: "8", } - { type: "WithCGO", target: "windows/*", id: "1" } - - { type: "WithCGO", target: "linux/386,linux/amd64", id: "2" } - - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "3" } - - { - type: "WithCGO", - target: "linux/arm,linux/arm-6,linux/arm-7", - id: "4", - } - - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "5" } - - { type: "WithCGO", target: "linux/mips64,linux/mips64le", id: "6" } - - { type: "WithCGO", target: "darwin-10.16/*", id: "7" } - - { type: "WithCGO", target: "android", id: "8" } + - { type: "WithCGO", target: "linux/386", id: "2" } + - { type: "WithCGO", target: "linux/amd64", id: "3" } + - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "4" } + - { type: "WithCGO", target: "linux/arm,", id: "5" } + - { type: "WithCGO", target: "linux/arm-6,linux/arm-7", id: "6" } + - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "7" } + - { type: "WithCGO", target: "linux/mips64", id: "8" } + - { type: "WithCGO", target: "linux/mips64le", id: "9" } + - { type: "WithCGO", target: "darwin-10.16/*", id: "10" } + - { type: "WithCGO", target: "android", id: "11" } steps: - name: Check out code into the Go module directory @@ -287,4 +286,4 @@ jobs: linux/amd64 linux/arm64/v8 tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} diff --git a/patch/add_debug_api.patch b/patch/add_debug_api.patch new file mode 100644 index 00000000..7134b378 --- /dev/null +++ b/patch/add_debug_api.patch @@ -0,0 +1,53 @@ +Subject: [PATCH] Chore: add debug api +--- +Index: hub/route/debug.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/hub/route/debug.go b/hub/route/debug.go +new file mode 100644 +--- /dev/null (revision df1007e2b14f7a526d176410995998bf06054657) ++++ b/hub/route/debug.go (revision df1007e2b14f7a526d176410995998bf06054657) +@@ -0,0 +1,21 @@ ++package route ++ ++import ( ++ "github.com/Dreamacro/clash/log" ++ "github.com/go-chi/chi/v5" ++ "github.com/go-chi/chi/v5/middleware" ++ "net/http" ++ "runtime" ++) ++ ++func debugRouter() http.Handler { ++ handler := middleware.Profiler() ++ r := chi.NewRouter() ++ r.Mount("/", handler) ++ r.Put("/gc", func(writer http.ResponseWriter, request *http.Request) { ++ log.Debugln("trigger GC") ++ runtime.GC() ++ }) ++ ++ return r ++} +Index: hub/route/server.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/hub/route/server.go b/hub/route/server.go +--- a/hub/route/server.go (revision f83fd6c690928ca7861196e3ca5af566303f95d5) ++++ b/hub/route/server.go (revision df1007e2b14f7a526d176410995998bf06054657) +@@ -59,6 +59,11 @@ + MaxAge: 300, + }) + r.Use(corsM.Handler) ++ ++ r.Group(func(r chi.Router) { ++ r.Mount("/debug", debugRouter()) ++ }) ++ + r.Group(func(r chi.Router) { + r.Use(authentication) + r.Get("/", hello) From fb9f09c97fc311d23689e6d6aaca1c381d16d59f Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 30 Jan 2023 20:39:13 +0800 Subject: [PATCH 078/126] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index aac16751..16460c53 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,10 @@ We also made a custom fork of yacd provide better support for this project, chec If you want to build an application that uses clash as a library, check out the the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library) +## Debugging +Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug API. + + ## Credits - [Dreamacro/clash](https://github.com/Dreamacro/clash) From 872c915cf780077da8cbb07ba036be70ec6bc00b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 30 Jan 2023 21:19:46 +0800 Subject: [PATCH 079/126] Chore: Add images for wiki --- docs/allocs.svg | 2387 +++++++++++++++++++++++++++++++++++++++++++++++ docs/heap.svg | 2182 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4569 insertions(+) create mode 100644 docs/allocs.svg create mode 100644 docs/heap.svg diff --git a/docs/allocs.svg b/docs/allocs.svg new file mode 100644 index 00000000..57deec50 --- /dev/null +++ b/docs/allocs.svg @@ -0,0 +1,2387 @@ + + + + + + +unnamed + + +cluster_L + + + + +Type: alloc_space + +Type: alloc_space +Time: Jan 30, 2023 at 9:18pm (CST) +Showing nodes accounting for 1777.16MB, 96.71% of 1837.65MB total +Dropped 188 nodes (cum <= 9.19MB) +Dropped 2 edges (freq <= 1.84MB) +Showing top 55 nodes out of 117 +See https://git.io/JfYMW for how to read the graph + + + +N1 + + +quic-go +(*client) +dial +func1 +0 of 1648.40MB (89.70%) + + + + + +N3 + + +quic-go +(*connection) +run +0 of 1648.40MB (89.70%) + + + + + +N1->N3 + + + + + + + 1648.40MB + + + + + +N2 + + +quic-go +(*connection) +sendPacket +0 of 1412.44MB (76.86%) + + + + + +N4 + + +quic-go +(*packetPacker) +PackPacket +30MB (1.63%) +of 956.14MB (52.03%) + + + + + +N2->N4 + + + + + + + 956.14MB + + + + + +N10 + + +quic-go +(*connection) +sendPackedPacket +0 of 456.30MB (24.83%) + + + + + +N2->N10 + + + + + + + 456.30MB + + + + + +N3->N2 + + + + + + + 1412.44MB + + + + + +N36 + + +quic-go +(*connection) +handleUnpackedShortHeaderPacket +0 of 235.46MB (12.81%) + + + + + +N3->N36 + + + + + + + 235.46MB + + + + + +NN4_0 + + + + + +16B..64B + + + + + +N4->NN4_0 + + + + + + + 30MB + + + + + +N6 + + +quic-go +(*packetPacker) +maybeGetShortHeaderPacket +0 of 722.12MB (39.30%) + + + + + +N4->N6 + + + + + + + 722.12MB + + + + + +N13 + + +quic-go +(*packetPacker) +appendPacket +118.51MB (6.45%) +of 204.01MB (11.10%) + + + + + +N4->N13 + + + + + + + 204.01MB + + + + + +N5 + + +quic-go +(*packetPacker) +composeNextPacket +162.51MB (8.84%) +of 446.09MB (24.28%) + + + + + +NN5_0 + + + + + +48B..64B + + + + + +N5->NN5_0 + + + + + + + 93.50MB + + + + + +NN5_1 + + + + + +16B..32B + + + + + +N5->NN5_1 + + + + + + + 69MB + + + + + +N25 + + +quic-go +(*framerI) +AppendStreamFrames +15.50MB (0.84%) +of 157.55MB (8.57%) + + + + + +N5->N25 + + + + + + + 157.55MB + + + + + +N34 + + +ackhandler +(*receivedPacketTracker) +GetAckFrame +0 of 126.04MB (6.86%) + + + + + +N5->N34 + + + + + + + 126.04MB + + + + + +N6->N5 + + + + + + + 446.09MB + + + + + +N8 + + +quic-go +(*packetPacker) +getShortHeader +276.03MB (15.02%) + + + + + +N6->N8 + + + + + + + 276.03MB + + + + + +N7 + + +sync +(*Pool) +Get +0 of 248.65MB (13.53%) + + + + + +N12 + + +ackhandler +glob +func1 +160.01MB (8.71%) + + + + + +N7->N12 + + + + + + + 160.01MB + + + + + +N19 + + +wire +init +0 +func1 +70.60MB (3.84%) + + + + + +N7->N19 + + + + + + + 70.60MB + + + + + +N44 + + +wire +glob +func1 +15MB (0.82%) + + + + + +N7->N44 + + + + + + + 15MB + + + + + +NN8_0 + + + + + +128B + + + + + +N8->NN8_0 + + + + + + + 276.03MB + + + + + +N9 + + +congestion +NewConnectionStateOnSentPacket +236.03MB (12.84%) + + + + + +NN9_0 + + + + + +128B + + + + + +N9->NN9_0 + + + + + + + 236.03MB + + + + + +N10->N7 + + + + + + + 160.01MB + + + + + +N17 + + +ackhandler +(*sentPacketHandler) +SentPacket +0 of 296.29MB (16.12%) + + + + + +N10->N17 + + + + + + + 296.29MB + + + + + +N11 + + +linkedlist +(*List[…]) +insertValue +120MB (6.53%) + + + + + +NN11_0 + + + + + +32B + + + + + +N11->NN11_0 + + + + + + + 113.50MB + + + + + +NN12_0 + + + + + +96B + + + + + +N12->NN12_0 + + + + + + + 160.01MB + + + + + +NN13_0 + + + + + +64B + + + + + +N13->NN13_0 + + + + + + + 118.51MB + + + + + +N18 + + +bytes +NewBuffer +85.50MB (4.65%) + + + + + +N13->N18 + + + + + + + 85.50MB + (inline) + + + + + +N14 + + +ackhandler +(*receivedPacketHistory) +AppendAckRanges +115.54MB (6.29%) + + + + + +NN14_0 + + + + + +512B + + + + + +N14->NN14_0 + + + + + + + 51.53MB + + + + + +NN14_1 + + + + + +256B + + + + + +N14->NN14_1 + + + + + + + 29.51MB + + + + + +NN14_2 + + + + + +128B + + + + + +N14->NN14_2 + + + + + + + 20MB + + + + + +N15 + + +quic-go +(*connection) +handleFrames +0 of 228.96MB (12.46%) + + + + + +N21 + + +wire +(*frameParser) +parseFrame +0 of 109.58MB (5.96%) + + + + + +N15->N21 + + + + + + + 109.58MB + + + + + +N23 + + +quic-go +(*connection) +handleFrame +0 of 119.38MB (6.50%) + + + + + +N15->N23 + + + + + + + 119.38MB + + + + + +N16 + + +quic-go +(*sendStream) +popStreamFrame +111.50MB (6.07%) +of 142.05MB (7.73%) + + + + + +NN16_0 + + + + + +16B + + + + + +N16->NN16_0 + + + + + + + 57MB + + + + + +NN16_1 + + + + + +32B + + + + + +N16->NN16_1 + + + + + + + 54.50MB + + + + + +N29 + + +wire +GetStreamFrame +0 of 70.60MB (3.84%) + + + + + +N16->N29 + + + + + + + 30.54MB + (inline) + + + + + +N17->N9 + + + + + + + 236.03MB + (inline) + + + + + +N17->N11 + + + + + + + 57.50MB + (inline) + + + + + +NN18_0 + + + + + +48B + + + + + +N18->NN18_0 + + + + + + + 85.50MB + + + + + +NN19_0 + + + + + +1.50kB + + + + + +N19->NN19_0 + + + + + + + 70.60MB + + + + + +N20 + + +geodata +LoadGeoSiteMatcher +0 of 74.20MB (4.04%) + + + + + +N33 + + +router +NewMphMatcherGroup +0 of 57.15MB (3.11%) + + + + + +N20->N33 + + + + + + + 57.15MB + + + + + +N40 + + +reflect +New +13MB (0.71%) + + + + + +N20->N40 + + + + + + + 11.50MB + + + + + +N24 + + +wire +parseAckFrame +65.02MB (3.54%) +of 69.52MB (3.78%) + + + + + +N21->N24 + + + + + + + 69.52MB + + + + + +N21->N29 + + + + + + + 40.06MB + (inline) + + + + + +N22 + + +quic-go +(*basicConn) +ReadPacket +35.50MB (1.93%) +of 59.01MB (3.21%) + + + + + +N22->N7 + + + + + + + 2MB + + + + + +NN22_0 + + + + + +96B + + + + + +N22->NN22_0 + + + + + + + 35.50MB + + + + + +N37 + + +net +(*UDPConn) +ReadFrom +18.50MB (1.01%) +of 22MB (1.20%) + + + + + +N22->N37 + + + + + + + 21.50MB + + + + + +N41 + + +ackhandler +(*sentPacketHandler) +ReceivedAck +0 of 90.10MB (4.90%) + + + + + +N23->N41 + + + + + + + 90.10MB + + + + + +N42 + + +quic-go +(*receiveStream) +handleStreamFrameImpl +7MB (0.38%) +of 29.28MB (1.59%) + + + + + +N23->N42 + + + + + + + 29.28MB + + + + + +N24->N7 + + + + + + + 4.50MB + + + + + +NN24_0 + + + + + +512B + + + + + +N24->NN24_0 + + + + + + + 32.52MB + + + + + +NN24_1 + + + + + +256B + + + + + +N24->NN24_1 + + + + + + + 18MB + + + + + +N25->N16 + + + + + + + 142.05MB + + + + + +NN25_0 + + + + + +16B + + + + + +N25->NN25_0 + + + + + + + 15.50MB + + + + + +N26 + + +runtime +main +0 of 79.85MB (4.35%) + + + + + +N52 + + +main +main +0 of 78.85MB (4.29%) + + + + + +N26->N52 + + + + + + + 78.85MB + + + + + +N27 + + +strmatcher +(*MphMatcherGroup) +Build +37.85MB (2.06%) + + + + + +N28 + + +ackhandler +(*sentPacketHandler) +detectLostPackets +func1 +0 of 79.59MB (4.33%) + + + + + +N35 + + +quic-go +(*sendStream) +queueRetransmission +23.59MB (1.28%) + + + + + +N28->N35 + + + + + + + 23.59MB + + + + + +N43 + + +linkedlist +(*List[…]) +InsertAfter +0 of 62.50MB (3.40%) + + + + + +N28->N43 + + + + + + + 56MB + + + + + +N29->N7 + + + + + + + 70.60MB + + + + + +N30 + + +common +NewGEOSITE +0 of 74.20MB (4.04%) + + + + + +N30->N20 + + + + + + + 25.91MB + + + + + +N46 + + +geodata +Verify +0 of 51.44MB (2.80%) + + + + + +N30->N46 + + + + + + + 48.29MB + + + + + +N31 + + +quic-go +(*packetHandlerMap) +listen +0 of 59.01MB (3.21%) + + + + + +N31->N22 + + + + + + + 59.01MB + + + + + +N32 + + +http +HandlerFunc +ServeHTTP +0 of 26.60MB (1.45%) + + + + + +N47 + + +chi +(*Mux) +routeHTTP +0 of 26.60MB (1.45%) + + + + + +N32->N47 + + + + + + + 26.10MB + + + + + +N48 + + +chi +(*Mux) +ServeHTTP +0 of 26.10MB (1.42%) + + + + + +N32->N48 + + + + + + + 25.59MB + + + + + +N33->N27 + + + + + + + 37.85MB + + + + + +N38 + + +strmatcher +(*MphMatcherGroup) +AddFullOrDomainPattern +18.80MB (1.02%) + + + + + +N33->N38 + + + + + + + 18.80MB + (inline) + + + + + +N34->N7 + + + + + + + 10.50MB + + + + + +N34->N14 + + + + + + + 115.54MB + + + + + +N36->N15 + + + + + + + 228.96MB + + + + + +NN37_0 + + + + + +48B + + + + + +N37->NN37_0 + + + + + + + 18.50MB + + + + + +N39 + + +sync +(*poolChain) +pushHead +14.30MB (0.78%) + + + + + +NN40_0 + + + + + +96B + + + + + +N40->NN40_0 + + + + + + + 11.50MB + + + + + +N41->N28 + + + + + + + 79.59MB + + + + + +N41->N39 + + + + + + + 5.51MB + + + + + +NN42_0 + + + + + +16B + + + + + +N42->NN42_0 + + + + + + + 7MB + + + + + +N49 + + +quic-go +(*frameSorter) +push +5.28MB (0.29%) +of 22.28MB (1.21%) + + + + + +N42->N49 + + + + + + + 22.28MB + + + + + +N43->N11 + + + + + + + 62.50MB + (inline) + + + + + +NN44_0 + + + + + +64B + + + + + +N44->NN44_0 + + + + + + + 15MB + + + + + +N45 + + +flate +NewWriter +10.58MB (0.58%) +of 17.16MB (0.93%) + + + + + +NN45_0 + + + + + +648kB + + + + + +N45->NN45_0 + + + + + + + 10.58MB + + + + + +N46->N20 + + + + + + + 48.29MB + + + + + +N47->N32 + + + + + + + 26.60MB + + + + + +N53 + + +pprof +(*Profile) +WriteTo +0 of 22.36MB (1.22%) + + + + + +N47->N53 + + + + + + + 22.36MB + + + + + +N48->N32 + + + + + + + 26.10MB + + + + + +N51 + + +tree +insert[…] +11MB (0.6%) + + + + + +N49->N51 + + + + + + + 11MB + + + + + +N50 + + +http +(*conn) +serve +0 of 24.10MB (1.31%) + + + + + +N50->N48 + + + + + + + 24.10MB + + + + + +NN51_0 + + + + + +48B + + + + + +N51->NN51_0 + + + + + + + 11MB + + + + + +N52->N30 + + + + + + + 74.20MB + + + + + +N54 + + +pprof +writeHeapInternal +0 of 22.36MB (1.22%) + + + + + +N53->N54 + + + + + + + 22.36MB + + + + + +N55 + + +pprof +writeHeapProto +0 of 22.36MB (1.22%) + + + + + +N54->N55 + + + + + + + 22.36MB + + + + + +N55->N45 + + + + + + + 16.28MB + + + + + diff --git a/docs/heap.svg b/docs/heap.svg new file mode 100644 index 00000000..0795977f --- /dev/null +++ b/docs/heap.svg @@ -0,0 +1,2182 @@ + + + + + + +unnamed + + +cluster_L + + + + +Type: inuse_space + +Type: inuse_space +Time: Jan 30, 2023 at 9:18pm (CST) +Showing nodes accounting for 12146.04kB, 100% of 12146.04kB total +Showing top 69 nodes out of 71 +See https://git.io/JfYMW for how to read the graph + + + +N1 + + +runtime +allocm +5637.50kB (46.41%) + + + + + +NN1_0 + + + + + +1kB + + + + + +N1->NN1_0 + + + + + + + 5637.50kB + + + + + +N2 + + +runtime +schedule +0 of 5637.50kB (46.41%) + + + + + +N68 + + +runtime +resetspinning +0 of 5637.50kB (46.41%) + + + + + +N2->N68 + + + + + + + 5637.50kB + + + + + +N3 + + +runtime +mstart +0 of 3587.50kB (29.54%) + + + + + +N62 + + +runtime +mstart0 +0 of 3587.50kB (29.54%) + + + + + +N3->N62 + + + + + + + 3587.50kB + + + + + +N4 + + +runtime +main +0 of 2836.92kB (23.36%) + + + + + +N61 + + +main +main +0 of 2836.92kB (23.36%) + + + + + +N4->N61 + + + + + + + 2836.92kB + + + + + +N5 + + +geodata +LoadGeoSiteMatcher +0 of 2836.92kB (23.36%) + + + + + +N10 + + +router +NewMphMatcherGroup +0 of 1812.91kB (14.93%) + + + + + +N5->N10 + + + + + + + 1812.91kB + + + + + +N27 + + +geodata +(*loader) +LoadGeoSite +0 of 1024.02kB (8.43%) + + + + + +N5->N27 + + + + + + + 1024.02kB + + + + + +N6 + + +strmatcher +(*MphMatcherGroup) +Build +1300.89kB (10.71%) + + + + + +NN6_0 + + + + + +1.14MB + + + + + +N6->NN6_0 + + + + + + + 1300.89kB + + + + + +N7 + + +runtime +mcall +0 of 2050kB (16.88%) + + + + + +N67 + + +runtime +park_m +0 of 2050kB (16.88%) + + + + + +N7->N67 + + + + + + + 2050kB + + + + + +N8 + + +impl +(*MessageInfo) +unmarshalPointer +0 of 1024.02kB (8.43%) + + + + + +N9 + + +impl +consumeStringValidateUTF8 +1024.02kB (8.43%) + + + + + +N8->N9 + + + + + + + 1024.02kB + + + + + +N58 + + +impl +consumeMessageSliceInfo +0 of 1024.02kB (8.43%) + + + + + +N8->N58 + + + + + + + 1024.02kB + + + + + +NN9_0 + + + + + +16B + + + + + +N9->NN9_0 + + + + + + + 1024.02kB + + + + + +N10->N6 + + + + + + + 1300.89kB + + + + + +N31 + + +strmatcher +(*MphMatcherGroup) +AddPattern +0 of 512.01kB (4.22%) + + + + + +N10->N31 + + + + + + + 512.01kB + + + + + +N11 + + +runtime +gcBgMarkWorker +512.02kB (4.22%) + + + + + +NN11_0 + + + + + +32B + + + + + +N11->NN11_0 + + + + + + + 512.02kB + + + + + +N12 + + +congestion +(*ConnectionStates) +Insert +596.16kB (4.91%) + + + + + +NN12_0 + + + + + +160kB + + + + + +N12->NN12_0 + + + + + + + 596.16kB + + + + + +N13 + + +bufio +NewReaderSize +514kB (4.23%) + + + + + +NN13_0 + + + + + +4kB + + + + + +N13->NN13_0 + + + + + + + 514kB + + + + + +N14 + + +quic-go +init +0 +func1 +512.75kB (4.22%) + + + + + +NN14_0 + + + + + +1.50kB + + + + + +N14->NN14_0 + + + + + + + 512.75kB + + + + + +N15 + + +trie +(*Node[…]) +optimize +512.44kB (4.22%) + + + + + +NN15_0 + + + + + +896B + + + + + +N15->NN15_0 + + + + + + + 512.44kB + + + + + +N16 + + +runtime +malg +512.20kB (4.22%) + + + + + +NN16_0 + + + + + +416B + + + + + +N16->NN16_0 + + + + + + + 512.20kB + + + + + +N17 + + +time +NewTicker +512.05kB (4.22%) + + + + + +NN17_0 + + + + + +96B + + + + + +N17->NN17_0 + + + + + + + 512.05kB + + + + + +N18 + + +strmatcher +(*MphMatcherGroup) +AddFullOrDomainPattern +512.01kB (4.22%) + + + + + +NN18_0 + + + + + +24B + + + + + +N18->NN18_0 + + + + + + + 512.01kB + + + + + +N19 + + +quic-go +(*client) +dial +func1 +0 of 596.16kB (4.91%) + + + + + +N49 + + +quic-go +(*connection) +run +0 of 596.16kB (4.91%) + + + + + +N19->N49 + + + + + + + 596.16kB + + + + + +N20 + + +mixed +handleConn +0 of 514kB (4.23%) + + + + + +N26 + + +net +NewBufferedConn +0 of 514kB (4.23%) + + + + + +N20->N26 + + + + + + + 514kB + + + + + +N21 + + +quic-go +(*packetHandlerMap) +listen +0 of 512.75kB (4.22%) + + + + + +N48 + + +quic-go +(*basicConn) +ReadPacket +0 of 512.75kB (4.22%) + + + + + +N21->N48 + + + + + + + 512.75kB + + + + + +N22 + + +executor +loadRuleProvider +func1 +0 of 512.44kB (4.22%) + + + + + +N40 + + +executor +loadProvider +0 of 512.44kB (4.22%) + + + + + +N22->N40 + + + + + + + 512.44kB + + + + + +N23 + + +runtime +systemstack +0 of 512.20kB (4.22%) + + + + + +N65 + + +runtime +newproc +func1 +0 of 512.20kB (4.22%) + + + + + +N23->N65 + + + + + + + 512.20kB + + + + + +N24 + + +statistic +(*Manager) +handle +0 of 512.05kB (4.22%) + + + + + +N24->N17 + + + + + + + 512.05kB + + + + + +N25 + + +bufio +NewReader +0 of 514kB (4.23%) + + + + + +N25->N13 + + + + + + + 514kB + (inline) + + + + + +N26->N25 + + + + + + + 514kB + (inline) + + + + + +N28 + + +geodata +(*loader) +LoadGeoSiteWithAttr +0 of 1024.02kB (8.43%) + + + + + +N27->N28 + + + + + + + 1024.02kB + + + + + +N29 + + +memconservative +(*memConservativeLoader) +LoadSiteByPath +0 of 1024.02kB (8.43%) + + + + + +N28->N29 + + + + + + + 1024.02kB + + + + + +N30 + + +memconservative +GeoSiteCache +Unmarshal +0 of 1024.02kB (8.43%) + + + + + +N29->N30 + + + + + + + 1024.02kB + + + + + +N59 + + +proto +Unmarshal +0 of 1024.02kB (8.43%) + + + + + +N30->N59 + + + + + + + 1024.02kB + + + + + +N31->N18 + + + + + + + 512.01kB + (inline) + + + + + +N32 + + +trie +(*DomainTrie[…]) +Optimize +0 of 512.44kB (4.22%) + + + + + +N32->N15 + + + + + + + 512.44kB + + + + + +N33 + + +config +Parse +0 of 2836.92kB (23.36%) + + + + + +N34 + + +config +ParseRawConfig +0 of 2836.92kB (23.36%) + + + + + +N33->N34 + + + + + + + 2836.92kB + + + + + +N35 + + +config +parseRules +0 of 2836.92kB (23.36%) + + + + + +N34->N35 + + + + + + + 2836.92kB + + + + + +N41 + + +rules +ParseRule +0 of 2836.92kB (23.36%) + + + + + +N35->N41 + + + + + + + 2836.92kB + + + + + +N36 + + +hub +Parse +0 of 2836.92kB (23.36%) + + + + + +N37 + + +executor +Parse +0 of 2836.92kB (23.36%) + + + + + +N36->N37 + + + + + + + 2836.92kB + (inline) + + + + + +N39 + + +executor +ParseWithPath +0 of 2836.92kB (23.36%) + + + + + +N37->N39 + + + + + + + 2836.92kB + + + + + +N38 + + +executor +ParseWithBytes +0 of 2836.92kB (23.36%) + + + + + +N38->N33 + + + + + + + 2836.92kB + + + + + +N39->N38 + + + + + + + 2836.92kB + (inline) + + + + + +N44 + + +provider +(*ruleSetProvider) +Initial +0 of 512.44kB (4.22%) + + + + + +N40->N44 + + + + + + + 512.44kB + + + + + +N42 + + +common +NewGEOSITE +0 of 2836.92kB (23.36%) + + + + + +N41->N42 + + + + + + + 2836.92kB + + + + + +N42->N5 + + + + + + + 2836.92kB + + + + + +N43 + + +provider +(*domainStrategy) +OnUpdate +0 of 512.44kB (4.22%) + + + + + +N43->N32 + + + + + + + 512.44kB + + + + + +N45 + + +provider +NewRuleSetProvider +func1 +0 of 512.44kB (4.22%) + + + + + +N44->N45 + + + + + + + 512.44kB + + + + + +N45->N43 + + + + + + + 512.44kB + + + + + +N46 + + +congestion +(*BandwidthSampler) +OnPacketSent +0 of 596.16kB (4.91%) + + + + + +N46->N12 + + + + + + + 596.16kB + (inline) + + + + + +N47 + + +congestion +(*bbrSender) +OnPacketSent +0 of 596.16kB (4.91%) + + + + + +N47->N46 + + + + + + + 596.16kB + + + + + +N53 + + +quic-go +getPacketBuffer +0 of 512.75kB (4.22%) + + + + + +N48->N53 + + + + + + + 512.75kB + (inline) + + + + + +N52 + + +quic-go +(*connection) +sendPackets +0 of 596.16kB (4.91%) + + + + + +N49->N52 + + + + + + + 596.16kB + + + + + +N50 + + +quic-go +(*connection) +sendPackedPacket +0 of 596.16kB (4.91%) + + + + + +N55 + + +ackhandler +(*sentPacketHandler) +SentPacket +0 of 596.16kB (4.91%) + + + + + +N50->N55 + + + + + + + 596.16kB + + + + + +N51 + + +quic-go +(*connection) +sendPacket +0 of 596.16kB (4.91%) + + + + + +N51->N50 + + + + + + + 596.16kB + + + + + +N52->N51 + + + + + + + 596.16kB + + + + + +N53->N14 + + + + + + + 512.75kB + + + + + +N54 + + +ackhandler +(*ccAdapter) +OnPacketSent +0 of 596.16kB (4.91%) + + + + + +N54->N47 + + + + + + + 596.16kB + + + + + +N56 + + +ackhandler +(*sentPacketHandler) +sentPacketImpl +0 of 596.16kB (4.91%) + + + + + +N55->N56 + + + + + + + 596.16kB + + + + + +N56->N54 + + + + + + + 596.16kB + + + + + +N57 + + +impl +(*MessageInfo) +unmarshal +0 of 1024.02kB (8.43%) + + + + + +N57->N8 + + + + + + + 1024.02kB + + + + + +N58->N8 + + + + + + + 1024.02kB + + + + + +N60 + + +proto +UnmarshalOptions +unmarshal +0 of 1024.02kB (8.43%) + + + + + +N59->N60 + + + + + + + 1024.02kB + + + + + +N60->N57 + + + + + + + 1024.02kB + + + + + +N61->N36 + + + + + + + 2836.92kB + + + + + +N63 + + +runtime +mstart1 +0 of 3587.50kB (29.54%) + + + + + +N62->N63 + + + + + + + 3587.50kB + + + + + +N63->N2 + + + + + + + 3587.50kB + + + + + +N64 + + +runtime +newm +0 of 5637.50kB (46.41%) + + + + + +N64->N1 + + + + + + + 5637.50kB + + + + + +N66 + + +runtime +newproc1 +0 of 512.20kB (4.22%) + + + + + +N65->N66 + + + + + + + 512.20kB + + + + + +N66->N16 + + + + + + + 512.20kB + + + + + +N67->N2 + + + + + + + 2050kB + + + + + +N69 + + +runtime +startm +0 of 5637.50kB (46.41%) + + + + + +N68->N69 + + + + + + + 5637.50kB + + + + + +N69->N64 + + + + + + + 5637.50kB + + + + + From f1ef6c2096b24b53f81c81e0e1e12201528c2024 Mon Sep 17 00:00:00 2001 From: qiaoweijie Date: Tue, 31 Jan 2023 15:26:18 +0800 Subject: [PATCH 080/126] fix: get tlsconfig err not handle, return nil pointer --- adapter/outbound/vless.go | 3 +++ component/tls/config.go | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index dd6e0f23..a24f2a6e 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -101,6 +101,9 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { wsOpts.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } else { wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) + if err != nil { + return nil, err + } } if v.option.ServerName != "" { diff --git a/component/tls/config.go b/component/tls/config.go index 14e5b20d..39d1b1fd 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -63,7 +63,7 @@ func convertFingerprint(fingerprint string) (*[32]byte, error) { } if len(fpByte) != 32 { - return nil, fmt.Errorf("fingerprint string length error,need sha25 fingerprint") + return nil, fmt.Errorf("fingerprint string length error,need sha256 fingerprint") } return (*[32]byte)(fpByte), nil } @@ -99,10 +99,10 @@ func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint strin if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { return nil, err } else { - tlsConfig=GetGlobalXTLSConfig(tlsConfig) - tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) - tlsConfig.InsecureSkipVerify = true - return tlsConfig, nil + tlsConfig = GetGlobalXTLSConfig(tlsConfig) + tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) + tlsConfig.InsecureSkipVerify = true + return tlsConfig, nil } } From 61b3b4f775442734bafdeb4f3f9db68b8fa860bd Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 31 Jan 2023 18:05:46 +0800 Subject: [PATCH 081/126] fix: Handle error earlier in DialContextWithDialer. chore: Fix typo. --- adapter/outbound/vless.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index a24f2a6e..a14bd528 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -236,12 +236,15 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta }(c) c, err = v.StreamConn(c, metadata) + if err != nil { + return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) + } return NewConn(c, v), err } // ListenPacketContext implements C.ProxyAdapter func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { - // vless 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 need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) if err != nil { @@ -282,7 +285,7 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // ListenPacketWithDialer implements C.ProxyAdapter func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - // vless 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 need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) if err != nil { From 2ee0f634e6e4ad04bdb05a159502f407e15ab26a Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 1 Feb 2023 22:16:06 +0800 Subject: [PATCH 082/126] feat: Add utls for modifying client's fingerprint. Currently only support TLS transport in TCP/GRPC/WS/HTTP for VLESS/Vmess and trojan-grpc. --- adapter/outbound/trojan.go | 44 +++++++++--------- adapter/outbound/vless.go | 68 ++++++++++++++------------- adapter/outbound/vmess.go | 37 +++++++++------ docs/config.yaml | 19 ++++---- go.mod | 4 ++ go.sum | 8 ++++ transport/gun/gun.go | 43 +++++++++++++---- transport/trojan/trojan.go | 15 +++--- transport/vmess/tls.go | 29 ++++++++++-- transport/vmess/utls.go | 90 ++++++++++++++++++++++++++++++++++++ transport/vmess/websocket.go | 32 ++++++++++--- 11 files changed, 285 insertions(+), 104 deletions(-) create mode 100644 transport/vmess/utls.go diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index c90ee377..cd0f1476 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -30,20 +30,21 @@ type Trojan struct { 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"` - SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` - Fingerprint string `proxy:"fingerprint,omitempty"` - UDP bool `proxy:"udp,omitempty"` - 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"` + 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"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + UDP bool `proxy:"udp,omitempty"` + 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"` + ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { @@ -212,12 +213,13 @@ 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, - FlowShow: option.FlowShow, - Fingerprint: option.Fingerprint, + Password: option.Password, + ALPN: option.ALPN, + ServerName: option.Server, + SkipCertVerify: option.SkipCertVerify, + FlowShow: option.FlowShow, + Fingerprint: option.Fingerprint, + ClientFingerprint: option.ClientFingerprint, } switch option.Network { @@ -277,7 +279,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } } - t.transport = gun.NewHTTP2Client(dialFn, tlsConfig) + t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint) t.gunTLSConfig = tlsConfig t.gunConfig = &gun.Config{ diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index a14bd528..96345a6d 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -12,10 +12,6 @@ import ( "strconv" "sync" - vmessSing "github.com/sagernet/sing-vmess" - "github.com/sagernet/sing-vmess/packetaddr" - M "github.com/sagernet/sing/common/metadata" - "github.com/Dreamacro/clash/common/convert" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" @@ -25,6 +21,10 @@ import ( "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" + + vmessSing "github.com/sagernet/sing-vmess" + "github.com/sagernet/sing-vmess/packetaddr" + M "github.com/sagernet/sing/common/metadata" ) const ( @@ -45,27 +45,28 @@ 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"` - PacketAddr bool `proxy:"packet-addr,omitempty"` - XUDP bool `proxy:"xudp,omitempty"` - PacketEncoding string `proxy:"packet-encoding,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"` - Fingerprint string `proxy:"fingerprint,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"` + TLS bool `proxy:"tls,omitempty"` + UDP bool `proxy:"udp,omitempty"` + PacketAddr bool `proxy:"packet-addr,omitempty"` + XUDP bool `proxy:"xudp,omitempty"` + PacketEncoding string `proxy:"packet-encoding,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"` + Fingerprint string `proxy:"fingerprint,omitempty"` + ServerName string `proxy:"servername,omitempty"` + ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { @@ -80,6 +81,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } @@ -179,9 +181,10 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) } else if v.option.TLS { tlsOpts := vmess.TLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, - FingerPrint: v.option.Fingerprint, + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + FingerPrint: v.option.Fingerprint, + ClientFingerprint: v.option.ClientFingerprint, } if isH2 { @@ -526,8 +529,9 @@ func NewVless(option VlessOption) (*Vless, error) { } gunConfig := &gun.Config{ - ServiceName: v.option.GrpcOpts.GrpcServiceName, - Host: v.option.ServerName, + ServiceName: v.option.GrpcOpts.GrpcServiceName, + Host: v.option.ServerName, + ClientFingerprint: v.option.ClientFingerprint, } tlsConfig := tlsC.GetGlobalTLSConfig(&tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, @@ -542,7 +546,9 @@ func NewVless(option VlessOption) (*Vless, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) + + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) + } return v, nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 727da2ee..1e90a1bc 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -11,15 +11,14 @@ import ( "strings" "sync" - tlsC "github.com/Dreamacro/clash/component/tls" - vmess "github.com/sagernet/sing-vmess" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" + tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/gun" clashVMess "github.com/Dreamacro/clash/transport/vmess" + vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing-vmess/packetaddr" M "github.com/sagernet/sing/common/metadata" ) @@ -60,6 +59,7 @@ type VmessOption struct { PacketEncoding string `proxy:"packet-encoding,omitempty"` GlobalPadding bool `proxy:"global-padding,omitempty"` AuthenticatedLength bool `proxy:"authenticated-length,omitempty"` + ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } type HTTPOptions struct { @@ -97,6 +97,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } @@ -134,8 +135,9 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) tlsOpts := &clashVMess.TLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + ClientFingerprint: v.option.ClientFingerprint, } if v.option.ServerName != "" { @@ -160,9 +162,10 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { case "h2": host, _, _ := net.SplitHostPort(v.addr) tlsOpts := clashVMess.TLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, - NextProtos: []string{"h2"}, + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + NextProtos: []string{"h2"}, + ClientFingerprint: v.option.ClientFingerprint, } if v.option.ServerName != "" { @@ -187,8 +190,9 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) tlsOpts := &clashVMess.TLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, + Host: host, + SkipCertVerify: v.option.SkipCertVerify, + ClientFingerprint: v.option.ClientFingerprint, } if v.option.ServerName != "" { @@ -252,7 +256,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta // ListenPacketContext implements C.ProxyAdapter func (v *Vmess) 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 + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) if err != nil { @@ -295,7 +299,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // ListenPacketWithDialer implements C.ProxyAdapter func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - // vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) if err != nil { @@ -402,8 +406,9 @@ func NewVmess(option VmessOption) (*Vmess, error) { } gunConfig := &gun.Config{ - ServiceName: v.option.GrpcOpts.GrpcServiceName, - Host: v.option.ServerName, + ServiceName: v.option.GrpcOpts.GrpcServiceName, + Host: v.option.ServerName, + ClientFingerprint: v.option.ClientFingerprint, } tlsConfig := &tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, @@ -418,7 +423,9 @@ func NewVmess(option VmessOption) (*Vmess, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) + + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) + } return v, nil } diff --git a/docs/config.yaml b/docs/config.yaml index 1215b21d..705867ff 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -23,7 +23,6 @@ geox-url: geosite: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat" mmdb: "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb" - log-level: debug # 日志等级 silent/error/warning/info/debug ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录 @@ -237,9 +236,9 @@ dns: # 配置查询域名使用的 DNS 服务器 nameserver-policy: - # 'www.baidu.com': '114.114.114.114' - # '+.internal.crop.com': '10.0.0.1' - 'geosite:cn': 'https://doh.pub/dns-query' + # 'www.baidu.com': '114.114.114.114' + # '+.internal.crop.com': '10.0.0.1' + "geosite:cn": "https://doh.pub/dns-query" proxies: # Shadowsocks @@ -255,9 +254,8 @@ proxies: server: server port: 443 cipher: chacha20-ietf-poly1305 - password: - "password" - # udp: true + password: "password" + # udp: true # udp-over-tcp: false # ip-version: ipv4 # 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer。默认使用 dual # ipv4:仅使用 IPv4 ipv6:仅使用 IPv6 @@ -319,6 +317,7 @@ proxies: # udp: true # tls: true # fingerprint: xxxx + # client-fingerprint: random # Available: "chrome","firefox","safari","random" # skip-cert-verify: true # servername: example.com # priority over wss host # network: ws @@ -483,6 +482,7 @@ proxies: # flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS # skip-cert-verify: true # fingerprint: xxxx + # client-fingerprint: random # Available: "chrome","firefox","safari","random" - name: "vless-ws" type: vless @@ -492,6 +492,7 @@ proxies: udp: true tls: true network: ws + # client-fingerprint: random # Available: "chrome","firefox","safari","random" servername: example.com # priority over wss host # skip-cert-verify: true # fingerprint: xxxx @@ -535,9 +536,7 @@ proxies: private-key: eCtXsJZ27+4PbhDkHnB923tkUn2Gj59wZw5wFA75MnU= public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= udp: true -# reserved: 'U4An' - - + # reserved: 'U4An' - name: tuic server: www.example.com port: 10443 diff --git a/go.mod b/go.mod index bccc2135..8773ecef 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,9 @@ require ( github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e github.com/miekg/dns v1.1.50 + github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 + github.com/refraction-networking/utls v1.2.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.1.6 github.com/sagernet/sing-vmess v0.1.1 @@ -48,6 +50,7 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect @@ -56,6 +59,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/josharian/native v1.1.0 // indirect + github.com/klauspost/compress v1.15.12 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/marten-seemann/qpack v0.3.0 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect diff --git a/go.sum b/go.sum index b850cce9..16829ad0 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -67,6 +69,8 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= +github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= @@ -103,6 +107,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e h1:ZpzW8y github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e/go.mod h1:hF5lqFsfWeDrImIQ5XkOTS8aucCWvK4GOoCUNYKTrPU= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= +github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= @@ -113,6 +119,8 @@ github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYx github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo= +github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 0ff68fca..a176e8fb 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -19,6 +19,8 @@ import ( "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" + U "github.com/Dreamacro/clash/transport/vmess" + utls "github.com/refraction-networking/utls" "go.uber.org/atomic" "golang.org/x/net/http2" @@ -51,8 +53,9 @@ type Conn struct { } type Config struct { - ServiceName string - Host string + ServiceName string + Host string + ClientFingerprint string } func (g *Conn) initRequest() { @@ -188,8 +191,9 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config) *TransportWrap { +func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *TransportWrap { wrap := TransportWrap{} + dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { pconn, err := dialFn(network, addr) if err != nil { @@ -197,17 +201,38 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config) *TransportWrap { } wrap.remoteAddr = pconn.RemoteAddr() - cn := tls.Client(pconn, cfg) - if err := cn.HandshakeContext(ctx); err != nil { + + if len(Fingerprint) != 0 { + if fingerprint, exists := U.GetFingerprint(Fingerprint); exists { + utlsConn := U.UClient(pconn, cfg, &utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: nil, + }) + if err := utlsConn.(*U.UConn).HandshakeContext(ctx); err != nil { + pconn.Close() + return nil, err + } + state := utlsConn.(*U.UConn).ConnectionState() + if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + utlsConn.Close() + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + } + return utlsConn, nil + } + } + + conn := tls.Client(pconn, cfg) + if err := conn.HandshakeContext(ctx); err != nil { pconn.Close() return nil, err } - state := cn.ConnectionState() + state := conn.ConnectionState() if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { - cn.Close() + conn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) } - return cn, nil + return conn, nil } wrap.Transport = &http2.Transport{ @@ -260,6 +285,6 @@ func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config) (net.C return conn, nil } - transport := NewHTTP2Client(dialFn, tlsConfig) + transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint) return StreamGunWithTransport(transport, cfg) } diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index ca7b9425..ef52712f 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -46,13 +46,14 @@ const ( ) type Option struct { - Password string - ALPN []string - ServerName string - SkipCertVerify bool - Fingerprint string - Flow string - FlowShow bool + Password string + ALPN []string + ServerName string + SkipCertVerify bool + Fingerprint string + Flow string + FlowShow bool + ClientFingerprint string } type WebsocketOption struct { diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 02442771..e60b117e 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -7,13 +7,16 @@ import ( tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" + + utls "github.com/refraction-networking/utls" ) type TLSConfig struct { - Host string - SkipCertVerify bool - FingerPrint string - NextProtos []string + Host string + SkipCertVerify bool + FingerPrint string + ClientFingerprint string + NextProtos []string } func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { @@ -32,11 +35,27 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { } } + if len(cfg.ClientFingerprint) != 0 { + if fingerprint, exists := GetFingerprint(cfg.ClientFingerprint); exists { + utlsConn := UClient(conn, tlsConfig, &utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: nil, + }) + + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + + err := utlsConn.(*UConn).HandshakeContext(ctx) + return utlsConn, err + } + } + 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 } diff --git a/transport/vmess/utls.go b/transport/vmess/utls.go new file mode 100644 index 00000000..4e53bed7 --- /dev/null +++ b/transport/vmess/utls.go @@ -0,0 +1,90 @@ +package vmess + +import ( + "crypto/tls" + "net" + + "github.com/Dreamacro/clash/log" + + "github.com/mroth/weightedrand/v2" + utls "github.com/refraction-networking/utls" +) + +type UConn struct { + *utls.UConn +} + +var initRandomFingerprint *utls.ClientHelloID + +func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { + utlsConn := utls.UClient(c, CopyConfig(config), *fingerprint) + return &UConn{UConn: utlsConn} +} + +func GetFingerprint(ClientFingerprint string) (*utls.ClientHelloID, bool) { + if initRandomFingerprint == nil { + initRandomFingerprint, _ = RollFingerprint() + } + if ClientFingerprint == "random" { + log.Debugln("use initial random HelloID:%s", initRandomFingerprint.Client) + return initRandomFingerprint, true + } + fingerprint, ok := Fingerprints[ClientFingerprint] + log.Debugln("use specified fingerprint:%s", fingerprint.Client) + return fingerprint, ok +} + +func RollFingerprint() (*utls.ClientHelloID, bool) { + chooser, _ := weightedrand.NewChooser( + weightedrand.NewChoice("chrome", 6), + weightedrand.NewChoice("safari", 3), + weightedrand.NewChoice("firefox", 1), + ) + initClient := chooser.Pick() + log.Debugln("initial random HelloID:%s", initClient) + fingerprint, ok := Fingerprints[initClient] + return fingerprint, ok +} + +var Fingerprints = map[string]*utls.ClientHelloID{ + "chrome": &utls.HelloChrome_Auto, + "firefox": &utls.HelloFirefox_Auto, + "safari": &utls.HelloSafari_Auto, + "randomized": &utls.HelloRandomized, +} + +func CopyConfig(c *tls.Config) *utls.Config { + return &utls.Config{ + RootCAs: c.RootCAs, + ServerName: c.ServerName, + InsecureSkipVerify: c.InsecureSkipVerify, + VerifyPeerCertificate: c.VerifyPeerCertificate, + } +} + +// WebsocketHandshake basically calls UConn.Handshake inside it but it will only send +// http/1.1 in its ALPN. +func (c *UConn) WebsocketHandshake() error { + // Build the handshake state. This will apply every variable of the TLS of the + // fingerprint in the UConn + if err := c.BuildHandshakeState(); err != nil { + return err + } + // Iterate over extensions and check for utls.ALPNExtension + hasALPNExtension := false + for _, extension := range c.Extensions { + if alpn, ok := extension.(*utls.ALPNExtension); ok { + hasALPNExtension = true + alpn.AlpnProtocols = []string{"http/1.1"} + break + } + } + if !hasALPNExtension { // Append extension if doesn't exists + c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}) + } + // Rebuild the client hello and do the handshake + if err := c.BuildHandshakeState(); err != nil { + return err + } + return c.Handshake() +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index b38c0006..a7ca82b3 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -8,6 +8,7 @@ import ( "encoding/binary" "errors" "fmt" + "io" "math/rand" "net" @@ -20,8 +21,9 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" - "github.com/gorilla/websocket" + + utls "github.com/refraction-networking/utls" ) type websocketConn struct { @@ -56,6 +58,7 @@ type WebsocketConfig struct { TLSConfig *tls.Config MaxEarlyData int EarlyDataHeaderName string + ClientFingerprint string } // Read implements net.Conn.Read() @@ -136,15 +139,15 @@ func (wsc *websocketConn) Upstream() any { } func (wsc *websocketConn) Close() error { - var errors []string + var e []string if err := wsc.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5)); err != nil { - errors = append(errors, err.Error()) + e = append(e, err.Error()) } if err := wsc.conn.Close(); err != nil { - errors = append(errors, err.Error()) + e = append(e, err.Error()) } - if len(errors) > 0 { - return fmt.Errorf("failed to close connection: %s", strings.Join(errors, ",")) + if len(e) > 0 { + return fmt.Errorf("failed to close connection: %s", strings.Join(e, ",")) } return nil } @@ -316,6 +319,7 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co } func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { + dialer := &websocket.Dialer{ NetDial: func(network, addr string) (net.Conn, error) { return conn, nil @@ -329,6 +333,22 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf if c.TLS { scheme = "wss" dialer.TLSClientConfig = c.TLSConfig + if len(c.ClientFingerprint) != 0 { + if fingerprint, exists := GetFingerprint(c.ClientFingerprint); exists { + dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { + utlsConn := UClient(conn, c.TLSConfig, &utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: fingerprint.Seed, + }) + + if err := utlsConn.(*UConn).WebsocketHandshake(); err != nil { + return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) + } + return utlsConn, nil + } + } + } } u, err := url.Parse(c.Path) From 61097d0826616f7002ed4458c98d7ad6019c4c59 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Feb 2023 15:39:57 +0800 Subject: [PATCH 083/126] chore: update to golang1.20 --- .github/workflows/build.yaml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yaml | 2 +- go.mod | 19 ++++++++-------- go.sum | 38 +++++++++++++++++--------------- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3e9d3d93..1def82ea 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -10,7 +10,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.20' check-latest: true cache: true - name: Build diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 3b97691f..d586ca28 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -114,7 +114,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: "1.19" + go-version: "1.20" check-latest: true - name: Test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c74637a6..478f13e1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,7 +13,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v3 with: - go-version: '1.19' + go-version: '1.20' check-latest: true cache: true diff --git a/go.mod b/go.mod index 8773ecef..0981a590 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 - github.com/metacubex/sing-shadowsocks v0.1.0 + github.com/metacubex/quic-go v0.32.0 + github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e github.com/miekg/dns v1.1.50 @@ -39,7 +39,7 @@ require ( go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 golang.org/x/crypto v0.5.0 - golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 + golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.5.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.4.0 @@ -61,22 +61,23 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.12 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect - github.com/marten-seemann/qpack v0.3.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-18 v0.2.0 // indirect + github.com/quic-go/qtls-go1-19 v0.2.0 // indirect + github.com/quic-go/qtls-go1-20 v0.1.0 // indirect github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/tools v0.2.0 // indirect gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b // indirect ) -replace gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b => github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8 +replace gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b => github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df diff --git a/go.sum b/go.sum index 16829ad0..de69d14f 100644 --- a/go.sum +++ b/go.sum @@ -78,12 +78,6 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= -github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g= -github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI= -github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE= -github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= @@ -95,12 +89,12 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8 h1:CrAPNUP06BvFDmzt+Bluqw9SqFK/q7VuGBUB7Cx3Bic= -github.com/metacubex/gvisor v0.0.0-20230129142733-94bf62304db8/go.mod h1:94x/o/BlxPAbw4phqHRac0/IzpcQRUP7ZQldDWV3TKU= -github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91 h1:CGn1ku3QZ/OjJjnRH4eO9jtXegdPQZUJ7y1Y6CppLd0= -github.com/metacubex/quic-go v0.31.1-0.20230117135846-c981c4c16e91/go.mod h1:8VvqBlJaARNcwAE9zrbhKI/I1R5Lu4gqmt3CSGrJl7s= -github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A= -github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= +github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df h1:3zQDj38NIi8KEPNq1mC9bb82QoGYW/z4HaCzRwHwpNY= +github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= +github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= +github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= +github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 h1:MNCGIpXhxXn9ck5bxfm/cW9Nr2FGQ5cakcGK0yKZcak= +github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b h1:k0Wnbfp7lsdBVVJY4YNbg0OxBiKWZSir8k10g0TuOlI= github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b/go.mod h1:lJWUpVKefklkLUL3ukp9Iapz+zSxS/fvfbevoUL2Vwg= github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e h1:ZpzW8ymNjU2Gi7ieJexUV8BDrIuBfCBaZdgAyB1RsYs= @@ -119,6 +113,14 @@ github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYx github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= +github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= +github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk= +github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= +github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo= github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= @@ -169,13 +171,13 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= +golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -234,8 +236,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From a298b9ea01dae42dbbb919c89b317ce67d2cb4c9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Feb 2023 21:03:24 +0800 Subject: [PATCH 084/126] chore: fix mips atomic panic --- go.mod | 2 ++ go.sum | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 0981a590..c5d00873 100644 --- a/go.mod +++ b/go.mod @@ -81,3 +81,5 @@ require ( ) replace gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b => github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df + +replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index de69d14f..7904547b 100644 --- a/go.sum +++ b/go.sum @@ -99,6 +99,8 @@ github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b h1:k0Wnbfp7ls github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b/go.mod h1:lJWUpVKefklkLUL3ukp9Iapz+zSxS/fvfbevoUL2Vwg= github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e h1:ZpzW8ymNjU2Gi7ieJexUV8BDrIuBfCBaZdgAyB1RsYs= github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e/go.mod h1:hF5lqFsfWeDrImIQ5XkOTS8aucCWvK4GOoCUNYKTrPU= +github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= +github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= @@ -162,8 +164,6 @@ github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8x github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= From 857d6e419f5e3f5bdbd724ae41f8651a32fc59c3 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 2 Feb 2023 21:29:12 +0800 Subject: [PATCH 085/126] fix: Parse CC fail in tuic. --- listener/inbound/tuic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index f3b8a5f2..58817fc6 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -12,7 +12,7 @@ type TuicOption struct { Token []string `inbound:"token"` Certificate string `inbound:"certificate"` PrivateKey string `inbound:"private-key"` - CongestionController string `inbound:"congestion-controllerr,omitempty"` + CongestionController string `inbound:"congestion-controller,omitempty"` MaxIdleTime int `inbound:"max-idle-timer,omitempty"` AuthenticationTimeout int `inbound:"authentication-timeoutr,omitempty"` ALPN []string `inbound:"alpnr,omitempty"` From 99662b616f5942eb8ffc69771d281ab1b43a08a9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Feb 2023 21:48:20 +0800 Subject: [PATCH 086/126] fix: tuic listener config name --- listener/inbound/tuic.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index 58817fc6..c74f73f6 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -13,10 +13,10 @@ type TuicOption struct { Certificate string `inbound:"certificate"` PrivateKey string `inbound:"private-key"` CongestionController string `inbound:"congestion-controller,omitempty"` - MaxIdleTime int `inbound:"max-idle-timer,omitempty"` - AuthenticationTimeout int `inbound:"authentication-timeoutr,omitempty"` - ALPN []string `inbound:"alpnr,omitempty"` - MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-sizer,omitempty"` + MaxIdleTime int `inbound:"max-idle-time,omitempty"` + AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"` + ALPN []string `inbound:"alpn,omitempty"` + MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` } func (o TuicOption) Equal(config C.InboundConfig) bool { From e1e1984d3e01b0506376bb0d58550b4fbecfc8a3 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Feb 2023 21:40:05 +0800 Subject: [PATCH 087/126] feat: nameserver policy support multiple server --- config/config.go | 30 ++++++++++++++++++++++++------ dns/enhancer.go | 2 +- dns/resolver.go | 10 +++++----- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/config/config.go b/config/config.go index 78f4eecb..3095fb1d 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,7 @@ import ( "net/netip" "net/url" "os" + "reflect" "runtime" "strconv" "strings" @@ -97,7 +98,7 @@ type DNS struct { DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie[netip.Addr] - NameServerPolicy map[string]dns.NameServer + NameServerPolicy map[string][]dns.NameServer ProxyServerNameserver []dns.NameServer } @@ -181,7 +182,7 @@ type RawDNS struct { FakeIPRange string `yaml:"fake-ip-range"` FakeIPFilter []string `yaml:"fake-ip-filter"` DefaultNameserver []string `yaml:"default-nameserver"` - NameServerPolicy map[string]string `yaml:"nameserver-policy"` + NameServerPolicy map[string]any `yaml:"nameserver-policy"` ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` } @@ -952,18 +953,35 @@ func parsePureDNSServer(server string) string { } } } -func parseNameServerPolicy(nsPolicy map[string]string, preferH3 bool) (map[string]dns.NameServer, error) { - policy := map[string]dns.NameServer{} +func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][]dns.NameServer, error) { + policy := map[string][]dns.NameServer{} for domain, server := range nsPolicy { - nameservers, err := parseNameServer([]string{server}, preferH3) + var ( + nameservers []dns.NameServer + err error + ) + + switch reflect.TypeOf(server).Kind() { + case reflect.Slice, reflect.Array: + origin := reflect.ValueOf(server) + servers := make([]string, 0) + for i := 0; i < origin.Len(); i++ { + servers = append(servers, fmt.Sprintf("%v", origin.Index(i))) + } + nameservers, err = parseNameServer(servers, preferH3) + case reflect.String: + nameservers, err = parseNameServer([]string{fmt.Sprintf("%v", server)}, preferH3) + default: + return nil, errors.New("server format error, must be string or array") + } if err != nil { return nil, err } if _, valid := trie.ValidAndSplitDomain(domain); !valid { return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain) } - policy[domain] = nameservers[0] + policy[domain] = nameservers } return policy, nil diff --git a/dns/enhancer.go b/dns/enhancer.go index 8b3ce282..76d4460e 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -109,7 +109,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer { if cfg.EnhancedMode != C.DNSNormal { fakePool = cfg.Pool - mapping = cache.New[netip.Addr, string](cache.WithSize[netip.Addr, string](4096), cache.WithStale[netip.Addr, string](true)) + mapping = cache.New(cache.WithSize[netip.Addr, string](4096), cache.WithStale[netip.Addr, string](true)) } return &ResolverEnhancer{ diff --git a/dns/resolver.go b/dns/resolver.go index 895b7393..8c983111 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -423,19 +423,19 @@ type Config struct { FallbackFilter FallbackFilter Pool *fakeip.Pool Hosts *trie.DomainTrie[netip.Addr] - Policy map[string]NameServer + Policy map[string][]NameServer } func NewResolver(config Config) *Resolver { defaultResolver := &Resolver{ main: transform(config.Default, nil), - lruCache: cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), } r := &Resolver{ ipv6: config.IPv6, main: transform(config.Main, defaultResolver), - lruCache: cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), hosts: config.Hosts, } @@ -464,11 +464,11 @@ func NewResolver(config Config) *Resolver { } r.geositePolicy = append(r.geositePolicy, geositePolicyRecord{ matcher: matcher, - policy: NewPolicy(transform([]NameServer{nameserver}, defaultResolver)), + policy: NewPolicy(transform(nameserver, defaultResolver)), inversedMatching: inverse, }) } else { - _ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) + _ = r.policy.Insert(domain, NewPolicy(transform(nameserver, defaultResolver))) } } r.policy.Optimize() From fe348e89c55d5b8640740c617eb648cbd8ecbba2 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Feb 2023 21:41:26 +0800 Subject: [PATCH 088/126] chore: add nameserver-policy demo --- docs/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 705867ff..89b3ce6d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -239,7 +239,7 @@ dns: # 'www.baidu.com': '114.114.114.114' # '+.internal.crop.com': '10.0.0.1' "geosite:cn": "https://doh.pub/dns-query" - + "www.baidu.com": [https://doh.pub/dns-query,https://dns.alidns.com/dns-query] proxies: # Shadowsocks # cipher支持: From cbc217e80aed76b5fd9300b380cdbf707981d502 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 1 Feb 2023 08:50:26 +0800 Subject: [PATCH 089/126] fix: Converter Shadowsocks password parse --- common/convert/converter.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/common/convert/converter.go b/common/convert/converter.go index d58e0bab..df0d9ffd 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -2,6 +2,7 @@ package convert import ( "bytes" + "encoding/base64" "encoding/json" "fmt" "github.com/Dreamacro/clash/log" @@ -283,14 +284,17 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { ) cipher = cipherRaw if password, found = urlSS.User.Password(); !found { - dcBuf, _ := enc.DecodeString(cipherRaw) + dcBuf, err := base64.RawURLEncoding.DecodeString(cipherRaw) + if err != nil { + dcBuf, _ = enc.DecodeString(cipherRaw) + } cipher, password, found = strings.Cut(string(dcBuf), ":") if !found { continue } - err := VerifyMethod(cipher, password) + err = VerifyMethod(cipher, password) if err != nil { - dcBuf, _ := encRaw.DecodeString(cipherRaw) + dcBuf, _ = encRaw.DecodeString(cipherRaw) cipher, password, found = strings.Cut(string(dcBuf), ":") } } From 4c25f5e73b86c9c8706054252c51f8a959b5ae43 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 5 Feb 2023 17:31:58 +0800 Subject: [PATCH 090/126] feat: Update utls support. * client-fingerprint is used to apply Utls for modifying ClientHello, it accepts "chrome","firefox","safari","ios","random" options. * Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. --- docs/config.yaml | 9 +++++---- transport/trojan/trojan.go | 32 ++++++++++++++++++++++---------- transport/vmess/tls.go | 25 +++++++++++++++++-------- transport/vmess/utls.go | 3 +++ 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 89b3ce6d..63bda11b 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -109,7 +109,7 @@ sniffer: HTTP: # 需要嗅探的端口 - ports: [ 80, 8080-8880 ] + ports: [80, 8080-8880] # 可覆盖 sniffer.override-destination override-destination: true force-domain: @@ -155,7 +155,7 @@ tunnels: - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn # full yaml config - - network: [ tcp, udp ] + - network: [tcp, udp] address: 127.0.0.1:7777 target: target.com proxy: proxy @@ -317,7 +317,7 @@ proxies: # udp: true # tls: true # fingerprint: xxxx - # client-fingerprint: random # Available: "chrome","firefox","safari","random" + # client-fingerprint: chrome # Available: "chrome","firefox","safari","ios","random", currently only support TLS transport in TCP/GRPC/WS/HTTP for VLESS/Vmess and trojan. # skip-cert-verify: true # servername: example.com # priority over wss host # network: ws @@ -423,6 +423,7 @@ proxies: server: server port: 443 password: yourpsk + # client-fingerprint: random # Available: "chrome","firefox","safari","random" # fingerprint: xxxx # udp: true # sni: example.com # aka server name @@ -802,7 +803,7 @@ listeners: listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - network: [ tcp, udp ] + network: [tcp, udp] target: target.com - name: tun-in-1 diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index ef52712f..235d4d38 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -116,15 +116,26 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } } + if len(t.option.ClientFingerprint) != 0 { + utlsConn, valid := vmess.GetUtlsConnWithClientFingerprint(conn, t.option.ClientFingerprint, tlsConfig) + if valid { + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + + err := utlsConn.(*vmess.UConn).HandshakeContext(ctx) + return utlsConn, err + + } + } + tlsConn := tls.Client(conn, tlsConfig) + // fix tls handshake not timeout ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - if err := tlsConn.HandshakeContext(ctx); err != nil { - return nil, err - } - return tlsConn, nil + err := tlsConn.HandshakeContext(ctx) + return tlsConn, err } } @@ -142,12 +153,13 @@ func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) } return vmess.StreamWebsocketConn(conn, &vmess.WebsocketConfig{ - Host: wsOptions.Host, - Port: wsOptions.Port, - Path: wsOptions.Path, - Headers: wsOptions.Headers, - TLS: true, - TLSConfig: tlsConfig, + Host: wsOptions.Host, + Port: wsOptions.Port, + Path: wsOptions.Path, + Headers: wsOptions.Headers, + TLS: true, + TLSConfig: tlsConfig, + ClientFingerprint: t.option.ClientFingerprint, }) } diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index e60b117e..7dbde61b 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -36,13 +36,8 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { } if len(cfg.ClientFingerprint) != 0 { - if fingerprint, exists := GetFingerprint(cfg.ClientFingerprint); exists { - utlsConn := UClient(conn, tlsConfig, &utls.ClientHelloID{ - Client: fingerprint.Client, - Version: fingerprint.Version, - Seed: nil, - }) - + utlsConn, valid := GetUtlsConnWithClientFingerprint(conn, cfg.ClientFingerprint, tlsConfig) + if valid { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() @@ -50,7 +45,6 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { return utlsConn, err } } - tlsConn := tls.Client(conn, tlsConfig) ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) @@ -59,3 +53,18 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { err := tlsConn.HandshakeContext(ctx) return tlsConn, err } + +func GetUtlsConnWithClientFingerprint(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) { + + if fingerprint, exists := GetFingerprint(ClientFingerprint); exists { + utlsConn := UClient(conn, tlsConfig, &utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: nil, + }) + + return utlsConn, true + } + + return nil, false +} diff --git a/transport/vmess/utls.go b/transport/vmess/utls.go index 4e53bed7..93a08111 100644 --- a/transport/vmess/utls.go +++ b/transport/vmess/utls.go @@ -38,6 +38,7 @@ func RollFingerprint() (*utls.ClientHelloID, bool) { chooser, _ := weightedrand.NewChooser( weightedrand.NewChoice("chrome", 6), weightedrand.NewChoice("safari", 3), + weightedrand.NewChoice("ios", 2), weightedrand.NewChoice("firefox", 1), ) initClient := chooser.Pick() @@ -50,6 +51,7 @@ var Fingerprints = map[string]*utls.ClientHelloID{ "chrome": &utls.HelloChrome_Auto, "firefox": &utls.HelloFirefox_Auto, "safari": &utls.HelloSafari_Auto, + "ios": &utls.HelloIOS_Auto, "randomized": &utls.HelloRandomized, } @@ -64,6 +66,7 @@ func CopyConfig(c *tls.Config) *utls.Config { // WebsocketHandshake basically calls UConn.Handshake inside it but it will only send // http/1.1 in its ALPN. +// Copy from https://github.com/XTLS/Xray-core/blob/main/transport/internet/tls/tls.go func (c *UConn) WebsocketHandshake() error { // Build the handshake state. This will apply every variable of the TLS of the // fingerprint in the UConn From 287986d52492aa6ac0a9988b4fc311b74165e488 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 5 Feb 2023 23:36:08 +0800 Subject: [PATCH 091/126] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 16460c53..cdfa3505 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ ## Wiki -Documentation is available on [Clash.Meta Wiki](https://docs.metacubex.one/). +Documentation and configuring examples are available on [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki) and [Clash.Meta Wiki](https://docs.metacubex.one/). ## Build @@ -62,9 +62,9 @@ If you need gvisor for tun stack, build with: go build -tags with_gvisor ``` -## Advanced usage of this fork + -### DNS configuration + ### IPTABLES configuration -Work on Linux OS who's supported `iptables` +Work on Linux OS which supported `iptables` ```yaml # Enable the TPROXY listener From c8b8b60b93b1726405b89d326c66faa03d2b55f9 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 6 Feb 2023 17:48:49 +0800 Subject: [PATCH 092/126] chore: override-destination default value is true --- config/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.go b/config/config.go index 3095fb1d..fd8621c3 100644 --- a/config/config.go +++ b/config/config.go @@ -410,6 +410,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { Ports: []string{}, ForceDnsMapping: true, ParsePureIp: true, + OverrideDest: true, }, Profile: Profile{ StoreSelected: true, From 05ca819823a88b80b0907ff8c10dad0ec3126b7d Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 7 Feb 2023 01:26:08 +0800 Subject: [PATCH 093/126] feat: add global-client-fingerprint. * Available: "chrome","firefox","safari","ios","random","none". * global-client-fingerprint will NOT overwrite the proxy's client-fingerprint setting when "client-fingerprint: none". --- adapter/outbound/trojan.go | 6 ++ adapter/outbound/vless.go | 5 ++ adapter/outbound/vmess.go | 5 ++ adapter/parser.go | 17 ++++++ config/config.go | 112 ++++++++++++++++++++----------------- docs/config.yaml | 11 +++- transport/vmess/utls.go | 22 ++++++++ 7 files changed, 123 insertions(+), 55 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index cd0f1476..5fe946b0 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -15,6 +15,7 @@ import ( "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" "github.com/Dreamacro/clash/transport/vless" + "github.com/Dreamacro/clash/transport/vmess" ) type Trojan struct { @@ -77,6 +78,11 @@ func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { // StreamConn implements C.ProxyAdapter func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error + + if vmess.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { + t.option.ClientFingerprint = vmess.GetGlobalFingerprint() + } + if t.transport != nil { c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig) } else { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 96345a6d..0550fd7a 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -71,6 +71,11 @@ type VlessOption struct { func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error + + if vmess.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { + v.option.ClientFingerprint = vmess.GetGlobalFingerprint() + } + switch v.option.Network { case "ws": diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 1e90a1bc..a2dff6ee 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -87,6 +87,11 @@ type WSOptions struct { // StreamConn implements C.ProxyAdapter func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error + + if clashVMess.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { + v.option.ClientFingerprint = clashVMess.GetGlobalFingerprint() + } + switch v.option.Network { case "ws": diff --git a/adapter/parser.go b/adapter/parser.go index 86fe96f9..97663540 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -2,9 +2,11 @@ package adapter import ( "fmt" + "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/common/structure" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/vmess" ) func ParseProxy(mapping map[string]any) (C.Proxy, error) { @@ -54,6 +56,11 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { Path: []string{"/"}, }, } + + if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + vmessOption.ClientFingerprint = GlobalUtlsClient + } + err = decoder.Decode(mapping, vmessOption) if err != nil { break @@ -61,6 +68,11 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { proxy, err = outbound.NewVmess(*vmessOption) case "vless": vlessOption := &outbound.VlessOption{} + + if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + vlessOption.ClientFingerprint = GlobalUtlsClient + } + err = decoder.Decode(mapping, vlessOption) if err != nil { break @@ -75,6 +87,11 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { proxy, err = outbound.NewSnell(*snellOption) case "trojan": trojanOption := &outbound.TrojanOption{} + + if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + trojanOption.ClientFingerprint = GlobalUtlsClient + } + err = decoder.Decode(mapping, trojanOption) if err != nil { break diff --git a/config/config.go b/config/config.go index fd8621c3..be2e49cf 100644 --- a/config/config.go +++ b/config/config.go @@ -14,9 +14,6 @@ import ( "strings" "time" - P "github.com/Dreamacro/clash/component/process" - SNIFF "github.com/Dreamacro/clash/component/sniffer" - "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outboundgroup" @@ -27,6 +24,8 @@ import ( "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata/router" + P "github.com/Dreamacro/clash/component/process" + SNIFF "github.com/Dreamacro/clash/component/sniffer" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" providerTypes "github.com/Dreamacro/clash/constant/provider" @@ -37,6 +36,7 @@ import ( "github.com/Dreamacro/clash/log" R "github.com/Dreamacro/clash/rules" RP "github.com/Dreamacro/clash/rules/provider" + "github.com/Dreamacro/clash/transport/vmess" T "github.com/Dreamacro/clash/tunnel" "gopkg.in/yaml.v3" @@ -46,18 +46,19 @@ import ( type General struct { Inbound Controller - Mode T.TunnelMode `json:"mode"` - UnifiedDelay bool - LogLevel log.LogLevel `json:"log-level"` - IPv6 bool `json:"ipv6"` - Interface string `json:"interface-name"` - RoutingMark int `json:"-"` - GeodataMode bool `json:"geodata-mode"` - GeodataLoader string `json:"geodata-loader"` - TCPConcurrent bool `json:"tcp-concurrent"` - FindProcessMode P.FindProcessMode `json:"find-process-mode"` - Sniffing bool `json:"sniffing"` - EBpf EBpf `json:"-"` + Mode T.TunnelMode `json:"mode"` + UnifiedDelay bool + LogLevel log.LogLevel `json:"log-level"` + IPv6 bool `json:"ipv6"` + Interface string `json:"interface-name"` + RoutingMark int `json:"-"` + GeodataMode bool `json:"geodata-mode"` + GeodataLoader string `json:"geodata-loader"` + TCPConcurrent bool `json:"tcp-concurrent"` + FindProcessMode P.FindProcessMode `json:"find-process-mode"` + Sniffing bool `json:"sniffing"` + EBpf EBpf `json:"-"` + GlobalClientFingerprint string `json:"global-client-fingerprint"` } // Inbound config @@ -234,32 +235,33 @@ type RawTuicServer struct { } type RawConfig struct { - Port int `yaml:"port"` - SocksPort int `yaml:"socks-port"` - RedirPort int `yaml:"redir-port"` - TProxyPort int `yaml:"tproxy-port"` - MixedPort int `yaml:"mixed-port"` - ShadowSocksConfig string `yaml:"ss-config"` - VmessConfig string `yaml:"vmess-config"` - InboundTfo bool `yaml:"inbound-tfo"` - Authentication []string `yaml:"authentication"` - AllowLan bool `yaml:"allow-lan"` - BindAddress string `yaml:"bind-address"` - Mode T.TunnelMode `yaml:"mode"` - UnifiedDelay bool `yaml:"unified-delay"` - LogLevel log.LogLevel `yaml:"log-level"` - IPv6 bool `yaml:"ipv6"` - ExternalController string `yaml:"external-controller"` - ExternalControllerTLS string `yaml:"external-controller-tls"` - ExternalUI string `yaml:"external-ui"` - Secret string `yaml:"secret"` - Interface string `yaml:"interface-name"` - RoutingMark int `yaml:"routing-mark"` - Tunnels []LC.Tunnel `yaml:"tunnels"` - GeodataMode bool `yaml:"geodata-mode"` - GeodataLoader string `yaml:"geodata-loader"` - TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` - FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` + Port int `yaml:"port"` + SocksPort int `yaml:"socks-port"` + RedirPort int `yaml:"redir-port"` + TProxyPort int `yaml:"tproxy-port"` + MixedPort int `yaml:"mixed-port"` + ShadowSocksConfig string `yaml:"ss-config"` + VmessConfig string `yaml:"vmess-config"` + InboundTfo bool `yaml:"inbound-tfo"` + Authentication []string `yaml:"authentication"` + AllowLan bool `yaml:"allow-lan"` + BindAddress string `yaml:"bind-address"` + Mode T.TunnelMode `yaml:"mode"` + UnifiedDelay bool `yaml:"unified-delay"` + LogLevel log.LogLevel `yaml:"log-level"` + IPv6 bool `yaml:"ipv6"` + ExternalController string `yaml:"external-controller"` + ExternalControllerTLS string `yaml:"external-controller-tls"` + ExternalUI string `yaml:"external-ui"` + Secret string `yaml:"secret"` + Interface string `yaml:"interface-name"` + RoutingMark int `yaml:"routing-mark"` + Tunnels []LC.Tunnel `yaml:"tunnels"` + GeodataMode bool `yaml:"geodata-mode"` + GeodataLoader string `yaml:"geodata-loader"` + TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` + FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` + GlobalClientFingerprint string `yaml:"global-client-fingerprint"` Sniffer RawSniffer `yaml:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` @@ -519,6 +521,11 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm + if len(config.General.GlobalClientFingerprint) != 0 { + log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint) + vmess.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) + } + return config, nil } @@ -552,17 +559,18 @@ func parseGeneral(cfg *RawConfig) (*General, error) { Secret: cfg.Secret, ExternalControllerTLS: cfg.ExternalControllerTLS, }, - UnifiedDelay: cfg.UnifiedDelay, - Mode: cfg.Mode, - LogLevel: cfg.LogLevel, - IPv6: cfg.IPv6, - Interface: cfg.Interface, - RoutingMark: cfg.RoutingMark, - GeodataMode: cfg.GeodataMode, - GeodataLoader: cfg.GeodataLoader, - TCPConcurrent: cfg.TCPConcurrent, - FindProcessMode: cfg.FindProcessMode, - EBpf: cfg.EBpf, + UnifiedDelay: cfg.UnifiedDelay, + Mode: cfg.Mode, + LogLevel: cfg.LogLevel, + IPv6: cfg.IPv6, + Interface: cfg.Interface, + RoutingMark: cfg.RoutingMark, + GeodataMode: cfg.GeodataMode, + GeodataLoader: cfg.GeodataLoader, + TCPConcurrent: cfg.TCPConcurrent, + FindProcessMode: cfg.FindProcessMode, + EBpf: cfg.EBpf, + GlobalClientFingerprint: cfg.GlobalClientFingerprint, }, nil } diff --git a/docs/config.yaml b/docs/config.yaml index 63bda11b..9fbfb62e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -15,6 +15,11 @@ bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为 true,'*'表示 # - off, 不匹配进程,推荐在路由器上使用此模式 find-process-mode: strict +# global-client-fingerprint:全局TLS指纹,优先低于proxy内的 client-fingerprint +# accepts "chrome","firefox","safari","ios","random","none" options. +# Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. +global-client-fingerprint: chrome + mode: rule #自定义 geox-url @@ -423,7 +428,7 @@ proxies: server: server port: 443 password: yourpsk - # client-fingerprint: random # Available: "chrome","firefox","safari","random" + # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" # fingerprint: xxxx # udp: true # sni: example.com # aka server name @@ -483,7 +488,7 @@ proxies: # flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS # skip-cert-verify: true # fingerprint: xxxx - # client-fingerprint: random # Available: "chrome","firefox","safari","random" + # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" - name: "vless-ws" type: vless @@ -493,7 +498,7 @@ proxies: udp: true tls: true network: ws - # client-fingerprint: random # Available: "chrome","firefox","safari","random" + # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" servername: example.com # priority over wss host # skip-cert-verify: true # fingerprint: xxxx diff --git a/transport/vmess/utls.go b/transport/vmess/utls.go index 93a08111..cae7d52f 100644 --- a/transport/vmess/utls.go +++ b/transport/vmess/utls.go @@ -15,20 +15,42 @@ type UConn struct { } var initRandomFingerprint *utls.ClientHelloID +var initUtlsClient string func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { utlsConn := utls.UClient(c, CopyConfig(config), *fingerprint) return &UConn{UConn: utlsConn} } +func SetGlobalUtlsClient(Client string) { + initUtlsClient = Client +} + +func HaveGlobalFingerprint() bool { + if len(initUtlsClient) != 0 && initUtlsClient != "none" { + return true + } + return false +} + +func GetGlobalFingerprint() string { + return initUtlsClient +} + func GetFingerprint(ClientFingerprint string) (*utls.ClientHelloID, bool) { + if ClientFingerprint == "none" { + return nil, false + } + if initRandomFingerprint == nil { initRandomFingerprint, _ = RollFingerprint() } + if ClientFingerprint == "random" { log.Debugln("use initial random HelloID:%s", initRandomFingerprint.Client) return initRandomFingerprint, true } + fingerprint, ok := Fingerprints[ClientFingerprint] log.Debugln("use specified fingerprint:%s", fingerprint.Client) return fingerprint, ok From 3555ff5f4e05b082dc5d54fbdfd2af0bac636c49 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 7 Feb 2023 13:19:19 +0800 Subject: [PATCH 094/126] chore: update docs/config.yml --- docs/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 9fbfb62e..35e85ecc 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -102,7 +102,7 @@ sniffer: # force-dns-mapping: false ## 对所有未获取到域名的流量进行强制嗅探 # parse-pure-ip: false - # 是否使用嗅探结果作为实际访问,默认 false + # 是否使用嗅探结果作为实际访问,默认 true # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false sniff: From 4fe798ec3b004ea86badc6afc88436f9680bfabe Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 7 Feb 2023 15:10:36 +0800 Subject: [PATCH 095/126] chore: update sing-vmess --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c5d00873..05aef87d 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,8 @@ require ( github.com/oschwald/geoip2-golang v1.8.0 github.com/refraction-networking/utls v1.2.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.6 - github.com/sagernet/sing-vmess v0.1.1 + github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 + github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 7904547b..8c5a8c2f 100644 --- a/go.sum +++ b/go.sum @@ -133,10 +133,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.6 h1:Qy63OUfKpcqKjfd5rPmUlj0RGjHZSK/PJn0duyCCsRg= -github.com/sagernet/sing v0.1.6/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= -github.com/sagernet/sing-vmess v0.1.1 h1:WMdkJcc3icIqpDQZGQ7X+jfLilooIZ0zAaC0qeQTWFU= -github.com/sagernet/sing-vmess v0.1.1/go.mod h1:COSSEmy19vMWOTEKIUSDiTEyx6yBfTYIzekDlCMow+Q= +github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 h1:qnXh4RjHsNjdZXkfbqwVqAzYUfc160gfkS5gepmsA+A= +github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 h1:+CFee8wEc79nFDBV8tDm2yKPrAXb5Mrf2Q5kM2Bb/xo= +github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= From 2d806df9b9d1a1cd777640e91c641eeb042893c1 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 7 Feb 2023 15:59:44 +0800 Subject: [PATCH 096/126] fix: sniff domain don't match geosite when override-destination value is false --- constant/metadata.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/constant/metadata.go b/constant/metadata.go index d57c21b6..f30426c1 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -135,7 +135,7 @@ type Metadata struct { SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` // Only domain rule - SniffHost string + SniffHost string } func (m *Metadata) RemoteAddress() string { @@ -165,7 +165,7 @@ func (m *Metadata) SourceDetail() string { func (m *Metadata) AddrType() int { switch true { - case m.Host != "" || !m.DstIP.IsValid(): + case m.Host != "" || m.SniffHost != "" || !m.DstIP.IsValid(): return socks5.AtypDomainName case m.DstIP.Is4(): return socks5.AtypIPv4 From 967254d9ca832efa143bb9496c34fc1a36c3ec97 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 7 Feb 2023 16:08:59 +0800 Subject: [PATCH 097/126] chore: move global-utls-client snippets to components\tls --- adapter/outbound/trojan.go | 5 +-- adapter/outbound/vless.go | 4 +- adapter/outbound/vmess.go | 4 +- adapter/parser.go | 9 +++-- {transport/vmess => component/tls}/utls.go | 44 +++++++++++++--------- config/config.go | 5 ++- transport/gun/gun.go | 16 +++----- transport/trojan/trojan.go | 2 +- transport/vmess/tls.go | 12 ++---- transport/vmess/websocket.go | 13 +++---- 10 files changed, 56 insertions(+), 58 deletions(-) rename {transport/vmess => component/tls}/utls.go (90%) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 5fe946b0..2a8cfe47 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -15,7 +15,6 @@ import ( "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" "github.com/Dreamacro/clash/transport/vless" - "github.com/Dreamacro/clash/transport/vmess" ) type Trojan struct { @@ -79,8 +78,8 @@ func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error - if vmess.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { - t.option.ClientFingerprint = vmess.GetGlobalFingerprint() + if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { + t.option.ClientFingerprint = tlsC.GetGlobalFingerprint() } if t.transport != nil { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 0550fd7a..e46e245d 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -72,8 +72,8 @@ type VlessOption struct { func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error - if vmess.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { - v.option.ClientFingerprint = vmess.GetGlobalFingerprint() + if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { + v.option.ClientFingerprint = tlsC.GetGlobalFingerprint() } switch v.option.Network { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index a2dff6ee..5da8c8b1 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -88,8 +88,8 @@ type WSOptions struct { func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error - if clashVMess.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { - v.option.ClientFingerprint = clashVMess.GetGlobalFingerprint() + if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { + v.option.ClientFingerprint = tlsC.GetGlobalFingerprint() } switch v.option.Network { diff --git a/adapter/parser.go b/adapter/parser.go index 97663540..d9c18694 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -3,10 +3,11 @@ package adapter import ( "fmt" + tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/common/structure" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/vmess" ) func ParseProxy(mapping map[string]any) (C.Proxy, error) { @@ -57,7 +58,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { }, } - if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { vmessOption.ClientFingerprint = GlobalUtlsClient } @@ -69,7 +70,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { case "vless": vlessOption := &outbound.VlessOption{} - if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { vlessOption.ClientFingerprint = GlobalUtlsClient } @@ -88,7 +89,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { case "trojan": trojanOption := &outbound.TrojanOption{} - if GlobalUtlsClient := vmess.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { trojanOption.ClientFingerprint = GlobalUtlsClient } diff --git a/transport/vmess/utls.go b/component/tls/utls.go similarity index 90% rename from transport/vmess/utls.go rename to component/tls/utls.go index cae7d52f..ed35bd99 100644 --- a/transport/vmess/utls.go +++ b/component/tls/utls.go @@ -1,4 +1,4 @@ -package vmess +package tls import ( "crypto/tls" @@ -14,29 +14,22 @@ type UConn struct { *utls.UConn } +type UClientHelloID struct { + *utls.ClientHelloID +} + var initRandomFingerprint *utls.ClientHelloID var initUtlsClient string -func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { - utlsConn := utls.UClient(c, CopyConfig(config), *fingerprint) +func UClient(c net.Conn, config *tls.Config, fingerprint *UClientHelloID) net.Conn { + utlsConn := utls.UClient(c, CopyConfig(config), utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: fingerprint.Seed, + }) return &UConn{UConn: utlsConn} } -func SetGlobalUtlsClient(Client string) { - initUtlsClient = Client -} - -func HaveGlobalFingerprint() bool { - if len(initUtlsClient) != 0 && initUtlsClient != "none" { - return true - } - return false -} - -func GetGlobalFingerprint() string { - return initUtlsClient -} - func GetFingerprint(ClientFingerprint string) (*utls.ClientHelloID, bool) { if ClientFingerprint == "none" { return nil, false @@ -113,3 +106,18 @@ func (c *UConn) WebsocketHandshake() error { } return c.Handshake() } + +func SetGlobalUtlsClient(Client string) { + initUtlsClient = Client +} + +func HaveGlobalFingerprint() bool { + if len(initUtlsClient) != 0 && initUtlsClient != "none" { + return true + } + return false +} + +func GetGlobalFingerprint() string { + return initUtlsClient +} diff --git a/config/config.go b/config/config.go index be2e49cf..ac6ddda7 100644 --- a/config/config.go +++ b/config/config.go @@ -4,6 +4,7 @@ import ( "container/list" "errors" "fmt" + "net" "net/netip" "net/url" @@ -26,6 +27,7 @@ import ( "github.com/Dreamacro/clash/component/geodata/router" P "github.com/Dreamacro/clash/component/process" SNIFF "github.com/Dreamacro/clash/component/sniffer" + tlsC "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" providerTypes "github.com/Dreamacro/clash/constant/provider" @@ -36,7 +38,6 @@ import ( "github.com/Dreamacro/clash/log" R "github.com/Dreamacro/clash/rules" RP "github.com/Dreamacro/clash/rules/provider" - "github.com/Dreamacro/clash/transport/vmess" T "github.com/Dreamacro/clash/tunnel" "gopkg.in/yaml.v3" @@ -523,7 +524,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { if len(config.General.GlobalClientFingerprint) != 0 { log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint) - vmess.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) + tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) } return config, nil diff --git a/transport/gun/gun.go b/transport/gun/gun.go index a176e8fb..8c096861 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -19,9 +19,7 @@ import ( "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" - U "github.com/Dreamacro/clash/transport/vmess" - utls "github.com/refraction-networking/utls" - + tlsC "github.com/Dreamacro/clash/component/tls" "go.uber.org/atomic" "golang.org/x/net/http2" ) @@ -203,17 +201,15 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T wrap.remoteAddr = pconn.RemoteAddr() if len(Fingerprint) != 0 { - if fingerprint, exists := U.GetFingerprint(Fingerprint); exists { - utlsConn := U.UClient(pconn, cfg, &utls.ClientHelloID{ - Client: fingerprint.Client, - Version: fingerprint.Version, - Seed: nil, + if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { + utlsConn := tlsC.UClient(pconn, cfg, &tlsC.UClientHelloID{ + ClientHelloID: fingerprint, }) - if err := utlsConn.(*U.UConn).HandshakeContext(ctx); err != nil { + if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { pconn.Close() return nil, err } - state := utlsConn.(*U.UConn).ConnectionState() + state := utlsConn.(*tlsC.UConn).ConnectionState() if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { utlsConn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 235d4d38..e336d9db 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -122,7 +122,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - err := utlsConn.(*vmess.UConn).HandshakeContext(ctx) + err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) return utlsConn, err } diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 7dbde61b..27924ccc 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -7,8 +7,6 @@ import ( tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" - - utls "github.com/refraction-networking/utls" ) type TLSConfig struct { @@ -41,7 +39,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - err := utlsConn.(*UConn).HandshakeContext(ctx) + err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) return utlsConn, err } } @@ -56,11 +54,9 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { func GetUtlsConnWithClientFingerprint(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) { - if fingerprint, exists := GetFingerprint(ClientFingerprint); exists { - utlsConn := UClient(conn, tlsConfig, &utls.ClientHelloID{ - Client: fingerprint.Client, - Version: fingerprint.Version, - Seed: nil, + if fingerprint, exists := tlsC.GetFingerprint(ClientFingerprint); exists { + utlsConn := tlsC.UClient(conn, tlsConfig, &tlsC.UClientHelloID{ + ClientHelloID: fingerprint, }) return utlsConn, true diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index a7ca82b3..d56cf07c 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -21,9 +21,8 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" + tlsC "github.com/Dreamacro/clash/component/tls" "github.com/gorilla/websocket" - - utls "github.com/refraction-networking/utls" ) type websocketConn struct { @@ -334,15 +333,13 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf scheme = "wss" dialer.TLSClientConfig = c.TLSConfig if len(c.ClientFingerprint) != 0 { - if fingerprint, exists := GetFingerprint(c.ClientFingerprint); exists { + if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { - utlsConn := UClient(conn, c.TLSConfig, &utls.ClientHelloID{ - Client: fingerprint.Client, - Version: fingerprint.Version, - Seed: fingerprint.Seed, + utlsConn := tlsC.UClient(conn, c.TLSConfig, &tlsC.UClientHelloID{ + ClientHelloID: fingerprint, }) - if err := utlsConn.(*UConn).WebsocketHandshake(); err != nil { + if err := utlsConn.(*tlsC.UConn).WebsocketHandshake(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } return utlsConn, nil From db54b438e60edd156c2a34e1b7fc70f7b66e4829 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 7 Feb 2023 17:51:37 +0800 Subject: [PATCH 098/126] chore: do not use extra pointer in UClient --- component/tls/utls.go | 28 ++++++++++++++-------------- transport/gun/gun.go | 4 +--- transport/vmess/tls.go | 4 +--- transport/vmess/websocket.go | 4 +--- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index ed35bd99..f965fc64 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -18,11 +18,11 @@ type UClientHelloID struct { *utls.ClientHelloID } -var initRandomFingerprint *utls.ClientHelloID +var initRandomFingerprint UClientHelloID var initUtlsClient string -func UClient(c net.Conn, config *tls.Config, fingerprint *UClientHelloID) net.Conn { - utlsConn := utls.UClient(c, CopyConfig(config), utls.ClientHelloID{ +func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) net.Conn { + utlsConn := utls.UClient(c, copyConfig(config), utls.ClientHelloID{ Client: fingerprint.Client, Version: fingerprint.Version, Seed: fingerprint.Seed, @@ -30,12 +30,12 @@ func UClient(c net.Conn, config *tls.Config, fingerprint *UClientHelloID) net.Co return &UConn{UConn: utlsConn} } -func GetFingerprint(ClientFingerprint string) (*utls.ClientHelloID, bool) { +func GetFingerprint(ClientFingerprint string) (UClientHelloID, bool) { if ClientFingerprint == "none" { - return nil, false + return UClientHelloID{}, false } - if initRandomFingerprint == nil { + if initRandomFingerprint.ClientHelloID == nil { initRandomFingerprint, _ = RollFingerprint() } @@ -49,7 +49,7 @@ func GetFingerprint(ClientFingerprint string) (*utls.ClientHelloID, bool) { return fingerprint, ok } -func RollFingerprint() (*utls.ClientHelloID, bool) { +func RollFingerprint() (UClientHelloID, bool) { chooser, _ := weightedrand.NewChooser( weightedrand.NewChoice("chrome", 6), weightedrand.NewChoice("safari", 3), @@ -62,15 +62,15 @@ func RollFingerprint() (*utls.ClientHelloID, bool) { return fingerprint, ok } -var Fingerprints = map[string]*utls.ClientHelloID{ - "chrome": &utls.HelloChrome_Auto, - "firefox": &utls.HelloFirefox_Auto, - "safari": &utls.HelloSafari_Auto, - "ios": &utls.HelloIOS_Auto, - "randomized": &utls.HelloRandomized, +var Fingerprints = map[string]UClientHelloID{ + "chrome": {&utls.HelloChrome_Auto}, + "firefox": {&utls.HelloFirefox_Auto}, + "safari": {&utls.HelloSafari_Auto}, + "ios": {&utls.HelloIOS_Auto}, + "randomized": {&utls.HelloRandomized}, } -func CopyConfig(c *tls.Config) *utls.Config { +func copyConfig(c *tls.Config) *utls.Config { return &utls.Config{ RootCAs: c.RootCAs, ServerName: c.ServerName, diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 8c096861..920e7adc 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -202,9 +202,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T if len(Fingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { - utlsConn := tlsC.UClient(pconn, cfg, &tlsC.UClientHelloID{ - ClientHelloID: fingerprint, - }) + utlsConn := tlsC.UClient(pconn, cfg, fingerprint) if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { pconn.Close() return nil, err diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 27924ccc..711c342d 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -55,9 +55,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { func GetUtlsConnWithClientFingerprint(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) { if fingerprint, exists := tlsC.GetFingerprint(ClientFingerprint); exists { - utlsConn := tlsC.UClient(conn, tlsConfig, &tlsC.UClientHelloID{ - ClientHelloID: fingerprint, - }) + utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint) return utlsConn, true } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index d56cf07c..2487b93a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -335,9 +335,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { - utlsConn := tlsC.UClient(conn, c.TLSConfig, &tlsC.UClientHelloID{ - ClientHelloID: fingerprint, - }) + utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) if err := utlsConn.(*tlsC.UConn).WebsocketHandshake(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) From 929b1675e3d222ffeaa6dc86bc60fb1353b4ed53 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 7 Feb 2023 21:29:40 +0800 Subject: [PATCH 099/126] chore: avoid repeated wrapper --- constant/metadata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constant/metadata.go b/constant/metadata.go index f30426c1..3b55a8be 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -148,7 +148,7 @@ func (m *Metadata) SourceAddress() string { func (m *Metadata) SourceDetail() string { if m.Type == INNER { - return fmt.Sprintf("[%s]", ClashName) + return fmt.Sprintf("%s", ClashName) } switch { From c83eb2e0c9d7ed88ac234a657acde05beccb879f Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 7 Feb 2023 21:29:40 +0800 Subject: [PATCH 100/126] chore: adjust log --- component/sniffer/dispatcher.go | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 0d6badf5..4faedfb0 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -94,29 +94,19 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { } func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { - dstIP := "" - if metadata.DstIP.IsValid() { - dstIP = metadata.DstIP.String() - } originHost := metadata.Host if originHost != host { - log.Infoln("[Sniffer] Sniff TCP [%s]-->[%s:%s] success, replace domain [%s]-->[%s]", - metadata.SourceDetail(), - dstIP, metadata.DstPort, - metadata.Host, host) - } else { - log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s:%s] success, replace domain [%s]-->[%s]", - metadata.SourceDetail(), - dstIP, metadata.DstPort, - metadata.Host, host) + if overrideDest { + metadata.Host = host + } else { + metadata.SniffHost = host + } + metadata.DNSMode = C.DNSNormal } - - if overrideDest { - metadata.Host = host - } else { - metadata.SniffHost = host - } - metadata.DNSMode = C.DNSNormal + log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", + metadata.SourceDetail(), + metadata.RemoteAddress(), + metadata.Host, host) } func (sd *SnifferDispatcher) Enable() bool { From 24419551a9e0ccb880b2f8f6132f833f35ca1490 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 8 Feb 2023 13:10:26 +0800 Subject: [PATCH 101/126] chore: update tfo-go for golang1.20 --- adapter/inbound/listen.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/adapter/inbound/listen.go b/adapter/inbound/listen.go index d481a56e..fa82db92 100644 --- a/adapter/inbound/listen.go +++ b/adapter/inbound/listen.go @@ -4,7 +4,7 @@ import ( "context" "net" - "github.com/database64128/tfo-go/v2" + "github.com/sagernet/tfo-go" ) var ( diff --git a/go.mod b/go.mod index 05aef87d..90c47a42 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/cilium/ebpf v0.9.3 github.com/coreos/go-iptables v0.6.0 - github.com/database64128/tfo-go/v2 v2.0.2 github.com/dlclark/regexp2 v1.7.0 github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 @@ -30,6 +29,7 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 + github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 8c5a8c2f..a79e6976 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,6 @@ github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc= github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/database64128/tfo-go/v2 v2.0.2 h1:5rGgkJeLEKlNaqredfrPQNLnctn1b+1fq/8tdKdOzJg= -github.com/database64128/tfo-go/v2 v2.0.2/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -137,6 +135,8 @@ github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 h1:qnXh4RjHsNjdZXk github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 h1:+CFee8wEc79nFDBV8tDm2yKPrAXb5Mrf2Q5kM2Bb/xo= github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= +github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= +github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= From 3fd3d830299f68f4876d7ef2a3a66945599d3a56 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 10 Feb 2023 10:03:37 +0800 Subject: [PATCH 102/126] feat: Attempts to send request with first payload on VLESS --- transport/vless/conn.go | 70 ++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 75eef495..0f4d3bf7 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -6,6 +6,8 @@ import ( "fmt" "io" "net" + "sync" + "time" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" @@ -21,6 +23,10 @@ type Conn struct { id *uuid.UUID addons *Addons received bool + + handshake chan struct{} + handshakeMutex sync.Mutex + err error } func (vc *Conn) Read(b []byte) (int, error) { @@ -47,7 +53,41 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { return vc.ExtendedConn.ReadBuffer(buffer) } -func (vc *Conn) sendRequest() (err error) { +func (vc *Conn) Write(p []byte) (int, error) { + select { + case <-vc.handshake: + default: + err := vc.sendRequest(p) + if err != nil { + return 0, err + } + } + return vc.ExtendedConn.Write(p) +} + +func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { + select { + case <-vc.handshake: + default: + err := vc.sendRequest(buffer.Bytes()) + if err != nil { + return err + } + } + return vc.ExtendedConn.WriteBuffer(buffer) +} + +func (vc *Conn) sendRequest(p []byte) (err error) { + vc.handshakeMutex.Lock() + defer vc.handshakeMutex.Unlock() + + select { + case <-vc.handshake: + return vc.err + default: + } + defer close(vc.handshake) + requestLen := 1 // protocol version requestLen += 16 // UUID requestLen += 1 // addons length @@ -65,6 +105,8 @@ func (vc *Conn) sendRequest() (err error) { requestLen += 1 // addr type requestLen += len(vc.dst.Addr) } + requestLen += len(p) + _buffer := buf.StackNewSize(requestLen) defer buf.KeepAlive(_buffer) buffer := buf.Dup(_buffer) @@ -93,25 +135,26 @@ func (vc *Conn) sendRequest() (err error) { ) } + buf.Must(buf.Error(buffer.Write(p))) + _, err = vc.ExtendedConn.Write(buffer.Bytes()) return } func (vc *Conn) recvResponse() error { - var err error var buf [1]byte - _, err = io.ReadFull(vc.ExtendedConn, buf[:]) - if err != nil { - return err + _, vc.err = io.ReadFull(vc.ExtendedConn, buf[:]) + if vc.err != nil { + return vc.err } if buf[0] != Version { return errors.New("unexpected response version") } - _, err = io.ReadFull(vc.ExtendedConn, buf[:]) - if err != nil { - return err + _, vc.err = io.ReadFull(vc.ExtendedConn, buf[:]) + if vc.err != nil { + return vc.err } length := int64(buf[0]) @@ -132,6 +175,7 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { ExtendedConn: N.NewExtendedConn(conn), id: client.uuid, dst: dst, + handshake: make(chan struct{}), } if !dst.UDP && client.Addons != nil { @@ -155,8 +199,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { } } - if err := c.sendRequest(); err != nil { - return nil, err - } + go func() { + select { + case <-c.handshake: + case <-time.After(200 * time.Millisecond): + _ = c.sendRequest(nil) + } + }() return c, nil } From a991bf90458854aa13617dcff15df19d76cca8bf Mon Sep 17 00:00:00 2001 From: metacubex Date: Fri, 10 Feb 2023 12:48:02 +0800 Subject: [PATCH 103/126] fix: missing sniffhost field in RESTful API --- constant/metadata.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constant/metadata.go b/constant/metadata.go index 3b55a8be..f1c68f68 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -135,7 +135,7 @@ type Metadata struct { SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` // Only domain rule - SniffHost string + SniffHost string `json:"sniffHost"` } func (m *Metadata) RemoteAddress() string { From 4643b5835e5f06de303fc2e061c9baca1f434bd0 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Feb 2023 13:01:53 +0800 Subject: [PATCH 104/126] chore: setting sniffHost value --- component/sniffer/dispatcher.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 4faedfb0..f4511b97 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -94,15 +94,11 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { } func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { - originHost := metadata.Host - if originHost != host { - if overrideDest { - metadata.Host = host - } else { - metadata.SniffHost = host - } - metadata.DNSMode = C.DNSNormal + metadata.SniffHost = host + if overrideDest { + metadata.Host = host } + metadata.DNSMode = C.DNSNormal log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", metadata.SourceDetail(), metadata.RemoteAddress(), From 83d719cf79ca65546249538040316b246c629714 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 11 Feb 2023 15:13:17 +0800 Subject: [PATCH 105/126] fix: VLESS handshake write --- transport/vless/conn.go | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 0f4d3bf7..aceda463 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -57,9 +57,14 @@ func (vc *Conn) Write(p []byte) (int, error) { select { case <-vc.handshake: default: - err := vc.sendRequest(p) - if err != nil { - return 0, err + if vc.sendRequest(p) { + if vc.err != nil { + return 0, vc.err + } + return len(p), vc.err + } + if vc.err != nil { + return 0, vc.err } } return vc.ExtendedConn.Write(p) @@ -69,21 +74,25 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { select { case <-vc.handshake: default: - err := vc.sendRequest(buffer.Bytes()) - if err != nil { - return err + if vc.sendRequest(buffer.Bytes()) { + return vc.err + } + if vc.err != nil { + return vc.err } } return vc.ExtendedConn.WriteBuffer(buffer) } -func (vc *Conn) sendRequest(p []byte) (err error) { +func (vc *Conn) sendRequest(p []byte) bool { vc.handshakeMutex.Lock() defer vc.handshakeMutex.Unlock() select { case <-vc.handshake: - return vc.err + // The handshake has been completed before. + // So return false to remind the caller. + return false default: } defer close(vc.handshake) @@ -93,9 +102,9 @@ func (vc *Conn) sendRequest(p []byte) (err error) { requestLen += 1 // addons length var addonsBytes []byte if vc.addons != nil { - addonsBytes, err = proto.Marshal(vc.addons) - if err != nil { - return err + addonsBytes, vc.err = proto.Marshal(vc.addons) + if vc.err != nil { + return true } } requestLen += len(addonsBytes) @@ -137,8 +146,8 @@ func (vc *Conn) sendRequest(p []byte) (err error) { buf.Must(buf.Error(buffer.Write(p))) - _, err = vc.ExtendedConn.Write(buffer.Bytes()) - return + _, vc.err = vc.ExtendedConn.Write(buffer.Bytes()) + return true } func (vc *Conn) recvResponse() error { @@ -203,7 +212,7 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { select { case <-c.handshake: case <-time.After(200 * time.Millisecond): - _ = c.sendRequest(nil) + c.sendRequest(nil) } }() return c, nil From cc2a775271e1b0f77ca9aaf63b9e674baad466b6 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 11 Feb 2023 16:40:01 +0800 Subject: [PATCH 106/126] feat: Converter support uTLS fingerprint field --- common/convert/converter.go | 6 ++++++ common/convert/v.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/common/convert/converter.go b/common/convert/converter.go index df0d9ffd..7d896d53 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -113,6 +113,12 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { trojan["grpc-opts"] = grpcOpts } + if fingerprint := query.Get("fp"); fingerprint == "" { + trojan["client-fingerprint"] = "chrome" + } else { + trojan["client-fingerprint"] = fingerprint + } + proxies = append(proxies, trojan) case "vless": diff --git a/common/convert/v.go b/common/convert/v.go index eb2073c3..606d8aff 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -29,6 +29,11 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m tls := strings.ToLower(query.Get("security")) if strings.HasSuffix(tls, "tls") { proxy["tls"] = true + if fingerprint := query.Get("fp"); fingerprint == "" { + proxy["client-fingerprint"] = "chrome" + } else { + proxy["client-fingerprint"] = fingerprint + } } if sni := query.Get("sni"); sni != "" { proxy["servername"] = sni From ce8929d1537f1f69a69ab68f7c90fb9b6bf475c6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 13 Feb 2023 10:14:59 +0800 Subject: [PATCH 107/126] chore: better bind in windows --- component/dialer/bind_darwin.go | 4 ++ component/dialer/bind_linux.go | 4 ++ component/dialer/bind_others.go | 12 ++++- component/dialer/bind_windows.go | 88 ++++++++++++++++++++++++++++++++ component/dialer/dialer.go | 12 ----- 5 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 component/dialer/bind_windows.go diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index 91d74987..8e88b461 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -62,3 +62,7 @@ func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address lc.Control = bindControl(ifaceObj.Index, lc.Control) return address, nil } + +func ParseNetwork(network string, addr netip.Addr) string { + return network +} diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go index ca88cb58..57a2e0c1 100644 --- a/component/dialer/bind_linux.go +++ b/component/dialer/bind_linux.go @@ -47,3 +47,7 @@ func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address return address, nil } + +func ParseNetwork(network string, addr netip.Addr) string { + return network +} diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index f732b1ce..5cb2fd62 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -1,4 +1,4 @@ -//go:build !linux && !darwin +//go:build !linux && !darwin && !windows package dialer @@ -91,3 +91,13 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add return addr.String(), nil } + +func ParseNetwork(network string, addr netip.Addr) string { + // fix bindIfaceToListenConfig() force bind to an ipv4 address + if !strings.HasSuffix(network, "4") && + !strings.HasSuffix(network, "6") && + addr.Unmap().Is6() { + network += "6" + } + return network +} diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go new file mode 100644 index 00000000..87b39bc2 --- /dev/null +++ b/component/dialer/bind_windows.go @@ -0,0 +1,88 @@ +package dialer + +import ( + "encoding/binary" + "net" + "net/netip" + "syscall" + "unsafe" + + "github.com/Dreamacro/clash/component/iface" +) + +const ( + IP_UNICAST_IF = 31 + IPV6_UNICAST_IF = 31 +) + +func bind4(handle syscall.Handle, ifaceIdx int) error { + var bytes [4]byte + binary.BigEndian.PutUint32(bytes[:], uint32(ifaceIdx)) + idx := *(*uint32)(unsafe.Pointer(&bytes[0])) + return syscall.SetsockoptInt(handle, syscall.IPPROTO_IP, IP_UNICAST_IF, int(idx)) +} + +func bind6(handle syscall.Handle, ifaceIdx int) error { + return syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx) +} + +type controlFn = func(network, address string, c syscall.RawConn) error + +func bindControl(ifaceIdx int, chain controlFn) controlFn { + return func(network, address string, c syscall.RawConn) (err error) { + defer func() { + if err == nil && chain != nil { + err = chain(network, address, c) + } + }() + + addrPort, err := netip.ParseAddrPort(address) + if err == nil && !addrPort.Addr().IsGlobalUnicast() { + return + } + + var innerErr error + err = c.Control(func(fd uintptr) { + handle := syscall.Handle(fd) + switch network { + case "tcp6", "udp6": + innerErr = bind6(handle, ifaceIdx) + _ = bind4(handle, ifaceIdx) + default: + innerErr = bind4(handle, ifaceIdx) + // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6 + _ = bind6(handle, ifaceIdx) + } + }) + + if innerErr != nil { + err = innerErr + } + + return + } +} + +func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { + ifaceObj, err := iface.ResolveInterface(ifaceName) + if err != nil { + return err + } + + dialer.Control = bindControl(ifaceObj.Index, dialer.Control) + return nil +} + +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { + ifaceObj, err := iface.ResolveInterface(ifaceName) + if err != nil { + return "", err + } + + lc.Control = bindControl(ifaceObj.Index, lc.Control) + return address, nil +} + +func ParseNetwork(network string, addr netip.Addr) string { + return network +} diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index d7c0f3db..e31936e9 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -6,7 +6,6 @@ import ( "fmt" "net" "net/netip" - "runtime" "strings" "sync" @@ -25,17 +24,6 @@ var ( ErrorDisableIPv6 = errors.New("IPv6 is disabled, dialer cancel") ) -func ParseNetwork(network string, addr netip.Addr) string { - if runtime.GOOS == "windows" { // fix bindIfaceToListenConfig() in windows force bind to an ipv4 address - if !strings.HasSuffix(network, "4") && - !strings.HasSuffix(network, "6") && - addr.Unmap().Is6() { - network += "6" - } - } - return network -} - func applyOptions(options ...Option) *option { opt := &option{ interfaceName: DefaultInterface.Load(), From ae42d351844628fa5ab2edc95813de6f9fd3f93f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 13 Feb 2023 11:14:19 +0800 Subject: [PATCH 108/126] chore: support golang1.20's dialer.ControlContext --- component/dialer/bind_darwin.go | 17 +++++------------ component/dialer/bind_linux.go | 17 +++++------------ component/dialer/bind_windows.go | 17 +++++------------ component/dialer/control.go | 22 ++++++++++++++++++++++ component/dialer/control_go119.go | 22 ++++++++++++++++++++++ component/dialer/control_go120.go | 26 ++++++++++++++++++++++++++ component/dialer/mark_linux.go | 14 +++++--------- component/dialer/reuse_unix.go | 13 +++---------- component/dialer/reuse_windows.go | 13 +++---------- 9 files changed, 96 insertions(+), 65 deletions(-) create mode 100644 component/dialer/control.go create mode 100644 component/dialer/control_go119.go create mode 100644 component/dialer/control_go120.go diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index 8e88b461..8705a708 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -1,6 +1,7 @@ package dialer import ( + "context" "net" "net/netip" "syscall" @@ -10,16 +11,8 @@ import ( "golang.org/x/sys/unix" ) -type controlFn = func(network, address string, c syscall.RawConn) error - -func bindControl(ifaceIdx int, chain controlFn) controlFn { - return func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() - +func bindControl(ifaceIdx int) controlFn { + return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { addrPort, err := netip.ParseAddrPort(address) if err == nil && !addrPort.Addr().IsGlobalUnicast() { return @@ -49,7 +42,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A return err } - dialer.Control = bindControl(ifaceObj.Index, dialer.Control) + addControlToDialer(dialer, bindControl(ifaceObj.Index)) return nil } @@ -59,7 +52,7 @@ func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address return "", err } - lc.Control = bindControl(ifaceObj.Index, lc.Control) + addControlToListenConfig(lc, bindControl(ifaceObj.Index)) return address, nil } diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go index 57a2e0c1..1ec98f3d 100644 --- a/component/dialer/bind_linux.go +++ b/component/dialer/bind_linux.go @@ -1,6 +1,7 @@ package dialer import ( + "context" "net" "net/netip" "syscall" @@ -8,16 +9,8 @@ import ( "golang.org/x/sys/unix" ) -type controlFn = func(network, address string, c syscall.RawConn) error - -func bindControl(ifaceName string, chain controlFn) controlFn { - return func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() - +func bindControl(ifaceName string) controlFn { + return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { addrPort, err := netip.ParseAddrPort(address) if err == nil && !addrPort.Addr().IsGlobalUnicast() { return @@ -37,13 +30,13 @@ func bindControl(ifaceName string, chain controlFn) controlFn { } func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { - dialer.Control = bindControl(ifaceName, dialer.Control) + addControlToDialer(dialer, bindControl(ifaceName)) return nil } func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) { - lc.Control = bindControl(ifaceName, lc.Control) + addControlToListenConfig(lc, bindControl(ifaceName)) return address, nil } diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index 87b39bc2..b680e90f 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -1,6 +1,7 @@ package dialer import ( + "context" "encoding/binary" "net" "net/netip" @@ -26,16 +27,8 @@ func bind6(handle syscall.Handle, ifaceIdx int) error { return syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx) } -type controlFn = func(network, address string, c syscall.RawConn) error - -func bindControl(ifaceIdx int, chain controlFn) controlFn { - return func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() - +func bindControl(ifaceIdx int) controlFn { + return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { addrPort, err := netip.ParseAddrPort(address) if err == nil && !addrPort.Addr().IsGlobalUnicast() { return @@ -69,7 +62,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.A return err } - dialer.Control = bindControl(ifaceObj.Index, dialer.Control) + addControlToDialer(dialer, bindControl(ifaceObj.Index)) return nil } @@ -79,7 +72,7 @@ func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address return "", err } - lc.Control = bindControl(ifaceObj.Index, lc.Control) + addControlToListenConfig(lc, bindControl(ifaceObj.Index)) return address, nil } diff --git a/component/dialer/control.go b/component/dialer/control.go new file mode 100644 index 00000000..26b1db76 --- /dev/null +++ b/component/dialer/control.go @@ -0,0 +1,22 @@ +package dialer + +import ( + "context" + "net" + "syscall" +) + +type controlFn = func(ctx context.Context, network, address string, c syscall.RawConn) error + +func addControlToListenConfig(lc *net.ListenConfig, fn controlFn) { + llc := *lc + lc.Control = func(network, address string, c syscall.RawConn) (err error) { + switch { + case llc.Control != nil: + if err = llc.Control(network, address, c); err != nil { + return + } + } + return fn(context.Background(), network, address, c) + } +} diff --git a/component/dialer/control_go119.go b/component/dialer/control_go119.go new file mode 100644 index 00000000..ec980586 --- /dev/null +++ b/component/dialer/control_go119.go @@ -0,0 +1,22 @@ +//go:build !go1.20 + +package dialer + +import ( + "context" + "net" + "syscall" +) + +func addControlToDialer(d *net.Dialer, fn controlFn) { + ld := *d + d.Control = func(network, address string, c syscall.RawConn) (err error) { + switch { + case ld.Control != nil: + if err = ld.Control(network, address, c); err != nil { + return + } + } + return fn(context.Background(), network, address, c) + } +} diff --git a/component/dialer/control_go120.go b/component/dialer/control_go120.go new file mode 100644 index 00000000..65e33f9c --- /dev/null +++ b/component/dialer/control_go120.go @@ -0,0 +1,26 @@ +//go:build go1.20 + +package dialer + +import ( + "context" + "net" + "syscall" +) + +func addControlToDialer(d *net.Dialer, fn controlFn) { + ld := *d + d.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { + switch { + case ld.ControlContext != nil: + if err = ld.ControlContext(ctx, network, address, c); err != nil { + return + } + case ld.Control != nil: + if err = ld.Control(network, address, c); err != nil { + return + } + } + return fn(ctx, network, address, c) + } +} diff --git a/component/dialer/mark_linux.go b/component/dialer/mark_linux.go index eaba5cf7..996c3dea 100644 --- a/component/dialer/mark_linux.go +++ b/component/dialer/mark_linux.go @@ -3,26 +3,22 @@ package dialer import ( + "context" "net" "net/netip" "syscall" ) func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ netip.Addr) { - dialer.Control = bindMarkToControl(mark, dialer.Control) + addControlToDialer(dialer, bindMarkToControl(mark)) } func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, _ string) { - lc.Control = bindMarkToControl(mark, lc.Control) + addControlToListenConfig(lc, bindMarkToControl(mark)) } -func bindMarkToControl(mark int, chain controlFn) controlFn { - return func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() +func bindMarkToControl(mark int) controlFn { + return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { addrPort, err := netip.ParseAddrPort(address) if err == nil && !addrPort.Addr().IsGlobalUnicast() { diff --git a/component/dialer/reuse_unix.go b/component/dialer/reuse_unix.go index 85fe5e5e..a0cf7388 100644 --- a/component/dialer/reuse_unix.go +++ b/component/dialer/reuse_unix.go @@ -3,6 +3,7 @@ package dialer import ( + "context" "net" "syscall" @@ -10,18 +11,10 @@ import ( ) func addrReuseToListenConfig(lc *net.ListenConfig) { - chain := lc.Control - - lc.Control = func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() - + addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error { return c.Control(func(fd uintptr) { unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) }) - } + }) } diff --git a/component/dialer/reuse_windows.go b/component/dialer/reuse_windows.go index 77fcf7ab..b8d0d809 100644 --- a/component/dialer/reuse_windows.go +++ b/component/dialer/reuse_windows.go @@ -1,6 +1,7 @@ package dialer import ( + "context" "net" "syscall" @@ -8,17 +9,9 @@ import ( ) func addrReuseToListenConfig(lc *net.ListenConfig) { - chain := lc.Control - - lc.Control = func(network, address string, c syscall.RawConn) (err error) { - defer func() { - if err == nil && chain != nil { - err = chain(network, address, c) - } - }() - + addControlToListenConfig(lc, func(ctx context.Context, network, address string, c syscall.RawConn) error { return c.Control(func(fd uintptr) { windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1) }) - } + }) } From e6d16e458fabe80230d9878c75826258efcd0ce4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 13 Feb 2023 20:50:11 +0800 Subject: [PATCH 109/126] chore: update gvisor --- go.mod | 8 +++----- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 90c47a42..d5e504eb 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,8 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.32.0 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 - github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b - github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e + github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b + github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 @@ -62,6 +62,7 @@ require ( github.com/klauspost/compress v1.15.12 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect + github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -77,9 +78,6 @@ require ( golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.2.0 // indirect - gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b // indirect ) -replace gvisor.dev/gvisor v0.0.0-20230128000341-b7014294633b => github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df - replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index a79e6976..7bdc889d 100644 --- a/go.sum +++ b/go.sum @@ -87,16 +87,16 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df h1:3zQDj38NIi8KEPNq1mC9bb82QoGYW/z4HaCzRwHwpNY= -github.com/metacubex/gvisor v0.0.0-20230202073621-9b7164de61df/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= +github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e h1:j4j2dlV2d//FAsQlRUriH6nvv36AEAhECbNy7narf1M= +github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e/go.mod h1:abc7OdNmWlhcNHz84ECEosd5ND5pnWQmD8W55p/4cuc= github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 h1:MNCGIpXhxXn9ck5bxfm/cW9Nr2FGQ5cakcGK0yKZcak= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= -github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b h1:k0Wnbfp7lsdBVVJY4YNbg0OxBiKWZSir8k10g0TuOlI= -github.com/metacubex/sing-tun v0.1.1-0.20230129141228-645f74b2208b/go.mod h1:lJWUpVKefklkLUL3ukp9Iapz+zSxS/fvfbevoUL2Vwg= -github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e h1:ZpzW8ymNjU2Gi7ieJexUV8BDrIuBfCBaZdgAyB1RsYs= -github.com/metacubex/sing-wireguard v0.0.0-20230129141512-65b25e764f8e/go.mod h1:hF5lqFsfWeDrImIQ5XkOTS8aucCWvK4GOoCUNYKTrPU= +github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b h1:ZF/oNrSCaxIFoZmFQCiUx67t9aENZjyuqw2n4zw3L2o= +github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b/go.mod h1:TjuaYuR/g1MaY3um89xTfRNt61FJ2IcI/m5zD8QBxw4= +github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8= +github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4/go.mod h1:p2VpJuxRefgVMxc8cmatMGSFNvYbjMYMsXJOe7qFstw= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= From d00d83abd471e5ce0ca776aebf1a56e23db5d8c7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 13 Feb 2023 22:06:09 +0800 Subject: [PATCH 110/126] fix: tun udp with 4in6 ip --- tunnel/connection.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tunnel/connection.go b/tunnel/connection.go index c63bab78..d8bd26c9 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -44,11 +44,12 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } fromUDPAddr := from.(*net.UDPAddr) - if fAddr.IsValid() { - fromAddr, _ := netip.AddrFromSlice(fromUDPAddr.IP) - fromAddr.Unmap() - if oAddr == fromAddr { - fromUDPAddr.IP = fAddr.AsSlice() + fromUDPAddr = &(*fromUDPAddr) // make a copy + if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { + if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) { + fromUDPAddr.IP = fAddr.Unmap().AsSlice() + } else { + fromUDPAddr.IP = fromAddr.Unmap().AsSlice() } } From 6fb4ebba15d1e4d4bbf74fee67899e4913e9ac2b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 13 Feb 2023 23:51:39 +0800 Subject: [PATCH 111/126] chore: Allow 0-RTT in Tuic server refers to: https://github.com/quic-go/quic-go/pull/3635 --- listener/tuic/server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 724d7418..a7ad69f6 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -52,6 +52,9 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet MaxIncomingStreams: ServerMaxIncomingStreams, MaxIncomingUniStreams: ServerMaxIncomingStreams, EnableDatagrams: true, + Allow0RTT: func(addr net.Addr) bool { + return true + }, } quicConfig.InitialStreamReceiveWindow = tuic.DefaultStreamReceiveWindow / 10 quicConfig.MaxStreamReceiveWindow = tuic.DefaultStreamReceiveWindow From 28c7de6185a23a9acc58cfbf158e7abc12e74669 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 14 Feb 2023 21:09:37 +0800 Subject: [PATCH 112/126] fix: avoid modifying the request message id --- dns/doh.go | 1 + dns/doq.go | 1 + 2 files changed, 2 insertions(+) diff --git a/dns/doh.go b/dns/doh.go index df3df6b4..0a9efe1c 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -109,6 +109,7 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D. // formats that include the ID field from the DNS message header, such // as "application/dns-message", SHOULD use a DNS ID of 0 in every DNS // request. + m=m.Copy() id := m.Id m.Id = 0 defer func() { diff --git a/dns/doq.go b/dns/doq.go index 1097b500..1354f177 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -89,6 +89,7 @@ func (doq *dnsOverQUIC) Address() string { return doq.addr } func (doq *dnsOverQUIC) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { // When sending queries over a QUIC connection, the DNS Message ID MUST be // set to zero. + m = m.Copy() id := m.Id m.Id = 0 defer func() { From b50071ed37bdbca545f5f47f2a799121ad983f49 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 15 Feb 2023 22:39:28 +0800 Subject: [PATCH 113/126] chore: better log time --- log/log.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/log/log.go b/log/log.go index f1053f44..acddeaff 100644 --- a/log/log.go +++ b/log/log.go @@ -18,6 +18,10 @@ var ( func init() { log.SetOutput(os.Stdout) log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + TimestampFormat: "2006-01-02T15:04:05.999999999Z07:00", + }) } type Event struct { From e59c35a308913dba76ee5b88a1a85906793f0095 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 16 Feb 2023 21:11:36 +0800 Subject: [PATCH 114/126] fix issue #357. Copy from upstream. --- transport/hysteria/conns/udp/hop.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/transport/hysteria/conns/udp/hop.go b/transport/hysteria/conns/udp/hop.go index c31f317f..53830ae4 100644 --- a/transport/hysteria/conns/udp/hop.go +++ b/transport/hysteria/conns/udp/hop.go @@ -212,6 +212,9 @@ func (c *ObfsUDPHopClientPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { func (c *ObfsUDPHopClientPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { c.connMutex.RLock() defer c.connMutex.RUnlock() + if c.closed { + return 0, net.ErrClosed + } /* // Check if the address is the server address if addr.String() != c.serverAddr.String() { @@ -237,6 +240,7 @@ func (c *ObfsUDPHopClientPacketConn) Close() error { err := c.currentConn.Close() close(c.closeChan) c.closed = true + c.serverAddrs = nil // For GC return err } From 6fe1766c831734e0964d646b15d62c569cf7148d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 17 Feb 2023 13:48:29 +0800 Subject: [PATCH 115/126] chore: add log --- config/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.go b/config/config.go index ac6ddda7..498b069f 100644 --- a/config/config.go +++ b/config/config.go @@ -1017,6 +1017,7 @@ func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainM if err := geodata.InitGeoSite(); err != nil { return nil, fmt.Errorf("can't initial GeoSite: %s", err) } + log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future") } for _, country := range countries { From b2d1cea7595975f69d4e440d89e9beca531cf1bf Mon Sep 17 00:00:00 2001 From: Ovear Date: Fri, 17 Feb 2023 16:31:00 +0800 Subject: [PATCH 116/126] fix: RoundRobin strategy of load balance when called multiple times (#390) --- adapter/outboundgroup/loadbalance.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 7dc4d3d3..48bd4994 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -115,11 +115,20 @@ func (lb *LoadBalance) SupportUDP() bool { } func strategyRoundRobin() strategyFn { + flag := true idx := 0 return func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy { length := len(proxies) for i := 0; i < length; i++ { - idx = (idx + 1) % length + flag = !flag + if flag { + idx = (idx - 1) % length + } else { + idx = (idx + 2) % length + } + if idx < 0 { + idx = idx + length + } proxy := proxies[idx] if proxy.Alive() { return proxy From 8e4dfbd10d22b1c6f67753c89e11c90dcaee984d Mon Sep 17 00:00:00 2001 From: Ovear Date: Fri, 17 Feb 2023 16:31:15 +0800 Subject: [PATCH 117/126] feat: introduce a new robust approach to handle tproxy udp. (#389) --- component/nat/table.go | 73 ++++++++++++++++++++++++-- constant/adapters.go | 25 +++++++++ listener/shadowsocks/utils.go | 8 +++ listener/sing/sing.go | 8 +++ listener/socks/utils.go | 9 ++++ listener/tproxy/packet.go | 98 ++++++++++++++++++++++++++++++++--- listener/tunnel/packet.go | 9 ++++ transport/tuic/server.go | 8 +++ tunnel/connection.go | 15 ++++++ tunnel/tunnel.go | 5 +- 10 files changed, 246 insertions(+), 12 deletions(-) diff --git a/component/nat/table.go b/component/nat/table.go index fbb16dec..5dcd91ed 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -1,6 +1,7 @@ package nat import ( + "net" "sync" C "github.com/Dreamacro/clash/constant" @@ -10,16 +11,24 @@ type Table struct { mapping sync.Map } -func (t *Table) Set(key string, pc C.PacketConn) { - t.mapping.Store(key, pc) +type Entry struct { + PacketConn C.PacketConn + LocalUDPConnMap sync.Map +} + +func (t *Table) Set(key string, e C.PacketConn) { + t.mapping.Store(key, &Entry{ + PacketConn: e, + LocalUDPConnMap: sync.Map{}, + }) } func (t *Table) Get(key string) C.PacketConn { - item, exist := t.mapping.Load(key) + entry, exist := t.getEntry(key) if !exist { return nil } - return item.(C.PacketConn) + return entry.PacketConn } func (t *Table) GetOrCreateLock(key string) (*sync.Cond, bool) { @@ -31,6 +40,62 @@ func (t *Table) Delete(key string) { t.mapping.Delete(key) } +func (t *Table) GetLocalConn(lAddr, rAddr string) *net.UDPConn { + entry, exist := t.getEntry(lAddr) + if !exist { + return nil + } + item, exist := entry.LocalUDPConnMap.Load(rAddr) + if !exist { + return nil + } + return item.(*net.UDPConn) +} + +func (t *Table) AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool { + entry, exist := t.getEntry(lAddr) + if !exist { + return false + } + entry.LocalUDPConnMap.Store(rAddr, conn) + return true +} + +func (t *Table) RangeLocalConn(lAddr string, f func(key, value any) bool) { + entry, exist := t.getEntry(lAddr) + if !exist { + return + } + entry.LocalUDPConnMap.Range(f) +} + +func (t *Table) GetOrCreateLockForLocalConn(lAddr, key string) (*sync.Cond, bool) { + entry, loaded := t.getEntry(lAddr) + if !loaded { + return nil, false + } + item, loaded := entry.LocalUDPConnMap.LoadOrStore(key, sync.NewCond(&sync.Mutex{})) + return item.(*sync.Cond), loaded +} + +func (t *Table) DeleteLocalConnMap(lAddr, key string) { + entry, loaded := t.getEntry(lAddr) + if !loaded { + return + } + entry.LocalUDPConnMap.Delete(key) +} + +func (t *Table) getEntry(key string) (*Entry, bool) { + item, ok := t.mapping.Load(key) + // This should not happen usually since this function called after PacketConn created + if !ok { + return nil, false + } + entry, ok := item.(*Entry) + return entry, ok +} + // New return *Cache func New() *Table { return &Table{} diff --git a/constant/adapters.go b/constant/adapters.go index 4480a953..879ee6d7 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "net/netip" + "sync" "time" "github.com/Dreamacro/clash/component/dialer" @@ -216,6 +217,10 @@ type UDPPacket interface { // LocalAddr returns the source IP/Port of packet LocalAddr() net.Addr + + SetNatTable(natTable NatTable) + + SetUdpInChan(in chan<- PacketAdapter) } type UDPPacketInAddr interface { @@ -227,3 +232,23 @@ type PacketAdapter interface { UDPPacket Metadata() *Metadata } + +type NatTable interface { + Set(key string, e PacketConn) + + Get(key string) PacketConn + + GetOrCreateLock(key string) (*sync.Cond, bool) + + Delete(key string) + + GetLocalConn(lAddr, rAddr string) *net.UDPConn + + AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool + + RangeLocalConn(lAddr string, f func(key, value any) bool) + + GetOrCreateLockForLocalConn(lAddr, key string) (*sync.Cond, bool) + + DeleteLocalConnMap(lAddr, key string) +} diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index 2e9fd003..eee5660a 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -7,6 +7,7 @@ import ( "net/url" "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -44,6 +45,13 @@ func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } +func (c *packet) SetNatTable(natTable C.NatTable) { + // no need +} + +func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { + // no need +} func ParseSSURL(s string) (addr, cipher, password string, err error) { u, err := url.Parse(s) if err != nil { diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 27a9d6ac..a3e15154 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -166,3 +166,11 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.lAddr } + +func (c *packet) SetNatTable(natTable C.NatTable) { + // no need +} + +func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { + // no need +} diff --git a/listener/socks/utils.go b/listener/socks/utils.go index 4c53b9e5..29898fda 100644 --- a/listener/socks/utils.go +++ b/listener/socks/utils.go @@ -4,6 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -39,3 +40,11 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } + +func (c *packet) SetNatTable(natTable C.NatTable) { + // no need +} + +func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { + // no need +} diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index e86a11ca..d66fac51 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -1,16 +1,22 @@ package tproxy import ( + "errors" + "fmt" + "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" "net" "net/netip" - - "github.com/Dreamacro/clash/common/pool" ) type packet struct { - pc net.PacketConn - lAddr netip.AddrPort - buf []byte + pc net.PacketConn + lAddr netip.AddrPort + buf []byte + natTable C.NatTable + in chan<- C.PacketAdapter } func (c *packet) Data() []byte { @@ -19,13 +25,12 @@ func (c *packet) Data() []byte { // WriteBack opens a new socket binding `addr` to write UDP packet back func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { - tc, err := dialUDP("udp", addr.(*net.UDPAddr).AddrPort(), c.lAddr) + tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.natTable, c.in) if err != nil { n = 0 return } n, err = tc.Write(b) - tc.Close() return } @@ -41,3 +46,82 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } + +func (c *packet) SetNatTable(natTable C.NatTable) { + c.natTable = natTable +} + +func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { + c.in = in +} + +// this function listen at rAddr and write to lAddr +// for here, rAddr is the ip/port client want to access +// lAddr is the ip/port client opened +func createOrGetLocalConn(rAddr, lAddr net.Addr, natTable C.NatTable, in chan<- C.PacketAdapter) (*net.UDPConn, error) { + remote := rAddr.String() + local := lAddr.String() + localConn := natTable.GetLocalConn(local, remote) + // localConn not exist + if localConn == nil { + lockKey := remote + "-lock" + cond, loaded := natTable.GetOrCreateLockForLocalConn(local, lockKey) + if loaded { + cond.L.Lock() + cond.Wait() + // we should get localConn here + localConn = natTable.GetLocalConn(local, remote) + if localConn == nil { + return nil, fmt.Errorf("localConn is nil, nat entry not exist") + } + cond.L.Unlock() + } else { + if cond == nil { + return nil, fmt.Errorf("cond is nil, nat entry not exist") + } + defer func() { + natTable.DeleteLocalConnMap(local, lockKey) + cond.Broadcast() + }() + conn, err := listenLocalConn(rAddr, lAddr, in) + if err != nil { + log.Errorln("listenLocalConn failed with error: %s, packet loss", err.Error()) + return nil, err + } + natTable.AddLocalConn(local, remote, conn) + localConn = conn + } + } + return localConn, nil +} + +// this function listen at rAddr +// and send what received to program itself, then send to real remote +func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter) (*net.UDPConn, error) { + additions := []inbound.Addition{ + inbound.WithInName("DEFAULT-TPROXY"), + inbound.WithSpecialRules(""), + } + lc, err := dialUDP("udp", rAddr.(*net.UDPAddr).AddrPort(), lAddr.(*net.UDPAddr).AddrPort()) + if err != nil { + return nil, err + } + go func() { + log.Debugln("TProxy listenLocalConn rAddr=%s lAddr=%s", rAddr.String(), lAddr.String()) + for { + buf := pool.Get(pool.UDPBufferSize) + br, err := lc.Read(buf) + if err != nil { + pool.Put(buf) + if errors.Is(err, net.ErrClosed) { + log.Debugln("TProxy local conn listener exit.. rAddr=%s lAddr=%s", rAddr.String(), lAddr.String()) + return + } + } + // since following localPackets are pass through this socket which listen rAddr + // I choose current listener as packet's packet conn + handlePacketConn(lc, in, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) + } + }() + return lc, nil +} diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go index 602f7675..fa85879f 100644 --- a/listener/tunnel/packet.go +++ b/listener/tunnel/packet.go @@ -4,6 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" ) type packet struct { @@ -33,3 +34,11 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } + +func (c *packet) SetNatTable(natTable C.NatTable) { + // no need +} + +func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { + // no need +} diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 2830b324..fdea899d 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -316,5 +316,13 @@ func (s *serverUDPPacket) Drop() { s.packet.DATA = nil } +func (s *serverUDPPacket) SetNatTable(natTable C.NatTable) { + // no need +} + +func (s *serverUDPPacket) SetUdpInChan(in chan<- C.PacketAdapter) { + // no need +} + var _ C.UDPPacket = &serverUDPPacket{} var _ C.UDPPacketInAddr = &serverUDPPacket{} diff --git a/tunnel/connection.go b/tunnel/connection.go index d8bd26c9..687b2887 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -2,6 +2,7 @@ package tunnel import ( "errors" + "github.com/Dreamacro/clash/log" "net" "net/netip" "time" @@ -32,6 +33,7 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, buf := pool.Get(pool.UDPBufferSize) defer func() { _ = pc.Close() + closeAllLocalCoon(key) natTable.Delete(key) _ = pool.Put(buf) }() @@ -60,6 +62,19 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } } +func closeAllLocalCoon(lAddr string) { + natTable.RangeLocalConn(lAddr, func(key, value any) bool { + conn, ok := value.(*net.UDPConn) + if !ok || conn == nil { + log.Debugln("Value %#v unknown value when closing TProxy local conn...", conn) + return true + } + conn.Close() + log.Debugln("Closing TProxy local conn... lAddr=%s rAddr=%s", lAddr, key) + return true + }) +} + func handleSocket(ctx C.ConnContext, outbound net.Conn) { N.Relay(ctx.Conn(), outbound) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 9c6c155f..5c3814bc 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -337,9 +337,12 @@ func handleUDPConn(packet C.PacketAdapter) { } oAddr := metadata.DstIP + natTable.Set(key, pc) + packet.SetNatTable(natTable) + packet.SetUdpInChan(udpQueue) + go handleUDPToLocal(packet, pc, key, oAddr, fAddr) - natTable.Set(key, pc) handle() }() } From d6ff5f7d9624ea48c0d67c36668b2ca6b3004236 Mon Sep 17 00:00:00 2001 From: kunish <17328586+kunish@users.noreply.github.com> Date: Fri, 17 Feb 2023 16:31:37 +0800 Subject: [PATCH 118/126] style: run go fmt on every .go file (#392) --- common/generics/list/list.go | 2 +- component/ebpf/redir/bpf_bpfeb.go | 7 ++++--- component/ebpf/redir/bpf_bpfel.go | 7 ++++--- component/ebpf/tc/bpf_bpfeb.go | 7 ++++--- component/ebpf/tc/bpf_bpfel.go | 7 ++++--- constant/dns.go | 2 +- dns/doh.go | 2 +- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/common/generics/list/list.go b/common/generics/list/list.go index a06a7c61..04d84180 100644 --- a/common/generics/list/list.go +++ b/common/generics/list/list.go @@ -5,10 +5,10 @@ // Package list implements a doubly linked list. // // To iterate over a list (where l is a *List): +// // for e := l.Front(); e != nil; e = e.Next() { // // do something with e.Value // } -// package list // Element is an element of a linked list. diff --git a/component/ebpf/redir/bpf_bpfeb.go b/component/ebpf/redir/bpf_bpfeb.go index ec0e1a77..57a526e8 100644 --- a/component/ebpf/redir/bpf_bpfeb.go +++ b/component/ebpf/redir/bpf_bpfeb.go @@ -41,9 +41,9 @@ func loadBpf() (*ebpf.CollectionSpec, error) { // // The following types are suitable as obj argument: // -// *bpfObjects -// *bpfPrograms -// *bpfMaps +// *bpfObjects +// *bpfPrograms +// *bpfMaps // // See ebpf.CollectionSpec.LoadAndAssign documentation for details. func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { @@ -134,5 +134,6 @@ func _BpfClose(closers ...io.Closer) error { } // Do not access this directly. +// //go:embed bpf_bpfeb.o var _BpfBytes []byte diff --git a/component/ebpf/redir/bpf_bpfel.go b/component/ebpf/redir/bpf_bpfel.go index ed859e5d..936b84eb 100644 --- a/component/ebpf/redir/bpf_bpfel.go +++ b/component/ebpf/redir/bpf_bpfel.go @@ -41,9 +41,9 @@ func loadBpf() (*ebpf.CollectionSpec, error) { // // The following types are suitable as obj argument: // -// *bpfObjects -// *bpfPrograms -// *bpfMaps +// *bpfObjects +// *bpfPrograms +// *bpfMaps // // See ebpf.CollectionSpec.LoadAndAssign documentation for details. func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { @@ -134,5 +134,6 @@ func _BpfClose(closers ...io.Closer) error { } // Do not access this directly. +// //go:embed bpf_bpfel.o var _BpfBytes []byte diff --git a/component/ebpf/tc/bpf_bpfeb.go b/component/ebpf/tc/bpf_bpfeb.go index 12847538..623986dc 100644 --- a/component/ebpf/tc/bpf_bpfeb.go +++ b/component/ebpf/tc/bpf_bpfeb.go @@ -28,9 +28,9 @@ func loadBpf() (*ebpf.CollectionSpec, error) { // // The following types are suitable as obj argument: // -// *bpfObjects -// *bpfPrograms -// *bpfMaps +// *bpfObjects +// *bpfPrograms +// *bpfMaps // // See ebpf.CollectionSpec.LoadAndAssign documentation for details. func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { @@ -115,5 +115,6 @@ func _BpfClose(closers ...io.Closer) error { } // Do not access this directly. +// //go:embed bpf_bpfeb.o var _BpfBytes []byte diff --git a/component/ebpf/tc/bpf_bpfel.go b/component/ebpf/tc/bpf_bpfel.go index c09e35bb..07daba12 100644 --- a/component/ebpf/tc/bpf_bpfel.go +++ b/component/ebpf/tc/bpf_bpfel.go @@ -28,9 +28,9 @@ func loadBpf() (*ebpf.CollectionSpec, error) { // // The following types are suitable as obj argument: // -// *bpfObjects -// *bpfPrograms -// *bpfMaps +// *bpfObjects +// *bpfPrograms +// *bpfMaps // // See ebpf.CollectionSpec.LoadAndAssign documentation for details. func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { @@ -115,5 +115,6 @@ func _BpfClose(closers ...io.Closer) error { } // Do not access this directly. +// //go:embed bpf_bpfel.o var _BpfBytes []byte diff --git a/constant/dns.go b/constant/dns.go index da68753c..3d97d97b 100644 --- a/constant/dns.go +++ b/constant/dns.go @@ -124,4 +124,4 @@ const ( HTTPVersion2 HTTPVersion = "h2" // HTTPVersion3 is HTTP/3. HTTPVersion3 HTTPVersion = "h3" -) \ No newline at end of file +) diff --git a/dns/doh.go b/dns/doh.go index 0a9efe1c..1e6528d9 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -109,7 +109,7 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D. // formats that include the ID field from the DNS message header, such // as "application/dns-message", SHOULD use a DNS ID of 0 in every DNS // request. - m=m.Copy() + m = m.Copy() id := m.Id m.Id = 0 defer func() { From 59cd89a9c94834583db5e94ece5d2d530f6cef61 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 17 Feb 2023 23:30:38 +0800 Subject: [PATCH 119/126] fix: parsing ipv6 doh error --- config/config.go | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/config/config.go b/config/config.go index 498b069f..d71fc63f 100644 --- a/config/config.go +++ b/config/config.go @@ -890,29 +890,24 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) addr, err = hostWithDefaultPort(u.Host, "853") dnsNetType = "tcp-tls" // DNS over TLS case "https": - host := u.Host - proxyAdapter = "" - if _, _, err := net.SplitHostPort(host); err != nil && strings.Contains(err.Error(), "missing port in address") { - host = net.JoinHostPort(host, "443") - } else { - if err != nil { - return nil, err - } - } - clearURL := url.URL{Scheme: "https", Host: host, Path: u.Path} - addr = clearURL.String() - dnsNetType = "https" // DNS over HTTPS - if len(u.Fragment) != 0 { - for _, s := range strings.Split(u.Fragment, "&") { - arr := strings.Split(s, "=") - if len(arr) == 0 { - continue - } else if len(arr) == 1 { - proxyAdapter = arr[0] - } else if len(arr) == 2 { - params[arr[0]] = arr[1] - } else { - params[arr[0]] = strings.Join(arr[1:], "=") + addr, err = hostWithDefaultPort(u.Host, "443") + if err == nil { + proxyAdapter = "" + clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path} + addr = clearURL.String() + dnsNetType = "https" // DNS over HTTPS + if len(u.Fragment) != 0 { + for _, s := range strings.Split(u.Fragment, "&") { + arr := strings.Split(s, "=") + if len(arr) == 0 { + continue + } else if len(arr) == 1 { + proxyAdapter = arr[0] + } else if len(arr) == 2 { + params[arr[0]] = arr[1] + } else { + params[arr[0]] = strings.Join(arr[1:], "=") + } } } } From fc50392ec797ccd5054effaee444ebd22304094d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 Feb 2023 13:16:07 +0800 Subject: [PATCH 120/126] chore: cleanup natTable's api --- constant/adapters.go | 4 ---- constant/listener.go | 2 +- hub/executor/executor.go | 8 +++++--- hub/route/configs.go | 5 +++-- listener/inbound/base.go | 2 +- listener/inbound/http.go | 2 +- listener/inbound/mixed.go | 2 +- listener/inbound/redir.go | 2 +- listener/inbound/shadowsocks.go | 2 +- listener/inbound/socks.go | 2 +- listener/inbound/tproxy.go | 4 ++-- listener/inbound/tuic.go | 2 +- listener/inbound/tun.go | 2 +- listener/inbound/tunnel.go | 2 +- listener/inbound/vmess.go | 2 +- listener/listener.go | 12 ++++++------ listener/shadowsocks/utils.go | 8 -------- listener/socks/utils.go | 9 --------- listener/tproxy/packet.go | 20 ++++++-------------- listener/tproxy/udp.go | 14 ++++++++------ listener/tunnel/packet.go | 9 --------- transport/tuic/server.go | 8 -------- tunnel/connection.go | 2 +- tunnel/tunnel.go | 7 +++++-- 24 files changed, 47 insertions(+), 85 deletions(-) diff --git a/constant/adapters.go b/constant/adapters.go index 879ee6d7..bf5f7fdb 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -217,10 +217,6 @@ type UDPPacket interface { // LocalAddr returns the source IP/Port of packet LocalAddr() net.Addr - - SetNatTable(natTable NatTable) - - SetUdpInChan(in chan<- PacketAdapter) } type UDPPacketInAddr interface { diff --git a/constant/listener.go b/constant/listener.go index a52c1946..6f9f169b 100644 --- a/constant/listener.go +++ b/constant/listener.go @@ -16,7 +16,7 @@ type MultiAddrListener interface { type InboundListener interface { Name() string - Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter) error + Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter, natTable NatTable) error Close() error Address() string RawAddress() string diff --git a/hub/executor/executor.go b/hub/executor/executor.go index d88e91dc..b3e33f98 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -137,8 +137,9 @@ func GetGeneral() *config.General { func updateListeners(listeners map[string]C.InboundListener) { tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() + natTable := tunnel.NatTable() - listener.PatchInboundListeners(listeners, tcpIn, udpIn, true) + listener.PatchInboundListeners(listeners, tcpIn, udpIn, natTable, true) } func updateExperimental(c *config.Config) { @@ -348,12 +349,13 @@ func updateGeneral(general *config.General, force bool) { tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() + natTable := tunnel.NatTable() listener.ReCreateHTTP(general.Port, tcpIn) listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) - listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn) + listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn, natTable) listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tcpIn, udpIn) - listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn) + listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn, natTable) listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) listener.ReCreateShadowSocks(general.ShadowSocksConfig, tcpIn, udpIn) listener.ReCreateVmess(general.VmessConfig, tcpIn, udpIn) diff --git a/hub/route/configs.go b/hub/route/configs.go index 5047c6d6..9e630b29 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -239,11 +239,12 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() + natTable := tunnel.NatTable() P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn) P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn) - P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn) - P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn) + P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn, natTable) + P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn, natTable) P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tcpIn, udpIn) P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tcpIn, udpIn) diff --git a/listener/inbound/base.go b/listener/inbound/base.go index 41be5b10..b132ac6c 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -61,7 +61,7 @@ func (b *Base) RawAddress() string { } // Listen implements constant.InboundListener -func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { return nil } diff --git a/listener/inbound/http.go b/listener/inbound/http.go index b19f0154..a93f9684 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -42,7 +42,7 @@ func (h *HTTP) Address() string { } // Listen implements constant.InboundListener -func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error h.l, err = http.New(h.RawAddress(), tcpIn, h.Additions()...) if err != nil { diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index a2920c69..dbba264c 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -50,7 +50,7 @@ func (m *Mixed) Address() string { } // Listen implements constant.InboundListener -func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error m.l, err = mixed.New(m.RawAddress(), tcpIn, m.Additions()...) if err != nil { diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 7a1685ba..4b88d895 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -42,7 +42,7 @@ func (r *Redir) Address() string { } // Listen implements constant.InboundListener -func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error r.l, err = redir.New(r.RawAddress(), tcpIn, r.Additions()...) if err != nil { diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index e6baa80c..40907485 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -57,7 +57,7 @@ func (s *ShadowSocks) Address() string { } // Listen implements constant.InboundListener -func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error s.l, err = sing_shadowsocks.New(s.ss, tcpIn, udpIn, s.Additions()...) if err != nil { diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index 010d08f9..aac2ee23 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -68,7 +68,7 @@ func (s *Socks) Address() string { } // Listen implements constant.InboundListener -func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error if s.stl, err = socks.New(s.RawAddress(), tcpIn, s.Additions()...); err != nil { return err diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 7aa8af8d..fa458d2c 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -49,7 +49,7 @@ func (t *TProxy) Address() string { } // Listen implements constant.InboundListener -func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error t.lTCP, err = tproxy.New(t.RawAddress(), tcpIn, t.Additions()...) if err != nil { @@ -57,7 +57,7 @@ func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter } if t.udp { if t.lUDP != nil { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, t.Additions()...) + t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, natTable, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index c74f73f6..f6641500 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -69,7 +69,7 @@ func (t *Tuic) Address() string { } // Listen implements constant.InboundListener -func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error t.l, err = tuic.New(t.ts, tcpIn, udpIn, t.Additions()...) if err != nil { diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 997164c2..ad215989 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -111,7 +111,7 @@ func (t *Tun) Address() string { } // Listen implements constant.InboundListener -func (t *Tun) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (t *Tun) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error t.l, err = sing_tun.New(t.tun, tcpIn, udpIn, t.Additions()...) if err != nil { diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 221f4cd6..41d024ef 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -74,7 +74,7 @@ func (t *Tunnel) Address() string { } // Listen implements constant.InboundListener -func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error for _, network := range t.config.Network { switch network { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 130e17c5..70e840a5 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -69,7 +69,7 @@ func (v *Vmess) Address() string { } // Listen implements constant.InboundListener -func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error { +func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { var err error users := make([]LC.VmessUser, len(v.config.Users)) for i, v := range v.config.Users { diff --git a/listener/listener.go b/listener/listener.go index d747d5f5..d8eb5c0c 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -207,7 +207,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("SOCKS proxy listening at: %s", socksListener.Address()) } -func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { redirMux.Lock() defer redirMux.Unlock() @@ -245,7 +245,7 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - redirUDPListener, err = tproxy.NewUDP(addr, udpIn) + redirUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) if err != nil { log.Warnln("Failed to start Redir UDP Listener: %s", err) } @@ -403,7 +403,7 @@ func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- return } -func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { tproxyMux.Lock() defer tproxyMux.Unlock() @@ -441,7 +441,7 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketA return } - tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn) + tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) if err != nil { log.Warnln("Failed to start TProxy UDP Listener: %s", err) } @@ -719,7 +719,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C } } -func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, dropOld bool) { +func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable, dropOld bool) { inboundMux.Lock() defer inboundMux.Unlock() @@ -731,7 +731,7 @@ func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn ch continue } } - if err := newListener.Listen(tcpIn, udpIn); err != nil { + if err := newListener.Listen(tcpIn, udpIn, natTable); err != nil { log.Errorln("Listener %s listen err: %s", name, err.Error()) continue } diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index eee5660a..2e9fd003 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -7,7 +7,6 @@ import ( "net/url" "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -45,13 +44,6 @@ func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } -func (c *packet) SetNatTable(natTable C.NatTable) { - // no need -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} func ParseSSURL(s string) (addr, cipher, password string, err error) { u, err := url.Parse(s) if err != nil { diff --git a/listener/socks/utils.go b/listener/socks/utils.go index 29898fda..4c53b9e5 100644 --- a/listener/socks/utils.go +++ b/listener/socks/utils.go @@ -4,7 +4,6 @@ import ( "net" "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -40,11 +39,3 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } - -func (c *packet) SetNatTable(natTable C.NatTable) { - // no need -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index d66fac51..e3a20414 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -15,8 +15,8 @@ type packet struct { pc net.PacketConn lAddr netip.AddrPort buf []byte - natTable C.NatTable in chan<- C.PacketAdapter + natTable C.NatTable } func (c *packet) Data() []byte { @@ -25,7 +25,7 @@ func (c *packet) Data() []byte { // WriteBack opens a new socket binding `addr` to write UDP packet back func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { - tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.natTable, c.in) + tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.in, c.natTable) if err != nil { n = 0 return @@ -47,18 +47,10 @@ func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } -func (c *packet) SetNatTable(natTable C.NatTable) { - c.natTable = natTable -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - c.in = in -} - // this function listen at rAddr and write to lAddr // for here, rAddr is the ip/port client want to access // lAddr is the ip/port client opened -func createOrGetLocalConn(rAddr, lAddr net.Addr, natTable C.NatTable, in chan<- C.PacketAdapter) (*net.UDPConn, error) { +func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { remote := rAddr.String() local := lAddr.String() localConn := natTable.GetLocalConn(local, remote) @@ -83,7 +75,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, natTable C.NatTable, in chan<- natTable.DeleteLocalConnMap(local, lockKey) cond.Broadcast() }() - conn, err := listenLocalConn(rAddr, lAddr, in) + conn, err := listenLocalConn(rAddr, lAddr, in, natTable) if err != nil { log.Errorln("listenLocalConn failed with error: %s, packet loss", err.Error()) return nil, err @@ -97,7 +89,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, natTable C.NatTable, in chan<- // this function listen at rAddr // and send what received to program itself, then send to real remote -func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter) (*net.UDPConn, error) { +func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { additions := []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), inbound.WithSpecialRules(""), @@ -120,7 +112,7 @@ func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter) (*net.UDP } // since following localPackets are pass through this socket which listen rAddr // I choose current listener as packet's packet conn - handlePacketConn(lc, in, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) + handlePacketConn(lc, in, natTable, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) } }() return lc, nil diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index f85c9ea9..d3727180 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -32,7 +32,7 @@ func (l *UDPListener) Close() error { return l.packetConn.Close() } -func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { +func NewUDP(addr string, in chan<- C.PacketAdapter, natTable C.NatTable, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), @@ -83,19 +83,21 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Additio // try to unmap 4in6 address lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port()) } - handlePacketConn(l, in, buf[:n], lAddr, rAddr, additions...) + handlePacketConn(l, in, natTable, buf[:n], lAddr, rAddr, additions...) } }() return rl, nil } -func handlePacketConn(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { +func handlePacketConn(pc net.PacketConn, in chan<- C.PacketAdapter, natTable C.NatTable, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { target := socks5.AddrFromStdAddrPort(rAddr) pkt := &packet{ - pc: pc, - lAddr: lAddr, - buf: buf, + pc: pc, + lAddr: lAddr, + buf: buf, + in: in, + natTable: natTable, } select { case in <- inbound.NewPacket(target, pkt, C.TPROXY, additions...): diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go index fa85879f..602f7675 100644 --- a/listener/tunnel/packet.go +++ b/listener/tunnel/packet.go @@ -4,7 +4,6 @@ import ( "net" "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" ) type packet struct { @@ -34,11 +33,3 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.pc.LocalAddr() } - -func (c *packet) SetNatTable(natTable C.NatTable) { - // no need -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} diff --git a/transport/tuic/server.go b/transport/tuic/server.go index fdea899d..2830b324 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -316,13 +316,5 @@ func (s *serverUDPPacket) Drop() { s.packet.DATA = nil } -func (s *serverUDPPacket) SetNatTable(natTable C.NatTable) { - // no need -} - -func (s *serverUDPPacket) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} - var _ C.UDPPacket = &serverUDPPacket{} var _ C.UDPPacketInAddr = &serverUDPPacket{} diff --git a/tunnel/connection.go b/tunnel/connection.go index 687b2887..bd8d1b63 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -2,7 +2,6 @@ package tunnel import ( "errors" - "github.com/Dreamacro/clash/log" "net" "net/netip" "time" @@ -10,6 +9,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 5c3814bc..695f2945 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -82,6 +82,11 @@ func UDPIn() chan<- C.PacketAdapter { return udpQueue } +// NatTable return nat table +func NatTable() C.NatTable { + return natTable +} + // Rules return all rules func Rules() []C.Rule { return rules @@ -338,8 +343,6 @@ func handleUDPConn(packet C.PacketAdapter) { oAddr := metadata.DstIP natTable.Set(key, pc) - packet.SetNatTable(natTable) - packet.SetUdpInChan(udpQueue) go handleUDPToLocal(packet, pc, key, oAddr, fAddr) From 6a89cc15c37dd6fef94efabdbfd23708beefc64e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 Feb 2023 13:32:26 +0800 Subject: [PATCH 121/126] chore: Considering remove GOAMD64=v2 of linux-amd64-compatible close https://github.com/MetaCubeX/Clash.Meta/issues/391 --- Makefile | 6 +++--- listener/tproxy/packet.go | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index b1ee532f..f7a637a9 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ darwin-amd64: GOARCH=amd64 GOOS=darwin GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ darwin-amd64-compatible: - GOARCH=amd64 GOOS=darwin GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + GOARCH=amd64 GOOS=darwin GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ darwin-arm64: GOARCH=arm64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ @@ -69,7 +69,7 @@ linux-amd64: GOARCH=amd64 GOOS=linux GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ linux-amd64-compatible: - GOARCH=amd64 GOOS=linux GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + GOARCH=amd64 GOOS=linux GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ linux-arm64: GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ @@ -120,7 +120,7 @@ windows-amd64: GOARCH=amd64 GOOS=windows GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe windows-amd64-compatible: - GOARCH=amd64 GOOS=windows GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe + GOARCH=amd64 GOOS=windows GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe windows-arm64: GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index e3a20414..2a274f61 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -3,12 +3,13 @@ package tproxy import ( "errors" "fmt" + "net" + "net/netip" + "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "net" - "net/netip" ) type packet struct { From cc3a9dd553be25575abf813c96e62d94eca0bbd8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 Feb 2023 13:58:08 +0800 Subject: [PATCH 122/126] fix: websocket headroom --- transport/vmess/websocket.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 2487b93a..cc747803 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -301,6 +301,10 @@ func (wsedc *websocketWithEarlyDataConn) SetWriteDeadline(t time.Time) error { return wsedc.Conn.SetWriteDeadline(t) } +func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool { + return wsedc.Conn == nil +} + func (wsedc *websocketWithEarlyDataConn) Upstream() any { return wsedc.Conn } From b9e63d3f7d92d26aae926ec691397347ee0bada9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 Feb 2023 14:16:03 +0800 Subject: [PATCH 123/126] fix: ensure return a nil interface not an interface with nil value --- transport/vmess/websocket.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index cc747803..71dabbdd 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -306,6 +306,9 @@ func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool { } func (wsedc *websocketWithEarlyDataConn) Upstream() any { + if wsedc.Conn == nil { // ensure return a nil interface not an interface with nil value + return nil + } return wsedc.Conn } From a61685ce01919804ee633d9beb410c5e41581255 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 Feb 2023 16:42:54 +0800 Subject: [PATCH 124/126] fix: disable header protection in vmess server --- go.mod | 2 +- go.sum | 4 ++-- listener/sing_vmess/server.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d5e504eb..c2a979dc 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/refraction-networking/utls v1.2.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 - github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 + github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 diff --git a/go.sum b/go.sum index 7bdc889d..076442ab 100644 --- a/go.sum +++ b/go.sum @@ -133,8 +133,8 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 h1:qnXh4RjHsNjdZXkfbqwVqAzYUfc160gfkS5gepmsA+A= github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= -github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564 h1:+CFee8wEc79nFDBV8tDm2yKPrAXb5Mrf2Q5kM2Bb/xo= -github.com/sagernet/sing-vmess v0.1.1-0.20230207064843-983dde690564/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= +github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb h1:oyd3w17fXNmWVYFUe17YVHJW5CLW9X2mxJFDP/IWrAM= +github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 859317f0..bb89ba99 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -42,7 +42,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe Additions: additions, } - service := vmess.NewService[string](h) + service := vmess.NewService[string](h, vmess.ServiceWithDisableHeaderProtection()) err = service.UpdateUsers( common.Map(config.Users, func(it LC.VmessUser) string { return it.Username From cd7d9fc4f5efcc6de678a1ba21747adc5b663769 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 18 Feb 2023 17:18:58 +0800 Subject: [PATCH 125/126] fix: socks5 serialize error #376 --- constant/metadata.go | 2 +- rules/common/geosite.go | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/constant/metadata.go b/constant/metadata.go index f1c68f68..599a6055 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -165,7 +165,7 @@ func (m *Metadata) SourceDetail() string { func (m *Metadata) AddrType() int { switch true { - case m.Host != "" || m.SniffHost != "" || !m.DstIP.IsValid(): + case m.Host != "" || !m.DstIP.IsValid(): return socks5.AtypDomainName case m.DstIP.Is4(): return socks5.AtypIPv4 diff --git a/rules/common/geosite.go b/rules/common/geosite.go index c0a3a1da..e89dc19b 100644 --- a/rules/common/geosite.go +++ b/rules/common/geosite.go @@ -9,7 +9,6 @@ import ( _ "github.com/Dreamacro/clash/component/geodata/standard" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" ) type GEOSITE struct { @@ -25,11 +24,10 @@ func (gs *GEOSITE) RuleType() C.RuleType { } func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) { - if metadata.AddrType() != socks5.AtypDomainName { + domain := metadata.RuleHost() + if len(domain) == 0 { return false, "" } - - domain := metadata.RuleHost() return gs.matcher.ApplyDomain(domain), gs.adapter } From 527fc2790bf4a883c0c8572f84002d3040522363 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 19 Feb 2023 01:23:06 +0800 Subject: [PATCH 126/126] chore: combine workflows --- .github/workflows/build.yaml | 22 -------- .../workflows/{prerelease.yml => build.yml} | 52 ++++++++++++++++--- .github/workflows/release.yaml | 36 ------------- dns/resolver.go | 2 +- 4 files changed, 45 insertions(+), 67 deletions(-) delete mode 100644 .github/workflows/build.yaml rename .github/workflows/{prerelease.yml => build.yml} (86%) delete mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index 1def82ea..00000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Build All -on: - workflow_dispatch: -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v3 - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.20' - check-latest: true - cache: true - - name: Build - run: make all - - name: Release - uses: softprops/action-gh-release@v1 - with: - files: bin/* - draft: true diff --git a/.github/workflows/prerelease.yml b/.github/workflows/build.yml similarity index 86% rename from .github/workflows/prerelease.yml rename to .github/workflows/build.yml index d586ca28..66b694de 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Prerelease +name: Build on: workflow_dispatch: push: @@ -8,10 +8,14 @@ on: branches: - Alpha - Beta + - Meta + tags: + - "v*" pull_request_target: branches: - Alpha - Beta + - Meta env: REGISTRY: docker.io jobs: @@ -93,7 +97,12 @@ jobs: shell: bash - name: Set variables - if: ${{github.ref_name==''}} + if: ${{github.ref_name=='Meta'}} + run: echo "VERSION=meta-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + shell: bash + + - name: Set variables + if: ${{github.ref_name=='' || github.ref_type=='tag'}} run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV shell: bash @@ -103,6 +112,7 @@ jobs: echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV + echo "BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV shell: bash - name: Set ENV @@ -118,7 +128,7 @@ jobs: check-latest: true - name: Test - if: ${{ github.ref_name=='Beta' && matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} + if: ${{ matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} run: | go test ./... @@ -158,7 +168,7 @@ jobs: ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} run: | mkdir bin - xgo --branch ${{ github.ref_name }} --targets="${{ matrix.job.target }}" --tags="${TAGS}" -ldflags="${LDFLAGS}" --out bin/${NAME} github.com/${{ github.repository }} + xgo --targets="${{ matrix.job.target }}" --tags="${TAGS}" -ldflags="${LDFLAGS}" --out bin/${NAME} ./ - name: Rename if: ${{ matrix.job.type=='WithCGO' }} @@ -189,9 +199,10 @@ jobs: name: artifact path: bin/ - Upload: + Upload-Prerelease: permissions: write-all - needs: [Build] + if: ${{ github.ref_type=='branch' }} + needs: [ Build ] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 @@ -217,7 +228,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Alpha + - name: Upload Prerelease uses: softprops/action-gh-release@v1 if: ${{ success() }} with: @@ -226,9 +237,34 @@ jobs: files: bin/* prerelease: true generate_release_notes: true + + Upload-Release: + permissions: write-all + if: ${{ github.ref_type=='tag' }} + needs: [ Build ] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: bin/ + + - name: Display structure of downloaded files + run: ls -R + working-directory: bin + + - name: Upload Release + uses: softprops/action-gh-release@v1 + if: ${{ success() }} + with: + tag: ${{ github.ref_name }} + tag_name: ${{ github.ref_name }} + files: bin/* + generate_release_notes: true + Docker: permissions: write-all - needs: [Build] + needs: [ Build ] runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index 478f13e1..00000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Release -on: - push: - tags: - - "v*" -jobs: - Build: - runs-on: ubuntu-latest - steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v3 - - - name: Setup Go - uses: actions/setup-go@v3 - with: - go-version: '1.20' - check-latest: true - cache: true - - - name: Test - run: | - go test ./... - - name: Build - if: success() - env: - NAME: Clash.Meta - BINDIR: bin - run: make -j$(($(nproc) + 1)) releases - - - name: Upload Release - uses: softprops/action-gh-release@v1 - if: ${{ success() && startsWith(github.ref, 'refs/tags/')}} - with: - tag: ${{ github.ref }} - files: bin/* - generate_release_notes: true diff --git a/dns/resolver.go b/dns/resolver.go index 8c983111..ac8917ca 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -457,7 +457,7 @@ func NewResolver(config Config) *Resolver { inverse = true groupname = groupname[1:] } - log.Debugln("adding geosite policy: %s inversed %s", groupname, inverse) + log.Debugln("adding geosite policy: %s inversed %t", groupname, inverse) matcher, err := NewGeoSite(groupname) if err != nil { continue