Compare commits

..

2 Commits

Author SHA1 Message Date
世界
637a8b6ed5 refactor: udp 2022-06-09 21:16:42 +08:00
世界
cd466f05d3 chore: reformat code 2022-06-09 21:08:46 +08:00
150 changed files with 932 additions and 1205 deletions

View File

@@ -251,8 +251,8 @@ User=clash-meta
Group=clash-meta Group=clash-meta
LimitNPROC=500 LimitNPROC=500
LimitNOFILE=1000000 LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CapabilityBoundingSet=cap_net_admin
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE AmbientCapabilities=cap_net_admin
Restart=always Restart=always
ExecStartPre=/usr/bin/sleep 1s ExecStartPre=/usr/bin/sleep 1s
ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta
@@ -274,7 +274,7 @@ $ systemctl start Clash-Meta
Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`. 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 [Dashboard For Meta](https://github.com/Clash-Mini/Dashboard).
![img.png](https://github.com/Clash-Mini/Dashboard/raw/master/View/Dashboard-Process.png) ![img.png](https://github.com/Clash-Mini/Dashboard/raw/master/View/Dashboard-Process.png)

View File

@@ -4,9 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/Dreamacro/clash/common/queue"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"net" "net"
"net/http" "net/http"
"net/netip" "net/netip"
@@ -14,6 +11,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/Dreamacro/clash/common/queue"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic" "go.uber.org/atomic"
) )
@@ -151,32 +151,25 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
} }
client := http.Client{ client := http.Client{
Timeout: 30 * time.Second,
Transport: transport, Transport: transport,
CheckRedirect: func(req *http.Request, via []*http.Request) error { CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse return http.ErrUseLastResponse
}, },
} }
defer client.CloseIdleConnections() defer client.CloseIdleConnections()
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return return
} }
_ = resp.Body.Close()
if unifiedDelay { if unifiedDelay {
second := time.Now() start = time.Now()
resp, err = client.Do(req) resp, err = client.Do(req)
if err == nil { if err != nil {
return
}
}
_ = resp.Body.Close() _ = resp.Body.Close()
start = second
}
}
t = uint16(time.Since(start) / time.Millisecond) t = uint16(time.Since(start) / time.Millisecond)
return return
} }

View File

@@ -2,7 +2,7 @@ package inbound
import ( import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" M "github.com/sagernet/sing/common/metadata"
) )
// PacketAdapter is a UDP Packet adapter for socks/redir/tun // PacketAdapter is a UDP Packet adapter for socks/redir/tun
@@ -17,8 +17,8 @@ func (s *PacketAdapter) Metadata() *C.Metadata {
} }
// NewPacket is PacketAdapter generator // NewPacket is PacketAdapter generator
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter { func NewPacket(target M.Socksaddr, packet C.UDPPacket, source C.Type) *PacketAdapter {
metadata := parseSocksAddr(target) metadata := socksAddrToMetadata(target)
metadata.NetWork = C.UDP metadata.NetWork = C.UDP
metadata.Type = source metadata.Type = source
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil { if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {

View File

@@ -10,8 +10,26 @@ import (
"github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
M "github.com/sagernet/sing/common/metadata"
) )
func socksAddrToMetadata(addr M.Socksaddr) *C.Metadata {
metadata := &C.Metadata{}
switch addr.Family() {
case M.AddressFamilyIPv4:
metadata.AddrType = C.AtypIPv4
metadata.DstIP = addr.Addr
case M.AddressFamilyIPv6:
metadata.AddrType = C.AtypIPv6
metadata.DstIP = addr.Addr
case M.AddressFamilyFqdn:
metadata.AddrType = C.AtypDomainName
metadata.Host = addr.Fqdn
}
metadata.DstPort = strconv.Itoa(int(addr.Port))
return metadata
}
func parseSocksAddr(target socks5.Addr) *C.Metadata { func parseSocksAddr(target socks5.Addr) *C.Metadata {
metadata := &C.Metadata{ metadata := &C.Metadata{
AddrType: int(target[0]), AddrType: int(target[0]),

View File

@@ -4,12 +4,16 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/gofrs/uuid"
"net" "net"
"strings" "strings"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/gofrs/uuid"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
) )
type Base struct { type Base struct {
@@ -157,6 +161,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
type packetConn struct { type packetConn struct {
net.PacketConn net.PacketConn
nc N.PacketConn
chain C.Chain chain C.Chain
actualRemoteDestination string actualRemoteDestination string
} }
@@ -175,8 +180,22 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
c.chain = append(c.chain, a.Name()) c.chain = append(c.chain, a.Name())
} }
func (c *packetConn) ReadPacket(buffer *buf.Buffer) (addr M.Socksaddr, err error) {
return c.nc.ReadPacket(buffer)
}
func (c *packetConn) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
return c.nc.WritePacket(buffer, addr)
}
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
return &packetConn{pc, []string{a.Name()}, parseRemoteDestination(a.Addr())} var nc N.PacketConn
if n, isNc := pc.(N.PacketConn); isNc {
nc = n
} else {
nc = &bufio.PacketConnWrapper{PacketConn: pc}
}
return &packetConn{pc, nc, []string{a.Name()}, parseRemoteDestination(a.Addr())}
} }
func parseRemoteDestination(addr string) string { func parseRemoteDestination(addr string) string {

View File

@@ -4,6 +4,8 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net" "net"
@@ -42,31 +44,23 @@ type Hysteria struct {
*Base *Base
client *core.Client client *core.Client
clientTransport *transport.ClientTransport
} }
func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
hdc := hyDialerWithContext{ tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), hyDialer(func() (net.PacketConn, error) {
ctx: ctx,
hyDialer: func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...) return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
}, }))
}
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), &hdc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewConn(tcpConn, h), nil return NewConn(tcpConn, h), nil
} }
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
hdc := hyDialerWithContext{ udpConn, err := h.client.DialUDP(hyDialer(func() (net.PacketConn, error) {
ctx: ctx,
hyDialer: func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...) return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
}, }))
}
udpConn, err := h.client.DialUDP(&hdc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -79,8 +73,11 @@ type HysteriaOption struct {
Server string `proxy:"server"` Server string `proxy:"server"`
Port int `proxy:"port"` Port int `proxy:"port"`
Protocol string `proxy:"protocol,omitempty"` Protocol string `proxy:"protocol,omitempty"`
Up string `proxy:"up"` Up string `proxy:"up,omitempty"`
Down string `proxy:"down"` UpMbps int `proxy:"up_mbps,omitempty"`
Down string `proxy:"down,omitempty"`
DownMbps int `proxy:"down_mbps,omitempty"`
Auth string `proxy:"auth,omitempty"`
AuthString string `proxy:"auth_str,omitempty"` AuthString string `proxy:"auth_str,omitempty"`
Obfs string `proxy:"obfs,omitempty"` Obfs string `proxy:"obfs,omitempty"`
SNI string `proxy:"sni,omitempty"` SNI string `proxy:"sni,omitempty"`
@@ -95,16 +92,22 @@ type HysteriaOption struct {
func (c *HysteriaOption) Speed() (uint64, uint64, error) { func (c *HysteriaOption) Speed() (uint64, uint64, error) {
var up, down uint64 var up, down uint64
if len(c.Up) > 0 {
up = stringToBps(c.Up) up = stringToBps(c.Up)
if up == 0 { if up == 0 {
return 0, 0, fmt.Errorf("invaild upload speed: %s", c.Up) return 0, 0, errors.New("invalid speed format")
} }
} else {
up = uint64(c.UpMbps) * mbpsToBps
}
if len(c.Down) > 0 {
down = stringToBps(c.Down) down = stringToBps(c.Down)
if down == 0 { if down == 0 {
return 0, 0, fmt.Errorf("invaild download speed: %s", c.Down) return 0, 0, errors.New("invalid speed format")
}
} else {
down = uint64(c.DownMbps) * mbpsToBps
} }
return up, down, nil return up, down, nil
} }
@@ -118,7 +121,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
serverName := option.Server serverName := option.Server
if option.SNI != "" { if option.SNI != "" {
serverName = option.SNI serverName = option.Server
} }
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
ServerName: serverName, ServerName: serverName,
@@ -170,18 +173,21 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
if !quicConfig.DisablePathMTUDiscovery && pmtud_fix.DisablePathMTUDiscovery { if !quicConfig.DisablePathMTUDiscovery && pmtud_fix.DisablePathMTUDiscovery {
log.Infoln("hysteria: Path MTU Discovery is not yet supported on this platform") log.Infoln("hysteria: Path MTU Discovery is not yet supported on this platform")
} }
var auth []byte
var auth = []byte(option.AuthString) if option.Auth != "" {
authBytes, err := base64.StdEncoding.DecodeString(option.Auth)
if err != nil {
return nil, fmt.Errorf("hysteria %s parse auth error: %w", addr, err)
}
auth = authBytes
} else {
auth = []byte(option.AuthString)
}
var obfuscator obfs.Obfuscator var obfuscator obfs.Obfuscator
if len(option.Obfs) > 0 { if len(option.Obfs) > 0 {
obfuscator = obfs.NewXPlusObfuscator([]byte(option.Obfs)) obfuscator = obfs.NewXPlusObfuscator([]byte(option.Obfs))
} }
up, down, _ := option.Speed()
up, down, err := option.Speed()
if err != nil {
return nil, err
}
client, err := core.NewClient( client, err := core.NewClient(
addr, option.Protocol, auth, tlsConfig, quicConfig, clientTransport, up, down, func(refBPS uint64) congestion.CongestionControl { addr, option.Protocol, auth, tlsConfig, quicConfig, clientTransport, up, down, func(refBPS uint64) congestion.CongestionControl {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS)) return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
@@ -200,6 +206,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
rmark: option.RoutingMark, rmark: option.RoutingMark,
}, },
client: client, client: client,
clientTransport: clientTransport,
}, nil }, nil
} }
@@ -207,12 +214,6 @@ func stringToBps(s string) uint64 {
if s == "" { if s == "" {
return 0 return 0
} }
// when have not unit, use Mbps
if v, err := strconv.Atoi(s); err == nil {
return stringToBps(fmt.Sprintf("%d Mbps", v))
}
m := rateStringRegexp.FindStringSubmatch(s) m := rateStringRegexp.FindStringSubmatch(s)
if m == nil { if m == nil {
return 0 return 0
@@ -262,15 +263,8 @@ func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return return
} }
type hyDialerWithContext struct { type hyDialer func() (net.PacketConn, error)
hyDialer func() (net.PacketConn, error)
ctx context.Context
}
func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) { func (h hyDialer) ListenPacket() (net.PacketConn, error) {
return h.hyDialer() return h()
}
func (h *hyDialerWithContext) Context() context.Context {
return h.ctx
} }

View File

@@ -7,7 +7,6 @@ import (
"net" "net"
"strconv" "strconv"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/common/structure"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
@@ -16,21 +15,14 @@ import (
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
"github.com/sagernet/sing-shadowsocks" "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowimpl" "github.com/sagernet/sing-shadowsocks/shadowimpl"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/uot"
) )
func init() {
buf.DefaultAllocator = pool.DefaultAllocator
}
type ShadowSocks struct { type ShadowSocks struct {
*Base *Base
method shadowsocks.Method method shadowsocks.Method
option *ShadowSocksOption
// obfs // obfs
obfsMode string obfsMode string
obfsOption *simpleObfsOption obfsOption *simpleObfsOption
@@ -47,7 +39,6 @@ type ShadowSocksOption struct {
UDP bool `proxy:"udp,omitempty"` UDP bool `proxy:"udp,omitempty"`
Plugin string `proxy:"plugin,omitempty"` Plugin string `proxy:"plugin,omitempty"`
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"`
} }
type simpleObfsOption struct { type simpleObfsOption struct {
@@ -80,10 +71,6 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
} }
} }
if metadata.NetWork == C.UDP && ss.option.UDPOverTCP {
metadata.Host = uot.UOTMagicAddress
metadata.DstPort = "443"
}
return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
} }
@@ -103,13 +90,6 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, op
// ListenPacketContext implements C.ProxyAdapter // ListenPacketContext implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
if ss.option.UDPOverTCP {
tcpConn, err := ss.DialContext(ctx, metadata, opts...)
if err != nil {
return nil, err
}
return newPacketConn(uot.NewClientConn(tcpConn), ss), nil
}
pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...) pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -124,19 +104,6 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta
return newPacketConn(pc, ss), nil return newPacketConn(pc, ss), nil
} }
// ListenPacketOnStreamConn implements C.ProxyAdapter
func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
if ss.option.UDPOverTCP {
return newPacketConn(uot.NewClientConn(c), ss), nil
}
return nil, errors.New("no support")
}
// SupportUOT implements C.ProxyAdapter
func (ss *ShadowSocks) SupportUOT() bool {
return ss.option.UDPOverTCP
}
func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
method, err := shadowimpl.FetchMethod(option.Cipher, option.Password) method, err := shadowimpl.FetchMethod(option.Cipher, option.Password)
@@ -194,7 +161,6 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
}, },
method: method, method: method,
option: &option,
obfsMode: obfsMode, obfsMode: obfsMode,
v2rayOption: v2rayOption, v2rayOption: v2rayOption,
obfsOption: obfsOption, obfsOption: obfsOption,

View File

@@ -3,7 +3,6 @@ package outbound
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
xtls "github.com/xtls/go"
"net" "net"
"strconv" "strconv"
"sync" "sync"
@@ -12,6 +11,7 @@ import (
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
xtls "github.com/xtls/go"
) )
var ( var (

View File

@@ -6,13 +6,13 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/common/convert"
"io" "io"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
"sync" "sync"
"github.com/Dreamacro/clash/common/convert"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
@@ -70,15 +70,16 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
Path: v.option.WSOpts.Path, Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData, MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
Headers: http.Header{},
} }
if len(v.option.WSOpts.Headers) != 0 { if len(v.option.WSOpts.Headers) != 0 {
header := http.Header{}
for key, value := range v.option.WSOpts.Headers { for key, value := range v.option.WSOpts.Headers {
wsOpts.Headers.Add(key, value) header.Add(key, value)
} }
wsOpts.Headers = header
} }
if v.option.TLS {
wsOpts.TLS = true wsOpts.TLS = true
wsOpts.TLSConfig = &tls.Config{ wsOpts.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS12,
@@ -90,13 +91,10 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
wsOpts.TLSConfig.ServerName = v.option.ServerName wsOpts.TLSConfig.ServerName = v.option.ServerName
} else if host := wsOpts.Headers.Get("Host"); host != "" { } else if host := wsOpts.Headers.Get("Host"); host != "" {
wsOpts.TLSConfig.ServerName = host wsOpts.TLSConfig.ServerName = host
}
} else { } else {
if host := wsOpts.Headers.Get("Host"); host == "" {
wsOpts.Headers.Set("Host", convert.RandHost()) wsOpts.Headers.Set("Host", convert.RandHost())
convert.SetUserAgent(wsOpts.Headers) convert.SetUserAgent(wsOpts.Headers)
} }
}
c, err = vmess.StreamWebsocketConn(c, wsOpts) c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http": case "http":
// readability first, so just copy default TLS logic // readability first, so just copy default TLS logic

View File

@@ -9,17 +9,13 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"sync"
"github.com/Dreamacro/clash/common/convert" "github.com/Dreamacro/clash/common/convert"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/gun"
clashVMess "github.com/Dreamacro/clash/transport/vmess" "github.com/Dreamacro/clash/transport/vmess"
"github.com/sagernet/sing-vmess"
"github.com/sagernet/sing-vmess/packetaddr"
M "github.com/sagernet/sing/common/metadata"
) )
type Vmess struct { type Vmess struct {
@@ -50,8 +46,10 @@ type VmessOption struct {
HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"`
GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"`
WSOpts WSOptions `proxy:"ws-opts,omitempty"` WSOpts WSOptions `proxy:"ws-opts,omitempty"`
PacketAddr bool `proxy:"packet-addr,omitempty"`
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"` // TODO: compatible with VMESS WS older version configurations
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
WSPath string `proxy:"ws-path,omitempty"`
} }
type HTTPOptions struct { type HTTPOptions struct {
@@ -83,13 +81,13 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
case "ws": case "ws":
host, port, _ := net.SplitHostPort(v.addr) host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &clashVMess.WebsocketConfig{ wsOpts := &vmess.WebsocketConfig{
Host: host, Host: host,
Port: port, Port: port,
Path: v.option.WSOpts.Path, Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData, MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
Headers: http.Header{}, Headers: make(http.Header),
} }
if len(v.option.WSOpts.Headers) != 0 { if len(v.option.WSOpts.Headers) != 0 {
@@ -111,17 +109,15 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
wsOpts.TLSConfig.ServerName = host wsOpts.TLSConfig.ServerName = host
} }
} else { } else {
if host := wsOpts.Headers.Get("Host"); host == "" {
wsOpts.Headers.Set("Host", convert.RandHost()) wsOpts.Headers.Set("Host", convert.RandHost())
convert.SetUserAgent(wsOpts.Headers) convert.SetUserAgent(wsOpts.Headers)
} }
} c, err = vmess.StreamWebsocketConn(c, wsOpts)
c, err = clashVMess.StreamWebsocketConn(c, wsOpts)
case "http": case "http":
// readability first, so just copy default TLS logic // readability first, so just copy default TLS logic
if v.option.TLS { if v.option.TLS {
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
tlsOpts := &clashVMess.TLSConfig{ tlsOpts := &vmess.TLSConfig{
Host: host, Host: host,
SkipCertVerify: v.option.SkipCertVerify, SkipCertVerify: v.option.SkipCertVerify,
} }
@@ -130,24 +126,27 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts.Host = v.option.ServerName tlsOpts.Host = v.option.ServerName
} }
c, err = clashVMess.StreamTLSConn(c, tlsOpts) c, err = vmess.StreamTLSConn(c, tlsOpts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else {
http.Header(v.option.HTTPOpts.Headers).Set("Host", convert.RandHost())
convert.SetUserAgent(v.option.HTTPOpts.Headers)
} }
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
httpOpts := &clashVMess.HTTPConfig{ httpOpts := &vmess.HTTPConfig{
Host: host, Host: host,
Method: v.option.HTTPOpts.Method, Method: v.option.HTTPOpts.Method,
Path: v.option.HTTPOpts.Path, Path: v.option.HTTPOpts.Path,
Headers: v.option.HTTPOpts.Headers, Headers: v.option.HTTPOpts.Headers,
} }
c = clashVMess.StreamHTTPConn(c, httpOpts) c = vmess.StreamHTTPConn(c, httpOpts)
case "h2": case "h2":
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
tlsOpts := clashVMess.TLSConfig{ tlsOpts := vmess.TLSConfig{
Host: host, Host: host,
SkipCertVerify: v.option.SkipCertVerify, SkipCertVerify: v.option.SkipCertVerify,
NextProtos: []string{"h2"}, NextProtos: []string{"h2"},
@@ -157,24 +156,24 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts.Host = v.option.ServerName tlsOpts.Host = v.option.ServerName
} }
c, err = clashVMess.StreamTLSConn(c, &tlsOpts) c, err = vmess.StreamTLSConn(c, &tlsOpts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
h2Opts := &clashVMess.H2Config{ h2Opts := &vmess.H2Config{
Hosts: v.option.HTTP2Opts.Host, Hosts: v.option.HTTP2Opts.Host,
Path: v.option.HTTP2Opts.Path, Path: v.option.HTTP2Opts.Path,
} }
c, err = clashVMess.StreamH2Conn(c, h2Opts) c, err = vmess.StreamH2Conn(c, h2Opts)
case "grpc": case "grpc":
c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig)
default: default:
// handle TLS // handle TLS
if v.option.TLS { if v.option.TLS {
host, _, _ := net.SplitHostPort(v.addr) host, _, _ := net.SplitHostPort(v.addr)
tlsOpts := &clashVMess.TLSConfig{ tlsOpts := &vmess.TLSConfig{
Host: host, Host: host,
SkipCertVerify: v.option.SkipCertVerify, SkipCertVerify: v.option.SkipCertVerify,
} }
@@ -183,18 +182,15 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
tlsOpts.Host = v.option.ServerName tlsOpts.Host = v.option.ServerName
} }
c, err = clashVMess.StreamTLSConn(c, tlsOpts) c, err = vmess.StreamTLSConn(c, tlsOpts)
} }
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
if metadata.NetWork == C.UDP {
return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) return v.client.StreamConn(c, parseVmessAddr(metadata))
} else {
return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
}
} }
// DialContext implements C.ProxyAdapter // DialContext implements C.ProxyAdapter
@@ -207,7 +203,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
} }
defer safeConnClose(c, err) defer safeConnClose(c, err)
c, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -237,11 +233,6 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
metadata.DstIP = ip metadata.DstIP = ip
} }
if v.option.PacketAddr {
metadata.Host = packetaddr.SeqPacketMagicAddress
metadata.DstPort = "443"
}
var c net.Conn var c net.Conn
// gun transport // gun transport
if v.transport != nil && len(opts) == 0 { if v.transport != nil && len(opts) == 0 {
@@ -251,7 +242,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
} }
defer safeConnClose(c, err) defer safeConnClose(c, err)
c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
} else { } else {
c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...) c, err = dialer.DialContext(ctx, "tcp", v.addr, v.Base.DialOptions(opts...)...)
if err != nil { if err != nil {
@@ -267,21 +258,11 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
return nil, fmt.Errorf("new vmess client error: %v", err) return nil, fmt.Errorf("new vmess client error: %v", err)
} }
if v.option.PacketAddr { return v.ListenPacketOnStreamConn(c, metadata)
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindClient(c)}, v), nil
} else if pc, ok := c.(net.PacketConn); ok {
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
}
return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil
} }
// ListenPacketOnStreamConn implements C.ProxyAdapter // ListenPacketOnStreamConn implements C.ProxyAdapter
func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
if v.option.PacketAddr {
return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindClient(c)}, v), nil
} else if pc, ok := c.(net.PacketConn); ok {
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
}
return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil
} }
@@ -292,11 +273,14 @@ func (v *Vmess) SupportUOT() bool {
func NewVmess(option VmessOption) (*Vmess, error) { func NewVmess(option VmessOption) (*Vmess, error) {
security := strings.ToLower(option.Cipher) security := strings.ToLower(option.Cipher)
var options []vmess.ClientOption client, err := vmess.NewClient(vmess.Config{
if option.AuthenticatedLength { UUID: option.UUID,
options = append(options, vmess.ClientWithAuthenticatedLength()) AlterID: uint16(option.AlterID),
} Security: security,
client, err := vmess.NewClient(option.UUID, security, option.AlterID, options...) HostName: option.Server,
Port: strconv.Itoa(option.Port),
IsAead: option.AlterID == 0,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -355,29 +339,44 @@ func NewVmess(option VmessOption) (*Vmess, error) {
v.gunConfig = gunConfig v.gunConfig = gunConfig
v.transport = gun.NewHTTP2Client(dialFn, tlsConfig) v.transport = gun.NewHTTP2Client(dialFn, tlsConfig)
} }
return v, nil return v, nil
} }
type threadSafePacketConn struct { func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
net.PacketConn var addrType byte
access sync.Mutex var addr []byte
switch metadata.AddrType {
case C.AtypIPv4:
addrType = byte(vmess.AtypIPv4)
addr = make([]byte, net.IPv4len)
copy(addr[:], metadata.DstIP.AsSlice())
case C.AtypIPv6:
addrType = byte(vmess.AtypIPv6)
addr = make([]byte, net.IPv6len)
copy(addr[:], metadata.DstIP.AsSlice())
case C.AtypDomainName:
addrType = byte(vmess.AtypDomainName)
addr = make([]byte, len(metadata.Host)+1)
addr[0] = byte(len(metadata.Host))
copy(addr[1:], []byte(metadata.Host))
} }
func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
c.access.Lock() return &vmess.DstAddr{
defer c.access.Unlock() UDP: metadata.NetWork == C.UDP,
return c.PacketConn.WriteTo(b, addr) AddrType: addrType,
Addr: addr,
Port: uint(port),
}
} }
type vmessPacketConn struct { type vmessPacketConn struct {
net.Conn net.Conn
rAddr net.Addr rAddr net.Addr
access sync.Mutex
} }
func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
uc.access.Lock()
defer uc.access.Unlock()
return uc.Conn.Write(b) return uc.Conn.Write(b)
} }

View File

@@ -4,11 +4,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/constant/provider"
"time"
) )
type Fallback struct { type Fallback struct {

View File

@@ -3,16 +3,17 @@ package outboundgroup
import ( import (
"context" "context"
"fmt" "fmt"
"sync"
"time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
types "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/dlclark/regexp2" "github.com/dlclark/regexp2"
"go.uber.org/atomic" "go.uber.org/atomic"
"sync"
"time"
) )
type GroupBase struct { type GroupBase struct {
@@ -111,11 +112,11 @@ func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16
wg.Add(1) wg.Add(1)
go func() { go func() {
delay, err := proxy.URLTest(ctx, url) delay, err := proxy.URLTest(ctx, url)
if err == nil {
lock.Lock() lock.Lock()
if err == nil {
mp[proxy.Name()] = delay mp[proxy.Name()] = delay
lock.Unlock()
} }
lock.Unlock()
wg.Done() wg.Done()
}() }()

View File

@@ -5,16 +5,15 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/common/cache"
"net" "net"
"time" "time"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/common/murmur3" "github.com/Dreamacro/clash/common/murmur3"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/constant/provider"
"golang.org/x/net/publicsuffix" "golang.org/x/net/publicsuffix"
) )

View File

@@ -43,7 +43,6 @@ func (f *fetcher[V]) Initial() (V, error) {
buf []byte buf []byte
err error err error
isLocal bool isLocal bool
forceUpdate bool
) )
if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil { if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil {
@@ -52,8 +51,10 @@ func (f *fetcher[V]) Initial() (V, error) {
f.updatedAt = &modTime f.updatedAt = &modTime
isLocal = true isLocal = true
if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { 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()) defer func() {
forceUpdate = true log.Infoln("[Provider] %s's proxies not updated for a long time, force refresh", f.Name())
go f.Update()
}()
} }
} else { } else {
buf, err = f.vehicle.Read() buf, err = f.vehicle.Read()
@@ -63,21 +64,7 @@ func (f *fetcher[V]) Initial() (V, error) {
return getZero[V](), err return getZero[V](), err
} }
var proxies V proxies, err := f.parser(buf)
if forceUpdate {
var forceBuf []byte
if forceBuf, err = f.vehicle.Read(); err == nil {
if proxies, err = f.parser(forceBuf); err == nil {
isLocal = false
buf = forceBuf
}
}
}
if err != nil || !forceUpdate {
proxies, err = f.parser(buf)
}
if err != nil { if err != nil {
if !isLocal { if !isLocal {
return getZero[V](), err return getZero[V](), err
@@ -202,7 +189,6 @@ func newFetcher[V any](name string, interval time.Duration, vehicle types.Vehicl
parser: parser, parser: parser,
done: make(chan struct{}, 1), done: make(chan struct{}, 1),
onUpdate: onUpdate, onUpdate: onUpdate,
interval: interval,
} }
} }

View File

@@ -2,12 +2,10 @@ package provider
import ( import (
"context" "context"
"github.com/Dreamacro/clash/common/singledo"
"time" "time"
"github.com/Dreamacro/clash/common/batch" "github.com/Dreamacro/clash/common/batch"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic" "go.uber.org/atomic"
) )
@@ -27,7 +25,6 @@ type HealthCheck struct {
lazy bool lazy bool
lastTouch *atomic.Int64 lastTouch *atomic.Int64
done chan struct{} done chan struct{}
singleDo *singledo.Single[struct{}]
} }
func (hc *HealthCheck) process() { func (hc *HealthCheck) process() {
@@ -65,7 +62,6 @@ func (hc *HealthCheck) touch() {
} }
func (hc *HealthCheck) check() { func (hc *HealthCheck) check() {
_, _, _ = hc.singleDo.Do(func() (struct{}, error) {
b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10)) b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10))
for _, proxy := range hc.proxies { for _, proxy := range hc.proxies {
p := proxy p := proxy
@@ -76,10 +72,7 @@ func (hc *HealthCheck) check() {
return false, nil return false, nil
}) })
} }
b.Wait() b.Wait()
return struct{}{}, nil
})
} }
func (hc *HealthCheck) close() { func (hc *HealthCheck) close() {
@@ -94,6 +87,5 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *He
lazy: lazy, lazy: lazy,
lastTouch: atomic.NewInt64(0), lastTouch: atomic.NewInt64(0),
done: make(chan struct{}, 1), done: make(chan struct{}, 1),
singleDo: singledo.NewSingle[struct{}](time.Second),
} }
} }

View File

@@ -4,16 +4,15 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/common/convert"
"github.com/dlclark/regexp2"
"math" "math"
"runtime" "runtime"
"time" "time"
"github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/common/convert"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
types "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider"
"github.com/dlclark/regexp2"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )

View File

@@ -2,12 +2,13 @@ package provider
import ( import (
"context" "context"
netHttp "github.com/Dreamacro/clash/component/http"
types "github.com/Dreamacro/clash/constant/provider"
"io" "io"
"net/http" "net/http"
"os" "os"
"time" "time"
netHttp "github.com/Dreamacro/clash/component/http"
types "github.com/Dreamacro/clash/constant/provider"
) )
type FileVehicle struct { type FileVehicle struct {

View File

@@ -14,7 +14,6 @@ func ExecCmd(cmdStr string) (string, error) {
cmd = exec.Command(args[0]) cmd = exec.Command(args[0])
} else { } else {
cmd = exec.Command(args[0], args[1:]...) cmd = exec.Command(args[0], args[1:]...)
} }
prepareBackgroundCommand(cmd) prepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput() out, err := cmd.CombinedOutput()

View File

@@ -7,5 +7,4 @@ import (
) )
func prepareBackgroundCommand(cmd *exec.Cmd) { func prepareBackgroundCommand(cmd *exec.Cmd) {
} }

View File

@@ -10,24 +10,34 @@ import (
"strings" "strings"
) )
var encRaw = base64.RawStdEncoding
var enc = base64.StdEncoding var enc = base64.StdEncoding
func DecodeBase64(buf []byte) []byte { func DecodeBase64(buf []byte) ([]byte, error) {
dBuf := make([]byte, encRaw.DecodedLen(len(buf))) dBuf := make([]byte, enc.DecodedLen(len(buf)))
n, err := encRaw.Decode(dBuf, buf) n, err := enc.Decode(dBuf, buf)
if err != nil { if err != nil {
n, err = enc.Decode(dBuf, buf) return nil, err
}
return dBuf[:n], nil
}
// DecodeBase64StringToString decode base64 string to string
func DecodeBase64StringToString(s string) (string, error) {
dBuf, err := enc.DecodeString(s)
if err != nil { if err != nil {
return buf return "", err
} }
}
return dBuf[:n] return string(dBuf), nil
} }
// ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config // ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config
func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
data := DecodeBase64(buf) data, err := DecodeBase64(buf)
if err != nil {
data = buf
}
arr := strings.Split(string(data), "\n") arr := strings.Split(string(data), "\n")
@@ -66,16 +76,8 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
hysteria["alpn"] = query.Get("alpn") hysteria["alpn"] = query.Get("alpn")
hysteria["auth_str"] = query.Get("auth") hysteria["auth_str"] = query.Get("auth")
hysteria["protocol"] = query.Get("protocol") hysteria["protocol"] = query.Get("protocol")
up := query.Get("up") hysteria["down_mbps"], _ = strconv.Atoi(query.Get("downmbps"))
down := query.Get("down") hysteria["up_mbps"], _ = strconv.Atoi(query.Get("upmbps"))
if up == "" {
up = query.Get("upmbps")
}
if down == "" {
down = query.Get("downmbps")
}
hysteria["down"] = down
hysteria["up"] = up
hysteria["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure")) hysteria["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure"))
proxies = append(proxies, hysteria) proxies = append(proxies, hysteria)
@@ -114,6 +116,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
headers := make(map[string]any) headers := make(map[string]any)
wsOpts := make(map[string]any) wsOpts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent() headers["User-Agent"] = RandUserAgent()
wsOpts["path"] = query.Get("path") wsOpts["path"] = query.Get("path")
@@ -147,11 +150,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
vless["uuid"] = urlVless.User.Username() vless["uuid"] = urlVless.User.Username()
vless["udp"] = true vless["udp"] = true
vless["skip-cert-verify"] = false vless["skip-cert-verify"] = false
vless["tls"] = false
tls := strings.ToLower(query.Get("security"))
if strings.Contains(tls, "tls") {
vless["tls"] = true
}
sni := query.Get("sni") sni := query.Get("sni")
if sni != "" { if sni != "" {
vless["servername"] = sni vless["servername"] = sni
@@ -163,53 +162,49 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
} }
network := strings.ToLower(query.Get("type")) network := strings.ToLower(query.Get("type"))
if network != "" {
fakeType := strings.ToLower(query.Get("headerType")) fakeType := strings.ToLower(query.Get("headerType"))
if fakeType == "http" { if network == "tcp" && fakeType == "http" {
network = "http" network = "http"
} else if network == "http" { }
if network == "http" {
network = "h2" network = "h2"
} }
vless["network"] = network vless["network"] = network
}
switch network { switch network {
case "tcp": case "http":
if fakeType != "none" {
headers := make(map[string]any) headers := make(map[string]any)
httpOpts := make(map[string]any) httpOpts := make(map[string]any)
httpOpts["path"] = []string{"/"}
if query.Get("host") != "" {
headers["Host"] = []string{query.Get("host")}
}
if query.Get("method") != "" { if query.Get("method") != "" {
httpOpts["method"] = query.Get("method") httpOpts["method"] = query.Get("method")
} }
if query.Get("path") != "" { if query.Get("path") != "" {
httpOpts["path"] = []string{query.Get("path")} httpOpts["path"] = query.Get("path")
} }
headers["User-Agent"] = RandUserAgent()
httpOpts["headers"] = headers httpOpts["headers"] = headers
vless["http-opts"] = httpOpts
}
case "http": vless["http-opts"] = httpOpts
case "h2":
headers := make(map[string]any) headers := make(map[string]any)
h2Opts := make(map[string]any) h2Opts := make(map[string]any)
h2Opts["path"] = []string{"/"}
if query.Get("path") != "" { headers["User-Agent"] = RandUserAgent()
h2Opts["path"] = []string{query.Get("path")} h2Opts["path"] = query.Get("path")
}
if query.Get("host") != "" {
h2Opts["host"] = []string{query.Get("host")}
}
h2Opts["headers"] = headers h2Opts["headers"] = headers
vless["h2-opts"] = h2Opts vless["h2-opts"] = h2Opts
case "ws": case "ws":
headers := make(map[string]any) headers := make(map[string]any)
wsOpts := make(map[string]any) wsOpts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent() headers["User-Agent"] = RandUserAgent()
headers["Host"] = query.Get("host")
wsOpts["path"] = query.Get("path") wsOpts["path"] = query.Get("path")
wsOpts["headers"] = headers wsOpts["headers"] = headers
@@ -224,7 +219,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
proxies = append(proxies, vless) proxies = append(proxies, vless)
case "vmess": case "vmess":
dcBuf, err := encRaw.DecodeString(body) dcBuf, err := enc.DecodeString(body)
if err != nil { if err != nil {
continue continue
} }
@@ -247,28 +242,23 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
vmess["alterId"] = values["aid"] vmess["alterId"] = values["aid"]
vmess["cipher"] = "auto" vmess["cipher"] = "auto"
vmess["udp"] = true vmess["udp"] = true
vmess["tls"] = false
vmess["skip-cert-verify"] = false vmess["skip-cert-verify"] = false
if values["cipher"] != nil && values["cipher"] != "" {
vmess["cipher"] = values["cipher"]
}
sni := values["sni"] sni := values["sni"]
if sni != "" { if sni != "" {
vmess["servername"] = sni vmess["sni"] = sni
} }
host := values["host"]
network := strings.ToLower(values["net"].(string)) network := strings.ToLower(values["net"].(string))
if values["type"] == "http" {
network = "http"
} else if network == "http" {
network = "h2"
}
vmess["network"] = network vmess["network"] = network
tls := strings.ToLower(values["tls"].(string)) tls := strings.ToLower(values["tls"].(string))
if strings.Contains(tls, "tls") { if tls != "" && tls != "0" && tls != "null" {
if host != nil {
vmess["servername"] = host
}
vmess["tls"] = true vmess["tls"] = true
} }
@@ -276,13 +266,11 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
case "http": case "http":
headers := make(map[string]any) headers := make(map[string]any)
httpOpts := make(map[string]any) httpOpts := make(map[string]any)
if values["host"] != "" && values["host"] != nil {
headers["Host"] = []string{values["host"].(string)} // headers["Host"] = RandHost()
} headers["User-Agent"] = RandUserAgent()
httpOpts["path"] = []string{"/"} httpOpts["method"] = values["method"]
if values["path"] != "" && values["path"] != nil { httpOpts["path"] = values["path"]
httpOpts["path"] = []string{values["path"].(string)}
}
httpOpts["headers"] = headers httpOpts["headers"] = headers
vmess["http-opts"] = httpOpts vmess["http-opts"] = httpOpts
@@ -290,10 +278,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
case "h2": case "h2":
headers := make(map[string]any) headers := make(map[string]any)
h2Opts := make(map[string]any) h2Opts := make(map[string]any)
if values["host"] != "" && values["host"] != nil {
headers["Host"] = []string{values["host"].(string)}
}
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
h2Opts["path"] = values["path"] h2Opts["path"] = values["path"]
h2Opts["headers"] = headers h2Opts["headers"] = headers
@@ -302,14 +289,15 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
case "ws": case "ws":
headers := make(map[string]any) headers := make(map[string]any)
wsOpts := make(map[string]any) wsOpts := make(map[string]any)
wsOpts["path"] = []string{"/"}
if values["host"] != "" && values["host"] != nil { headers["Host"] = RandHost()
headers["Host"] = values["host"].(string) headers["User-Agent"] = RandUserAgent()
}
if values["path"] != "" && values["path"] != nil { if values["path"] != nil {
wsOpts["path"] = values["path"].(string) wsOpts["path"] = values["path"]
} }
wsOpts["headers"] = headers wsOpts["headers"] = headers
vmess["ws-opts"] = wsOpts vmess["ws-opts"] = wsOpts
case "grpc": case "grpc":
@@ -330,7 +318,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
port := urlSS.Port() port := urlSS.Port()
if port == "" { if port == "" {
dcBuf, err := encRaw.DecodeString(urlSS.Host) dcBuf, err := enc.DecodeString(urlSS.Host)
if err != nil { if err != nil {
continue continue
} }
@@ -347,10 +335,11 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
) )
if password, found = urlSS.User.Password(); !found { if password, found = urlSS.User.Password(); !found {
dcBuf, _ := enc.DecodeString(cipher) dcBuf, err := enc.DecodeString(cipher)
if !strings.Contains(string(dcBuf), "2022-blake3") { if err != nil {
dcBuf, _ = encRaw.DecodeString(cipher) continue
} }
cipher, password, found = strings.Cut(string(dcBuf), ":") cipher, password, found = strings.Cut(string(dcBuf), ":")
if !found { if !found {
continue continue
@@ -365,19 +354,11 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
ss["port"] = urlSS.Port() ss["port"] = urlSS.Port()
ss["cipher"] = cipher ss["cipher"] = cipher
ss["password"] = password ss["password"] = password
query := urlSS.Query()
ss["udp"] = true ss["udp"] = true
if strings.Contains(query.Get("plugin"), "obfs") {
obfsParams := strings.Split(query.Get("plugin"), ";")
ss["plugin"] = "obfs"
ss["plugin-opts"] = map[string]any{
"host": obfsParams[2][10:],
"mode": obfsParams[1][5:],
}
}
proxies = append(proxies, ss) proxies = append(proxies, ss)
case "ssr": case "ssr":
dcBuf, err := encRaw.DecodeString(body) dcBuf, err := enc.DecodeString(body)
if err != nil { if err != nil {
continue continue
} }
@@ -449,7 +430,7 @@ func urlSafe(data string) string {
} }
func decodeUrlSafe(data string) string { func decodeUrlSafe(data string) string {
dcBuf, err := base64.RawURLEncoding.DecodeString(data) dcBuf, err := base64.URLEncoding.DecodeString(data)
if err != nil { if err != nil {
return "" return ""
} }

View File

@@ -6,9 +6,15 @@ import (
"errors" "errors"
"math/bits" "math/bits"
"sync" "sync"
"github.com/sagernet/sing/common/buf"
) )
var DefaultAllocator = NewAllocator() var defaultAllocator = NewAllocator()
func init() {
buf.DefaultAllocator = defaultAllocator
}
// Allocator for incoming frames, optimized to prevent overwriting after zeroing // Allocator for incoming frames, optimized to prevent overwriting after zeroing
type Allocator struct { type Allocator struct {

View File

@@ -13,9 +13,9 @@ const (
) )
func Get(size int) []byte { func Get(size int) []byte {
return DefaultAllocator.Get(size) return defaultAllocator.Get(size)
} }
func Put(buf []byte) error { func Put(buf []byte) error {
return DefaultAllocator.Put(buf) return defaultAllocator.Put(buf)
} }

View File

@@ -1,9 +1,10 @@
package utils package utils
import ( import (
"github.com/gofrs/uuid"
"reflect" "reflect"
"testing" "testing"
"github.com/gofrs/uuid"
) )
func TestUUIDMap(t *testing.T) { func TestUUIDMap(t *testing.T) {

View File

@@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/common/nnip"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"github.com/insomniacslk/dhcp/dhcpv4" "github.com/insomniacslk/dhcp/dhcpv4"
) )

View File

@@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@@ -4,10 +4,11 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/component/resolver"
"net" "net"
"net/netip" "net/netip"
"sync" "sync"
"github.com/Dreamacro/clash/component/resolver"
) )
var ( var (
@@ -56,10 +57,6 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
o(cfg) o(cfg)
} }
if DisableIPv6 {
network = "udp4"
}
lc := &net.ListenConfig{} lc := &net.ListenConfig{}
if cfg.interfaceName != "" { if cfg.interfaceName != "" {
addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address) addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address)
@@ -170,10 +167,7 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt
go startRacer(ctx, network+"4", host, opt.direct, false) go startRacer(ctx, network+"4", host, opt.direct, false)
go startRacer(ctx, network+"6", host, opt.direct, true) go startRacer(ctx, network+"6", host, opt.direct, true)
count := 2 for res := range results {
for i := 0; i < count; i++ {
select {
case res := <-results:
if res.error == nil { if res.error == nil {
return res.Conn, nil return res.Conn, nil
} }
@@ -193,9 +187,6 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt
return nil, primary.error return nil, primary.error
} }
} }
case <-ctx.Done():
break
}
} }
return nil, errors.New("never touched") return nil, errors.New("never touched")
@@ -230,6 +221,7 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
} }
results := make(chan dialResult) results := make(chan dialResult)
tcpRacer := func(ctx context.Context, ip netip.Addr) { tcpRacer := func(ctx context.Context, ip netip.Addr) {
result := dialResult{ip: ip} result := dialResult{ip: ip}
@@ -256,13 +248,13 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
} }
connCount := len(ips) connCount := len(ips)
for i := 0; i < connCount; i++ { for res := range results {
select { connCount--
case res := <-results:
if res.error == nil { if res.error == nil {
return res.Conn, nil return res.Conn, nil
} }
case <-ctx.Done():
if connCount == 0 {
break break
} }
} }

View File

@@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/component/trie"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
) )

View File

@@ -3,10 +3,10 @@ package geodata
import ( import (
"errors" "errors"
"fmt" "fmt"
C "github.com/Dreamacro/clash/constant"
"strings" "strings"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
) )

View File

@@ -1,52 +0,0 @@
package geodata
import (
"fmt"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"io"
"net/http"
"os"
)
var initFlag bool
func InitGeoSite() error {
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
log.Infoln("Can't find GeoSite.dat, start download")
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
log.Infoln("Download GeoSite.dat finish")
}
if !initFlag {
if err := Verify(C.GeositeName); err != nil {
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
if err := os.Remove(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
}
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
}
initFlag = true
}
return nil
}
func downloadGeoSite(path string) (err error) {
resp, err := http.Get(C.GeoSiteUrl)
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}

View File

@@ -329,7 +329,6 @@ func NewGeoIPMatcher(geoip *GeoIP) (*GeoIPMatcher, error) {
} }
func (m *MultiGeoIPMatcher) ApplyIp(ip net.IP) bool { func (m *MultiGeoIPMatcher) ApplyIp(ip net.IP) bool {
for _, matcher := range m.matchers { for _, matcher := range m.matchers {
if matcher.Match(ip) { if matcher.Match(ip) {
return true return true

View File

@@ -7,10 +7,11 @@
package router package router
import ( import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
sync "sync" sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
) )
const ( const (

View File

@@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )

View File

@@ -2,6 +2,7 @@ package geodata
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
) )

View File

@@ -2,14 +2,15 @@ package http
import ( import (
"context" "context"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/log"
"io" "io"
"net" "net"
"net/http" "net/http"
URL "net/url" URL "net/url"
"strings" "strings"
"time" "time"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/log"
) )
const ( const (
@@ -60,5 +61,4 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st
client := http.Client{Transport: transport} client := http.Client{Transport: transport}
return client.Do(req) return client.Do(req)
} }

View File

@@ -1,11 +1,11 @@
package mmdb package mmdb
import ( import (
"github.com/oschwald/geoip2-golang"
"sync" "sync"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/oschwald/geoip2-golang"
) )
var ( var (

View File

@@ -2,10 +2,11 @@ package process
import ( import (
"errors" "errors"
"github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant"
"net" "net"
"net/netip" "net/netip"
"github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant"
) )
var ( var (

View File

@@ -7,7 +7,6 @@ import (
"unsafe" "unsafe"
"github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/common/nnip"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/common/nnip"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )

View File

@@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/component/profile" "github.com/Dreamacro/clash/component/profile"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
) )

View File

@@ -173,7 +173,7 @@ func ResolveAllIPv4WithResolver(host string, r Resolver) ([]netip.Addr, error) {
ip, err := netip.ParseAddr(host) ip, err := netip.ParseAddr(host)
if err == nil { if err == nil {
if ip.Is4() || ip.Is4In6() { if ip.Is4() {
return []netip.Addr{ip}, nil return []netip.Addr{ip}, nil
} }
return []netip.Addr{}, ErrIPVersion return []netip.Addr{}, ErrIPVersion

View File

@@ -2,18 +2,17 @@ package sniffer
import ( import (
"errors" "errors"
"github.com/Dreamacro/clash/constant/sniffer"
"net" "net"
"net/netip" "net/netip"
"strconv" "strconv"
"time" "time"
"github.com/Dreamacro/clash/component/trie"
CN "github.com/Dreamacro/clash/common/net" CN "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
) )
@@ -143,7 +142,8 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) {
} }
func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTrie[bool], func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTrie[bool],
skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16]) (*SnifferDispatcher, error) { skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16],
) (*SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{ dispatcher := SnifferDispatcher{
enable: true, enable: true,
foreDomain: forceDomain, foreDomain: forceDomain,

View File

@@ -3,9 +3,10 @@ package sniffer
import ( import (
"bytes" "bytes"
"errors" "errors"
C "github.com/Dreamacro/clash/constant"
"net" "net"
"strings" "strings"
C "github.com/Dreamacro/clash/constant"
) )
var ( var (

View File

@@ -13,8 +13,7 @@ var (
errNotClientHello = errors.New("not client hello") errNotClientHello = errors.New("not client hello")
) )
type TLSSniffer struct { type TLSSniffer struct{}
}
func (tls *TLSSniffer) Protocol() string { func (tls *TLSSniffer) Protocol() string {
return "tls" return "tls"

View File

@@ -2,9 +2,7 @@ package trie
import "errors" import "errors"
var ( var ErrorOverMaxValue = errors.New("the value don't over max value")
ErrorOverMaxValue = errors.New("the value don't over max value")
)
type IpCidrNode struct { type IpCidrNode struct {
Mark bool Mark bool

View File

@@ -1,8 +1,9 @@
package trie package trie
import ( import (
"github.com/Dreamacro/clash/log"
"net" "net"
"github.com/Dreamacro/clash/log"
) )
type IPV6 bool type IPV6 bool

View File

@@ -49,7 +49,6 @@ func TestIpv4Search(t *testing.T) {
assert.Equal(t, false, trie.IsContain(net.ParseIP("22"))) assert.Equal(t, false, trie.IsContain(net.ParseIP("22")))
assert.Equal(t, false, trie.IsContain(net.ParseIP(""))) assert.Equal(t, false, trie.IsContain(net.ParseIP("")))
} }
func TestIpv6AddSuccess(t *testing.T) { func TestIpv6AddSuccess(t *testing.T) {
@@ -96,5 +95,4 @@ func TestIpv6Search(t *testing.T) {
assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213")) assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213"))
assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22"))) assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22")))
} }

View File

@@ -4,8 +4,6 @@ import (
"container/list" "container/list"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"net" "net"
"net/netip" "net/netip"
"net/url" "net/url"
@@ -15,14 +13,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/Dreamacro/clash/common/utils"
R "github.com/Dreamacro/clash/rules"
RP "github.com/Dreamacro/clash/rules/provider"
"github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/outboundgroup" "github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/adapter/provider" "github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/auth" "github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/fakeip"
@@ -32,10 +27,13 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
providerTypes "github.com/Dreamacro/clash/constant/provider" providerTypes "github.com/Dreamacro/clash/constant/provider"
snifferTypes "github.com/Dreamacro/clash/constant/sniffer" snifferTypes "github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/dns"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
R "github.com/Dreamacro/clash/rules"
RP "github.com/Dreamacro/clash/rules/provider"
T "github.com/Dreamacro/clash/tunnel" T "github.com/Dreamacro/clash/tunnel"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@@ -254,7 +252,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
rawCfg := &RawConfig{ rawCfg := &RawConfig{
AllowLan: false, AllowLan: false,
BindAddress: "*", BindAddress: "*",
IPv6: true,
Mode: T.Rule, Mode: T.Rule,
GeodataMode: C.GeodataMode, GeodataMode: C.GeodataMode,
GeodataLoader: "memconservative", GeodataLoader: "memconservative",
@@ -266,7 +263,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
Proxy: []map[string]any{}, Proxy: []map[string]any{},
ProxyGroup: []map[string]any{}, ProxyGroup: []map[string]any{},
TCPConcurrent: false, TCPConcurrent: false,
EnableProcess: false, EnableProcess: true,
Tun: RawTun{ Tun: RawTun{
Enable: false, Enable: false,
Device: "", Device: "",
@@ -282,7 +279,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
}, },
DNS: RawDNS{ DNS: RawDNS{
Enable: false, Enable: false,
IPv6: false,
UseHosts: true, UseHosts: true,
EnhancedMode: C.DNSMapping, EnhancedMode: C.DNSMapping,
FakeIPRange: "198.18.0.1/16", FakeIPRange: "198.18.0.1/16",
@@ -535,7 +531,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName()) log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
// parse rule provider // parse rule provider
for name, mapping := range cfg.RuleProvider { for name, mapping := range cfg.RuleProvider {
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule) rp, err := RP.ParseRuleProvider(name, mapping)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -668,7 +664,7 @@ func parseNameServer(servers []string) ([]dns.NameServer, error) {
addr = u.Host addr = u.Host
dnsNetType = "dhcp" // UDP from DHCP dnsNetType = "dhcp" // UDP from DHCP
case "quic": case "quic":
addr, err = hostWithDefaultPort(u.Host, "853") addr, err = hostWithDefaultPort(u.Host, "784")
dnsNetType = "quic" // DNS over QUIC dnsNetType = "quic" // DNS over QUIC
default: default:
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
@@ -725,7 +721,7 @@ func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) {
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) { func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
var sites []*router.DomainMatcher var sites []*router.DomainMatcher
if len(countries) > 0 { if len(countries) > 0 {
if err := geodata.InitGeoSite(); err != nil { if err := initGeoSite(); err != nil {
return nil, fmt.Errorf("can't initial GeoSite: %s", err) return nil, fmt.Errorf("can't initial GeoSite: %s", err)
} }
} }

View File

@@ -2,16 +2,18 @@ package config
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/mmdb"
"io" "io"
"net/http" "net/http"
"os" "os"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/mmdb"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
) )
var initFlag bool
func downloadMMDB(path string) (err error) { func downloadMMDB(path string) (err error) {
resp, err := http.Get(C.MmdbUrl) resp, err := http.Get(C.MmdbUrl)
if err != nil { if err != nil {
@@ -46,6 +48,46 @@ func downloadGeoIP(path string) (err error) {
return err return err
} }
func downloadGeoSite(path string) (err error) {
resp, err := http.Get(C.GeoSiteUrl)
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
func initGeoSite() error {
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
log.Infoln("Can't find GeoSite.dat, start download")
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
log.Infoln("Download GeoSite.dat finish")
}
if !initFlag {
if err := geodata.Verify(C.GeositeName); err != nil {
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
if err := os.Remove(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
}
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
}
initFlag = true
}
return nil
}
func initGeoIP() error { func initGeoIP() error {
if C.GeodataMode { if C.GeodataMode {
if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) { if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {

View File

@@ -2,13 +2,14 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil"
"net/http"
"runtime"
"github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata"
_ "github.com/Dreamacro/clash/component/geodata/standard" _ "github.com/Dreamacro/clash/component/geodata/standard"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/oschwald/geoip2-golang" "github.com/oschwald/geoip2-golang"
"io/ioutil"
"net/http"
"runtime"
) )
func UpdateGeoDatabases() error { func UpdateGeoDatabases() error {

View File

@@ -7,6 +7,8 @@ import (
"time" "time"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/sagernet/sing/common/buf"
N "github.com/sagernet/sing/common/network"
) )
// Adapter Type // Adapter Type
@@ -75,6 +77,7 @@ type Conn interface {
type PacketConn interface { type PacketConn interface {
net.PacketConn net.PacketConn
Connection Connection
N.PacketConn
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed // Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error) // WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
} }
@@ -184,7 +187,7 @@ func (at AdapterType) String() string {
// UDPPacket contains the data of UDP packet, and offers control/info of UDP packet's source // UDPPacket contains the data of UDP packet, and offers control/info of UDP packet's source
type UDPPacket interface { type UDPPacket interface {
// Data get the payload of UDP Packet // Data get the payload of UDP Packet
Data() []byte Data() *buf.Buffer
// WriteBack writes the payload with source IP/Port equals addr // WriteBack writes the payload with source IP/Port equals addr
// - variable source IP/Port is important to STUN // - variable source IP/Port is important to STUN
@@ -192,8 +195,7 @@ type UDPPacket interface {
// this is important when using Fake-IP. // this is important when using Fake-IP.
WriteBack(b []byte, addr net.Addr) (n int, err error) WriteBack(b []byte, addr net.Addr) (n int, err error)
// Drop call after packet is used, could recycle buffer in this function. N.PacketWriter
Drop()
// LocalAddr returns the source IP/Port of packet // LocalAddr returns the source IP/Port of packet
LocalAddr() net.Addr LocalAddr() net.Addr

View File

@@ -6,6 +6,8 @@ import (
"net" "net"
"net/netip" "net/netip"
"strconv" "strconv"
M "github.com/sagernet/sing/common/metadata"
) )
// Socks addr type // Socks addr type
@@ -170,6 +172,18 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
} }
} }
func (m *Metadata) Socksaddr() M.Socksaddr {
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
if m.Host != "" {
return M.Socksaddr{
Fqdn: m.Host,
Port: uint16(port),
}
} else {
return M.SocksaddrFromAddrPort(m.DstIP, uint16(port))
}
}
func (m *Metadata) String() string { func (m *Metadata) String() string {
if m.Host != "" { if m.Host != "" {
return m.Host return m.Host

View File

@@ -13,9 +13,7 @@ const (
HTTP HTTP
) )
var ( var List = []Type{TLS, HTTP}
List = []Type{TLS, HTTP}
)
type Type int type Type int

View File

@@ -4,7 +4,6 @@ import (
"net" "net"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
) )

View File

@@ -4,15 +4,14 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"go.uber.org/atomic"
"net" "net"
"net/netip" "net/netip"
"strings" "strings"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns" D "github.com/miekg/dns"
"go.uber.org/atomic"
) )
type client struct { type client struct {

View File

@@ -2,7 +2,6 @@ package dns
import ( import (
"context" "context"
"go.uber.org/atomic"
"net" "net"
"net/netip" "net/netip"
"sync" "sync"
@@ -11,8 +10,8 @@ import (
"github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/dhcp"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns" D "github.com/miekg/dns"
"go.uber.org/atomic"
) )
const ( const (

View File

@@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns" D "github.com/miekg/dns"
) )

View File

@@ -5,19 +5,19 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
"github.com/lucas-clemente/quic-go"
"net" "net"
"strconv" "strconv"
"sync" "sync"
"time" "time"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/lucas-clemente/quic-go"
D "github.com/miekg/dns" D "github.com/miekg/dns"
) )
const NextProtoDQ = "doq" const NextProtoDQ = "doq-i00"
var bytesPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }} var bytesPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
@@ -93,7 +93,7 @@ func isActive(s quic.Connection) bool {
// getSession - opens or returns an existing quic.Connection // getSession - opens or returns an existing quic.Connection
// useCached - if true and cached session exists, return it right away // useCached - if true and cached session exists, return it right away
// otherwise - forcibly creates a new session // otherwise - forcibly creates a new session
func (dc *quicClient) getSession(ctx context.Context) (quic.Connection, error) { func (dc *quicClient) getSession() (quic.Connection, error) {
var session quic.Connection var session quic.Connection
dc.RLock() dc.RLock()
session = dc.session session = dc.session
@@ -111,14 +111,14 @@ func (dc *quicClient) getSession(ctx context.Context) (quic.Connection, error) {
defer dc.Unlock() defer dc.Unlock()
var err error var err error
session, err = dc.openSession(ctx) session, err = dc.openSession()
if err != nil { if err != nil {
// This does not look too nice, but QUIC (or maybe quic-go) // This does not look too nice, but QUIC (or maybe quic-go)
// doesn't seem stable enough. // doesn't seem stable enough.
// Maybe retransmissions aren't fully implemented in quic-go? // Maybe retransmissions aren't fully implemented in quic-go?
// Anyways, the simple solution is to make a second try when // Anyways, the simple solution is to make a second try when
// it fails to open the QUIC session. // it fails to open the QUIC session.
session, err = dc.openSession(ctx) session, err = dc.openSession()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -127,11 +127,11 @@ func (dc *quicClient) getSession(ctx context.Context) (quic.Connection, error) {
return session, nil return session, nil
} }
func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error) { func (dc *quicClient) openSession() (quic.Connection, error) {
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
InsecureSkipVerify: false, InsecureSkipVerify: true,
NextProtos: []string{ NextProtos: []string{
NextProtoDQ, "http/1.1", "h2", NextProtoDQ,
}, },
SessionTicketsDisabled: false, SessionTicketsDisabled: false,
} }
@@ -149,7 +149,6 @@ func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error)
) )
host, port, err := net.SplitHostPort(dc.addr) host, port, err := net.SplitHostPort(dc.addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -163,12 +162,12 @@ func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error)
udpAddr := net.UDPAddr{IP: ip.AsSlice(), Port: p} udpAddr := net.UDPAddr{IP: ip.AsSlice(), Port: p}
if dc.proxyAdapter == "" { if dc.proxyAdapter == "" {
udp, err = dialer.ListenPacket(ctx, "udp", "") udp, err = dialer.ListenPacket(context.Background(), "udp", "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else { } else {
conn, err := dialContextExtra(ctx, dc.proxyAdapter, "udp", ip, port) conn, err := dialContextExtra(context.Background(), dc.proxyAdapter, "udp", ip, port)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -181,7 +180,7 @@ func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error)
udp = wrapConn udp = wrapConn
} }
session, err := quic.DialContext(ctx, udp, &udpAddr, host, tlsConfig, quicConfig) session, err := quic.Dial(udp, &udpAddr, host, tlsConfig, quicConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open QUIC session: %w", err) return nil, fmt.Errorf("failed to open QUIC session: %w", err)
} }
@@ -190,7 +189,7 @@ func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error)
} }
func (dc *quicClient) openStream(ctx context.Context) (quic.Stream, error) { func (dc *quicClient) openStream(ctx context.Context) (quic.Stream, error) {
session, err := dc.getSession(ctx) session, err := dc.getSession()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -2,6 +2,7 @@ package dns
import ( import (
"net/netip" "net/netip"
"strings"
"github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router" "github.com/Dreamacro/clash/component/geodata/router"
@@ -9,7 +10,6 @@ import (
"github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"strings"
) )
type fallbackIPFilter interface { type fallbackIPFilter interface {

View File

@@ -12,7 +12,6 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
D "github.com/miekg/dns" D "github.com/miekg/dns"
) )
@@ -46,11 +45,11 @@ func withHosts(hosts *trie.DomainTrie[netip.Addr], mapping *cache.LruCache[netip
rr.A = ip.AsSlice() rr.A = ip.AsSlice()
msg.Answer = []D.RR{rr} msg.Answer = []D.RR{rr}
} else if q.Qtype == D.TypeAAAA { } else if ip.Is6() && q.Qtype == D.TypeAAAA {
rr := &D.AAAA{} rr := &D.AAAA{}
rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10} rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10}
ip := ip.As16() rr.AAAA = ip.AsSlice()
rr.AAAA = ip[:]
msg.Answer = []D.RR{rr} msg.Answer = []D.RR{rr}
} else { } else {
return next(ctx, r) return next(ctx, r)

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"go.uber.org/atomic"
"math/rand" "math/rand"
"net/netip" "net/netip"
"time" "time"
@@ -16,8 +15,8 @@ import (
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
D "github.com/miekg/dns" D "github.com/miekg/dns"
"go.uber.org/atomic"
"golang.org/x/sync/singleflight" "golang.org/x/sync/singleflight"
) )

View File

@@ -7,7 +7,6 @@ import (
"github.com/Dreamacro/clash/common/sockopt" "github.com/Dreamacro/clash/common/sockopt"
"github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
D "github.com/miekg/dns" D "github.com/miekg/dns"
) )

View File

@@ -15,7 +15,6 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
D "github.com/miekg/dns" D "github.com/miekg/dns"
) )
@@ -152,9 +151,17 @@ func (wpc *wrapPacketConn) LocalAddr() net.Addr {
} }
func dialContextExtra(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) { func dialContextExtra(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) {
adapter, ok := tunnel.Proxies()[adapterName]
if !ok {
opts = append(opts, dialer.WithInterface(adapterName))
adapter, _ = tunnel.Proxies()[tunnel.Direct.String()]
}
networkType := C.TCP networkType := C.TCP
if network == "udp" { if network == "udp" {
if !adapter.SupportUDP() {
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", adapterName)
}
networkType = C.UDP networkType = C.UDP
} }
@@ -171,29 +178,6 @@ func dialContextExtra(ctx context.Context, adapterName string, network string, d
DstPort: port, DstPort: port,
} }
adapter, ok := tunnel.Proxies()[adapterName]
if !ok {
opts = append(opts, dialer.WithInterface(adapterName))
if C.TCP == networkType {
return dialer.DialContext(ctx, network, dstIP.String()+":"+port, opts...)
} else {
packetConn, err := dialer.ListenPacket(ctx, network, dstIP.String()+":"+port, opts...)
if err != nil {
return nil, err
}
return &wrapPacketConn{
PacketConn: packetConn,
rAddr: metadata.UDPAddr(),
}, nil
}
}
if networkType == C.UDP && !adapter.SupportUDP() {
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", adapterName)
}
if networkType == C.UDP { if networkType == C.UDP {
packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...) packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...)
if err != nil { if err != nil {

9
go.mod
View File

@@ -13,9 +13,8 @@ require (
github.com/lucas-clemente/quic-go v0.27.2 github.com/lucas-clemente/quic-go v0.27.2
github.com/miekg/dns v1.1.49 github.com/miekg/dns v1.1.49
github.com/oschwald/geoip2-golang v1.7.0 github.com/oschwald/geoip2-golang v1.7.0
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c github.com/sagernet/sing v0.0.0-20220609123159-a93588755159
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.2 github.com/stretchr/testify v1.7.2
github.com/tobyxdd/hysteria v1.0.4 github.com/tobyxdd/hysteria v1.0.4
@@ -28,7 +27,7 @@ require (
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70 golang.org/x/exp v0.0.0-20220608143224-64259d1afd70
golang.org/x/net v0.0.0-20220607020251-c690dde0001d golang.org/x/net v0.0.0-20220607020251-c690dde0001d
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68
golang.org/x/time v0.0.0-20220411224347-583f2d630306 golang.org/x/time v0.0.0-20220411224347-583f2d630306
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4 golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e
@@ -39,7 +38,7 @@ require (
replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
replace github.com/tobyxdd/hysteria => github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256 replace github.com/tobyxdd/hysteria => github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15
replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.27.1-0.20220512040129-ed2a645d9218 replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.27.1-0.20220512040129-ed2a645d9218

18
go.sum
View File

@@ -40,8 +40,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256 h1:wm5RrQfwJS63pe5G15AKdXfrwlIYFciwCs3MrVxzxSU= github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15 h1:SraqLzYEGfrV8ETkVYc5evvCrn95hMFdCtcXXP8bA9Y=
github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256/go.mod h1:bXVjOca4Xf3JRenwuPKu02XaOiZwejrMSlgsu/U88J4= github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15/go.mod h1:bXVjOca4Xf3JRenwuPKu02XaOiZwejrMSlgsu/U88J4=
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc= github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -305,12 +305,10 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c h1:98QC0wtaD648MFPw82KaT1O9LloQgR4ZyIDtNtsno8Y= github.com/sagernet/sing v0.0.0-20220609123159-a93588755159 h1:G3fww5jjADkHWi6yDOEzkZbQ6lnrytv0mKesBtEslxo=
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c/go.mod h1:I67R/q5f67xDExL2kL3RLIP7kGJBOPkYXkpRAykgC+E= github.com/sagernet/sing v0.0.0-20220609123159-a93588755159/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c h1:Jhgjyb2jXL4GtwJec6/kgeTqaQXsvMiNX2wAkGOSD3I= github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c/go.mod h1:ng5pxdNnKZWlxzZTXRqWeY0ftzhScPZmjgJGJeRuPYY= github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec h1:jUSfKmyL6K9O2TvIvcVacZ4eNXHYbNSfdph+DRPyVlU=
github.com/sagernet/sing-vmess v0.0.0-20220616051646-3d3fc5d01eec/go.mod h1:jDZ8fJgOea7Y7MMHWgfqwLBVLnhtW2zuxS5wjtDaB84=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
@@ -566,8 +564,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -2,7 +2,6 @@ package executor
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/inner"
"net/netip" "net/netip"
"os" "os"
"runtime" "runtime"
@@ -14,6 +13,7 @@ import (
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
G "github.com/Dreamacro/clash/component/geodata" G "github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/process"
"github.com/Dreamacro/clash/component/profile" "github.com/Dreamacro/clash/component/profile"
"github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
@@ -25,6 +25,7 @@ import (
"github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/dns"
P "github.com/Dreamacro/clash/listener" P "github.com/Dreamacro/clash/listener"
authStore "github.com/Dreamacro/clash/listener/auth" authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
@@ -88,10 +89,6 @@ func ApplyConfig(cfg *config.Config, force bool) {
updateTun(cfg.Tun) updateTun(cfg.Tun)
updateExperimental(cfg) updateExperimental(cfg)
// DON'T Delete
// ClashX will use this line to determine if the 'Meta' has finished booting
log.Infoln("Apply all configs finished.")
log.SetLevel(cfg.General.LogLevel) log.SetLevel(cfg.General.LogLevel)
} }
@@ -130,9 +127,7 @@ func GetGeneral() *config.General {
return general return general
} }
func updateExperimental(c *config.Config) { func updateExperimental(c *config.Config) {}
runtime.GC()
}
func updateDNS(c *config.DNS, generalIPv6 bool) { func updateDNS(c *config.DNS, generalIPv6 bool) {
if !c.Enable { if !c.Enable {
@@ -229,7 +224,6 @@ func loadRuleProvider(ruleProviders map[string]provider.RuleProvider) {
go func() { go func() {
defer func() { <-ch; wg.Done() }() defer func() { <-ch; wg.Done() }()
loadProvider(ruleProvider) loadProvider(ruleProvider)
}() }()
} }
@@ -279,8 +273,8 @@ func updateSniffer(sniffer *config.Sniffer) {
func updateGeneral(general *config.General, force bool) { func updateGeneral(general *config.General, force bool) {
log.SetLevel(general.LogLevel) log.SetLevel(general.LogLevel)
process.EnableFindProcess(general.EnableProcess)
tunnel.SetMode(general.Mode) tunnel.SetMode(general.Mode)
tunnel.SetAlwaysFindProcess(general.EnableProcess)
dialer.DisableIPv6 = !general.IPv6 dialer.DisableIPv6 = !general.IPv6
if !dialer.DisableIPv6 { if !dialer.DisableIPv6 {
log.Infoln("Use IPv6") log.Infoln("Use IPv6")

View File

@@ -4,7 +4,6 @@ import (
"net/http" "net/http"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )

View File

@@ -1,11 +1,11 @@
package route package route
import ( import (
"github.com/Dreamacro/clash/component/dialer"
"net/http" "net/http"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
"github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant"
@@ -13,7 +13,6 @@ import (
P "github.com/Dreamacro/clash/listener" P "github.com/Dreamacro/clash/listener"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )
@@ -46,7 +45,6 @@ type configSchema struct {
IPv6 *bool `json:"ipv6"` IPv6 *bool `json:"ipv6"`
Sniffing *bool `json:"sniffing"` Sniffing *bool `json:"sniffing"`
TcpConcurrent *bool `json:"tcp-concurrent"` TcpConcurrent *bool `json:"tcp-concurrent"`
InterfaceName *string `json:"interface-name"`
} }
func getConfigs(w http.ResponseWriter, r *http.Request) { func getConfigs(w http.ResponseWriter, r *http.Request) {
@@ -86,10 +84,6 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
dialer.SetDial(*general.TcpConcurrent) dialer.SetDial(*general.TcpConcurrent)
} }
if general.InterfaceName != nil {
dialer.DefaultInterface.Store(*general.InterfaceName)
}
ports := P.GetPorts() ports := P.GetPorts()
tcpIn := tunnel.TCPIn() tcpIn := tunnel.TCPIn()

View File

@@ -8,7 +8,6 @@ import (
"time" "time"
"github.com/Dreamacro/clash/tunnel/statistic" "github.com/Dreamacro/clash/tunnel/statistic"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"

View File

@@ -2,14 +2,15 @@ package route
import ( import (
"context" "context"
"net/http"
"strconv"
"time"
"github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
"net/http"
"strconv"
"time"
) )
func GroupRouter() http.Handler { func GroupRouter() http.Handler {
@@ -64,11 +65,10 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) {
return return
} }
ctx, cancel := context.WithTimeout(r.Context(), time.Millisecond*time.Duration(timeout)) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
defer cancel() defer cancel()
dm, err := group.URLTest(ctx, url) dm, err := group.URLTest(ctx, url)
if err != nil { if err != nil {
render.Status(r, http.StatusGatewayTimeout) render.Status(r, http.StatusGatewayTimeout)
render.JSON(w, r, newError(err.Error())) render.JSON(w, r, newError(err.Error()))

View File

@@ -6,7 +6,6 @@ import (
"github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )

View File

@@ -12,14 +12,11 @@ import (
"github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/profile/cachefile"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )
var ( var SwitchProxiesCallback func(sGroup string, sProxy string)
SwitchProxiesCallback func(sGroup string, sProxy string)
)
func proxyRouter() http.Handler { func proxyRouter() http.Handler {
r := chi.NewRouter() r := chi.NewRouter()

View File

@@ -1,11 +1,10 @@
package route package route
import ( import (
"github.com/Dreamacro/clash/constant"
"net/http" "net/http"
"github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
) )

View File

@@ -12,7 +12,6 @@ import (
_ "github.com/Dreamacro/clash/constant/mime" _ "github.com/Dreamacro/clash/constant/mime"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel/statistic" "github.com/Dreamacro/clash/tunnel/statistic"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/cors" "github.com/go-chi/cors"
"github.com/go-chi/render" "github.com/go-chi/render"

View File

@@ -1,9 +1,10 @@
package inner package inner
import ( import (
"net"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"net"
) )
var tcpIn chan<- C.ConnContext var tcpIn chan<- C.ConnContext

View File

@@ -2,8 +2,6 @@ package proxy
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"net" "net"
"sort" "sort"
"strconv" "strconv"
@@ -13,12 +11,14 @@ import (
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/http" "github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/listener/mixed" "github.com/Dreamacro/clash/listener/mixed"
"github.com/Dreamacro/clash/listener/redir" "github.com/Dreamacro/clash/listener/redir"
"github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/listener/socks"
"github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/listener/tun" "github.com/Dreamacro/clash/listener/tun"
"github.com/Dreamacro/clash/listener/tun/ipstack" "github.com/Dreamacro/clash/listener/tun/ipstack"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
) )

View File

@@ -4,11 +4,11 @@ import (
"net" "net"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/common/sockopt" "github.com/Dreamacro/clash/common/sockopt"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5" "github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
) )
type UDPListener struct { type UDPListener struct {
@@ -49,34 +49,35 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
} }
go func() { go func() {
for { for {
buf := pool.Get(pool.UDPBufferSize) buffer := buf.NewPacket()
n, remoteAddr, err := l.ReadFrom(buf) n, remoteAddr, err := l.ReadFrom(buffer.FreeBytes())
if err != nil { if err != nil {
pool.Put(buf) buffer.Release()
if sl.closed { if sl.closed {
break break
} }
continue continue
} }
handleSocksUDP(l, in, buf[:n], remoteAddr) buffer.Extend(n)
handleSocksUDP(l, in, buffer, remoteAddr)
} }
}() }()
return sl, nil return sl, nil
} }
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) { func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buffer *buf.Buffer, addr net.Addr) {
target, payload, err := socks5.DecodeUDPPacket(buf) buffer.Advance(3)
target, err := M.SocksaddrSerializer.ReadAddrPort(buffer)
if err != nil { if err != nil {
// Unresolved UDP packet, return buffer to the pool // Unresolved UDP packet, return buffer to the pool
pool.Put(buf) buffer.Release()
return return
} }
packet := &packet{ packet := &packet{
pc: pc, pc: pc,
rAddr: addr, rAddr: addr,
payload: payload, payload: buffer,
bufRef: buf,
} }
select { select {
case in <- inbound.NewPacket(target, packet, C.SOCKS5): case in <- inbound.NewPacket(target, packet, C.SOCKS5):

View File

@@ -3,18 +3,19 @@ package socks
import ( import (
"net" "net"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
) )
type packet struct { type packet struct {
pc net.PacketConn pc net.PacketConn
rAddr net.Addr rAddr net.Addr
payload []byte payload *buf.Buffer
bufRef []byte
} }
func (c *packet) Data() []byte { func (c *packet) Data() *buf.Buffer {
return c.payload return c.payload
} }
@@ -27,11 +28,15 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
return c.pc.WriteTo(packet, c.rAddr) return c.pc.WriteTo(packet, c.rAddr)
} }
func (c *packet) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
header := buf.With(buffer.ExtendHeader(3 + M.SocksaddrSerializer.AddrPortLen(destination)))
common.Must(header.WriteZeroN(3))
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
return common.Error(c.pc.WriteTo(buffer.Bytes(), c.rAddr))
}
// LocalAddr returns the source IP/Port of UDP Packet // LocalAddr returns the source IP/Port of UDP Packet
func (c *packet) LocalAddr() net.Addr { func (c *packet) LocalAddr() net.Addr {
return c.rAddr return c.rAddr
} }
func (c *packet) Drop() {
pool.Put(c.bufRef)
}

View File

@@ -3,15 +3,16 @@ package tproxy
import ( import (
"net" "net"
"github.com/Dreamacro/clash/common/pool" "github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
) )
type packet struct { type packet struct {
lAddr *net.UDPAddr lAddr *net.UDPAddr
buf []byte buf *buf.Buffer
} }
func (c *packet) Data() []byte { func (c *packet) Data() *buf.Buffer {
return c.buf return c.buf
} }
@@ -27,11 +28,18 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
return return
} }
func (c *packet) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
defer buffer.Release()
tc, err := dialUDP("udp", addr.UDPAddr(), c.lAddr)
defer tc.Close()
if err != nil {
return err
}
_, err = tc.Write(buffer.Bytes())
return nil
}
// LocalAddr returns the source IP/Port of UDP Packet // LocalAddr returns the source IP/Port of UDP Packet
func (c *packet) LocalAddr() net.Addr { func (c *packet) LocalAddr() net.Addr {
return c.lAddr return c.lAddr
} }
func (c *packet) Drop() {
pool.Put(c.buf)
}

View File

@@ -4,9 +4,9 @@ import (
"net" "net"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" "github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
) )
type UDPListener struct { type UDPListener struct {
@@ -57,10 +57,10 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
go func() { go func() {
oob := make([]byte, 1024) oob := make([]byte, 1024)
for { for {
buf := pool.Get(pool.UDPBufferSize) buffer := buf.NewPacket()
n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob) n, oobn, _, lAddr, err := c.ReadMsgUDP(buffer.FreeBytes(), oob)
if err != nil { if err != nil {
pool.Put(buf) buffer.Release()
if rl.closed { if rl.closed {
break break
} }
@@ -71,21 +71,21 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
if err != nil { if err != nil {
continue continue
} }
handlePacketConn(l, in, buf[:n], lAddr, rAddr) buffer.Extend(n)
handlePacketConn(l, in, buffer, lAddr, rAddr)
} }
}() }()
return rl, nil return rl, nil
} }
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) { func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf *buf.Buffer, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
target := socks5.ParseAddrToSocksAddr(rAddr)
pkt := &packet{ pkt := &packet{
lAddr: lAddr, lAddr: lAddr,
buf: buf, buf: buf,
} }
select { select {
case in <- inbound.NewPacket(target, pkt, C.TPROXY): case in <- inbound.NewPacket(M.SocksaddrFromNet(rAddr), pkt, C.TPROXY):
default: default:
} }
} }

View File

@@ -5,7 +5,6 @@ package device
// Device is the interface that implemented by network layer devices (e.g. tun), // Device is the interface that implemented by network layer devices (e.g. tun),
// and easy to use as stack.LinkEndpoint. // and easy to use as stack.LinkEndpoint.
type Device interface { type Device interface {
// Name returns the current name of the device. // Name returns the current name of the device.
Name() string Name() string

View File

@@ -7,7 +7,6 @@ import (
"strconv" "strconv"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )

View File

@@ -3,8 +3,9 @@
package fdbased package fdbased
import ( import (
"gvisor.dev/gvisor/pkg/tcpip/stack"
"os" "os"
"gvisor.dev/gvisor/pkg/tcpip/stack"
) )
type FD struct { type FD struct {

View File

@@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased" "gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile" "gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
) )

View File

@@ -14,7 +14,6 @@ import (
"unsafe" "unsafe"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/driver/memmod" "golang.zx2c4.com/wireguard/windows/driver/memmod"
) )

View File

@@ -7,7 +7,6 @@ import (
"unsafe" "unsafe"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased" "gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile" "gvisor.dev/gvisor/pkg/tcpip/link/rawfile"

View File

@@ -8,7 +8,6 @@ import (
"runtime" "runtime"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
) )

View File

@@ -4,6 +4,7 @@ package tun
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/tun/device/iobased" "github.com/Dreamacro/clash/listener/tun/device/iobased"
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
) )

View File

@@ -16,7 +16,6 @@ type TUN struct {
} }
func closeIO(t *TUN) { func closeIO(t *TUN) {
} }
func newEq(t *TUN) error { func newEq(t *TUN) error {

View File

@@ -2,7 +2,6 @@ package tun
import ( import (
"github.com/Dreamacro/clash/listener/tun/device/tun/driver" "github.com/Dreamacro/clash/listener/tun/device/tun/driver"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
) )

View File

@@ -1,12 +1,13 @@
package commons package commons
import ( import (
"time"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"go.uber.org/atomic" "go.uber.org/atomic"
"time"
) )
var ( var (

View File

@@ -3,11 +3,12 @@
package commons package commons
import ( import (
"time"
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"go.uber.org/atomic" "go.uber.org/atomic"
"time"
) )
var ( var (

View File

@@ -2,14 +2,13 @@ package commons
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/log"
"net" "net"
"time" "time"
"github.com/Dreamacro/clash/log"
) )
var ( var defaultRoutes = []string{"1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1"}
defaultRoutes = []string{"1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1"}
)
func ipv4MaskString(bits int) string { func ipv4MaskString(bits int) string {
m := net.CIDRMask(bits, 32) m := net.CIDRMask(bits, 32)

View File

@@ -2,11 +2,12 @@ package commons
import ( import (
"fmt" "fmt"
"net"
"net/netip"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"net"
"net/netip"
) )
func GetAutoDetectInterface() (ifn string, err error) { func GetAutoDetectInterface() (ifn string, err error) {
@@ -60,7 +61,7 @@ func ConfigInterfaceAddress(dev device.Device, addr netip.Prefix, forceMTU int,
func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) error { func configInterfaceRouting(index int, interfaceName string, ip netip.Addr) error {
const tableId = 1981801 const tableId = 1981801
var pref = 9000 pref := 9000
for _, route := range defaultRoutes { for _, route := range defaultRoutes {
_, ipn, err := net.ParseCIDR(route) _, ipn, err := net.ParseCIDR(route)

View File

@@ -4,10 +4,11 @@ package commons
import ( import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/tun/device"
"github.com/vishvananda/netlink"
"net" "net"
"net/netip" "net/netip"
"github.com/Dreamacro/clash/listener/tun/device"
"github.com/vishvananda/netlink"
) )
func GetAutoDetectInterface() (string, error) { func GetAutoDetectInterface() (string, error) {

View File

@@ -10,7 +10,6 @@ import (
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/device/tun" "github.com/Dreamacro/clash/listener/tun/device/tun"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/services" "golang.zx2c4.com/wireguard/windows/services"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"

View File

@@ -15,6 +15,8 @@ import (
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons" D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/sagernet/sing/common/buf"
M "github.com/sagernet/sing/common/metadata"
) )
var _ adapter.Handler = (*gvHandler)(nil) var _ adapter.Handler = (*gvHandler)(nil)
@@ -96,27 +98,24 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
return return
} }
target := socks5.ParseAddrToSocksAddr(rAddr) target := M.SocksaddrFromNet(rAddr)
go func() { go func() {
for { for {
buf := pool.Get(pool.UDPBufferSize) buffer := buf.NewPacket()
n, addr, err := tunConn.ReadFrom(buf) n, addr, err := tunConn.ReadFrom(buffer.FreeBytes())
if err != nil { if err != nil {
_ = pool.Put(buf) buffer.Release()
break break
} }
buffer.Truncate(n)
payload := buf[:n]
if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) { if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) {
go func() { go func() {
defer func() { defer buffer.Release()
_ = pool.Put(buf)
}()
msg, err1 := D.RelayDnsPacket(payload) msg, err1 := D.RelayDnsPacket(buffer.Bytes())
if err1 != nil { if err1 != nil {
return return
} }
@@ -130,7 +129,7 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
gvPacket := &packet{ gvPacket := &packet{
pc: tunConn, pc: tunConn,
rAddr: addr, rAddr: addr,
payload: payload, payload: buffer,
} }
select { select {

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
"gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/stack"
) )

View File

@@ -4,7 +4,6 @@ package gvisor
import ( import (
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
"gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack" "gvisor.dev/gvisor/pkg/tcpip/stack"

View File

@@ -11,7 +11,6 @@ import (
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/ipstack" "github.com/Dreamacro/clash/listener/tun/ipstack"
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
"gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"

View File

@@ -4,12 +4,13 @@ package gvisor
import ( import (
"fmt" "fmt"
"net/netip"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/ipstack" "github.com/Dreamacro/clash/listener/tun/ipstack"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"net/netip"
) )
// New allocates a new *gvStack with given options. // New allocates a new *gvStack with given options.

Some files were not shown because too many files have changed in this diff Show More