From a6c144038b9eef39d87a1b84e71af2a0a75043a7 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Thu, 22 Dec 2022 12:00:56 +0800 Subject: [PATCH 1/6] Chore: improve redir getorigdst --- listener/redir/tcp_linux.go | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/listener/redir/tcp_linux.go b/listener/redir/tcp_linux.go index c4a47d8e..a8b6d967 100644 --- a/listener/redir/tcp_linux.go +++ b/listener/redir/tcp_linux.go @@ -1,12 +1,16 @@ package redir import ( + "encoding/binary" "errors" "net" + "net/netip" "syscall" "unsafe" "github.com/Dreamacro/clash/transport/socks5" + + "golang.org/x/sys/unix" ) const ( @@ -25,27 +29,22 @@ func parserPacket(conn net.Conn) (socks5.Addr, error) { return nil, err } - var addr socks5.Addr + var addr netip.AddrPort rc.Control(func(fd uintptr) { addr, err = getorigdst(fd) }) - return addr, err + return socks5.AddrFromStdAddrPort(addr), err } // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c -func getorigdst(fd uintptr) (socks5.Addr, error) { - raw := syscall.RawSockaddrInet4{} - siz := uint32(unsafe.Sizeof(raw)) - if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { - return nil, err +func getorigdst(fd uintptr) (netip.AddrPort, error) { + addr := unix.RawSockaddrInet4{} + size := uint32(unsafe.Sizeof(addr)) + if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0); err != nil { + return netip.AddrPort{}, err } - - addr := make([]byte, 1+net.IPv4len+2) - addr[0] = socks5.AtypIPv4 - copy(addr[1:1+net.IPv4len], raw.Addr[:]) - port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian - addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] - return addr, nil + port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:]) + return netip.AddrPortFrom(netip.AddrFrom4(addr.Addr), port), nil } From d8ac82be36303e5e9e351e0a1281bd9886f54788 Mon Sep 17 00:00:00 2001 From: igoogolx <27353191+igoogolx@users.noreply.github.com> Date: Thu, 22 Dec 2022 12:09:24 +0800 Subject: [PATCH 2/6] Fix: broken build badge (#2470) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6dff747b..0f1a05df 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

- Github Actions + Github Actions From cdc7d449a606f83b814ee0df3674749b94b285a0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 22 Dec 2022 12:42:38 +0800 Subject: [PATCH 3/6] Fix: safeConnClose not working (#2463) --- adapter/outbound/http.go | 4 +++- adapter/outbound/shadowsocks.go | 4 +++- adapter/outbound/shadowsocksr.go | 4 +++- adapter/outbound/snell.go | 4 +++- adapter/outbound/socks5.go | 8 ++++++-- adapter/outbound/trojan.go | 12 +++++++++--- adapter/outbound/vmess.go | 16 ++++++++++++---- 7 files changed, 39 insertions(+), 13 deletions(-) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 480710dc..b7425100 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -63,7 +63,9 @@ func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata, opts ...di } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = h.StreamConn(c, metadata) if err != nil { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 6ed78050..e1878dfa 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -81,7 +81,9 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, op } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = ss.StreamConn(c, metadata) return NewConn(c, ss), err diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 57ef5604..4542eebc 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -66,7 +66,9 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = ssr.StreamConn(c, metadata) return NewConn(c, ssr), err diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 07f3d89d..ab791908 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -80,7 +80,9 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = s.StreamConn(c, metadata) return NewConn(c, s), err diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 3269457d..4f816211 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -69,7 +69,9 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts .. } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = ss.StreamConn(c, metadata) if err != nil { @@ -95,7 +97,9 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, c = cc } - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) tcpKeepAlive(c) var user *socks5.User diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 064cd3c2..fa549df0 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -109,7 +109,9 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ... } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = t.StreamConn(c, metadata) if err != nil { @@ -129,13 +131,17 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) } else { c, err = dialer.DialContext(ctx, "tcp", t.addr, t.Base.DialOptions(opts...)...) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) tcpKeepAlive(c) c, err = t.plainStream(c) if err != nil { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index aaa9105d..8fa74fbd 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -195,7 +195,9 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d if err != nil { return nil, err } - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = v.client.StreamConn(c, parseVmessAddr(metadata)) if err != nil { @@ -210,7 +212,9 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = v.StreamConn(c, metadata) return NewConn(c, v), err @@ -234,7 +238,9 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o if err != nil { return nil, err } - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = v.client.StreamConn(c, parseVmessAddr(metadata)) } else { @@ -243,7 +249,9 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } tcpKeepAlive(c) - defer safeConnClose(c, err) + defer func(c net.Conn) { + safeConnClose(c, err) + }(c) c, err = v.StreamConn(c, metadata) } From 4a579177833f6cec6014d8894cf985f6689b5f26 Mon Sep 17 00:00:00 2001 From: ALICE Date: Thu, 22 Dec 2022 13:30:23 +0800 Subject: [PATCH 4/6] Chore: skip cache acme challenge dns msg (#2469) --- dns/util.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dns/util.go b/dns/util.go index df3a3331..05c734e8 100644 --- a/dns/util.go +++ b/dns/util.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "strings" "time" "github.com/Dreamacro/clash/common/cache" @@ -16,6 +17,12 @@ import ( ) func putMsgToCache(c *cache.LruCache, key string, msg *D.Msg) { + // skip dns cache for acme challenge + if q := msg.Question[0]; q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge") { + log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name) + return + } + var ttl uint32 switch { case len(msg.Answer) != 0: From fbca37c42b444429c4841983306553ffa2109cc0 Mon Sep 17 00:00:00 2001 From: embeddedlove <118641459+embeddedlove@users.noreply.github.com> Date: Thu, 22 Dec 2022 19:25:30 +0800 Subject: [PATCH 5/6] Feature: REDIRECT support IPv6 (#2473) --- listener/redir/tcp_linux.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/listener/redir/tcp_linux.go b/listener/redir/tcp_linux.go index a8b6d967..b65c34ee 100644 --- a/listener/redir/tcp_linux.go +++ b/listener/redir/tcp_linux.go @@ -32,7 +32,11 @@ func parserPacket(conn net.Conn) (socks5.Addr, error) { var addr netip.AddrPort rc.Control(func(fd uintptr) { - addr, err = getorigdst(fd) + if ip4 := c.LocalAddr().(*net.TCPAddr).IP.To4(); ip4 != nil { + addr, err = getorigdst(fd) + } else { + addr, err = getorigdst6(fd) + } }) return socks5.AddrFromStdAddrPort(addr), err @@ -48,3 +52,13 @@ func getorigdst(fd uintptr) (netip.AddrPort, error) { port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:]) return netip.AddrPortFrom(netip.AddrFrom4(addr.Addr), port), nil } + +func getorigdst6(fd uintptr) (netip.AddrPort, error) { + addr := unix.RawSockaddrInet6{} + size := uint32(unsafe.Sizeof(addr)) + if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0); err != nil { + return netip.AddrPort{}, err + } + port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:]) + return netip.AddrPortFrom(netip.AddrFrom16(addr.Addr), port), nil +} From 2301b909d25587f2846f049363af5b9b4769d098 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Sat, 31 Dec 2022 16:30:29 +0800 Subject: [PATCH 6/6] Fix: immediately update provider when modtime too old --- adapter/provider/fetcher.go | 52 +++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/adapter/provider/fetcher.go b/adapter/provider/fetcher.go index 4a7be8b1..297e82f7 100644 --- a/adapter/provider/fetcher.go +++ b/adapter/provider/fetcher.go @@ -21,6 +21,7 @@ type parser = func([]byte) (any, error) type fetcher struct { name string vehicle types.Vehicle + interval time.Duration updatedAt *time.Time ticker *time.Ticker done chan struct{} @@ -39,15 +40,17 @@ func (f *fetcher) VehicleType() types.VehicleType { func (f *fetcher) Initial() (any, error) { var ( - buf []byte - err error - isLocal bool + buf []byte + err error + isLocal bool + immediatelyUpdate bool ) if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil { buf, err = os.ReadFile(f.vehicle.Path()) modTime := stat.ModTime() f.updatedAt = &modTime isLocal = true + immediatelyUpdate = time.Since(modTime) > f.interval } else { buf, err = f.vehicle.Read() } @@ -86,7 +89,7 @@ func (f *fetcher) Initial() (any, error) { // pull proxies automatically if f.ticker != nil { - go f.pullLoop() + go f.pullLoop(immediatelyUpdate) } return proxies, nil @@ -130,25 +133,33 @@ func (f *fetcher) Destroy() error { return nil } -func (f *fetcher) pullLoop() { +func (f *fetcher) pullLoop(immediately bool) { + update := func() { + elm, same, err := f.Update() + if err != nil { + log.Warnln("[Provider] %s pull error: %s", f.Name(), err.Error()) + return + } + + if same { + log.Debugln("[Provider] %s's proxies doesn't change", f.Name()) + return + } + + log.Infoln("[Provider] %s's proxies update", f.Name()) + if f.onUpdate != nil { + f.onUpdate(elm) + } + } + + if immediately { + update() + } + for { select { case <-f.ticker.C: - elm, same, err := f.Update() - if err != nil { - log.Warnln("[Provider] %s pull error: %s", f.Name(), err.Error()) - continue - } - - if same { - log.Debugln("[Provider] %s's proxies doesn't change", f.Name()) - continue - } - - log.Infoln("[Provider] %s's proxies update", f.Name()) - if f.onUpdate != nil { - f.onUpdate(elm) - } + update() case <-f.done: f.ticker.Stop() return @@ -178,6 +189,7 @@ func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, pars name: name, ticker: ticker, vehicle: vehicle, + interval: interval, parser: parser, done: make(chan struct{}, 1), onUpdate: onUpdate,