Compare commits
72 Commits
dev-refact
...
v1.12.0
Author | SHA1 | Date | |
---|---|---|---|
10d2d14938 | |||
8ce9737f3d | |||
6b44178108 | |||
6664547f43 | |||
10383e2701 | |||
f4b9f2965f | |||
2ba933d16a | |||
669961e496 | |||
f979491013 | |||
0d55b28805 | |||
9c70e649ca | |||
8c079bf5bc | |||
2cdf4a0532 | |||
4ba34ce672 | |||
637f1b5aed | |||
56a87125e0 | |||
6fedc8d942 | |||
dbb834d964 | |||
449946cc15 | |||
c3671a154d | |||
6874fb785b | |||
5141ddc96e | |||
6a03371731 | |||
b658bb415b | |||
85405a54c7 | |||
30a0834e72 | |||
109a76e1fc | |||
c1a99b9be4 | |||
bf55428954 | |||
5e55d6b08f | |||
21098d2627 | |||
8da67ba61c | |||
54a0947bb4 | |||
a562b249a2 | |||
5af17f70b4 | |||
ca5bb91977 | |||
bbac54433e | |||
b6a5ec6490 | |||
aaf700f0b5 | |||
2ce89aca1e | |||
efdf69022a | |||
d4d1d4cc2a | |||
a8c4900891 | |||
930a7af8e7 | |||
77acd4ba8d | |||
691cf1d8d6 | |||
d1decb8e58 | |||
625c4a1079 | |||
341ef19099 | |||
2563b20019 | |||
1b3b5b4dfe | |||
2e6bdc5636 | |||
be298cfa16 | |||
277e71b26a | |||
f7c903a586 | |||
ff4a5bef9b | |||
d8dc44e786 | |||
c968104a19 | |||
f7481ecadf | |||
85c37b473a | |||
23bc231df3 | |||
2146b605f7 | |||
8853e97b40 | |||
7d04904109 | |||
a5acd3aa97 | |||
099aa1e3c2 | |||
63fdb348db | |||
81ee44f6c0 | |||
130a3a261d | |||
94368f43eb | |||
eea9a12560 | |||
0a4570b55c |
@ -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
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
|
||||||
AmbientCapabilities=cap_net_admin
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
|
||||||
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/Clash-Mini/Dashboard).
|
To display process name in GUI please use [Dashboard For Meta](https://github.com/MetaCubeX/clash-dashboard).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ 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"
|
||||||
@ -11,9 +14,6 @@ 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,25 +151,32 @@ 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 {
|
||||||
start = time.Now()
|
second := time.Now()
|
||||||
resp, err = client.Do(req)
|
resp, err = client.Do(req)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return
|
_ = resp.Body.Close()
|
||||||
|
start = second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = resp.Body.Close()
|
|
||||||
t = uint16(time.Since(start) / time.Millisecond)
|
t = uint16(time.Since(start) / time.Millisecond)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package inbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 M.Socksaddr, packet C.UDPPacket, source C.Type) *PacketAdapter {
|
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
|
||||||
metadata := socksAddrToMetadata(target)
|
metadata := parseSocksAddr(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 {
|
||||||
|
@ -10,26 +10,8 @@ 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]),
|
||||||
|
@ -4,16 +4,12 @@ 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 {
|
||||||
@ -161,7 +157,6 @@ 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
|
||||||
}
|
}
|
||||||
@ -180,22 +175,8 @@ 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 {
|
||||||
var nc N.PacketConn
|
return &packetConn{pc, []string{a.Name()}, parseRemoteDestination(a.Addr())}
|
||||||
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 {
|
||||||
|
@ -86,7 +86,7 @@ func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 增加headers
|
//增加headers
|
||||||
if len(h.option.Headers) != 0 {
|
if len(h.option.Headers) != 0 {
|
||||||
for key, value := range h.option.Headers {
|
for key, value := range h.option.Headers {
|
||||||
req.Header.Add(key, value)
|
req.Header.Add(key, value)
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@ -43,24 +41,32 @@ var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`)
|
|||||||
type Hysteria struct {
|
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) {
|
||||||
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), hyDialer(func() (net.PacketConn, error) {
|
hdc := hyDialerWithContext{
|
||||||
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
ctx: ctx,
|
||||||
}))
|
hyDialer: func() (net.PacketConn, error) {
|
||||||
|
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) {
|
||||||
udpConn, err := h.client.DialUDP(hyDialer(func() (net.PacketConn, error) {
|
hdc := hyDialerWithContext{
|
||||||
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
|
ctx: ctx,
|
||||||
}))
|
hyDialer: func() (net.PacketConn, error) {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@ -73,11 +79,8 @@ 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,omitempty"`
|
Up string `proxy:"up"`
|
||||||
UpMbps int `proxy:"up_mbps,omitempty"`
|
Down string `proxy:"down"`
|
||||||
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"`
|
||||||
@ -92,22 +95,16 @@ 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, errors.New("invalid speed format")
|
return 0, 0, fmt.Errorf("invaild download speed: %s", c.Down)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
down = uint64(c.DownMbps) * mbpsToBps
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return up, down, nil
|
return up, down, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +118,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.Server
|
serverName = option.SNI
|
||||||
}
|
}
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
@ -173,21 +170,18 @@ 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
|
|
||||||
if option.Auth != "" {
|
var auth = []byte(option.AuthString)
|
||||||
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))
|
||||||
@ -205,8 +199,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
|
|||||||
iface: option.Interface,
|
iface: option.Interface,
|
||||||
rmark: option.RoutingMark,
|
rmark: option.RoutingMark,
|
||||||
},
|
},
|
||||||
client: client,
|
client: client,
|
||||||
clientTransport: clientTransport,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +207,12 @@ 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
|
||||||
@ -263,8 +262,15 @@ func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type hyDialer func() (net.PacketConn, error)
|
type hyDialerWithContext struct {
|
||||||
|
hyDialer func() (net.PacketConn, error)
|
||||||
func (h hyDialer) ListenPacket() (net.PacketConn, error) {
|
ctx context.Context
|
||||||
return h()
|
}
|
||||||
|
|
||||||
|
func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) {
|
||||||
|
return h.hyDialer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hyDialerWithContext) Context() context.Context {
|
||||||
|
return h.ctx
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ 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"
|
||||||
@ -15,14 +16,21 @@ 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
|
||||||
@ -39,6 +47,7 @@ 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 {
|
||||||
@ -71,6 +80,10 @@ 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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +103,13 @@ 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
|
||||||
@ -104,6 +124,19 @@ 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)
|
||||||
@ -161,6 +194,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||||||
},
|
},
|
||||||
method: method,
|
method: method,
|
||||||
|
|
||||||
|
option: &option,
|
||||||
obfsMode: obfsMode,
|
obfsMode: obfsMode,
|
||||||
v2rayOption: v2rayOption,
|
v2rayOption: v2rayOption,
|
||||||
obfsOption: obfsOption,
|
obfsOption: obfsOption,
|
||||||
|
@ -3,6 +3,7 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
xtls "github.com/xtls/go"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
@ -11,7 +12,6 @@ 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 (
|
||||||
|
@ -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,30 +70,32 @@ 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 {
|
||||||
header.Add(key, value)
|
wsOpts.Headers.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,
|
||||||
ServerName: host,
|
ServerName: host,
|
||||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"http/1.1"},
|
||||||
}
|
}
|
||||||
if v.option.ServerName != "" {
|
if v.option.ServerName != "" {
|
||||||
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 {
|
||||||
wsOpts.Headers.Set("Host", convert.RandHost())
|
if host := wsOpts.Headers.Get("Host"); host == "" {
|
||||||
convert.SetUserAgent(wsOpts.Headers)
|
wsOpts.Headers.Set("Host", convert.RandHost())
|
||||||
|
convert.SetUserAgent(wsOpts.Headers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
||||||
case "http":
|
case "http":
|
||||||
|
@ -9,13 +9,17 @@ 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"
|
||||||
"github.com/Dreamacro/clash/transport/vmess"
|
clashVMess "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 {
|
||||||
@ -31,25 +35,23 @@ type Vmess struct {
|
|||||||
|
|
||||||
type VmessOption struct {
|
type VmessOption struct {
|
||||||
BasicOption
|
BasicOption
|
||||||
Name string `proxy:"name"`
|
Name string `proxy:"name"`
|
||||||
Server string `proxy:"server"`
|
Server string `proxy:"server"`
|
||||||
Port int `proxy:"port"`
|
Port int `proxy:"port"`
|
||||||
UUID string `proxy:"uuid"`
|
UUID string `proxy:"uuid"`
|
||||||
AlterID int `proxy:"alterId"`
|
AlterID int `proxy:"alterId"`
|
||||||
Cipher string `proxy:"cipher"`
|
Cipher string `proxy:"cipher"`
|
||||||
UDP bool `proxy:"udp,omitempty"`
|
UDP bool `proxy:"udp,omitempty"`
|
||||||
Network string `proxy:"network,omitempty"`
|
Network string `proxy:"network,omitempty"`
|
||||||
TLS bool `proxy:"tls,omitempty"`
|
TLS bool `proxy:"tls,omitempty"`
|
||||||
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
|
||||||
ServerName string `proxy:"servername,omitempty"`
|
ServerName string `proxy:"servername,omitempty"`
|
||||||
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
|
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
|
||||||
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"`
|
||||||
// TODO: compatible with VMESS WS older version configurations
|
AuthenticatedLength bool `proxy:"authenticated-length,omitempty"`
|
||||||
WSHeaders map[string]string `proxy:"ws-headers,omitempty"`
|
|
||||||
WSPath string `proxy:"ws-path,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPOptions struct {
|
type HTTPOptions struct {
|
||||||
@ -81,13 +83,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 := &vmess.WebsocketConfig{
|
wsOpts := &clashVMess.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: make(http.Header),
|
Headers: http.Header{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(v.option.WSOpts.Headers) != 0 {
|
if len(v.option.WSOpts.Headers) != 0 {
|
||||||
@ -109,15 +111,17 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||||||
wsOpts.TLSConfig.ServerName = host
|
wsOpts.TLSConfig.ServerName = host
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wsOpts.Headers.Set("Host", convert.RandHost())
|
if host := wsOpts.Headers.Get("Host"); host == "" {
|
||||||
convert.SetUserAgent(wsOpts.Headers)
|
wsOpts.Headers.Set("Host", convert.RandHost())
|
||||||
|
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 := &vmess.TLSConfig{
|
tlsOpts := &clashVMess.TLSConfig{
|
||||||
Host: host,
|
Host: host,
|
||||||
SkipCertVerify: v.option.SkipCertVerify,
|
SkipCertVerify: v.option.SkipCertVerify,
|
||||||
}
|
}
|
||||||
@ -126,27 +130,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 = vmess.StreamTLSConn(c, tlsOpts)
|
c, err = clashVMess.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 := &vmess.HTTPConfig{
|
httpOpts := &clashVMess.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 = vmess.StreamHTTPConn(c, httpOpts)
|
c = clashVMess.StreamHTTPConn(c, httpOpts)
|
||||||
case "h2":
|
case "h2":
|
||||||
host, _, _ := net.SplitHostPort(v.addr)
|
host, _, _ := net.SplitHostPort(v.addr)
|
||||||
tlsOpts := vmess.TLSConfig{
|
tlsOpts := clashVMess.TLSConfig{
|
||||||
Host: host,
|
Host: host,
|
||||||
SkipCertVerify: v.option.SkipCertVerify,
|
SkipCertVerify: v.option.SkipCertVerify,
|
||||||
NextProtos: []string{"h2"},
|
NextProtos: []string{"h2"},
|
||||||
@ -156,24 +157,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 = vmess.StreamTLSConn(c, &tlsOpts)
|
c, err = clashVMess.StreamTLSConn(c, &tlsOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
h2Opts := &vmess.H2Config{
|
h2Opts := &clashVMess.H2Config{
|
||||||
Hosts: v.option.HTTP2Opts.Host,
|
Hosts: v.option.HTTP2Opts.Host,
|
||||||
Path: v.option.HTTP2Opts.Path,
|
Path: v.option.HTTP2Opts.Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err = vmess.StreamH2Conn(c, h2Opts)
|
c, err = clashVMess.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 := &vmess.TLSConfig{
|
tlsOpts := &clashVMess.TLSConfig{
|
||||||
Host: host,
|
Host: host,
|
||||||
SkipCertVerify: v.option.SkipCertVerify,
|
SkipCertVerify: v.option.SkipCertVerify,
|
||||||
}
|
}
|
||||||
@ -182,15 +183,18 @@ 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 = vmess.StreamTLSConn(c, tlsOpts)
|
c, err = clashVMess.StreamTLSConn(c, tlsOpts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if metadata.NetWork == C.UDP {
|
||||||
return v.client.StreamConn(c, parseVmessAddr(metadata))
|
return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
} else {
|
||||||
|
return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
@ -203,7 +207,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.StreamConn(c, parseVmessAddr(metadata))
|
c, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -233,6 +237,11 @@ 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 {
|
||||||
@ -242,7 +251,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
|||||||
}
|
}
|
||||||
defer safeConnClose(c, err)
|
defer safeConnClose(c, err)
|
||||||
|
|
||||||
c, err = v.client.StreamConn(c, parseVmessAddr(metadata))
|
c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
|
||||||
} 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 {
|
||||||
@ -258,11 +267,21 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.ListenPacketOnStreamConn(c, metadata)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,14 +292,11 @@ 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)
|
||||||
client, err := vmess.NewClient(vmess.Config{
|
var options []vmess.ClientOption
|
||||||
UUID: option.UUID,
|
if option.AuthenticatedLength {
|
||||||
AlterID: uint16(option.AlterID),
|
options = append(options, vmess.ClientWithAuthenticatedLength())
|
||||||
Security: security,
|
}
|
||||||
HostName: option.Server,
|
client, err := vmess.NewClient(option.UUID, security, option.AlterID, options...)
|
||||||
Port: strconv.Itoa(option.Port),
|
|
||||||
IsAead: option.AlterID == 0,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -339,44 +355,29 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
|
type threadSafePacketConn struct {
|
||||||
var addrType byte
|
net.PacketConn
|
||||||
var addr []byte
|
access sync.Mutex
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
port, _ := strconv.ParseUint(metadata.DstPort, 10, 16)
|
func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
return &vmess.DstAddr{
|
c.access.Lock()
|
||||||
UDP: metadata.NetWork == C.UDP,
|
defer c.access.Unlock()
|
||||||
AddrType: addrType,
|
return c.PacketConn.WriteTo(b, addr)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,11 @@ 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 {
|
||||||
|
@ -3,17 +3,16 @@ 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"
|
||||||
types "github.com/Dreamacro/clash/constant/provider"
|
|
||||||
"github.com/Dreamacro/clash/constant/provider"
|
"github.com/Dreamacro/clash/constant/provider"
|
||||||
|
types "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 {
|
||||||
@ -112,11 +111,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)
|
||||||
lock.Lock()
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
lock.Lock()
|
||||||
mp[proxy.Name()] = delay
|
mp[proxy.Name()] = delay
|
||||||
|
lock.Unlock()
|
||||||
}
|
}
|
||||||
lock.Unlock()
|
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
@ -5,15 +5,16 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,9 +40,10 @@ func (f *fetcher[V]) VehicleType() types.VehicleType {
|
|||||||
|
|
||||||
func (f *fetcher[V]) Initial() (V, error) {
|
func (f *fetcher[V]) Initial() (V, error) {
|
||||||
var (
|
var (
|
||||||
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 {
|
||||||
@ -51,10 +52,8 @@ 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()) {
|
||||||
defer func() {
|
log.Infoln("[Provider] %s not updated for a long time, force refresh", f.Name())
|
||||||
log.Infoln("[Provider] %s's proxies not updated for a long time, force refresh", f.Name())
|
forceUpdate = true
|
||||||
go f.Update()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf, err = f.vehicle.Read()
|
buf, err = f.vehicle.Read()
|
||||||
@ -64,7 +63,21 @@ func (f *fetcher[V]) Initial() (V, error) {
|
|||||||
return getZero[V](), err
|
return getZero[V](), err
|
||||||
}
|
}
|
||||||
|
|
||||||
proxies, err := f.parser(buf)
|
var proxies V
|
||||||
|
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
|
||||||
@ -189,6 +202,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,12 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,6 +27,7 @@ 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() {
|
||||||
@ -62,17 +65,21 @@ func (hc *HealthCheck) touch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hc *HealthCheck) check() {
|
func (hc *HealthCheck) check() {
|
||||||
b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10))
|
_, _, _ = hc.singleDo.Do(func() (struct{}, error) {
|
||||||
for _, proxy := range hc.proxies {
|
b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10))
|
||||||
p := proxy
|
for _, proxy := range hc.proxies {
|
||||||
b.Go(p.Name(), func() (bool, error) {
|
p := proxy
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
|
b.Go(p.Name(), func() (bool, error) {
|
||||||
defer cancel()
|
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
|
||||||
_, _ = p.URLTest(ctx, hc.url)
|
defer cancel()
|
||||||
return false, nil
|
_, _ = p.URLTest(ctx, hc.url)
|
||||||
})
|
return false, nil
|
||||||
}
|
})
|
||||||
b.Wait()
|
}
|
||||||
|
|
||||||
|
b.Wait()
|
||||||
|
return struct{}{}, nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hc *HealthCheck) close() {
|
func (hc *HealthCheck) close() {
|
||||||
@ -87,5 +94,6 @@ 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,16 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,13 +2,12 @@ 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 {
|
||||||
|
@ -14,6 +14,7 @@ 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()
|
||||||
|
@ -7,4 +7,5 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func prepareBackgroundCommand(cmd *exec.Cmd) {
|
func prepareBackgroundCommand(cmd *exec.Cmd) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,34 +10,24 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var encRaw = base64.RawStdEncoding
|
||||||
var enc = base64.StdEncoding
|
var enc = base64.StdEncoding
|
||||||
|
|
||||||
func DecodeBase64(buf []byte) ([]byte, error) {
|
func DecodeBase64(buf []byte) []byte {
|
||||||
dBuf := make([]byte, enc.DecodedLen(len(buf)))
|
dBuf := make([]byte, encRaw.DecodedLen(len(buf)))
|
||||||
n, err := enc.Decode(dBuf, buf)
|
n, err := encRaw.Decode(dBuf, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
n, err = enc.Decode(dBuf, buf)
|
||||||
|
if err != nil {
|
||||||
|
return buf
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return dBuf[:n]
|
||||||
return dBuf[:n], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeBase64StringToString decode base64 string to string
|
|
||||||
func DecodeBase64StringToString(s string) (string, error) {
|
|
||||||
dBuf, err := enc.DecodeString(s)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
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, err := DecodeBase64(buf)
|
data := DecodeBase64(buf)
|
||||||
if err != nil {
|
|
||||||
data = buf
|
|
||||||
}
|
|
||||||
|
|
||||||
arr := strings.Split(string(data), "\n")
|
arr := strings.Split(string(data), "\n")
|
||||||
|
|
||||||
@ -76,8 +66,16 @@ 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")
|
||||||
hysteria["down_mbps"], _ = strconv.Atoi(query.Get("downmbps"))
|
up := query.Get("up")
|
||||||
hysteria["up_mbps"], _ = strconv.Atoi(query.Get("upmbps"))
|
down := query.Get("down")
|
||||||
|
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)
|
||||||
@ -116,7 +114,6 @@ 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")
|
||||||
@ -150,7 +147,11 @@ 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
|
||||||
@ -162,49 +163,53 @@ 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" {
|
||||||
}
|
network = "h2"
|
||||||
if network == "http" {
|
|
||||||
network = "h2"
|
|
||||||
}
|
|
||||||
vless["network"] = network
|
|
||||||
}
|
}
|
||||||
|
vless["network"] = network
|
||||||
switch network {
|
switch network {
|
||||||
|
case "tcp":
|
||||||
|
if fakeType != "none" {
|
||||||
|
headers := 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") != "" {
|
||||||
|
httpOpts["method"] = query.Get("method")
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Get("path") != "" {
|
||||||
|
httpOpts["path"] = []string{query.Get("path")}
|
||||||
|
}
|
||||||
|
httpOpts["headers"] = headers
|
||||||
|
vless["http-opts"] = httpOpts
|
||||||
|
}
|
||||||
|
|
||||||
case "http":
|
case "http":
|
||||||
headers := make(map[string]any)
|
|
||||||
httpOpts := make(map[string]any)
|
|
||||||
|
|
||||||
if query.Get("method") != "" {
|
|
||||||
httpOpts["method"] = query.Get("method")
|
|
||||||
}
|
|
||||||
if query.Get("path") != "" {
|
|
||||||
httpOpts["path"] = query.Get("path")
|
|
||||||
}
|
|
||||||
headers["User-Agent"] = RandUserAgent()
|
|
||||||
httpOpts["headers"] = headers
|
|
||||||
|
|
||||||
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{"/"}
|
||||||
headers["User-Agent"] = RandUserAgent()
|
if query.Get("path") != "" {
|
||||||
h2Opts["path"] = query.Get("path")
|
h2Opts["path"] = []string{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
|
||||||
|
|
||||||
@ -219,7 +224,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
|||||||
proxies = append(proxies, vless)
|
proxies = append(proxies, vless)
|
||||||
|
|
||||||
case "vmess":
|
case "vmess":
|
||||||
dcBuf, err := enc.DecodeString(body)
|
dcBuf, err := encRaw.DecodeString(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -242,23 +247,28 @@ 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["sni"] = sni
|
vmess["servername"] = 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 tls != "" && tls != "0" && tls != "null" {
|
if strings.Contains(tls, "tls") {
|
||||||
if host != nil {
|
|
||||||
vmess["servername"] = host
|
|
||||||
}
|
|
||||||
vmess["tls"] = true
|
vmess["tls"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,11 +276,13 @@ 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"] = RandHost()
|
headers["Host"] = []string{values["host"].(string)}
|
||||||
headers["User-Agent"] = RandUserAgent()
|
}
|
||||||
httpOpts["method"] = values["method"]
|
httpOpts["path"] = []string{"/"}
|
||||||
httpOpts["path"] = values["path"]
|
if values["path"] != "" && values["path"] != nil {
|
||||||
|
httpOpts["path"] = []string{values["path"].(string)}
|
||||||
|
}
|
||||||
httpOpts["headers"] = headers
|
httpOpts["headers"] = headers
|
||||||
|
|
||||||
vmess["http-opts"] = httpOpts
|
vmess["http-opts"] = httpOpts
|
||||||
@ -278,9 +290,10 @@ 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
|
||||||
|
|
||||||
@ -289,15 +302,14 @@ 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{"/"}
|
||||||
headers["Host"] = RandHost()
|
if values["host"] != "" && values["host"] != nil {
|
||||||
headers["User-Agent"] = RandUserAgent()
|
headers["Host"] = values["host"].(string)
|
||||||
|
}
|
||||||
if values["path"] != nil {
|
if values["path"] != "" && values["path"] != nil {
|
||||||
wsOpts["path"] = values["path"]
|
wsOpts["path"] = values["path"].(string)
|
||||||
}
|
}
|
||||||
wsOpts["headers"] = headers
|
wsOpts["headers"] = headers
|
||||||
|
|
||||||
vmess["ws-opts"] = wsOpts
|
vmess["ws-opts"] = wsOpts
|
||||||
|
|
||||||
case "grpc":
|
case "grpc":
|
||||||
@ -318,7 +330,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
|||||||
port := urlSS.Port()
|
port := urlSS.Port()
|
||||||
|
|
||||||
if port == "" {
|
if port == "" {
|
||||||
dcBuf, err := enc.DecodeString(urlSS.Host)
|
dcBuf, err := encRaw.DecodeString(urlSS.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -335,11 +347,10 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if password, found = urlSS.User.Password(); !found {
|
if password, found = urlSS.User.Password(); !found {
|
||||||
dcBuf, err := enc.DecodeString(cipher)
|
dcBuf, _ := enc.DecodeString(cipher)
|
||||||
if err != nil {
|
if !strings.Contains(string(dcBuf), "2022-blake3") {
|
||||||
continue
|
dcBuf, _ = encRaw.DecodeString(cipher)
|
||||||
}
|
}
|
||||||
|
|
||||||
cipher, password, found = strings.Cut(string(dcBuf), ":")
|
cipher, password, found = strings.Cut(string(dcBuf), ":")
|
||||||
if !found {
|
if !found {
|
||||||
continue
|
continue
|
||||||
@ -354,11 +365,19 @@ 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 := enc.DecodeString(body)
|
dcBuf, err := encRaw.DecodeString(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -430,7 +449,7 @@ func urlSafe(data string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeUrlSafe(data string) string {
|
func decodeUrlSafe(data string) string {
|
||||||
dcBuf, err := base64.URLEncoding.DecodeString(data)
|
dcBuf, err := base64.RawURLEncoding.DecodeString(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,9 @@ 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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
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) {
|
||||||
|
@ -8,6 +8,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,11 +4,10 @@ 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 (
|
||||||
@ -57,6 +56,10 @@ 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)
|
||||||
@ -167,25 +170,31 @@ 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)
|
||||||
|
|
||||||
for res := range results {
|
count := 2
|
||||||
if res.error == nil {
|
for i := 0; i < count; i++ {
|
||||||
return res.Conn, nil
|
select {
|
||||||
}
|
case res := <-results:
|
||||||
|
if res.error == nil {
|
||||||
if !res.ipv6 {
|
return res.Conn, nil
|
||||||
primary = res
|
|
||||||
} else {
|
|
||||||
fallback = res
|
|
||||||
}
|
|
||||||
|
|
||||||
if primary.done && fallback.done {
|
|
||||||
if primary.resolved {
|
|
||||||
return nil, primary.error
|
|
||||||
} else if fallback.resolved {
|
|
||||||
return nil, fallback.error
|
|
||||||
} else {
|
|
||||||
return nil, primary.error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !res.ipv6 {
|
||||||
|
primary = res
|
||||||
|
} else {
|
||||||
|
fallback = res
|
||||||
|
}
|
||||||
|
|
||||||
|
if primary.done && fallback.done {
|
||||||
|
if primary.resolved {
|
||||||
|
return nil, primary.error
|
||||||
|
} else if fallback.resolved {
|
||||||
|
return nil, fallback.error
|
||||||
|
} else {
|
||||||
|
return nil, primary.error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +230,6 @@ 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}
|
||||||
|
|
||||||
@ -248,13 +256,13 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
|
|||||||
}
|
}
|
||||||
|
|
||||||
connCount := len(ips)
|
connCount := len(ips)
|
||||||
for res := range results {
|
for i := 0; i < connCount; i++ {
|
||||||
connCount--
|
select {
|
||||||
if res.error == nil {
|
case res := <-results:
|
||||||
return res.Conn, nil
|
if res.error == nil {
|
||||||
}
|
return res.Conn, nil
|
||||||
|
}
|
||||||
if connCount == 0 {
|
case <-ctx.Done():
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
52
component/geodata/init.go
Normal file
52
component/geodata/init.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -329,6 +329,7 @@ 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
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -2,15 +2,14 @@ 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 (
|
||||||
@ -61,4 +60,5 @@ 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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 (
|
||||||
|
@ -2,11 +2,10 @@ package process
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/nnip"
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -7,6 +7,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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() {
|
if ip.Is4() || ip.Is4In6() {
|
||||||
return []netip.Addr{ip}, nil
|
return []netip.Addr{ip}, nil
|
||||||
}
|
}
|
||||||
return []netip.Addr{}, ErrIPVersion
|
return []netip.Addr{}, ErrIPVersion
|
||||||
|
@ -2,17 +2,18 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -116,13 +117,13 @@ func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Meta
|
|||||||
|
|
||||||
host, err := sniffer.SniffTCP(bytes)
|
host, err := sniffer.SniffTCP(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
|
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = netip.ParseAddr(host)
|
_, err = netip.ParseAddr(host)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
|
//log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +143,7 @@ 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],
|
skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16]) (*SnifferDispatcher, error) {
|
||||||
) (*SnifferDispatcher, error) {
|
|
||||||
dispatcher := SnifferDispatcher{
|
dispatcher := SnifferDispatcher{
|
||||||
enable: true,
|
enable: true,
|
||||||
foreDomain: forceDomain,
|
foreDomain: forceDomain,
|
||||||
|
@ -3,10 +3,9 @@ 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 (
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
package sniffer
|
package sniffer
|
||||||
|
|
||||||
// TODO
|
//TODO
|
||||||
|
@ -13,7 +13,8 @@ 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"
|
||||||
|
@ -2,7 +2,9 @@ package trie
|
|||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var ErrorOverMaxValue = errors.New("the value don't over max value")
|
var (
|
||||||
|
ErrorOverMaxValue = errors.New("the value don't over max value")
|
||||||
|
)
|
||||||
|
|
||||||
type IpCidrNode struct {
|
type IpCidrNode struct {
|
||||||
Mark bool
|
Mark bool
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IPV6 bool
|
type IPV6 bool
|
||||||
|
@ -49,6 +49,7 @@ 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) {
|
||||||
@ -95,4 +96,5 @@ 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")))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ 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"
|
||||||
@ -13,11 +15,14 @@ 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"
|
||||||
@ -27,13 +32,10 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -252,6 +254,7 @@ 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",
|
||||||
@ -263,7 +266,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: true,
|
EnableProcess: false,
|
||||||
Tun: RawTun{
|
Tun: RawTun{
|
||||||
Enable: false,
|
Enable: false,
|
||||||
Device: "",
|
Device: "",
|
||||||
@ -279,6 +282,7 @@ 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",
|
||||||
@ -330,7 +334,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
|||||||
|
|
||||||
func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
log.Infoln("Start initial configuration in progress") // Segment finished in xxm
|
log.Infoln("Start initial configuration in progress") //Segment finished in xxm
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
config.Experimental = &rawCfg.Experimental
|
config.Experimental = &rawCfg.Experimental
|
||||||
config.Profile = &rawCfg.Profile
|
config.Profile = &rawCfg.Profile
|
||||||
@ -384,7 +388,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
|
||||||
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) // Segment finished in xxm
|
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +535,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)
|
rp, err := RP.ParseRuleProvider(name, mapping, R.ParseRule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -664,7 +668,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, "784")
|
addr, err = hostWithDefaultPort(u.Host, "853")
|
||||||
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)
|
||||||
@ -721,7 +725,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 := initGeoSite(); err != nil {
|
if err := geodata.InitGeoSite(); err != nil {
|
||||||
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
|
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,16 @@ 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 {
|
||||||
@ -48,46 +46,6 @@ 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) {
|
||||||
|
@ -2,14 +2,13 @@ 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 {
|
||||||
|
@ -7,8 +7,6 @@ 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
|
||||||
@ -77,7 +75,6 @@ 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)
|
||||||
}
|
}
|
||||||
@ -187,7 +184,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() *buf.Buffer
|
Data() []byte
|
||||||
|
|
||||||
// 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
|
||||||
@ -195,7 +192,8 @@ 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)
|
||||||
|
|
||||||
N.PacketWriter
|
// Drop call after packet is used, could recycle buffer in this function.
|
||||||
|
Drop()
|
||||||
|
|
||||||
// LocalAddr returns the source IP/Port of packet
|
// LocalAddr returns the source IP/Port of packet
|
||||||
LocalAddr() net.Addr
|
LocalAddr() net.Addr
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Socks addr type
|
// Socks addr type
|
||||||
@ -172,18 +170,6 @@ 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
|
||||||
|
@ -13,7 +13,9 @@ const (
|
|||||||
HTTP
|
HTTP
|
||||||
)
|
)
|
||||||
|
|
||||||
var List = []Type{TLS, HTTP}
|
var (
|
||||||
|
List = []Type{TLS, HTTP}
|
||||||
|
)
|
||||||
|
|
||||||
type Type int
|
type Type int
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,14 +4,15 @@ 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 {
|
||||||
|
@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"go.uber.org/atomic"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
@ -10,8 +11,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 (
|
||||||
|
@ -9,6 +9,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
29
dns/doq.go
29
dns/doq.go
@ -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-i00"
|
const NextProtoDQ = "doq"
|
||||||
|
|
||||||
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() (quic.Connection, error) {
|
func (dc *quicClient) getSession(ctx context.Context) (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() (quic.Connection, error) {
|
|||||||
defer dc.Unlock()
|
defer dc.Unlock()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
session, err = dc.openSession()
|
session, err = dc.openSession(ctx)
|
||||||
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()
|
session, err = dc.openSession(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -127,11 +127,11 @@ func (dc *quicClient) getSession() (quic.Connection, error) {
|
|||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *quicClient) openSession() (quic.Connection, error) {
|
func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error) {
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: false,
|
||||||
NextProtos: []string{
|
NextProtos: []string{
|
||||||
"http/1.1", "h2", NextProtoDQ,
|
NextProtoDQ,
|
||||||
},
|
},
|
||||||
SessionTicketsDisabled: false,
|
SessionTicketsDisabled: false,
|
||||||
}
|
}
|
||||||
@ -149,6 +149,7 @@ func (dc *quicClient) openSession() (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
|
||||||
}
|
}
|
||||||
@ -162,12 +163,12 @@ func (dc *quicClient) openSession() (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(context.Background(), "udp", "")
|
udp, err = dialer.ListenPacket(ctx, "udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
conn, err := dialContextExtra(context.Background(), dc.proxyAdapter, "udp", ip, port)
|
conn, err := dialContextExtra(ctx, dc.proxyAdapter, "udp", ip, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -180,7 +181,7 @@ func (dc *quicClient) openSession() (quic.Connection, error) {
|
|||||||
udp = wrapConn
|
udp = wrapConn
|
||||||
}
|
}
|
||||||
|
|
||||||
session, err := quic.Dial(udp, &udpAddr, host, tlsConfig, quicConfig)
|
session, err := quic.DialContext(ctx, 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)
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ func (dc *quicClient) openSession() (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()
|
session, err := dc.getSession(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ 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"
|
||||||
@ -10,6 +9,7 @@ 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 {
|
||||||
|
@ -12,6 +12,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,11 +46,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 ip.Is6() && q.Qtype == D.TypeAAAA {
|
} else if 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}
|
||||||
rr.AAAA = ip.AsSlice()
|
ip := ip.As16()
|
||||||
|
rr.AAAA = ip[:]
|
||||||
msg.Answer = []D.RR{rr}
|
msg.Answer = []D.RR{rr}
|
||||||
} else {
|
} else {
|
||||||
return next(ctx, r)
|
return next(ctx, r)
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go.uber.org/atomic"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
@ -15,8 +16,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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
34
dns/util.go
34
dns/util.go
@ -15,6 +15,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,17 +152,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +171,29 @@ 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
9
go.mod
@ -13,8 +13,9 @@ 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-20220609123159-a93588755159
|
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c
|
||||||
|
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
|
||||||
@ -27,7 +28,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-20220608164250-635b8c9b7f68
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c
|
||||||
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
|
||||||
@ -38,7 +39,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.20220607074613-210c46c75b15
|
replace github.com/tobyxdd/hysteria => github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256
|
||||||
|
|
||||||
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
18
go.sum
@ -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.20220607074613-210c46c75b15 h1:SraqLzYEGfrV8ETkVYc5evvCrn95hMFdCtcXXP8bA9Y=
|
github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256 h1:wm5RrQfwJS63pe5G15AKdXfrwlIYFciwCs3MrVxzxSU=
|
||||||
github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15/go.mod h1:bXVjOca4Xf3JRenwuPKu02XaOiZwejrMSlgsu/U88J4=
|
github.com/MetaCubeX/hysteria v1.0.5-0.20220626134949-6fa84cd3e256/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,10 +305,12 @@ 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-20220609123159-a93588755159 h1:G3fww5jjADkHWi6yDOEzkZbQ6lnrytv0mKesBtEslxo=
|
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c h1:98QC0wtaD648MFPw82KaT1O9LloQgR4ZyIDtNtsno8Y=
|
||||||
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
|
github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c/go.mod h1:I67R/q5f67xDExL2kL3RLIP7kGJBOPkYXkpRAykgC+E=
|
||||||
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 h1:Jhgjyb2jXL4GtwJec6/kgeTqaQXsvMiNX2wAkGOSD3I=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220627234717-689e0165ef2c/go.mod h1:ng5pxdNnKZWlxzZTXRqWeY0ftzhScPZmjgJGJeRuPYY=
|
||||||
|
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=
|
||||||
@ -564,8 +566,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-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
|
||||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/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=
|
||||||
|
@ -2,6 +2,7 @@ package executor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/listener/inner"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -13,7 +14,6 @@ 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,7 +25,6 @@ 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"
|
||||||
@ -89,6 +88,10 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +130,9 @@ 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 {
|
||||||
@ -224,6 +229,7 @@ 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)
|
||||||
|
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,8 +279,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")
|
||||||
|
@ -4,6 +4,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -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,6 +13,7 @@ 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"
|
||||||
)
|
)
|
||||||
@ -45,6 +46,7 @@ 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) {
|
||||||
@ -84,6 +86,10 @@ 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()
|
||||||
|
@ -8,6 +8,7 @@ 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"
|
||||||
|
@ -2,15 +2,14 @@ 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 {
|
||||||
@ -65,10 +64,11 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
|
ctx, cancel := context.WithTimeout(r.Context(), 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()))
|
||||||
|
@ -6,6 +6,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -12,11 +12,14 @@ 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 SwitchProxiesCallback func(sGroup string, sProxy string)
|
var (
|
||||||
|
SwitchProxiesCallback func(sGroup string, sProxy string)
|
||||||
|
)
|
||||||
|
|
||||||
func proxyRouter() http.Handler {
|
func proxyRouter() http.Handler {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
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"
|
||||||
)
|
)
|
||||||
|
@ -12,6 +12,7 @@ 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"
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
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
|
||||||
|
@ -2,6 +2,8 @@ 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"
|
||||||
@ -11,14 +13,12 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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/sagernet/sing/common/buf"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPListener struct {
|
type UDPListener struct {
|
||||||
@ -49,35 +49,34 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
buffer := buf.NewPacket()
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
n, remoteAddr, err := l.ReadFrom(buffer.FreeBytes())
|
n, remoteAddr, err := l.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buffer.Release()
|
pool.Put(buf)
|
||||||
if sl.closed {
|
if sl.closed {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buffer.Extend(n)
|
handleSocksUDP(l, in, buf[:n], remoteAddr)
|
||||||
handleSocksUDP(l, in, buffer, remoteAddr)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return sl, nil
|
return sl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buffer *buf.Buffer, addr net.Addr) {
|
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
|
||||||
buffer.Advance(3)
|
target, payload, err := socks5.DecodeUDPPacket(buf)
|
||||||
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
|
||||||
buffer.Release()
|
pool.Put(buf)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
packet := &packet{
|
packet := &packet{
|
||||||
pc: pc,
|
pc: pc,
|
||||||
rAddr: addr,
|
rAddr: addr,
|
||||||
payload: buffer,
|
payload: payload,
|
||||||
|
bufRef: buf,
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case in <- inbound.NewPacket(target, packet, C.SOCKS5):
|
case in <- inbound.NewPacket(target, packet, C.SOCKS5):
|
||||||
|
@ -3,19 +3,18 @@ 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 *buf.Buffer
|
payload []byte
|
||||||
|
bufRef []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Data() *buf.Buffer {
|
func (c *packet) Data() []byte {
|
||||||
return c.payload
|
return c.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,15 +27,11 @@ 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)
|
||||||
|
}
|
||||||
|
@ -3,16 +3,15 @@ package tproxy
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/Dreamacro/clash/common/pool"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type packet struct {
|
type packet struct {
|
||||||
lAddr *net.UDPAddr
|
lAddr *net.UDPAddr
|
||||||
buf *buf.Buffer
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Data() *buf.Buffer {
|
func (c *packet) Data() []byte {
|
||||||
return c.buf
|
return c.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,18 +27,11 @@ 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)
|
||||||
|
}
|
||||||
|
@ -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/sagernet/sing/common/buf"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
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 {
|
||||||
buffer := buf.NewPacket()
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
n, oobn, _, lAddr, err := c.ReadMsgUDP(buffer.FreeBytes(), oob)
|
n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buffer.Release()
|
pool.Put(buf)
|
||||||
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
|
||||||
}
|
}
|
||||||
buffer.Extend(n)
|
handlePacketConn(l, in, buf[:n], lAddr, rAddr)
|
||||||
handlePacketConn(l, in, buffer, lAddr, rAddr)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return rl, nil
|
return rl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf *buf.Buffer, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
|
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, 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(M.SocksaddrFromNet(rAddr), pkt, C.TPROXY):
|
case in <- inbound.NewPacket(target, pkt, C.TPROXY):
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ 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
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
package fdbased
|
package fdbased
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FD struct {
|
type FD struct {
|
||||||
|
@ -4,6 +4,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -7,6 +7,7 @@ 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"
|
||||||
|
@ -8,6 +8,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -16,6 +16,7 @@ type TUN struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func closeIO(t *TUN) {
|
func closeIO(t *TUN) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEq(t *TUN) error {
|
func newEq(t *TUN) error {
|
||||||
|
@ -2,6 +2,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -1,13 +1,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"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
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 (
|
||||||
|
@ -2,13 +2,14 @@ package commons
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Dreamacro/clash/log"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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"}
|
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"}
|
||||||
|
)
|
||||||
|
|
||||||
func ipv4MaskString(bits int) string {
|
func ipv4MaskString(bits int) string {
|
||||||
m := net.CIDRMask(bits, 32)
|
m := net.CIDRMask(bits, 32)
|
||||||
|
@ -2,12 +2,11 @@ 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) {
|
||||||
@ -61,7 +60,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
|
||||||
pref := 9000
|
var pref = 9000
|
||||||
|
|
||||||
for _, route := range defaultRoutes {
|
for _, route := range defaultRoutes {
|
||||||
_, ipn, err := net.ParseCIDR(route)
|
_, ipn, err := net.ParseCIDR(route)
|
||||||
|
@ -4,11 +4,10 @@ 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/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAutoDetectInterface() (string, error) {
|
func GetAutoDetectInterface() (string, error) {
|
||||||
|
@ -10,6 +10,7 @@ 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"
|
||||||
|
@ -15,8 +15,6 @@ 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)
|
||||||
@ -98,24 +96,27 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target := M.SocksaddrFromNet(rAddr)
|
target := socks5.ParseAddrToSocksAddr(rAddr)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
buffer := buf.NewPacket()
|
buf := pool.Get(pool.UDPBufferSize)
|
||||||
|
|
||||||
n, addr, err := tunConn.ReadFrom(buffer.FreeBytes())
|
n, addr, err := tunConn.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
buffer.Release()
|
_ = pool.Put(buf)
|
||||||
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 buffer.Release()
|
defer func() {
|
||||||
|
_ = pool.Put(buf)
|
||||||
|
}()
|
||||||
|
|
||||||
msg, err1 := D.RelayDnsPacket(buffer.Bytes())
|
msg, err1 := D.RelayDnsPacket(payload)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -129,7 +130,7 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
|||||||
gvPacket := &packet{
|
gvPacket := &packet{
|
||||||
pc: tunConn,
|
pc: tunConn,
|
||||||
rAddr: addr,
|
rAddr: addr,
|
||||||
payload: buffer,
|
payload: payload,
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -6,6 +6,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ 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"
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user