From b3d75948138403284f7e7a532807d2701dc46781 Mon Sep 17 00:00:00 2001 From: Anankke Date: Tue, 12 Apr 2022 22:06:06 -0400 Subject: [PATCH 01/12] Chore: add `none` alias to `dummy` on ShadowsocksR (#2056) --- adapter/outbound/shadowsocksr.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index a5f07ef6..ea1c2838 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -92,6 +92,12 @@ func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Me } func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { + // SSR protocol compatibility + // https://github.com/Dreamacro/clash/pull/2056 + if option.Cipher == "none" { + option.Cipher = "dummy" + } + addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) cipher := option.Cipher password := option.Password @@ -103,13 +109,14 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { ivSize int key []byte ) + if option.Cipher == "dummy" { ivSize = 0 key = core.Kdf(option.Password, 16) } else { ciph, ok := coreCiph.(*core.StreamCipher) if !ok { - return nil, fmt.Errorf("%s is not dummy or a supported stream cipher in ssr", cipher) + return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher) } ivSize = ciph.IVSize() key = ciph.Key From ca76e5cf0eacb682f139a65b39352c72b1ac0b08 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:47:47 +0800 Subject: [PATCH 02/12] Chore: fix typo --- component/resolver/enhancer.go | 6 +++--- dns/enhancer.go | 2 +- hub/executor/executor.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/component/resolver/enhancer.go b/component/resolver/enhancer.go index 503211c4..5a8c4f4f 100644 --- a/component/resolver/enhancer.go +++ b/component/resolver/enhancer.go @@ -15,7 +15,7 @@ type Enhancer interface { FindHostByIP(net.IP) (string, bool) FlushFakeIP() error InsertHostByIP(net.IP, string) - StoreFakePoolSate() + StoreFakePoolState() } func FakeIPEnabled() bool { @@ -79,8 +79,8 @@ func FlushFakeIP() error { return nil } -func StoreFakePoolSate() { +func StoreFakePoolState() { if mapper := DefaultHostMapper; mapper != nil { - mapper.StoreFakePoolSate() + mapper.StoreFakePoolState() } } diff --git a/dns/enhancer.go b/dns/enhancer.go index 4e828987..ff654765 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -101,7 +101,7 @@ func (h *ResolverEnhancer) PatchFrom(o *ResolverEnhancer) { } } -func (h *ResolverEnhancer) StoreFakePoolSate() { +func (h *ResolverEnhancer) StoreFakePoolState() { if h.fakePool != nil { h.fakePool.StoreState() } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index ace85c51..c9583a11 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -347,7 +347,7 @@ func updateMitm(mitm *config.Mitm) { func Shutdown() { P.Cleanup() tproxy.CleanupTProxyIPTables() - resolver.StoreFakePoolSate() + resolver.StoreFakePoolState() log.Warnln("Clash shutting down") } From c282d662ca78e4044bb7b2af44f37ed58bdcd9bc Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Wed, 13 Apr 2022 17:51:21 +0800 Subject: [PATCH 03/12] Fix: make golangci lint support multi GOOS --- Makefile | 6 +++++- component/process/process_windows.go | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index aed9ca4b..36d7b3a2 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,11 @@ all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST) releases: $(gz_releases) $(zip_releases) lint: - golangci-lint run ./... + GOOS=darwin golangci-lint run ./... + GOOS=windows golangci-lint run ./... + GOOS=linux golangci-lint run ./... + GOOS=freebsd golangci-lint run ./... + GOOS=openbsd golangci-lint run ./... clean: rm $(BINDIR)/* diff --git a/component/process/process_windows.go b/component/process/process_windows.go index e2fb96ca..c51a36f6 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -174,7 +174,7 @@ func newSearcher(isV4, isTCP bool) *searcher { func getTransportTable(fn uintptr, family int, class int) ([]byte, error) { for size, buf := uint32(8), make([]byte, 8); ; { ptr := unsafe.Pointer(&buf[0]) - err, _, _ := syscall.Syscall6(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0) + err, _, _ := syscall.SyscallN(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0) switch err { case 0: @@ -209,7 +209,7 @@ func getExecPathFromPID(pid uint32) (string, error) { buf := make([]uint16, syscall.MAX_LONG_PATH) size := uint32(len(buf)) - r1, _, err := syscall.Syscall6( + r1, _, err := syscall.SyscallN( queryProcName, 4, uintptr(h), uintptr(1), From 4dfba73e5cd015f610ba6864546426e72db605a2 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Thu, 14 Apr 2022 23:27:49 +0800 Subject: [PATCH 04/12] Fix: SyscallN should not use nargs --- component/process/process_windows.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/component/process/process_windows.go b/component/process/process_windows.go index c51a36f6..26a389a0 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -174,7 +174,7 @@ func newSearcher(isV4, isTCP bool) *searcher { func getTransportTable(fn uintptr, family int, class int) ([]byte, error) { for size, buf := uint32(8), make([]byte, 8); ; { ptr := unsafe.Pointer(&buf[0]) - err, _, _ := syscall.SyscallN(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0) + err, _, _ := syscall.SyscallN(fn, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0) switch err { case 0: @@ -210,12 +210,12 @@ func getExecPathFromPID(pid uint32) (string, error) { buf := make([]uint16, syscall.MAX_LONG_PATH) size := uint32(len(buf)) r1, _, err := syscall.SyscallN( - queryProcName, 4, + queryProcName, uintptr(h), uintptr(1), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&size)), - 0, 0) + ) if r1 == 0 { return "", err } From 2c9a4d276a07f1567f6ca1ae7e736a4dfa4b21da Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Thu, 14 Apr 2022 23:37:41 +0800 Subject: [PATCH 05/12] Chore: add more github action cache --- .github/workflows/docker.yml | 4 ++++ .github/workflows/release.yml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 18590edd..19fe0d88 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -49,6 +49,8 @@ jobs: platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 push: true tags: 'dreamacro/clash:dev,ghcr.io/dreamacro/clash:dev' + cache-from: type=gha + cache-to: type=gha,mode=max - name: Get all docker tags if: startsWith(github.ref, 'refs/tags/') @@ -74,3 +76,5 @@ jobs: platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 push: true tags: ${{steps.tags.outputs.result}} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8226d875..08f97ba3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,9 @@ jobs: - name: Cache go module uses: actions/cache@v2 with: - path: ~/go/pkg/mod + path: | + ~/go/pkg/mod + ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- From 6327cf74342ee6113412c17e2bbb88f592836104 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Fri, 15 Apr 2022 00:29:21 +0800 Subject: [PATCH 06/12] Chore: adjust mitm proxy --- listener/mitm/client.go | 2 - listener/mitm/proxy.go | 100 +++++++++++++++++---------------------- listener/mitm/session.go | 7 +++ listener/mitm/utils.go | 7 +++ 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/listener/mitm/client.go b/listener/mitm/client.go index 278de173..a9ef56d1 100644 --- a/listener/mitm/client.go +++ b/listener/mitm/client.go @@ -13,8 +13,6 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -var ErrCertUnsupported = errors.New("tls: client cert unsupported") - func newClient(source net.Addr, userAgent string, in chan<- C.ConnContext) *http.Client { return &http.Client{ Transport: &http.Transport{ diff --git a/listener/mitm/proxy.go b/listener/mitm/proxy.go index 88fef3db..ce5e8f2e 100644 --- a/listener/mitm/proxy.go +++ b/listener/mitm/proxy.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/cache" N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" @@ -63,7 +62,7 @@ readLoop: session := newSession(conn, request, response) - source = parseSourceAddress(session.request, c, source) + source = parseSourceAddress(session.request, c.RemoteAddr(), source) session.request.RemoteAddr = source.String() if !trusted { @@ -80,42 +79,45 @@ readLoop: break readLoop // close connection } - if couldBeWithManInTheMiddleAttack(session.request.URL.Host, opt) { - b := make([]byte, 1) - if _, err = session.conn.Read(b); err != nil { - handleError(opt, session, err) + if strings.HasSuffix(session.request.URL.Host, ":80") { + goto readLoop + } + + b := make([]byte, 1) + if _, err = session.conn.Read(b); err != nil { + handleError(opt, session, err) + break readLoop // close connection + } + + buff := make([]byte, session.conn.(*N.BufferedConn).Buffered()) + if _, err = session.conn.Read(buff); err != nil { + handleError(opt, session, err) + break readLoop // close connection + } + + mrConn := &multiReaderConn{ + Conn: session.conn, + reader: io.MultiReader(bytes.NewReader(b), bytes.NewReader(buff), session.conn), + } + + // TLS handshake. + if b[0] == 0x16 { + // TODO serve by generic host name maybe better? + tlsConn := tls.Server(mrConn, opt.CertConfig.NewTLSConfigForHost(session.request.URL.Host)) + + // Handshake with the local client + if err = tlsConn.Handshake(); err != nil { + session.response = session.NewErrorResponse(fmt.Errorf("handshake failed: %w", err)) + _ = writeResponse(session, false) break readLoop // close connection } - buff := make([]byte, session.conn.(*N.BufferedConn).Buffered()) - _, _ = session.conn.Read(buff) - - mrc := &multiReaderConn{ - Conn: session.conn, - reader: io.MultiReader(bytes.NewReader(b), bytes.NewReader(buff), session.conn), - } - - // TLS handshake. - if b[0] == 0x16 { - // TODO serve by generic host name maybe better? - tlsConn := tls.Server(mrc, opt.CertConfig.NewTLSConfigForHost(session.request.URL.Host)) - - // Handshake with the local client - if err = tlsConn.Handshake(); err != nil { - handleError(opt, session, err) - break readLoop // close connection - } - - c = tlsConn - goto startOver // hijack and decrypt tls connection - } - - // maybe it's the others encrypted connection - in <- inbound.NewHTTPS(session.request, mrc) + c = tlsConn + } else { + c = mrConn } - // maybe it's a http connection - goto readLoop + goto startOver } prepareRequest(c, session.request) @@ -149,7 +151,7 @@ readLoop: session.request.RequestURI = "" if session.request.URL.Host == "" { - session.response = session.NewErrorResponse(errors.New("invalid URL")) + session.response = session.NewErrorResponse(ErrInvalidURL) } else { client = newClientBySourceAndUserAgentIfNil(client, session.request, source, in) @@ -202,9 +204,7 @@ func writeResponse(session *Session, keepAlive bool) error { session.response.Header.Set("Keep-Alive", "timeout=25") } - // session.response.Close = !keepAlive // let handler do it - - return session.response.Write(session.conn) + return session.writeResponse() } func handleApiRequest(session *Session, opt *Option) error { @@ -224,7 +224,7 @@ func handleApiRequest(session *Session, opt *Option) error { session.response.Header.Set("Content-Type", "application/x-x509-ca-cert") session.response.ContentLength = int64(len(b)) - return session.response.Write(session.conn) + return session.writeResponse() } b := ` @@ -254,7 +254,7 @@ func handleApiRequest(session *Session, opt *Option) error { session.response.Header.Set("Content-Type", "text/html;charset=utf-8") session.response.ContentLength = int64(len(b)) - return session.response.Write(session.conn) + return session.writeResponse() } func handleError(opt *Option, session *Session, err error) { @@ -292,38 +292,26 @@ func prepareRequest(conn net.Conn, request *http.Request) { H.RemoveExtraHTTPHostPort(request) } -func couldBeWithManInTheMiddleAttack(hostname string, opt *Option) bool { - if opt.CertConfig == nil { - return false - } - - if _, port, err := net.SplitHostPort(hostname); err == nil && (port == "443" || port == "8443") { - return true - } - - return false -} - -func parseSourceAddress(req *http.Request, c net.Conn, source net.Addr) net.Addr { +func parseSourceAddress(req *http.Request, connSource, source net.Addr) net.Addr { if source != nil { return source } sourceAddress := req.Header.Get("Origin-Request-Source-Address") if sourceAddress == "" { - return c.RemoteAddr() + return connSource } req.Header.Del("Origin-Request-Source-Address") host, port, err := net.SplitHostPort(sourceAddress) if err != nil { - return c.RemoteAddr() + return connSource } p, err := strconv.ParseUint(port, 10, 16) if err != nil { - return c.RemoteAddr() + return connSource } if ip := net.ParseIP(host); ip != nil { @@ -333,7 +321,7 @@ func parseSourceAddress(req *http.Request, c net.Conn, source net.Addr) net.Addr } } - return c.RemoteAddr() + return connSource } func newClientBySourceAndUserAgentIfNil(cli *http.Client, req *http.Request, source net.Addr, in chan<- C.ConnContext) *http.Client { diff --git a/listener/mitm/session.go b/listener/mitm/session.go index 42c7faf7..c2622a69 100644 --- a/listener/mitm/session.go +++ b/listener/mitm/session.go @@ -39,6 +39,13 @@ func (s *Session) NewErrorResponse(err error) *http.Response { return NewErrorResponse(s.request, err) } +func (s *Session) writeResponse() error { + if s.response == nil { + return ErrInvalidResponse + } + return s.response.Write(s.conn) +} + func newSession(conn net.Conn, request *http.Request, response *http.Response) *Session { return &Session{ conn: conn, diff --git a/listener/mitm/utils.go b/listener/mitm/utils.go index 8ca8054d..5c3b15bd 100644 --- a/listener/mitm/utils.go +++ b/listener/mitm/utils.go @@ -3,6 +3,7 @@ package mitm import ( "bytes" "compress/gzip" + "errors" "fmt" "io" "io/ioutil" @@ -14,6 +15,12 @@ import ( "golang.org/x/text/transform" ) +var ( + ErrCertUnsupported = errors.New("tls: client cert unsupported") + ErrInvalidResponse = errors.New("invalid response") + ErrInvalidURL = errors.New("invalid URL") +) + type multiReaderConn struct { net.Conn reader io.Reader From 46f7c5e5653d167e3e1c5e69edf41369436a1d45 Mon Sep 17 00:00:00 2001 From: "Author: littoy" <103546957+littoy@users.noreply.github.com> Date: Fri, 15 Apr 2022 00:46:07 +0800 Subject: [PATCH 07/12] Fix: only rule mode need break conn when sni update --- tunnel/statistic/sniffing.go | 12 +++++++++--- tunnel/statistic/tracker.go | 2 +- tunnel/tunnel.go | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tunnel/statistic/sniffing.go b/tunnel/statistic/sniffing.go index 2d1f1bfd..5f8136c8 100644 --- a/tunnel/statistic/sniffing.go +++ b/tunnel/statistic/sniffing.go @@ -16,6 +16,7 @@ type sniffing struct { metadata *C.Metadata totalWrite *atomic.Uint64 + allowBreak bool } func (r *sniffing) Read(b []byte) (int, error) { @@ -30,8 +31,12 @@ func (r *sniffing) Write(b []byte) (int, error) { } else { resolver.InsertHostByIP(r.metadata.DstIP, header.Domain()) log.Warnln("use sni update host: %s ip: %s", header.Domain(), r.metadata.DstIP.String()) - r.Conn.Close() - return 0, errors.New("sni update, break current link to avoid leaks") + if r.allowBreak { + r.Conn.Close() + return 0, errors.New("sni update, break current link to avoid leaks") + } else { + r.metadata.Host = header.Domain() + } } } @@ -45,10 +50,11 @@ func (r *sniffing) Close() error { return r.Conn.Close() } -func NewSniffing(conn C.Conn, metadata *C.Metadata) C.Conn { +func NewSniffing(conn C.Conn, metadata *C.Metadata, rule C.Rule) C.Conn { return &sniffing{ Conn: conn, metadata: metadata, totalWrite: atomic.NewUint64(0), + allowBreak: rule != nil, } } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 1b24c107..b86fce6e 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -80,7 +80,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R } manager.Join(t) - return NewSniffing(t, metadata) + return NewSniffing(t, metadata, rule) } type udpTracker struct { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index e16782a7..8360052a 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -303,7 +303,7 @@ func handleTCPConn(connCtx C.ConnContext) { defer cancel() if MitmOutbound != nil && metadata.Type != C.MITM { if remoteConn, err1 := MitmOutbound.DialContext(ctx, metadata); err1 == nil { - remoteConn = statistic.NewSniffing(remoteConn, metadata) + remoteConn = statistic.NewSniffing(remoteConn, metadata, nil) defer func(remoteConn C.Conn) { _ = remoteConn.Close() }(remoteConn) From e010940b614900c4c249a4d535de1bffc0632a98 Mon Sep 17 00:00:00 2001 From: Kr328 Date: Sat, 16 Apr 2022 15:31:26 +0800 Subject: [PATCH 08/12] Improve: replace bootstrap dns (#2080) --- component/resolver/defaults.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 component/resolver/defaults.go diff --git a/component/resolver/defaults.go b/component/resolver/defaults.go new file mode 100644 index 00000000..8a04bd17 --- /dev/null +++ b/component/resolver/defaults.go @@ -0,0 +1,12 @@ +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris + +package resolver + +import _ "unsafe" + +//go:linkname defaultNS net.defaultNS +var defaultNS []string + +func init() { + defaultNS = []string{"114.114.114.114:53", "8.8.8.8:53"} +} From 33d23dad6cd31746bbdcbcd02ce49de4087fc75b Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:05:12 +0800 Subject: [PATCH 09/12] Chore: remove TODO --- adapter/outbound/http.go | 2 +- adapter/outbound/mitm.go | 18 ++++++++---------- listener/listener.go | 7 +++---- listener/mitm/proxy.go | 38 ++++++++++++-------------------------- listener/mitm/utils.go | 10 ---------- 5 files changed, 24 insertions(+), 51 deletions(-) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index ff87af6f..91d4f381 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -90,7 +90,7 @@ func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { } if metadata.Type == C.MITM { - req.Header.Add("Origin-Request-Source-Address", metadata.SourceAddress()) + req.Header.Set("Origin-Request-Source-Address", metadata.SourceAddress()) } if err := req.Write(rw); err != nil { diff --git a/adapter/outbound/mitm.go b/adapter/outbound/mitm.go index faa04a4c..a8fd6cfb 100644 --- a/adapter/outbound/mitm.go +++ b/adapter/outbound/mitm.go @@ -7,26 +7,23 @@ import ( "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" - - "go.uber.org/atomic" ) var ( errIgnored = errors.New("not match in mitm host lists") httpProxyClient = NewHttp(HttpOption{}) - MiddlemanServerAddress = atomic.NewString("") - MiddlemanRewriteHosts *trie.DomainTrie[bool] + MiddlemanRewriteHosts *trie.DomainTrie[bool] ) type Mitm struct { *Base + serverAddr string } // DialContext implements C.ProxyAdapter -func (d *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) { - addr := MiddlemanServerAddress.Load() - if addr == "" || MiddlemanRewriteHosts == nil { +func (m *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) { + if MiddlemanRewriteHosts == nil { return nil, errIgnored } @@ -41,7 +38,7 @@ func (d *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...diale metadata.DstIP = nil } - c, err := dialer.DialContext(ctx, "tcp", addr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0)}...) + c, err := dialer.DialContext(ctx, "tcp", m.serverAddr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0)}...) if err != nil { return nil, err } @@ -55,14 +52,15 @@ func (d *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...diale return nil, err } - return NewConn(c, d), nil + return NewConn(c, m), nil } -func NewMitm() *Mitm { +func NewMitm(serverAddr string) *Mitm { return &Mitm{ Base: &Base{ name: "Mitm", tp: C.Mitm, }, + serverAddr: serverAddr, } } diff --git a/listener/listener.go b/listener/listener.go index a8137849..f75a282f 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -10,6 +10,7 @@ import ( "os" "strconv" "sync" + "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/outbound" @@ -360,7 +361,6 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) { if mitmListener.RawAddress() == addr { return } - outbound.MiddlemanServerAddress.Store("") tunnel.MitmOutbound = nil _ = mitmListener.Close() mitmListener = nil @@ -401,7 +401,7 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) { return } - certOption.SetValidity(cert.TTL << 3) + certOption.SetValidity(time.Hour * 24 * 90) certOption.SetOrganization("Clash ManInTheMiddle Proxy Services") opt := &mitm.Option{ @@ -416,8 +416,7 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) { return } - outbound.MiddlemanServerAddress.Store(mitmListener.Address()) - tunnel.MitmOutbound = outbound.NewMitm() + tunnel.MitmOutbound = outbound.NewMitm(mitmListener.Address()) log.Infoln("Mitm proxy listening at: %s", mitmListener.Address()) } diff --git a/listener/mitm/proxy.go b/listener/mitm/proxy.go index ce5e8f2e..0ab138fc 100644 --- a/listener/mitm/proxy.go +++ b/listener/mitm/proxy.go @@ -32,8 +32,8 @@ func HandleConn(c net.Conn, opt *Option, in chan<- C.ConnContext, cache *cache.C }() startOver: - if tc, ok := c.(*net.TCPConn); ok { - _ = tc.SetKeepAlive(true) + if tcpConn, ok := c.(*net.TCPConn); ok { + _ = tcpConn.SetKeepAlive(true) } var conn *N.BufferedConn @@ -47,14 +47,13 @@ startOver: readLoop: for { - err := conn.SetDeadline(time.Now().Add(30 * time.Second)) // use SetDeadline instead of Proxy-Connection keep-alive - if err != nil { + // use SetDeadline instead of Proxy-Connection keep-alive + if err := conn.SetDeadline(time.Now().Add(30 * time.Second)); err != nil { break readLoop } request, err := H.ReadRequest(conn.Reader()) if err != nil { - handleError(opt, nil, err) break readLoop } @@ -83,27 +82,15 @@ readLoop: goto readLoop } - b := make([]byte, 1) - if _, err = session.conn.Read(b); err != nil { + b, err := conn.Peek(1) + if err != nil { handleError(opt, session, err) break readLoop // close connection } - buff := make([]byte, session.conn.(*N.BufferedConn).Buffered()) - if _, err = session.conn.Read(buff); err != nil { - handleError(opt, session, err) - break readLoop // close connection - } - - mrConn := &multiReaderConn{ - Conn: session.conn, - reader: io.MultiReader(bytes.NewReader(b), bytes.NewReader(buff), session.conn), - } - // TLS handshake. if b[0] == 0x16 { - // TODO serve by generic host name maybe better? - tlsConn := tls.Server(mrConn, opt.CertConfig.NewTLSConfigForHost(session.request.URL.Host)) + tlsConn := tls.Server(conn, opt.CertConfig.NewTLSConfigForHost(session.request.URL.Host)) // Handshake with the local client if err = tlsConn.Handshake(); err != nil { @@ -114,7 +101,7 @@ readLoop: c = tlsConn } else { - c = mrConn + c = conn } goto startOver @@ -122,8 +109,11 @@ readLoop: prepareRequest(c, session.request) + H.RemoveHopByHopHeaders(session.request.Header) + H.RemoveExtraHTTPHostPort(session.request) + // hijack api - if session.request.URL.Host == opt.ApiHost { + if session.request.URL.Hostname() == opt.ApiHost { if err = handleApiRequest(session, opt); err != nil { handleError(opt, session, err) break readLoop @@ -162,7 +152,6 @@ readLoop: handleError(opt, session, err) session.response = session.NewErrorResponse(err) if errors.Is(err, ErrCertUnsupported) || strings.Contains(err.Error(), "x509: ") { - // TODO block unsupported host? _ = writeResponse(session, false) break readLoop } @@ -287,9 +276,6 @@ func prepareRequest(conn net.Conn, request *http.Request) { if request.Header.Get("Accept-Encoding") != "" { request.Header.Set("Accept-Encoding", "gzip") } - - H.RemoveHopByHopHeaders(request.Header) - H.RemoveExtraHTTPHostPort(request) } func parseSourceAddress(req *http.Request, connSource, source net.Addr) net.Addr { diff --git a/listener/mitm/utils.go b/listener/mitm/utils.go index 5c3b15bd..a84c75cf 100644 --- a/listener/mitm/utils.go +++ b/listener/mitm/utils.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "io/ioutil" - "net" "net/http" "time" @@ -21,15 +20,6 @@ var ( ErrInvalidURL = errors.New("invalid URL") ) -type multiReaderConn struct { - net.Conn - reader io.Reader -} - -func (c *multiReaderConn) Read(buf []byte) (int, error) { - return c.reader.Read(buf) -} - func NewResponse(code int, body io.Reader, req *http.Request) *http.Response { if body == nil { body = &bytes.Buffer{} From 29c775331a6ebd9dd5cf52efe1ea7d481d22e632 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:46:13 +0800 Subject: [PATCH 10/12] Chore: IpToAddr --- common/nnip/netip.go | 53 +++++++++++++++++++ component/fakeip/pool.go | 40 ++------------ component/fakeip/pool_test.go | 8 ++- dns/enhancer.go | 11 ++-- dns/middleware.go | 3 +- dns/util.go | 17 ------ .../tun/ipstack/commons/router_windows.go | 5 +- listener/tun/ipstack/gvisor/handler.go | 24 +++++---- listener/tun/ipstack/system/mars/mars.go | 4 +- listener/tun/ipstack/system/mars/nat/nat.go | 36 ++++++------- listener/tun/ipstack/system/mars/nat/udp.go | 8 ++- listener/tun/ipstack/system/mars/tcpip/ip.go | 6 --- listener/tun/ipstack/system/stack.go | 37 ++++++++----- listener/tun/tun_adapter.go | 3 +- 14 files changed, 136 insertions(+), 119 deletions(-) create mode 100644 common/nnip/netip.go diff --git a/common/nnip/netip.go b/common/nnip/netip.go new file mode 100644 index 00000000..e4566138 --- /dev/null +++ b/common/nnip/netip.go @@ -0,0 +1,53 @@ +package nnip + +import ( + "encoding/binary" + "net" + "net/netip" +) + +// IpToAddr converts the net.IP to netip.Addr. +// If slice's length is not 4 or 16, IpToAddr returns netip.Addr{} +func IpToAddr(slice net.IP) netip.Addr { + ip := slice + if len(ip) != 4 { + if ip = slice.To4(); ip == nil { + ip = slice + } + } + + if addr, ok := netip.AddrFromSlice(ip); ok { + return addr + } + return netip.Addr{} +} + +// UnMasked returns p's last IP address. +// If p is invalid, UnMasked returns netip.Addr{} +func UnMasked(p netip.Prefix) netip.Addr { + if !p.IsValid() { + return netip.Addr{} + } + + buf := p.Addr().As16() + + hi := binary.BigEndian.Uint64(buf[:8]) + lo := binary.BigEndian.Uint64(buf[8:]) + + bits := p.Bits() + if bits <= 32 { + bits += 96 + } + + hi = hi | ^uint64(0)>>bits + lo = lo | ^(^uint64(0) << (128 - bits)) + + binary.BigEndian.PutUint64(buf[:8], hi) + binary.BigEndian.PutUint64(buf[8:], lo) + + addr := netip.AddrFrom16(buf) + if p.Addr().Is4() { + return addr.Unmap() + } + return addr +} diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 57613a48..0137f705 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -1,12 +1,11 @@ package fakeip import ( - "encoding/binary" "errors" - "math/bits" "net/netip" "sync" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/trie" ) @@ -16,11 +15,6 @@ const ( cycleKey = "key-cycle-fake-ip" ) -type uint128 struct { - hi uint64 - lo uint64 -} - type store interface { GetByHost(host string) (netip.Addr, bool) PutByHost(host string, ip netip.Addr) @@ -122,7 +116,7 @@ func (p *Pool) FlushFakeIP() error { err := p.store.FlushFakeIP() if err == nil { p.cycle = false - p.offset = p.first + p.offset = p.first.Prev() } return err } @@ -173,10 +167,10 @@ func New(options Options) (*Pool, error) { hostAddr = options.IPNet.Masked().Addr() gateway = hostAddr.Next() first = gateway.Next().Next() - last = add(hostAddr, 1< Date: Wed, 20 Apr 2022 01:52:51 +0800 Subject: [PATCH 11/12] Refactor: metadata use netip.Addr --- adapter/adapter.go | 17 +++-- adapter/inbound/util.go | 24 +++---- adapter/outbound/mitm.go | 5 -- adapter/outbound/util.go | 14 ++-- adapter/outbound/vless.go | 4 +- adapter/outbound/vmess.go | 4 +- adapter/outboundgroup/loadbalance.go | 2 +- adapter/outboundgroup/util.go | 15 ++-- component/dhcp/dhcp.go | 22 ++++-- component/dialer/bind_darwin.go | 12 ++-- component/dialer/bind_linux.go | 12 ++-- component/dialer/bind_others.go | 17 ++--- component/dialer/dialer.go | 9 +-- component/dialer/mark_linux.go | 18 +++-- component/dialer/mark_nonlinux.go | 5 +- component/dialer/resolver.go | 7 +- component/iface/iface.go | 37 +++++----- component/process/process.go | 18 ++--- component/process/process_darwin.go | 16 +++-- component/process/process_freebsd_amd64.go | 17 ++--- component/process/process_linux.go | 27 +++---- component/process/process_other.go | 4 +- component/process/process_windows.go | 13 ++-- component/resolver/enhancer.go | 24 +++---- component/resolver/{patch.go => local.go} | 0 component/resolver/resolver.go | 82 ++++++++++++---------- config/config.go | 12 ++-- constant/metadata.go | 51 +++++++------- constant/rule_extra.go | 6 +- dns/client.go | 9 ++- dns/dhcp.go | 8 +-- dns/enhancer.go | 47 ++++++------- dns/filters.go | 14 ++-- dns/middleware.go | 9 ++- dns/resolver.go | 35 +++++---- dns/util.go | 14 ++-- listener/mitm/proxy.go | 19 ++--- listener/tun/ipstack/system/stack.go | 5 +- listener/tun/tun_adapter.go | 2 +- rule/base.go | 10 +-- rule/geoip.go | 4 +- rule/ipcidr.go | 10 +-- transport/socks4/socks4.go | 32 ++++----- tunnel/statistic/sniffing.go | 2 +- tunnel/tunnel.go | 15 ++-- 45 files changed, 369 insertions(+), 360 deletions(-) rename component/resolver/{patch.go => local.go} (100%) diff --git a/adapter/adapter.go b/adapter/adapter.go index 986cd045..cffc0fb2 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "net/http" + "net/netip" "net/url" "time" _ "unsafe" @@ -62,9 +63,9 @@ func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // DelayHistory implements C.Proxy func (p *Proxy) DelayHistory() []C.DelayHistory { - queue := p.history.Copy() + queueM := p.history.Copy() histories := []C.DelayHistory{} - for _, item := range queue { + for _, item := range queueM { histories = append(histories, item) } return histories @@ -93,7 +94,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { } mapping := map[string]any{} - json.Unmarshal(inner, &mapping) + _ = json.Unmarshal(inner, &mapping) mapping["history"] = p.DelayHistory() mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() @@ -125,7 +126,9 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { if err != nil { return } - defer instance.Close() + defer func() { + _ = instance.Close() + }() req, err := http.NewRequest(http.MethodHead, url, nil) if err != nil { @@ -134,7 +137,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { req = req.WithContext(ctx) transport := &http.Transport{ - Dial: func(string, string) (net.Conn, error) { + DialContext: func(context.Context, string, string) (net.Conn, error) { return instance, nil }, // from http.DefaultTransport @@ -156,7 +159,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { if err != nil { return } - resp.Body.Close() + _ = resp.Body.Close() t = uint16(time.Since(start) / time.Millisecond) return } @@ -187,7 +190,7 @@ func urlToMetadata(rawURL string) (addr C.Metadata, err error) { addr = C.Metadata{ AddrType: C.AtypDomainName, Host: u.Hostname(), - DstIP: nil, + DstIP: netip.Addr{}, DstPort: port, } return diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 07577ec0..5dd4148d 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -3,9 +3,11 @@ package inbound import ( "net" "net/http" + "net/netip" "strconv" "strings" + "github.com/Dreamacro/clash/common/nnip" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -21,12 +23,10 @@ func parseSocksAddr(target socks5.Addr) *C.Metadata { metadata.Host = strings.TrimRight(string(target[2:2+target[1]]), ".") metadata.DstPort = strconv.Itoa((int(target[2+target[1]]) << 8) | int(target[2+target[1]+1])) case socks5.AtypIPv4: - ip := net.IP(target[1 : 1+net.IPv4len]) - metadata.DstIP = ip + metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv4len])) metadata.DstPort = strconv.Itoa((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1])) case socks5.AtypIPv6: - ip := net.IP(target[1 : 1+net.IPv6len]) - metadata.DstIP = ip + metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv6len])) metadata.DstPort = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1])) } @@ -47,14 +47,14 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { NetWork: C.TCP, AddrType: C.AtypDomainName, Host: host, - DstIP: nil, + DstIP: netip.Addr{}, DstPort: port, } - ip := net.ParseIP(host) - if ip != nil { + ip, err := netip.ParseAddr(host) + if err == nil { switch { - case ip.To4() == nil: + case ip.Is6(): metadata.AddrType = C.AtypIPv6 default: metadata.AddrType = C.AtypIPv4 @@ -65,12 +65,12 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr string) (net.IP, string, error) { +func parseAddr(addr string) (netip.Addr, string, error) { host, port, err := net.SplitHostPort(addr) if err != nil { - return nil, "", err + return netip.Addr{}, "", err } - ip := net.ParseIP(host) - return ip, port, nil + ip, err := netip.ParseAddr(host) + return ip, port, err } diff --git a/adapter/outbound/mitm.go b/adapter/outbound/mitm.go index a8fd6cfb..4532b6b6 100644 --- a/adapter/outbound/mitm.go +++ b/adapter/outbound/mitm.go @@ -33,11 +33,6 @@ func (m *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...diale metadata.Type = C.MITM - if metadata.Host != "" { - metadata.AddrType = C.AtypDomainName - metadata.DstIP = nil - } - c, err := dialer.DialContext(ctx, "tcp", m.serverAddr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0)}...) if err != nil { return nil, err diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 9322adc5..8fa1d503 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -13,8 +13,8 @@ import ( func tcpKeepAlive(c net.Conn) { if tcp, ok := c.(*net.TCPConn); ok { - tcp.SetKeepAlive(true) - tcp.SetKeepAlivePeriod(30 * time.Second) + _ = tcp.SetKeepAlive(true) + _ = tcp.SetKeepAlivePeriod(30 * time.Second) } } @@ -25,14 +25,14 @@ func serializesSocksAddr(metadata *C.Metadata) []byte { port := []byte{uint8(p >> 8), uint8(p & 0xff)} switch metadata.AddrType { case socks5.AtypDomainName: - len := uint8(len(metadata.Host)) + lenM := uint8(len(metadata.Host)) host := []byte(metadata.Host) - buf = [][]byte{{aType, len}, host, port} + buf = [][]byte{{aType, lenM}, host, port} case socks5.AtypIPv4: - host := metadata.DstIP.To4() + host := metadata.DstIP.AsSlice() buf = [][]byte{{aType}, host, port} case socks5.AtypIPv6: - host := metadata.DstIP.To16() + host := metadata.DstIP.AsSlice() buf = [][]byte{{aType}, host, port} } return bytes.Join(buf, nil) @@ -53,6 +53,6 @@ func resolveUDPAddr(network, address string) (*net.UDPAddr, error) { func safeConnClose(c net.Conn, err error) { if err != nil { - c.Close() + _ = c.Close() } } diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 908c4de8..8fddeca2 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -263,11 +263,11 @@ func parseVlessAddr(metadata *C.Metadata) *vless.DstAddr { case C.AtypIPv4: addrType = byte(vless.AtypIPv4) addr = make([]byte, net.IPv4len) - copy(addr[:], metadata.DstIP.To4()) + copy(addr[:], metadata.DstIP.AsSlice()) case C.AtypIPv6: addrType = byte(vless.AtypIPv6) addr = make([]byte, net.IPv6len) - copy(addr[:], metadata.DstIP.To16()) + copy(addr[:], metadata.DstIP.AsSlice()) case C.AtypDomainName: addrType = byte(vless.AtypDomainName) addr = make([]byte, len(metadata.Host)+1) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index c36baf6c..b32349d0 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -342,11 +342,11 @@ func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr { case C.AtypIPv4: addrType = byte(vmess.AtypIPv4) addr = make([]byte, net.IPv4len) - copy(addr[:], metadata.DstIP.To4()) + copy(addr[:], metadata.DstIP.AsSlice()) case C.AtypIPv6: addrType = byte(vmess.AtypIPv6) addr = make([]byte, net.IPv6len) - copy(addr[:], metadata.DstIP.To16()) + copy(addr[:], metadata.DstIP.AsSlice()) case C.AtypDomainName: addrType = byte(vmess.AtypDomainName) addr = make([]byte, len(metadata.Host)+1) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 380b0d06..d0ae4fe3 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -50,7 +50,7 @@ func getKey(metadata *C.Metadata) string { } } - if metadata.DstIP == nil { + if !metadata.DstIP.IsValid() { return "" } diff --git a/adapter/outboundgroup/util.go b/adapter/outboundgroup/util.go index 70d71078..266fce8d 100644 --- a/adapter/outboundgroup/util.go +++ b/adapter/outboundgroup/util.go @@ -3,6 +3,7 @@ package outboundgroup import ( "fmt" "net" + "net/netip" "time" C "github.com/Dreamacro/clash/constant" @@ -15,20 +16,20 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { return } - ip := net.ParseIP(host) - if ip == nil { + ip, err := netip.ParseAddr(host) + if err != nil { addr = &C.Metadata{ AddrType: C.AtypDomainName, Host: host, - DstIP: nil, + DstIP: netip.Addr{}, DstPort: port, } return - } else if ip4 := ip.To4(); ip4 != nil { + } else if ip.Is4() { addr = &C.Metadata{ AddrType: C.AtypIPv4, Host: "", - DstIP: ip4, + DstIP: ip, DstPort: port, } return @@ -45,7 +46,7 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { func tcpKeepAlive(c net.Conn) { if tcp, ok := c.(*net.TCPConn); ok { - tcp.SetKeepAlive(true) - tcp.SetKeepAlivePeriod(30 * time.Second) + _ = tcp.SetKeepAlive(true) + _ = tcp.SetKeepAlivePeriod(30 * time.Second) } } diff --git a/component/dhcp/dhcp.go b/component/dhcp/dhcp.go index b7e9f506..be2c578a 100644 --- a/component/dhcp/dhcp.go +++ b/component/dhcp/dhcp.go @@ -4,7 +4,9 @@ import ( "context" "errors" "net" + "net/netip" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/iface" "github.com/insomniacslk/dhcp/dhcpv4" @@ -15,14 +17,16 @@ var ( ErrNotFound = errors.New("DNS option not found") ) -func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, error) { +func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]netip.Addr, error) { conn, err := ListenDHCPClient(context, ifaceName) if err != nil { return nil, err } - defer conn.Close() + defer func() { + _ = conn.Close() + }() - result := make(chan []net.IP, 1) + result := make(chan []netip.Addr, 1) ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { @@ -52,7 +56,7 @@ func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, er } } -func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []net.IP) { +func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []netip.Addr) { defer close(result) buf := make([]byte, dhcpv4.MaxMessageSize) @@ -77,11 +81,17 @@ func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- [] } dns := pkt.DNS() - if len(dns) == 0 { + l := len(dns) + if l == 0 { return } - result <- dns + dnsAddr := make([]netip.Addr, l) + for i := 0; i < l; i++ { + dnsAddr[i] = nnip.IpToAddr(dns[i]) + } + + result <- dnsAddr return } diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index 57e09bb5..91d74987 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -2,6 +2,7 @@ package dialer import ( "net" + "net/netip" "syscall" "github.com/Dreamacro/clash/component/iface" @@ -19,12 +20,9 @@ func bindControl(ifaceIdx int, chain controlFn) controlFn { } }() - ipStr, _, err := net.SplitHostPort(address) - if err == nil { - ip := net.ParseIP(ipStr) - if ip != nil && !ip.IsGlobalUnicast() { - return - } + addrPort, err := netip.ParseAddrPort(address) + if err == nil && !addrPort.Addr().IsGlobalUnicast() { + return } var innerErr error @@ -45,7 +43,7 @@ func bindControl(ifaceIdx int, chain controlFn) controlFn { } } -func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error { +func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { return err diff --git a/component/dialer/bind_linux.go b/component/dialer/bind_linux.go index 97d37cfa..ca88cb58 100644 --- a/component/dialer/bind_linux.go +++ b/component/dialer/bind_linux.go @@ -2,6 +2,7 @@ package dialer import ( "net" + "net/netip" "syscall" "golang.org/x/sys/unix" @@ -17,12 +18,9 @@ func bindControl(ifaceName string, chain controlFn) controlFn { } }() - ipStr, _, err := net.SplitHostPort(address) - if err == nil { - ip := net.ParseIP(ipStr) - if ip != nil && !ip.IsGlobalUnicast() { - return - } + addrPort, err := netip.ParseAddrPort(address) + if err == nil && !addrPort.Addr().IsGlobalUnicast() { + return } var innerErr error @@ -38,7 +36,7 @@ func bindControl(ifaceName string, chain controlFn) controlFn { } } -func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error { +func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error { dialer.Control = bindControl(ifaceName, dialer.Control) return nil diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 51b2ef68..f732b1ce 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -4,27 +4,28 @@ package dialer import ( "net" + "net/netip" "strconv" "strings" "github.com/Dreamacro/clash/component/iface" ) -func lookupLocalAddr(ifaceName string, network string, destination net.IP, port int) (net.Addr, error) { +func lookupLocalAddr(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { ifaceObj, err := iface.ResolveInterface(ifaceName) if err != nil { return nil, err } - var addr *net.IPNet + var addr *netip.Prefix switch network { case "udp4", "tcp4": addr, err = ifaceObj.PickIPv4Addr(destination) case "tcp6", "udp6": addr, err = ifaceObj.PickIPv6Addr(destination) default: - if destination != nil { - if destination.To4() != nil { + if destination.IsValid() { + if destination.Is4() { addr, err = ifaceObj.PickIPv4Addr(destination) } else { addr, err = ifaceObj.PickIPv6Addr(destination) @@ -39,12 +40,12 @@ func lookupLocalAddr(ifaceName string, network string, destination net.IP, port if strings.HasPrefix(network, "tcp") { return &net.TCPAddr{ - IP: addr.IP, + IP: addr.Addr().AsSlice(), Port: port, }, nil } else if strings.HasPrefix(network, "udp") { return &net.UDPAddr{ - IP: addr.IP, + IP: addr.Addr().AsSlice(), Port: port, }, nil } @@ -52,7 +53,7 @@ func lookupLocalAddr(ifaceName string, network string, destination net.IP, port return nil, iface.ErrAddrNotFound } -func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination net.IP) error { +func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { if !destination.IsGlobalUnicast() { return nil } @@ -83,7 +84,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add local, _ := strconv.ParseUint(port, 10, 16) - addr, err := lookupLocalAddr(ifaceName, network, nil, int(local)) + addr, err := lookupLocalAddr(ifaceName, network, netip.Addr{}, int(local)) if err != nil { return "", err } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 19a5fdd2..16e6eed1 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net" + "net/netip" "github.com/Dreamacro/clash/component/resolver" ) @@ -29,7 +30,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option return nil, err } - var ip net.IP + var ip netip.Addr switch network { case "tcp4", "udp4": if !opt.direct { @@ -88,7 +89,7 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio return lc.ListenPacket(ctx, network, address) } -func dialContext(ctx context.Context, network string, destination net.IP, port string, opt *option) (net.Conn, error) { +func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { dialer := &net.Dialer{} if opt.interfaceName != "" { if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil { @@ -128,12 +129,12 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt case results <- result: case <-returned: if result.Conn != nil { - result.Conn.Close() + _ = result.Conn.Close() } } }() - var ip net.IP + var ip netip.Addr if ipv6 { if !direct { ip, result.error = resolver.ResolveIPv6ProxyServerHost(host) diff --git a/component/dialer/mark_linux.go b/component/dialer/mark_linux.go index e54873bc..41b61863 100644 --- a/component/dialer/mark_linux.go +++ b/component/dialer/mark_linux.go @@ -4,14 +4,15 @@ package dialer import ( "net" + "net/netip" "syscall" ) -func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) { +func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ netip.Addr) { dialer.Control = bindMarkToControl(mark, dialer.Control) } -func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) { +func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, _ string) { lc.Control = bindMarkToControl(mark, lc.Control) } @@ -23,20 +24,17 @@ func bindMarkToControl(mark int, chain controlFn) controlFn { } }() - ipStr, _, err := net.SplitHostPort(address) - if err == nil { - ip := net.ParseIP(ipStr) - if ip != nil && !ip.IsGlobalUnicast() { - return - } + addrPort, err := netip.ParseAddrPort(address) + if err == nil && !addrPort.Addr().IsGlobalUnicast() { + return } return c.Control(func(fd uintptr) { switch network { case "tcp4", "udp4": - syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark) + _ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark) case "tcp6", "udp6": - syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark) + _ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark) } }) } diff --git a/component/dialer/mark_nonlinux.go b/component/dialer/mark_nonlinux.go index 98645e48..ea448276 100644 --- a/component/dialer/mark_nonlinux.go +++ b/component/dialer/mark_nonlinux.go @@ -4,6 +4,7 @@ package dialer import ( "net" + "net/netip" "sync" "github.com/Dreamacro/clash/log" @@ -17,10 +18,10 @@ func printMarkWarn() { }) } -func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) { +func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ netip.Addr) { printMarkWarn() } -func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) { +func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, _ string) { printMarkWarn() } diff --git a/component/dialer/resolver.go b/component/dialer/resolver.go index 08be81b6..ea38a90e 100644 --- a/component/dialer/resolver.go +++ b/component/dialer/resolver.go @@ -3,6 +3,7 @@ package dialer import ( "context" "net" + "net/netip" ) func init() { @@ -18,9 +19,9 @@ func resolverDialContext(ctx context.Context, network, address string) (net.Conn interfaceName := DefaultInterface.Load() if interfaceName != "" { - dstIP := net.ParseIP(address) - if dstIP != nil { - bindIfaceToDialer(interfaceName, d, network, dstIP) + dstIP, err := netip.ParseAddr(address) + if err == nil { + _ = bindIfaceToDialer(interfaceName, d, network, dstIP) } } diff --git a/component/iface/iface.go b/component/iface/iface.go index df290811..637d4876 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -3,6 +3,7 @@ package iface import ( "errors" "net" + "net/netip" "time" "github.com/Dreamacro/clash/common/singledo" @@ -11,7 +12,7 @@ import ( type Interface struct { Index int Name string - Addrs []*net.IPNet + Addrs []*netip.Prefix HardwareAddr net.HardwareAddr } @@ -37,14 +38,18 @@ func ResolveInterface(name string) (*Interface, error) { continue } - ipNets := make([]*net.IPNet, 0, len(addrs)) + ipNets := make([]*netip.Prefix, 0, len(addrs)) for _, addr := range addrs { ipNet := addr.(*net.IPNet) - if v4 := ipNet.IP.To4(); v4 != nil { - ipNet.IP = v4 + ip, _ := netip.AddrFromSlice(ipNet.IP) + + ones, bits := ipNet.Mask.Size() + if bits == 32 { + ip = ip.Unmap() } - ipNets = append(ipNets, ipNet) + pf := netip.PrefixFrom(ip, ones) + ipNets = append(ipNets, &pf) } r[iface.Name] = &Interface{ @@ -74,35 +79,35 @@ func FlushCache() { interfaces.Reset() } -func (iface *Interface) PickIPv4Addr(destination net.IP) (*net.IPNet, error) { - return iface.pickIPAddr(destination, func(addr *net.IPNet) bool { - return addr.IP.To4() != nil +func (iface *Interface) PickIPv4Addr(destination netip.Addr) (*netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { + return addr.Addr().Is4() }) } -func (iface *Interface) PickIPv6Addr(destination net.IP) (*net.IPNet, error) { - return iface.pickIPAddr(destination, func(addr *net.IPNet) bool { - return addr.IP.To4() == nil +func (iface *Interface) PickIPv6Addr(destination netip.Addr) (*netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { + return addr.Addr().Is6() }) } -func (iface *Interface) pickIPAddr(destination net.IP, accept func(addr *net.IPNet) bool) (*net.IPNet, error) { - var fallback *net.IPNet +func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *netip.Prefix) bool) (*netip.Prefix, error) { + var fallback *netip.Prefix for _, addr := range iface.Addrs { if !accept(addr) { continue } - if fallback == nil && !addr.IP.IsLinkLocalUnicast() { + if fallback == nil && !addr.Addr().IsLinkLocalUnicast() { fallback = addr - if destination == nil { + if !destination.IsValid() { break } } - if destination != nil && addr.Contains(destination) { + if destination.IsValid() && addr.Contains(destination) { return addr, nil } } diff --git a/component/process/process.go b/component/process/process.go index deaf11b5..677a74cb 100644 --- a/component/process/process.go +++ b/component/process/process.go @@ -3,7 +3,9 @@ package process import ( "errors" "net" + "net/netip" + "github.com/Dreamacro/clash/common/nnip" C "github.com/Dreamacro/clash/constant" ) @@ -18,7 +20,7 @@ const ( UDP = "udp" ) -func FindProcessName(network string, srcIP net.IP, srcPort int) (string, error) { +func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) { return findProcessName(network, srcIP, srcPort) } @@ -27,23 +29,23 @@ func ShouldFindProcess(metadata *C.Metadata) bool { return false } for _, ip := range localIPs { - if ip.Equal(metadata.SrcIP) { + if ip == metadata.SrcIP { return true } } return false } -func AppendLocalIPs(ip ...net.IP) { +func AppendLocalIPs(ip ...netip.Addr) { localIPs = append(ip, localIPs...) } -func getLocalIPs() []net.IP { - ips := []net.IP{net.IPv4zero, net.IPv6zero} +func getLocalIPs() []netip.Addr { + ips := []netip.Addr{netip.IPv4Unspecified(), netip.IPv6Unspecified()} netInterfaces, err := net.Interfaces() if err != nil { - ips = append(ips, net.IPv4(127, 0, 0, 1), net.IPv6loopback) + ips = append(ips, netip.AddrFrom4([4]byte{127, 0, 0, 1}), nnip.IpToAddr(net.IPv6loopback)) return ips } @@ -53,7 +55,7 @@ func getLocalIPs() []net.IP { for _, address := range adds { if ipNet, ok := address.(*net.IPNet); ok { - ips = append(ips, ipNet.IP) + ips = append(ips, nnip.IpToAddr(ipNet.IP)) } } } @@ -62,7 +64,7 @@ func getLocalIPs() []net.IP { return ips } -var localIPs []net.IP +var localIPs []netip.Addr func init() { localIPs = getLocalIPs() diff --git a/component/process/process_darwin.go b/component/process/process_darwin.go index 6ae04552..2368f239 100644 --- a/component/process/process_darwin.go +++ b/component/process/process_darwin.go @@ -2,10 +2,12 @@ package process import ( "encoding/binary" - "net" + "net/netip" "syscall" "unsafe" + "github.com/Dreamacro/clash/common/nnip" + "golang.org/x/sys/unix" ) @@ -15,7 +17,7 @@ const ( proccallnumpidinfo = 0x2 ) -func findProcessName(network string, ip net.IP, port int) (string, error) { +func findProcessName(network string, ip netip.Addr, port int) (string, error) { var spath string switch network { case TCP: @@ -26,7 +28,7 @@ func findProcessName(network string, ip net.IP, port int) (string, error) { return "", ErrInvalidNetwork } - isIPv4 := ip.To4() != nil + isIPv4 := ip.Is4() value, err := syscall.Sysctl(spath) if err != nil { @@ -57,19 +59,19 @@ func findProcessName(network string, ip net.IP, port int) (string, error) { // xinpcb_n.inp_vflag flag := buf[inp+44] - var srcIP net.IP + var srcIP netip.Addr switch { case flag&0x1 > 0 && isIPv4: // ipv4 - srcIP = net.IP(buf[inp+76 : inp+80]) + srcIP = nnip.IpToAddr(buf[inp+76 : inp+80]) case flag&0x2 > 0 && !isIPv4: // ipv6 - srcIP = net.IP(buf[inp+64 : inp+80]) + srcIP = nnip.IpToAddr(buf[inp+64 : inp+80]) default: continue } - if !ip.Equal(srcIP) && (network == TCP || !srcIP.IsUnspecified()) { + if ip != srcIP && (network == TCP || !srcIP.IsUnspecified()) { continue } diff --git a/component/process/process_freebsd_amd64.go b/component/process/process_freebsd_amd64.go index f3e64646..466cd249 100644 --- a/component/process/process_freebsd_amd64.go +++ b/component/process/process_freebsd_amd64.go @@ -3,13 +3,14 @@ package process import ( "encoding/binary" "fmt" - "net" + "net/netip" "strconv" "strings" "sync" "syscall" "unsafe" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/log" ) @@ -20,7 +21,7 @@ var ( once sync.Once ) -func findProcessName(network string, ip net.IP, srcPort int) (string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) { once.Do(func() { if err := initSearcher(); err != nil { log.Errorln("Initialize PROCESS-NAME failed: %s", err.Error()) @@ -102,7 +103,7 @@ type searcher struct { pid int } -func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint32, error) { +func (s *searcher) Search(buf []byte, ip netip.Addr, port uint16, isTCP bool) (uint32, error) { var itemSize int var inpOffset int @@ -116,7 +117,7 @@ func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint3 inpOffset = s.udpInpOffset } - isIPv4 := ip.To4() != nil + isIPv4 := ip.Is4() // skip the first xinpgen block for i := s.headSize; i+itemSize <= len(buf); i += itemSize { inp := i + inpOffset @@ -130,19 +131,19 @@ func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint3 // xinpcb.inp_vflag flag := buf[inp+s.vflag] - var srcIP net.IP + var srcIP netip.Addr switch { case flag&0x1 > 0 && isIPv4: // ipv4 - srcIP = net.IP(buf[inp+s.ip : inp+s.ip+4]) + srcIP = nnip.IpToAddr(buf[inp+s.ip : inp+s.ip+4]) case flag&0x2 > 0 && !isIPv4: // ipv6 - srcIP = net.IP(buf[inp+s.ip-12 : inp+s.ip+4]) + srcIP = nnip.IpToAddr(buf[inp+s.ip-12 : inp+s.ip+4]) default: continue } - if !ip.Equal(srcIP) { + if ip != srcIP { continue } diff --git a/component/process/process_linux.go b/component/process/process_linux.go index 1dfd0eda..2c01f17f 100644 --- a/component/process/process_linux.go +++ b/component/process/process_linux.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "net" + "net/netip" "os" "path" "strings" @@ -31,7 +32,7 @@ const ( pathProc = "/proc" ) -func findProcessName(network string, ip net.IP, srcPort int) (string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) { inode, uid, err := resolveSocketByNetlink(network, ip, srcPort) if err != nil { return "", err @@ -40,7 +41,7 @@ func findProcessName(network string, ip net.IP, srcPort int) (string, error) { return resolveProcessNameByProcSearch(inode, uid) } -func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int32, error) { +func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32, int32, error) { var family byte var protocol byte @@ -53,7 +54,7 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3 return 0, 0, ErrInvalidNetwork } - if ip.To4() != nil { + if ip.Is4() { family = syscall.AF_INET } else { family = syscall.AF_INET6 @@ -65,10 +66,12 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3 if err != nil { return 0, 0, fmt.Errorf("dial netlink: %w", err) } - defer syscall.Close(socket) + defer func() { + _ = syscall.Close(socket) + }() - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100}) - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100}) + _ = syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100}) + _ = syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100}) if err := syscall.Connect(socket, &syscall.SockaddrNetlink{ Family: syscall.AF_NETLINK, @@ -84,7 +87,9 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3 } rb := pool.Get(pool.RelayBufferSize) - defer pool.Put(rb) + defer func() { + _ = pool.Put(rb) + }() n, err := syscall.Read(socket, rb) if err != nil { @@ -111,14 +116,10 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3 return inode, uid, nil } -func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte { +func packSocketDiagRequest(family, protocol byte, source netip.Addr, sourcePort uint16) []byte { s := make([]byte, 16) - if v4 := source.To4(); v4 != nil { - copy(s, v4) - } else { - copy(s, source) - } + copy(s, source.AsSlice()) buf := make([]byte, sizeOfSocketDiagRequest) diff --git a/component/process/process_other.go b/component/process/process_other.go index c9e486f6..5f78fca0 100644 --- a/component/process/process_other.go +++ b/component/process/process_other.go @@ -2,8 +2,8 @@ package process -import "net" +import "net/netip" -func findProcessName(network string, ip net.IP, srcPort int) (string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) { return "", ErrPlatformNotSupport } diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 26a389a0..778675d4 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -2,11 +2,12 @@ package process import ( "fmt" - "net" + "net/netip" "sync" "syscall" "unsafe" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/log" "golang.org/x/sys/windows" @@ -57,7 +58,7 @@ func initWin32API() error { return nil } -func findProcessName(network string, ip net.IP, srcPort int) (string, error) { +func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) { once.Do(func() { err := initWin32API() if err != nil { @@ -67,7 +68,7 @@ func findProcessName(network string, ip net.IP, srcPort int) (string, error) { } }) family := windows.AF_INET - if ip.To4() == nil { + if ip.Is6() { family = windows.AF_INET6 } @@ -107,7 +108,7 @@ type searcher struct { tcpState int } -func (s *searcher) Search(b []byte, ip net.IP, port uint16) (uint32, error) { +func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error) { n := int(readNativeUint32(b[:4])) itemSize := s.itemSize for i := 0; i < n; i++ { @@ -131,9 +132,9 @@ func (s *searcher) Search(b []byte, ip net.IP, port uint16) (uint32, error) { continue } - srcIP := net.IP(row[s.ip : s.ip+s.ipSize]) + srcIP := nnip.IpToAddr(row[s.ip : s.ip+s.ipSize]) // windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto - if !ip.Equal(srcIP) && (!srcIP.IsUnspecified() || s.tcpState != -1) { + if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) { continue } diff --git a/component/resolver/enhancer.go b/component/resolver/enhancer.go index 5a8c4f4f..f00a13b3 100644 --- a/component/resolver/enhancer.go +++ b/component/resolver/enhancer.go @@ -1,20 +1,18 @@ package resolver -import ( - "net" -) +import "net/netip" var DefaultHostMapper Enhancer type Enhancer interface { FakeIPEnabled() bool MappingEnabled() bool - IsFakeIP(net.IP) bool - IsFakeBroadcastIP(net.IP) bool - IsExistFakeIP(net.IP) bool - FindHostByIP(net.IP) (string, bool) + IsFakeIP(netip.Addr) bool + IsFakeBroadcastIP(netip.Addr) bool + IsExistFakeIP(netip.Addr) bool + FindHostByIP(netip.Addr) (string, bool) FlushFakeIP() error - InsertHostByIP(net.IP, string) + InsertHostByIP(netip.Addr, string) StoreFakePoolState() } @@ -34,7 +32,7 @@ func MappingEnabled() bool { return false } -func IsFakeIP(ip net.IP) bool { +func IsFakeIP(ip netip.Addr) bool { if mapper := DefaultHostMapper; mapper != nil { return mapper.IsFakeIP(ip) } @@ -42,7 +40,7 @@ func IsFakeIP(ip net.IP) bool { return false } -func IsFakeBroadcastIP(ip net.IP) bool { +func IsFakeBroadcastIP(ip netip.Addr) bool { if mapper := DefaultHostMapper; mapper != nil { return mapper.IsFakeBroadcastIP(ip) } @@ -50,7 +48,7 @@ func IsFakeBroadcastIP(ip net.IP) bool { return false } -func IsExistFakeIP(ip net.IP) bool { +func IsExistFakeIP(ip netip.Addr) bool { if mapper := DefaultHostMapper; mapper != nil { return mapper.IsExistFakeIP(ip) } @@ -58,13 +56,13 @@ func IsExistFakeIP(ip net.IP) bool { return false } -func InsertHostByIP(ip net.IP, host string) { +func InsertHostByIP(ip netip.Addr, host string) { if mapper := DefaultHostMapper; mapper != nil { mapper.InsertHostByIP(ip, host) } } -func FindHostByIP(ip net.IP) (string, bool) { +func FindHostByIP(ip netip.Addr) (string, bool) { if mapper := DefaultHostMapper; mapper != nil { return mapper.FindHostByIP(ip) } diff --git a/component/resolver/patch.go b/component/resolver/local.go similarity index 100% rename from component/resolver/patch.go rename to component/resolver/local.go diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 3c8ba384..7fe625c1 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -6,9 +6,9 @@ import ( "math/rand" "net" "net/netip" - "strings" "time" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/trie" ) @@ -37,29 +37,29 @@ var ( ) type Resolver interface { - ResolveIP(host string) (ip net.IP, err error) - ResolveIPv4(host string) (ip net.IP, err error) - ResolveIPv6(host string) (ip net.IP, err error) + ResolveIP(host string) (ip netip.Addr, err error) + ResolveIPv4(host string) (ip netip.Addr, err error) + ResolveIPv6(host string) (ip netip.Addr, err error) } // ResolveIPv4 with a host, return ipv4 -func ResolveIPv4(host string) (net.IP, error) { +func ResolveIPv4(host string) (netip.Addr, error) { return ResolveIPv4WithResolver(host, DefaultResolver) } -func ResolveIPv4WithResolver(host string, r Resolver) (net.IP, error) { +func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) { if node := DefaultHosts.Search(host); node != nil { if ip := node.Data; ip.Is4() { - return ip.AsSlice(), nil + return ip, nil } } - ip := net.ParseIP(host) - if ip != nil { - if !strings.Contains(host, ":") { + ip, err := netip.ParseAddr(host) + if err == nil { + if ip.Is4() { return ip, nil } - return nil, ErrIPVersion + return netip.Addr{}, ErrIPVersion } if r != nil { @@ -71,39 +71,44 @@ func ResolveIPv4WithResolver(host string, r Resolver) (net.IP, error) { defer cancel() ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip4", host) if err != nil { - return nil, err + return netip.Addr{}, err } else if len(ipAddrs) == 0 { - return nil, ErrIPNotFound + return netip.Addr{}, ErrIPNotFound } - return ipAddrs[rand.Intn(len(ipAddrs))], nil + ip := ipAddrs[rand.Intn(len(ipAddrs))].To4() + if ip == nil { + return netip.Addr{}, ErrIPVersion + } + + return netip.AddrFrom4(*(*[4]byte)(ip)), nil } - return nil, ErrIPNotFound + return netip.Addr{}, ErrIPNotFound } // ResolveIPv6 with a host, return ipv6 -func ResolveIPv6(host string) (net.IP, error) { +func ResolveIPv6(host string) (netip.Addr, error) { return ResolveIPv6WithResolver(host, DefaultResolver) } -func ResolveIPv6WithResolver(host string, r Resolver) (net.IP, error) { +func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) { if DisableIPv6 { - return nil, ErrIPv6Disabled + return netip.Addr{}, ErrIPv6Disabled } if node := DefaultHosts.Search(host); node != nil { if ip := node.Data; ip.Is6() { - return ip.AsSlice(), nil + return ip, nil } } - ip := net.ParseIP(host) - if ip != nil { - if strings.Contains(host, ":") { + ip, err := netip.ParseAddr(host) + if err == nil { + if ip.Is6() { return ip, nil } - return nil, ErrIPVersion + return netip.Addr{}, ErrIPVersion } if r != nil { @@ -115,22 +120,21 @@ func ResolveIPv6WithResolver(host string, r Resolver) (net.IP, error) { defer cancel() ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip6", host) if err != nil { - return nil, err + return netip.Addr{}, err } else if len(ipAddrs) == 0 { - return nil, ErrIPNotFound + return netip.Addr{}, ErrIPNotFound } - return ipAddrs[rand.Intn(len(ipAddrs))], nil + return netip.AddrFrom16(*(*[16]byte)(ipAddrs[rand.Intn(len(ipAddrs))])), nil } - return nil, ErrIPNotFound + return netip.Addr{}, ErrIPNotFound } // ResolveIPWithResolver same as ResolveIP, but with a resolver -func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) { +func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) { if node := DefaultHosts.Search(host); node != nil { - ip := node.Data - return ip.Unmap().AsSlice(), nil + return node.Data, nil } if r != nil { @@ -142,30 +146,30 @@ func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) { return ResolveIPv4(host) } - ip := net.ParseIP(host) - if ip != nil { + ip, err := netip.ParseAddr(host) + if err == nil { return ip, nil } if DefaultResolver == nil { ipAddr, err := net.ResolveIPAddr("ip", host) if err != nil { - return nil, err + return netip.Addr{}, err } - return ipAddr.IP, nil + return nnip.IpToAddr(ipAddr.IP), nil } - return nil, ErrIPNotFound + return netip.Addr{}, ErrIPNotFound } // ResolveIP with a host, return ip -func ResolveIP(host string) (net.IP, error) { +func ResolveIP(host string) (netip.Addr, error) { return ResolveIPWithResolver(host, DefaultResolver) } // ResolveIPv4ProxyServerHost proxies server host only -func ResolveIPv4ProxyServerHost(host string) (net.IP, error) { +func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) { if ProxyServerHostResolver != nil { return ResolveIPv4WithResolver(host, ProxyServerHostResolver) } @@ -173,7 +177,7 @@ func ResolveIPv4ProxyServerHost(host string) (net.IP, error) { } // ResolveIPv6ProxyServerHost proxies server host only -func ResolveIPv6ProxyServerHost(host string) (net.IP, error) { +func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) { if ProxyServerHostResolver != nil { return ResolveIPv6WithResolver(host, ProxyServerHostResolver) } @@ -181,7 +185,7 @@ func ResolveIPv6ProxyServerHost(host string) (net.IP, error) { } // ResolveProxyServerHost proxies server host only -func ResolveProxyServerHost(host string) (net.IP, error) { +func ResolveProxyServerHost(host string) (netip.Addr, error) { if ProxyServerHostResolver != nil { return ResolveIPWithResolver(host, ProxyServerHostResolver) } diff --git a/config/config.go b/config/config.go index cc8423b7..71d468c0 100644 --- a/config/config.go +++ b/config/config.go @@ -83,7 +83,7 @@ type DNS struct { type FallbackFilter struct { GeoIP bool `yaml:"geoip"` GeoIPCode string `yaml:"geoip-code"` - IPCIDR []*net.IPNet `yaml:"ipcidr"` + IPCIDR []*netip.Prefix `yaml:"ipcidr"` Domain []string `yaml:"domain"` GeoSite []*router.DomainMatcher `yaml:"geosite"` } @@ -640,15 +640,15 @@ func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServe return policy, nil } -func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) { - var ipNets []*net.IPNet +func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) { + var ipNets []*netip.Prefix for idx, ip := range ips { - _, ipnet, err := net.ParseCIDR(ip) + ipnet, err := netip.ParsePrefix(ip) if err != nil { return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error()) } - ipNets = append(ipNets, ipnet) + ipNets = append(ipNets, &ipnet) } return ipNets, nil @@ -696,7 +696,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.R IPv6: cfg.IPv6, EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ - IPCIDR: []*net.IPNet{}, + IPCIDR: []*netip.Prefix{}, GeoSite: []*router.DomainMatcher{}, }, } diff --git a/constant/metadata.go b/constant/metadata.go index 70ed909b..df08f377 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -3,6 +3,7 @@ package constant import ( "encoding/json" "net" + "net/netip" "strconv" ) @@ -72,22 +73,22 @@ func (t Type) MarshalJSON() ([]byte, error) { // Metadata is used to store connection address type Metadata struct { - NetWork NetWork `json:"network"` - Type Type `json:"type"` - SrcIP net.IP `json:"sourceIP"` - DstIP net.IP `json:"destinationIP"` - SrcPort string `json:"sourcePort"` - DstPort string `json:"destinationPort"` - AddrType int `json:"-"` - Host string `json:"host"` - DNSMode DNSMode `json:"dnsMode"` - Process string `json:"process"` - ProcessPath string `json:"processPath"` - UserAgent string `json:"userAgent"` + NetWork NetWork `json:"network"` + Type Type `json:"type"` + SrcIP netip.Addr `json:"sourceIP"` + DstIP netip.Addr `json:"destinationIP"` + SrcPort string `json:"sourcePort"` + DstPort string `json:"destinationPort"` + AddrType int `json:"-"` + Host string `json:"host"` + DNSMode DNSMode `json:"dnsMode"` + Process string `json:"process"` + ProcessPath string `json:"processPath"` + UserAgent string `json:"userAgent"` } func (m *Metadata) RemoteAddress() string { - if m.DstIP != nil { + if m.DstIP.IsValid() { return net.JoinHostPort(m.DstIP.String(), m.DstPort) } else { return net.JoinHostPort(m.String(), m.DstPort) @@ -99,33 +100,33 @@ func (m *Metadata) SourceAddress() string { } func (m *Metadata) Resolved() bool { - return m.DstIP != nil + return m.DstIP.IsValid() } // Pure is used to solve unexpected behavior // when dialing proxy connection in DNSMapping mode. func (m *Metadata) Pure() *Metadata { - if m.DNSMode == DNSMapping && m.DstIP != nil { - copy := *m - copy.Host = "" - if copy.DstIP.To4() != nil { - copy.AddrType = AtypIPv4 + if m.DNSMode == DNSMapping && m.DstIP.IsValid() { + copyM := *m + copyM.Host = "" + if copyM.DstIP.Is4() { + copyM.AddrType = AtypIPv4 } else { - copy.AddrType = AtypIPv6 + copyM.AddrType = AtypIPv6 } - return © + return ©M } return m } func (m *Metadata) UDPAddr() *net.UDPAddr { - if m.NetWork != UDP || m.DstIP == nil { + if m.NetWork != UDP || !m.DstIP.IsValid() { return nil } port, _ := strconv.ParseUint(m.DstPort, 10, 16) return &net.UDPAddr{ - IP: m.DstIP, + IP: m.DstIP.AsSlice(), Port: int(port), } } @@ -133,7 +134,7 @@ func (m *Metadata) UDPAddr() *net.UDPAddr { func (m *Metadata) String() string { if m.Host != "" { return m.Host - } else if m.DstIP != nil { + } else if m.DstIP.IsValid() { return m.DstIP.String() } else { return "" @@ -141,5 +142,5 @@ func (m *Metadata) String() string { } func (m *Metadata) Valid() bool { - return m.Host != "" || m.DstIP != nil + return m.Host != "" || m.DstIP.IsValid() } diff --git a/constant/rule_extra.go b/constant/rule_extra.go index c7669ecd..a115319f 100644 --- a/constant/rule_extra.go +++ b/constant/rule_extra.go @@ -1,7 +1,7 @@ package constant import ( - "net" + "net/netip" "strings" "github.com/Dreamacro/clash/component/geodata/router" @@ -9,7 +9,7 @@ import ( type RuleExtra struct { Network NetWork - SourceIPs []*net.IPNet + SourceIPs []*netip.Prefix ProcessNames []string } @@ -17,7 +17,7 @@ func (re *RuleExtra) NotMatchNetwork(network NetWork) bool { return re.Network != ALLNet && re.Network != network } -func (re *RuleExtra) NotMatchSourceIP(srcIP net.IP) bool { +func (re *RuleExtra) NotMatchSourceIP(srcIP netip.Addr) bool { if re.SourceIPs == nil { return false } diff --git a/dns/client.go b/dns/client.go index fec3e39c..b536f0b1 100644 --- a/dns/client.go +++ b/dns/client.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "fmt" "net" + "net/netip" "strings" "github.com/Dreamacro/clash/component/dialer" @@ -28,10 +29,10 @@ func (c *client) Exchange(m *D.Msg) (*D.Msg, error) { func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { var ( - ip net.IP + ip netip.Addr err error ) - if ip = net.ParseIP(c.host); ip == nil { + if ip, err = netip.ParseAddr(c.host); err != nil { if c.r == nil { return nil, fmt.Errorf("dns %s not a valid ip", c.host) } else { @@ -62,7 +63,9 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) if err != nil { return nil, err } - defer conn.Close() + defer func() { + _ = conn.Close() + }() // miekg/dns ExchangeContext doesn't respond to context cancel. // this is a workaround diff --git a/dns/dhcp.go b/dns/dhcp.go index f964cec8..e0d6c7f0 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -1,9 +1,9 @@ package dns import ( - "bytes" "context" "net" + "net/netip" "sync" "time" @@ -27,7 +27,7 @@ type dhcpClient struct { ifaceInvalidate time.Time dnsInvalidate time.Time - ifaceAddr *net.IPNet + ifaceAddr *netip.Prefix done chan struct{} resolver *Resolver err error @@ -127,12 +127,12 @@ func (d *dhcpClient) invalidate() (bool, error) { return false, err } - addr, err := ifaceObj.PickIPv4Addr(nil) + addr, err := ifaceObj.PickIPv4Addr(netip.Addr{}) if err != nil { return false, err } - if time.Now().Before(d.dnsInvalidate) && d.ifaceAddr.IP.Equal(addr.IP) && bytes.Equal(d.ifaceAddr.Mask, addr.Mask) { + if time.Now().Before(d.dnsInvalidate) && d.ifaceAddr == addr { return false, nil } diff --git a/dns/enhancer.go b/dns/enhancer.go index 95703b9b..6e1d03ac 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -1,11 +1,9 @@ package dns import ( - "net" "net/netip" "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/fakeip" C "github.com/Dreamacro/clash/constant" ) @@ -24,54 +22,51 @@ func (h *ResolverEnhancer) MappingEnabled() bool { return h.mode == C.DNSFakeIP || h.mode == C.DNSMapping } -func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool { +func (h *ResolverEnhancer) IsExistFakeIP(ip netip.Addr) bool { if !h.FakeIPEnabled() { return false } if pool := h.fakePool; pool != nil { - return pool.Exist(nnip.IpToAddr(ip)) + return pool.Exist(ip) } return false } -func (h *ResolverEnhancer) IsFakeIP(ip net.IP) bool { - if !h.FakeIPEnabled() { - return false - } - - addr := nnip.IpToAddr(ip) - - if pool := h.fakePool; pool != nil { - return pool.IPNet().Contains(addr) && addr != pool.Gateway() && addr != pool.Broadcast() - } - - return false -} - -func (h *ResolverEnhancer) IsFakeBroadcastIP(ip net.IP) bool { +func (h *ResolverEnhancer) IsFakeIP(ip netip.Addr) bool { if !h.FakeIPEnabled() { return false } if pool := h.fakePool; pool != nil { - return pool.Broadcast() == nnip.IpToAddr(ip) + return pool.IPNet().Contains(ip) && ip != pool.Gateway() && ip != pool.Broadcast() } return false } -func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) { - addr := nnip.IpToAddr(ip) +func (h *ResolverEnhancer) IsFakeBroadcastIP(ip netip.Addr) bool { + if !h.FakeIPEnabled() { + return false + } + if pool := h.fakePool; pool != nil { - if host, existed := pool.LookBack(addr); existed { + return pool.Broadcast() == ip + } + + return false +} + +func (h *ResolverEnhancer) FindHostByIP(ip netip.Addr) (string, bool) { + if pool := h.fakePool; pool != nil { + if host, existed := pool.LookBack(ip); existed { return host, true } } if mapping := h.mapping; mapping != nil { - if host, existed := h.mapping.Get(addr); existed { + if host, existed := h.mapping.Get(ip); existed { return host, true } } @@ -79,9 +74,9 @@ func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) { return "", false } -func (h *ResolverEnhancer) InsertHostByIP(ip net.IP, host string) { +func (h *ResolverEnhancer) InsertHostByIP(ip netip.Addr, host string) { if mapping := h.mapping; mapping != nil { - h.mapping.Set(nnip.IpToAddr(ip), host) + h.mapping.Set(ip, host) } } diff --git a/dns/filters.go b/dns/filters.go index 6f316198..1f294b53 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -1,7 +1,7 @@ package dns import ( - "net" + "net/netip" "strings" "github.com/Dreamacro/clash/component/geodata/router" @@ -10,23 +10,23 @@ import ( ) type fallbackIPFilter interface { - Match(net.IP) bool + Match(netip.Addr) bool } type geoipFilter struct { code string } -func (gf *geoipFilter) Match(ip net.IP) bool { - record, _ := mmdb.Instance().Country(ip) +func (gf *geoipFilter) Match(ip netip.Addr) bool { + record, _ := mmdb.Instance().Country(ip.AsSlice()) return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate() } type ipnetFilter struct { - ipnet *net.IPNet + ipnet *netip.Prefix } -func (inf *ipnetFilter) Match(ip net.IP) bool { +func (inf *ipnetFilter) Match(ip netip.Addr) bool { return inf.ipnet.Contains(ip) } @@ -41,7 +41,7 @@ type domainFilter struct { func NewDomainFilter(domains []string) *domainFilter { df := domainFilter{tree: trie.New[bool]()} for _, domain := range domains { - df.tree.Insert(domain, true) + _ = df.tree.Insert(domain, true) } return &df } diff --git a/dns/middleware.go b/dns/middleware.go index e227e588..ce410eba 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -1,7 +1,6 @@ package dns import ( - "net" "net/netip" "strings" "time" @@ -88,21 +87,21 @@ func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware { host := strings.TrimRight(q.Name, ".") for _, ans := range msg.Answer { - var ip net.IP + var ip netip.Addr var ttl uint32 switch a := ans.(type) { case *D.A: - ip = a.A + ip = nnip.IpToAddr(a.A) ttl = a.Hdr.Ttl case *D.AAAA: - ip = a.AAAA + ip = nnip.IpToAddr(a.AAAA) ttl = a.Hdr.Ttl default: continue } - mapping.SetWithExpire(nnip.IpToAddr(ip), host, time.Now().Add(time.Second*time.Duration(ttl))) + mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*time.Duration(ttl))) } return msg, nil diff --git a/dns/resolver.go b/dns/resolver.go index afa0d99a..accd9a8c 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math/rand" - "net" "net/netip" "strings" "time" @@ -46,8 +45,8 @@ type Resolver struct { } // ResolveIP request with TypeA and TypeAAAA, priority return TypeA -func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) { - ch := make(chan net.IP, 1) +func (r *Resolver) ResolveIP(host string) (ip netip.Addr, err error) { + ch := make(chan netip.Addr, 1) go func() { defer close(ch) ip, err := r.resolveIP(host, D.TypeAAAA) @@ -64,23 +63,23 @@ func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) { ip, open := <-ch if !open { - return nil, resolver.ErrIPNotFound + return netip.Addr{}, resolver.ErrIPNotFound } return ip, nil } // ResolveIPv4 request with TypeA -func (r *Resolver) ResolveIPv4(host string) (ip net.IP, err error) { +func (r *Resolver) ResolveIPv4(host string) (ip netip.Addr, err error) { return r.resolveIP(host, D.TypeA) } // ResolveIPv6 request with TypeAAAA -func (r *Resolver) ResolveIPv6(host string) (ip net.IP, err error) { +func (r *Resolver) ResolveIPv6(host string) (ip netip.Addr, err error) { return r.resolveIP(host, D.TypeAAAA) } -func (r *Resolver) shouldIPFallback(ip net.IP) bool { +func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { for _, filter := range r.fallbackIPFilters { if filter.Match(ip) { return true @@ -101,10 +100,10 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e } q := m.Question[0] - cache, expireTime, hit := r.lruCache.GetWithExpire(q.String()) + cacheM, expireTime, hit := r.lruCache.GetWithExpire(q.String()) if hit { now := time.Now() - msg = cache.Copy() + msg = cacheM.Copy() if expireTime.Before(now) { setMsgTTL(msg, uint32(1)) // Continue fetch go r.exchangeWithoutCache(ctx, m) @@ -256,16 +255,16 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er return } -func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error) { - ip = net.ParseIP(host) - if ip != nil { - isIPv4 := ip.To4() != nil +func (r *Resolver) resolveIP(host string, dnsType uint16) (ip netip.Addr, err error) { + ip, err = netip.ParseAddr(host) + if err == nil { + isIPv4 := ip.Is4() if dnsType == D.TypeAAAA && !isIPv4 { return ip, nil } else if dnsType == D.TypeA && isIPv4 { return ip, nil } else { - return nil, resolver.ErrIPVersion + return netip.Addr{}, resolver.ErrIPVersion } } @@ -274,13 +273,13 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error) msg, err := r.Exchange(query) if err != nil { - return nil, err + return netip.Addr{}, err } ips := msgToIP(msg) ipLength := len(ips) if ipLength == 0 { - return nil, resolver.ErrIPNotFound + return netip.Addr{}, resolver.ErrIPNotFound } ip = ips[rand.Intn(ipLength)] @@ -319,7 +318,7 @@ type NameServer struct { type FallbackFilter struct { GeoIP bool GeoIPCode string - IPCIDR []*net.IPNet + IPCIDR []*netip.Prefix Domain []string GeoSite []*router.DomainMatcher } @@ -360,7 +359,7 @@ func NewResolver(config Config) *Resolver { if len(config.Policy) != 0 { r.policy = trie.New[*Policy]() for domain, nameserver := range config.Policy { - r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) + _ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver))) } } diff --git a/dns/util.go b/dns/util.go index 759b2209..86d410d4 100644 --- a/dns/util.go +++ b/dns/util.go @@ -5,9 +5,11 @@ import ( "crypto/tls" "fmt" "net" + "net/netip" "time" "github.com/Dreamacro/clash/common/cache" + "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" @@ -96,15 +98,15 @@ func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg { return msg } -func msgToIP(msg *D.Msg) []net.IP { - ips := []net.IP{} +func msgToIP(msg *D.Msg) []netip.Addr { + ips := []netip.Addr{} for _, answer := range msg.Answer { switch ans := answer.(type) { case *D.AAAA: - ips = append(ips, ans.AAAA) + ips = append(ips, nnip.IpToAddr(ans.AAAA)) case *D.A: - ips = append(ips, ans.A) + ips = append(ips, nnip.IpToAddr(ans.A)) } } @@ -129,7 +131,7 @@ func (wpc *wrapPacketConn) RemoteAddr() net.Addr { return wpc.rAddr } -func dialContextWithProxyAdapter(ctx context.Context, adapterName string, network string, dstIP net.IP, port string, opts ...dialer.Option) (net.Conn, error) { +func dialContextWithProxyAdapter(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 { return nil, fmt.Errorf("proxy adapter [%s] not found", adapterName) @@ -144,7 +146,7 @@ func dialContextWithProxyAdapter(ctx context.Context, adapterName string, networ } addrType := C.AtypIPv4 - if dstIP.To4() == nil { + if dstIP.Is6() { addrType = C.AtypIPv6 } diff --git a/listener/mitm/proxy.go b/listener/mitm/proxy.go index 0ab138fc..d24de227 100644 --- a/listener/mitm/proxy.go +++ b/listener/mitm/proxy.go @@ -9,7 +9,7 @@ import ( "io" "net" "net/http" - "strconv" + "net/netip" "strings" "time" @@ -290,24 +290,15 @@ func parseSourceAddress(req *http.Request, connSource, source net.Addr) net.Addr req.Header.Del("Origin-Request-Source-Address") - host, port, err := net.SplitHostPort(sourceAddress) + addrPort, err := netip.ParseAddrPort(sourceAddress) if err != nil { return connSource } - p, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return connSource + return &net.TCPAddr{ + IP: addrPort.Addr().AsSlice(), + Port: int(addrPort.Port()), } - - if ip := net.ParseIP(host); ip != nil { - return &net.TCPAddr{ - IP: ip, - Port: int(p), - } - } - - return connSource } func newClientBySourceAndUserAgentIfNil(cli *http.Client, req *http.Request, source net.Addr, in chan<- C.ConnContext) *http.Client { diff --git a/listener/tun/ipstack/system/stack.go b/listener/tun/ipstack/system/stack.go index 6ffc6d7d..16fd37d0 100644 --- a/listener/tun/ipstack/system/stack.go +++ b/listener/tun/ipstack/system/stack.go @@ -83,6 +83,7 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref lAddr := conn.LocalAddr().(*net.TCPAddr) rAddr := conn.RemoteAddr().(*net.TCPAddr) + lAddrPort := netip.AddrPortFrom(nnip.IpToAddr(lAddr.IP), uint16(lAddr.Port)) rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port)) if rAddrPort.Addr().IsLoopback() { @@ -135,8 +136,8 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref metadata := &C.Metadata{ NetWork: C.TCP, Type: C.TUN, - SrcIP: lAddr.IP, - DstIP: rAddr.IP, + SrcIP: lAddrPort.Addr(), + DstIP: rAddrPort.Addr(), SrcPort: strconv.Itoa(lAddr.Port), DstPort: strconv.Itoa(rAddr.Port), AddrType: C.AtypIPv4, diff --git a/listener/tun/tun_adapter.go b/listener/tun/tun_adapter.go index fdfbfdf5..fd02cb9c 100644 --- a/listener/tun/tun_adapter.go +++ b/listener/tun/tun_adapter.go @@ -50,7 +50,7 @@ func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.Con tunAddress = netip.MustParsePrefix("198.18.0.1/16") } - process.AppendLocalIPs(tunAddress.Masked().Addr().Next().AsSlice()) + process.AppendLocalIPs(tunAddress.Masked().Addr().Next()) // open tun device tunDevice, err = parseDevice(devName, uint32(mtu)) diff --git a/rule/base.go b/rule/base.go index 94513cd9..c89e985f 100644 --- a/rule/base.go +++ b/rule/base.go @@ -2,7 +2,7 @@ package rules import ( "errors" - "net" + "net/netip" "strings" C "github.com/Dreamacro/clash/constant" @@ -50,17 +50,17 @@ func findNetwork(params []string) C.NetWork { return C.ALLNet } -func findSourceIPs(params []string) []*net.IPNet { - var ips []*net.IPNet +func findSourceIPs(params []string) []*netip.Prefix { + var ips []*netip.Prefix for _, p := range params { if p == noResolve || len(p) < 7 { continue } - _, ipnet, err := net.ParseCIDR(p) + ipnet, err := netip.ParsePrefix(p) if err != nil { continue } - ips = append(ips, ipnet) + ips = append(ips, &ipnet) } if len(ips) > 0 { diff --git a/rule/geoip.go b/rule/geoip.go index 62f4b8a6..b1faa7bc 100644 --- a/rule/geoip.go +++ b/rule/geoip.go @@ -21,7 +21,7 @@ func (g *GEOIP) RuleType() C.RuleType { func (g *GEOIP) Match(metadata *C.Metadata) bool { ip := metadata.DstIP - if ip == nil { + if !ip.IsValid() { return false } @@ -34,7 +34,7 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool { resolver.IsFakeBroadcastIP(ip) } - record, _ := mmdb.Instance().Country(ip) + record, _ := mmdb.Instance().Country(ip.AsSlice()) return strings.EqualFold(record.Country.IsoCode, g.country) } diff --git a/rule/ipcidr.go b/rule/ipcidr.go index db55e465..25dab66e 100644 --- a/rule/ipcidr.go +++ b/rule/ipcidr.go @@ -1,7 +1,7 @@ package rules import ( - "net" + "net/netip" C "github.com/Dreamacro/clash/constant" ) @@ -22,7 +22,7 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption { type IPCIDR struct { *Base - ipnet *net.IPNet + ipnet *netip.Prefix adapter string isSourceIP bool noResolveIP bool @@ -40,7 +40,7 @@ func (i *IPCIDR) Match(metadata *C.Metadata) bool { if i.isSourceIP { ip = metadata.SrcIP } - return ip != nil && i.ipnet.Contains(ip) + return ip.IsValid() && i.ipnet.Contains(ip) } func (i *IPCIDR) Adapter() string { @@ -56,14 +56,14 @@ func (i *IPCIDR) ShouldResolveIP() bool { } func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) { - _, ipnet, err := net.ParseCIDR(s) + ipnet, err := netip.ParsePrefix(s) if err != nil { return nil, errPayload } ipcidr := &IPCIDR{ Base: &Base{}, - ipnet: ipnet, + ipnet: &ipnet, adapter: adapter, } diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go index a2941624..0d5c5a77 100644 --- a/transport/socks4/socks4.go +++ b/transport/socks4/socks4.go @@ -6,6 +6,7 @@ import ( "errors" "io" "net" + "net/netip" "strconv" "github.com/Dreamacro/clash/component/auth" @@ -40,6 +41,8 @@ var ( ErrRequestUnknownCode = errors.New("request failed with unknown code") ) +var subnet = netip.PrefixFrom(netip.IPv4Unspecified(), 24) + func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr string, command Command, err error) { var req [8]byte if _, err = io.ReadFull(rw, req[:]); err != nil { @@ -57,8 +60,8 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s } var ( - dstIP = req[4:8] // [4]byte - dstPort = req[2:4] // [2]byte + dstIP = netip.AddrFrom4(*(*[4]byte)(req[4:8])) // [4]byte + dstPort = req[2:4] // [2]byte ) var ( @@ -83,7 +86,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s if host != "" { addr = net.JoinHostPort(host, port) } else { - addr = net.JoinHostPort(net.IP(dstIP).String(), port) + addr = net.JoinHostPort(dstIP.String(), port) } // SOCKS4 only support USERID auth. @@ -97,7 +100,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s var reply [8]byte reply[0] = 0x00 // reply code reply[1] = code // result code - copy(reply[4:8], dstIP) + copy(reply[4:8], dstIP.AsSlice()) copy(reply[2:4], dstPort) _, wErr := rw.Write(reply[:]) @@ -118,20 +121,18 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri return err } - ip := net.ParseIP(host) - if ip == nil /* HOST */ { - ip = net.IPv4(0, 0, 0, 1).To4() - } else if ip.To4() == nil /* IPv6 */ { + dstIP, err := netip.ParseAddr(host) + if err != nil /* HOST */ { + dstIP = netip.AddrFrom4([4]byte{0, 0, 0, 1}) + } else if dstIP.Is6() /* IPv6 */ { return errIPv6NotSupported } - dstIP := ip.To4() - req := &bytes.Buffer{} req.WriteByte(Version) req.WriteByte(command) - binary.Write(req, binary.BigEndian, uint16(port)) - req.Write(dstIP) + _ = binary.Write(req, binary.BigEndian, uint16(port)) + req.Write(dstIP.AsSlice()) req.WriteString(userID) req.WriteByte(0) /* NULL */ @@ -174,12 +175,7 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri // Internet Assigned Numbers Authority -- such an address is inadmissible // as a destination IP address and thus should never occur if the client // can resolve the domain name.) -func isReservedIP(ip net.IP) bool { - subnet := net.IPNet{ - IP: net.IPv4zero, - Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00), - } - +func isReservedIP(ip netip.Addr) bool { return !ip.IsUnspecified() && subnet.Contains(ip) } diff --git a/tunnel/statistic/sniffing.go b/tunnel/statistic/sniffing.go index 5f8136c8..30716a09 100644 --- a/tunnel/statistic/sniffing.go +++ b/tunnel/statistic/sniffing.go @@ -32,7 +32,7 @@ func (r *sniffing) Write(b []byte) (int, error) { resolver.InsertHostByIP(r.metadata.DstIP, header.Domain()) log.Warnln("use sni update host: %s ip: %s", header.Domain(), r.metadata.DstIP.String()) if r.allowBreak { - r.Conn.Close() + _ = r.Conn.Close() return 0, errors.New("sni update, break current link to avoid leaks") } else { r.metadata.Host = header.Domain() diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 8360052a..a16b5232 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "path/filepath" "runtime" "strconv" @@ -131,15 +132,15 @@ func process() { } func needLookupIP(metadata *C.Metadata) bool { - return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP != nil + return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP.IsValid() } func preHandleMetadata(metadata *C.Metadata) error { // handle IP string on host - if ip := net.ParseIP(metadata.Host); ip != nil { + if ip, err := netip.ParseAddr(metadata.Host); err == nil { metadata.DstIP = ip metadata.Host = "" - if ip.To4() != nil { + if ip.Is4() { metadata.AddrType = C.AtypIPv4 } else { metadata.AddrType = C.AtypIPv6 @@ -154,11 +155,11 @@ func preHandleMetadata(metadata *C.Metadata) error { metadata.AddrType = C.AtypDomainName metadata.DNSMode = C.DNSMapping if resolver.FakeIPEnabled() { - metadata.DstIP = nil + metadata.DstIP = netip.Addr{} metadata.DNSMode = C.DNSFakeIP } else if node := resolver.DefaultHosts.Search(host); node != nil { // redir-host should lookup the hosts - metadata.DstIP = node.Data.AsSlice() + metadata.DstIP = node.Data } } else if resolver.IsFakeIP(metadata.DstIP) { return fmt.Errorf("fake DNS record %s missing", metadata.DstIP) @@ -348,7 +349,7 @@ func handleTCPConn(connCtx C.ConnContext) { } func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool { - return rule.ShouldResolveIP() && metadata.Host != "" && metadata.DstIP == nil + return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid() } func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { @@ -358,7 +359,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { var resolved bool if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { - metadata.DstIP = node.Data.AsSlice() + metadata.DstIP = node.Data resolved = true } From 567fe74f10cc7d7c927875894352060d5cc36f9a Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Wed, 20 Apr 2022 01:59:57 +0800 Subject: [PATCH 12/12] Chore: update dependencies --- go.mod | 6 +++--- go.sum | 12 ++++++------ test/go.mod | 6 +++--- test/go.sum | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index d4f55367..934ee95d 100644 --- a/go.mod +++ b/go.mod @@ -19,16 +19,16 @@ require ( go.uber.org/atomic v1.9.0 go.uber.org/automaxprocs v1.5.1 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab golang.org/x/time v0.0.0-20220411224347-583f2d630306 golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 - gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b + gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b ) require ( diff --git a/go.sum b/go.sum index 56e3f8f3..bcfdfad0 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -122,8 +122,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 h1:NubxfvTRuNb4RVzWrIDAUzUvREH1HkCD4JjyQTSG9As= -golang.org/x/sys v0.0.0-20220412071739-889880a91fd5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -159,5 +159,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b h1:JW1pUBe6A3H+b0B9DwEOcfK+TLS/04A3A9cettPpfV0= -gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI= +gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b h1:zBJp2eKSoNIV6+9LO3bRhlnuK280Oyrwc6OeFIN6VzU= +gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI= diff --git a/test/go.mod b/test/go.mod index 0c6954a5..a24e2c63 100644 --- a/test/go.mod +++ b/test/go.mod @@ -8,7 +8,7 @@ require ( github.com/docker/go-connections v0.4.0 github.com/miekg/dns v1.1.48 github.com/stretchr/testify v1.7.1 - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 ) replace github.com/Dreamacro/clash => ../ @@ -42,7 +42,7 @@ require ( golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect golang.org/x/tools v0.1.9 // indirect @@ -56,5 +56,5 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gotest.tools/v3 v3.1.0 // indirect - gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b // indirect + gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b // indirect ) diff --git a/test/go.sum b/test/go.sum index ad42d1ba..1c7952fa 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1012,8 +1012,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1143,8 +1143,8 @@ golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 h1:NubxfvTRuNb4RVzWrIDAUzUvREH1HkCD4JjyQTSG9As= -golang.org/x/sys v0.0.0-20220412071739-889880a91fd5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1413,8 +1413,8 @@ gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= -gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b h1:JW1pUBe6A3H+b0B9DwEOcfK+TLS/04A3A9cettPpfV0= -gvisor.dev/gvisor v0.0.0-20220412020520-6917e582612b/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI= +gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b h1:zBJp2eKSoNIV6+9LO3bRhlnuK280Oyrwc6OeFIN6VzU= +gvisor.dev/gvisor v0.0.0-20220419020849-1f2f4462d45b/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=