diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86352a15..bbf8e721 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,7 +126,7 @@ jobs: shell: bash - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: "1.20" check-latest: true @@ -223,7 +223,7 @@ jobs: working-directory: bin - name: Delete current release assets - uses: andreaswilli/delete-release-assets-action@v2.0.0 + uses: 8Mi-Tech/delete-release-assets-action@main with: github_token: ${{ secrets.GITHUB_TOKEN }} tag: Prerelease-${{ github.ref_name }} @@ -246,18 +246,14 @@ jobs: Release created at ${{ env.BUILDTIME }} Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
- ### release version - `default(not specified in file name)`: compiled with GOAMD64=v3 - `cgo`: support lwip tun stack, compiled with GOAMD64=v1 - `compatible`: compiled with GOAMD64=v1 - Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64). + [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/Clash.Meta/wiki/FAQ) + [查看文档 / Docs](https://metacubex.github.io/Meta-Docs/) EOF - name: Upload Prerelease uses: softprops/action-gh-release@v1 if: ${{ success() }} with: - tag: ${{ github.ref_name }} tag_name: Prerelease-${{ github.ref_name }} files: | bin/* @@ -284,7 +280,6 @@ jobs: uses: softprops/action-gh-release@v1 if: ${{ success() }} with: - tag: ${{ github.ref_name }} tag_name: ${{ github.ref_name }} files: bin/* generate_release_notes: true @@ -309,10 +304,10 @@ jobs: working-directory: bin - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Setup Docker buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: latest @@ -320,7 +315,7 @@ jobs: # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}} - name: Show files @@ -329,7 +324,7 @@ jobs: ls bin/ - name: Log into registry if: github.event_name != 'pull_request' - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_HUB_USER }} @@ -339,7 +334,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push Docker image id: build-and-push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . file: ./Dockerfile diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 5966e784..47307ed7 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -16,6 +16,12 @@ func WithInName(name string) Addition { } } +func WithInUser(user string) Addition { + return func(metadata *C.Metadata) { + metadata.InUser = user + } +} + func WithSpecialRules(specialRules string) Addition { return func(metadata *C.Metadata) { metadata.SpecialRules = specialRules diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index a6b1288c..e41ee925 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -30,21 +30,18 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad return context.NewConnContext(conn, metadata) } -func NewInner(conn net.Conn, dst string, host string) *context.ConnContext { +func NewInner(conn net.Conn, address string) *context.ConnContext { metadata := &C.Metadata{} metadata.NetWork = C.TCP metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal - metadata.Host = host metadata.Process = C.ClashName - if h, port, err := net.SplitHostPort(dst); err == nil { + if h, port, err := net.SplitHostPort(address); err == nil { metadata.DstPort = port - if host == "" { - if ip, err := netip.ParseAddr(h); err == nil { - metadata.DstIP = ip - } else { - metadata.Host = h - } + if ip, err := netip.ParseAddr(h); err == nil { + metadata.DstIP = ip + } else { + metadata.Host = h } } diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 367638b8..f2ce56c9 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -45,8 +45,8 @@ func (b *Base) Type() C.AdapterType { return b.tp } -// StreamConn implements C.ProxyAdapter -func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { return c, C.ErrNotSupport } @@ -220,7 +220,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { } type packetConn struct { - net.PacketConn + N.EnhancePacketConn chain C.Chain adapterName string connID string @@ -242,15 +242,28 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) { } func (c *packetConn) LocalAddr() net.Addr { - lAddr := c.PacketConn.LocalAddr() + lAddr := c.EnhancePacketConn.LocalAddr() return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy } +func (c *packetConn) Upstream() any { + return c.EnhancePacketConn +} + +func (c *packetConn) WriterReplaceable() bool { + return true +} + +func (c *packetConn) ReaderReplaceable() bool { + return true +} + func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { + epc := N.NewEnhancePacketConn(pc) if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn - pc = N.NewDeadlinePacketConn(pc) // most conn from outbound can't handle readDeadline correctly + epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly } - return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} + return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index eae37d7a..94b59cd0 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -3,8 +3,6 @@ package outbound import ( "context" "errors" - "net" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" @@ -39,11 +37,7 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if err != nil { return nil, err } - return newPacketConn(&directPacketConn{pc}, d), nil -} - -type directPacketConn struct { - net.PacketConn + return newPacketConn(pc, d), nil } func NewDirect() *Direct { diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 2d5fd899..78735b2d 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -10,7 +10,6 @@ import ( "io" "net" "net/http" - "net/url" "strconv" "github.com/Dreamacro/clash/component/dialer" @@ -41,12 +40,10 @@ type HttpOption struct { Headers map[string]string `proxy:"headers,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (h *Http) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (h *Http) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if h.tlsConfig != nil { cc := tls.Client(c, h.tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := cc.HandshakeContext(ctx) c = cc if err != nil { @@ -83,7 +80,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad safeConnClose(c, err) }(c) - c, err = h.StreamConn(c, metadata) + c, err = h.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } @@ -98,34 +95,36 @@ func (h *Http) SupportWithDialer() C.NetWork { func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { addr := metadata.RemoteAddress() - req := &http.Request{ - Method: http.MethodConnect, - URL: &url.URL{ - Host: addr, - }, - Host: addr, - Header: http.Header{ - "Proxy-Connection": []string{"Keep-Alive"}, - }, + HeaderString := "CONNECT " + addr + " HTTP/1.1\r\n" + tempHeaders := map[string]string{ + "Host": addr, + "User-Agent": "Go-http-client/1.1", + "Proxy-Connection": "Keep-Alive", } - //增加headers - if len(h.option.Headers) != 0 { - for key, value := range h.option.Headers { - req.Header.Add(key, value) - } + for key, value := range h.option.Headers { + tempHeaders[key] = value } if h.user != "" && h.pass != "" { auth := h.user + ":" + h.pass - req.Header.Add("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) + tempHeaders["Proxy-Authorization"] = "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) } - if err := req.Write(rw); err != nil { + for key, value := range tempHeaders { + HeaderString += key + ": " + value + "\r\n" + } + + HeaderString += "\r\n" + + _, err := rw.Write([]byte(HeaderString)) + + if err != nil { return err } - resp, err := http.ReadResponse(bufio.NewReader(rw), req) + resp, err := http.ReadResponse(bufio.NewReader(rw), nil) + if err != nil { return err } diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 6024ea10..7da4975d 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -318,6 +318,16 @@ func (c *hyPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { return } +func (c *hyPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + b, addrStr, err := c.UDPConn.ReadFrom() + if err != nil { + return + } + data = b + addr = M.ParseSocksaddr(addrStr).UDPAddr() + return +} + func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { err = c.UDPConn.WriteTo(p, M.SocksaddrFromNet(addr).String()) if err != nil { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index e2ed24c2..32558eac 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -6,7 +6,6 @@ import ( "fmt" "net" "strconv" - "time" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/structure" @@ -17,13 +16,10 @@ import ( "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" - "github.com/Dreamacro/clash/transport/socks5" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" - shadowsocks "github.com/metacubex/sing-shadowsocks" - "github.com/metacubex/sing-shadowsocks/shadowimpl" - "github.com/sagernet/sing/common/bufio" + "github.com/metacubex/sing-shadowsocks2" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" ) @@ -87,14 +83,7 @@ type restlsOption struct { RestlsScript string `obfs:"restls-script,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { - // fix tls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - return ss.StreamConnContext(ctx, c, metadata) -} - +// StreamConnContext implements C.ProxyAdapter func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { useEarly := false switch ss.obfsMode { @@ -105,7 +94,7 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port) case "websocket": var err error - c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption) + c, err = v2rayObfs.NewV2rayObfs(ctx, c, ss.v2rayOption) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } @@ -196,7 +185,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr)) + pc = ss.method.DialPacketConn(N.NewBindPacketConn(pc, addr)) return newPacketConn(pc, ss), nil } @@ -234,7 +223,9 @@ func (ss *ShadowSocks) SupportUOT() bool { func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) - method, err := shadowimpl.FetchMethod(option.Cipher, option.Password, time.Now) + method, err := shadowsocks.CreateMethod(context.Background(), option.Cipher, shadowsocks.MethodOptions{ + Password: option.Password, + }) if err != nil { return nil, fmt.Errorf("ss %s initialize error: %w", addr, err) } @@ -312,7 +303,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { switch option.UDPOverTCPVersion { case uot.Version, uot.LegacyVersion: case 0: - option.UDPOverTCPVersion = uot.Version + option.UDPOverTCPVersion = uot.LegacyVersion default: return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion) } @@ -338,36 +329,3 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { restlsConfig: restlsConfig, }, nil } - -type ssPacketConn struct { - net.PacketConn - rAddr net.Addr -} - -func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) - if err != nil { - return - } - return spc.PacketConn.WriteTo(packet[3:], spc.rAddr) -} - -func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, _, e := spc.PacketConn.ReadFrom(b) - if e != nil { - return 0, nil, e - } - - addr := socks5.SplitAddr(b[:n]) - if addr == nil { - return 0, nil, errors.New("parse addr error") - } - - udpAddr := addr.UDPAddr() - if udpAddr == nil { - return 0, nil, errors.New("parse addr error") - } - - copy(b, b[len(addr):]) - return n - len(addr), udpAddr, e -} diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 2b94ab0c..07778032 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -2,16 +2,19 @@ package outbound import ( "context" + "errors" "fmt" "net" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/shadowsocks/core" "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" + "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/ssr/obfs" "github.com/Dreamacro/clash/transport/ssr/protocol" ) @@ -38,8 +41,8 @@ type ShadowSocksROption struct { UDP bool `proxy:"udp,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = ssr.obfs.StreamConn(c) c = ssr.cipher.StreamConn(c) var ( @@ -83,7 +86,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia safeConnClose(c, err) }(c) - c, err = ssr.StreamConn(c, metadata) + c, err = ssr.StreamConnContext(ctx, c, metadata) return NewConn(c, ssr), err } @@ -110,9 +113,9 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di return nil, err } - pc = ssr.cipher.PacketConn(pc) - pc = ssr.protocol.PacketConn(pc) - return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil + epc := ssr.cipher.PacketConn(N.NewEnhancePacketConn(pc)) + epc = ssr.protocol.PacketConn(epc) + return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil } // SupportWithDialer implements C.ProxyAdapter @@ -188,3 +191,62 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { protocol: protocol, }, nil } + +type ssrPacketConn struct { + N.EnhancePacketConn + rAddr net.Addr +} + +func (spc *ssrPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) + if err != nil { + return + } + return spc.EnhancePacketConn.WriteTo(packet[3:], spc.rAddr) +} + +func (spc *ssrPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + n, _, e := spc.EnhancePacketConn.ReadFrom(b) + if e != nil { + return 0, nil, e + } + + addr := socks5.SplitAddr(b[:n]) + if addr == nil { + return 0, nil, errors.New("parse addr error") + } + + udpAddr := addr.UDPAddr() + if udpAddr == nil { + return 0, nil, errors.New("parse addr error") + } + + copy(b, b[len(addr):]) + return n - len(addr), udpAddr, e +} + +func (spc *ssrPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, _, err = spc.EnhancePacketConn.WaitReadFrom() + if err != nil { + return nil, nil, nil, err + } + + _addr := socks5.SplitAddr(data) + if _addr == nil { + if put != nil { + put() + } + return nil, nil, nil, errors.New("parse addr error") + } + + addr = _addr.UDPAddr() + if addr == nil { + if put != nil { + put() + } + return nil, nil, nil, errors.New("parse addr error") + } + + data = data[len(_addr):] + return +} diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index acfdfe99..555a0ecb 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -92,7 +92,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if pc == nil { return nil, E.New("packetConn is nil") } - return newPacketConn(CN.NewRefPacketConn(pc, s), s.ProxyAdapter), nil + return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(pc), s), s.ProxyAdapter), nil } func (s *SingMux) SupportUDP() bool { diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 1ec0a430..fc1f4eb3 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -52,8 +52,8 @@ func streamConn(c net.Conn, option streamOption) *snell.Snell { return snell.StreamConn(c, option.psk, option.version) } -// StreamConn implements C.ProxyAdapter -func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (s *Snell) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption}) if metadata.NetWork == C.UDP { err := snell.WriteUDPHeader(c, s.version) @@ -101,7 +101,7 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = s.StreamConn(c, metadata) + c, err = s.StreamConnContext(ctx, c, metadata) return NewConn(c, s), err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 26f5733b..9af4d0fc 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -39,12 +39,10 @@ type Socks5Option struct { Fingerprint string `proxy:"fingerprint,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (ss *Socks5) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if ss.tls { cc := tls.Client(c, ss.tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := cc.HandshakeContext(ctx) c = cc if err != nil { @@ -88,7 +86,7 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me safeConnClose(c, err) }(c) - c, err = ss.StreamConn(c, metadata) + c, err = ss.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index b9bbc33f..81fb1ceb 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -50,7 +50,7 @@ type TrojanOption struct { ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } -func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { +func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) { if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) wsOpts := &trojan.WebsocketOption{ @@ -71,14 +71,14 @@ func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { wsOpts.Headers = header } - return t.instance.StreamWebsocketConn(c, wsOpts) + return t.instance.StreamWebsocketConn(ctx, c, wsOpts) } - return t.instance.StreamConn(c) + return t.instance.StreamConn(ctx, c) } -// StreamConn implements C.ProxyAdapter -func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { @@ -88,7 +88,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) if t.transport != nil { c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig) } else { - c, err = t.plainStream(c) + c, err = t.plainStream(ctx, c) } if err != nil { @@ -151,7 +151,7 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = t.StreamConn(c, metadata) + c, err = t.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } @@ -199,7 +199,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me safeConnClose(c, err) }(c) tcpKeepAlive(c) - c, err = t.plainStream(c) + c, err = t.plainStream(ctx, c) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index d7db27d5..e3aff5fb 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -13,6 +13,7 @@ import ( "sync" "github.com/Dreamacro/clash/common/convert" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -74,7 +75,7 @@ type VlessOption struct { ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } -func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { @@ -128,10 +129,10 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { convert.SetUserAgent(wsOpts.Headers) } } - c, err = vmess.StreamWebsocketConn(c, wsOpts) + c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic - c, err = v.streamTLSOrXTLSConn(c, false) + c, err = v.streamTLSOrXTLSConn(ctx, c, false) if err != nil { return nil, err } @@ -146,7 +147,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = vmess.StreamHTTPConn(c, httpOpts) case "h2": - c, err = v.streamTLSOrXTLSConn(c, true) + c, err = v.streamTLSOrXTLSConn(ctx, c, true) if err != nil { return nil, err } @@ -162,7 +163,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { default: // default tcp network // handle TLS And XTLS - c, err = v.streamTLSOrXTLSConn(c, false) + c, err = v.streamTLSOrXTLSConn(ctx, c, false) } if err != nil { @@ -200,7 +201,7 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err return } -func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) { +func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { host, _, _ := net.SplitHostPort(v.addr) if v.isLegacyXTLSEnabled() && !isH2 { @@ -214,7 +215,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) xtlsOpts.Host = v.option.ServerName } - return vless.StreamXTLSConn(conn, &xtlsOpts) + return vless.StreamXTLSConn(ctx, conn, &xtlsOpts) } else if v.option.TLS { tlsOpts := vmess.TLSConfig{ @@ -233,7 +234,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) tlsOpts.Host = v.option.ServerName } - return vmess.StreamTLSConn(conn, &tlsOpts) + return vmess.StreamTLSConn(ctx, conn, &tlsOpts) } return conn, nil @@ -282,7 +283,7 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -347,7 +348,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } @@ -372,15 +373,15 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada } if v.option.XUDP { - return newPacketConn(&threadSafePacketConn{ - PacketConn: vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), - }, v), nil + return newPacketConn(N.NewThreadSafePacketConn( + vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), + ), v), nil } else if v.option.PacketAddr { - return newPacketConn(&threadSafePacketConn{ - PacketConn: packetaddr.NewConn(&vlessPacketConn{ + return newPacketConn(N.NewThreadSafePacketConn( + packetaddr.NewConn(&vlessPacketConn{ Conn: c, rAddr: metadata.UDPAddr(), }, M.SocksaddrFromNet(metadata.UDPAddr())), - }, v), nil + ), v), nil } return newPacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil } @@ -595,15 +596,19 @@ func NewVless(option VlessOption) (*Vless, error) { Host: v.option.ServerName, ClientFingerprint: v.option.ClientFingerprint, } - tlsConfig := tlsC.GetGlobalTLSConfig(&tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, - }) - - if v.option.ServerName == "" { - host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host - gunConfig.Host = host + if option.ServerName == "" { + gunConfig.Host = v.addr + } + var tlsConfig *tls.Config + if option.TLS { + tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + InsecureSkipVerify: v.option.SkipCertVerify, + ServerName: v.option.ServerName, + }) + if option.ServerName == "" { + host, _, _ := net.SplitHostPort(v.addr) + tlsConfig.ServerName = host + } } v.gunTLSConfig = tlsConfig diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 8901f3d5..058ce49d 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -89,8 +89,8 @@ type WSOptions struct { EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { @@ -138,7 +138,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { wsOpts.TLSConfig.ServerName = host } } - c, err = clashVMess.StreamWebsocketConn(c, wsOpts) + c, err = clashVMess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic if v.option.TLS { @@ -153,7 +153,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if v.option.ServerName != "" { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) if err != nil { return nil, err } @@ -182,7 +182,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, &tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, &tlsOpts) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) } } @@ -294,7 +294,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) return NewConn(c, v), err } @@ -355,7 +355,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } @@ -379,7 +379,7 @@ func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada } if pc, ok := c.(net.PacketConn); ok { - return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil + return newPacketConn(N.NewThreadSafePacketConn(pc), v), nil } return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil } @@ -413,13 +413,6 @@ func NewVmess(option VmessOption) (*Vmess, error) { option.PacketAddr = false } - switch option.Network { - case "h2", "grpc": - if !option.TLS { - option.TLS = true - } - } - v := &Vmess{ Base: &Base{ name: option.Name, @@ -464,15 +457,19 @@ func NewVmess(option VmessOption) (*Vmess, error) { Host: v.option.ServerName, ClientFingerprint: v.option.ClientFingerprint, } - tlsConfig := &tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, + if option.ServerName == "" { + gunConfig.Host = v.addr } - - if v.option.ServerName == "" { - host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host - gunConfig.Host = host + var tlsConfig *tls.Config + if option.TLS { + tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + InsecureSkipVerify: v.option.SkipCertVerify, + ServerName: v.option.ServerName, + }) + if option.ServerName == "" { + host, _, _ := net.SplitHostPort(v.addr) + tlsConfig.ServerName = host + } } v.gunTLSConfig = tlsConfig @@ -489,17 +486,6 @@ func NewVmess(option VmessOption) (*Vmess, error) { return v, nil } -type threadSafePacketConn struct { - net.PacketConn - access sync.Mutex -} - -func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { - c.access.Lock() - defer c.access.Unlock() - return c.PacketConn.WriteTo(b, addr) -} - type vmessPacketConn struct { net.Conn rAddr net.Addr diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 67cd9092..c12321f3 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -67,7 +67,7 @@ type WireGuardPeerOption struct { PublicKey string `proxy:"public-key,omitempty"` PreSharedKey string `proxy:"pre-shared-key,omitempty"` Reserved []uint8 `proxy:"reserved,omitempty"` - AllowedIPs []string `proxy:"allowed_ips,omitempty"` + AllowedIPs []string `proxy:"allowed-ips,omitempty"` } type wgSingDialer struct { @@ -499,9 +499,9 @@ func (r *refProxyAdapter) MarshalJSON() ([]byte, error) { return nil, C.ErrNotSupport } -func (r *refProxyAdapter) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +func (r *refProxyAdapter) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if r.proxyAdapter != nil { - return r.proxyAdapter.StreamConn(c, metadata) + return r.proxyAdapter.StreamConnContext(ctx, c, metadata) } return nil, C.ErrNotSupport } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 8e253e63..895ca421 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -130,10 +130,6 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { } } - if len(proxies) == 0 { - return append(proxies, tunnel.Proxies()["COMPATIBLE"]) - } - if len(gb.providers) > 1 && len(gb.filterRegs) > 1 { var newProxies []C.Proxy proxiesSet := map[string]struct{}{} @@ -189,6 +185,10 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { proxies = newProxies } + if len(proxies) == 0 { + return append(proxies, tunnel.Proxies()["COMPATIBLE"]) + } + return proxies } diff --git a/common/net/bind.go b/common/net/bind.go index 1e20a8c0..231c24c2 100644 --- a/common/net/bind.go +++ b/common/net/bind.go @@ -3,34 +3,43 @@ package net import "net" type bindPacketConn struct { - net.PacketConn + EnhancePacketConn rAddr net.Addr } -func (wpc *bindPacketConn) Read(b []byte) (n int, err error) { - n, _, err = wpc.PacketConn.ReadFrom(b) +func (c *bindPacketConn) Read(b []byte) (n int, err error) { + n, _, err = c.EnhancePacketConn.ReadFrom(b) return n, err } -func (wpc *bindPacketConn) Write(b []byte) (n int, err error) { - return wpc.PacketConn.WriteTo(b, wpc.rAddr) +func (c *bindPacketConn) WaitRead() (data []byte, put func(), err error) { + data, put, _, err = c.EnhancePacketConn.WaitReadFrom() + return } -func (wpc *bindPacketConn) RemoteAddr() net.Addr { - return wpc.rAddr +func (c *bindPacketConn) Write(b []byte) (n int, err error) { + return c.EnhancePacketConn.WriteTo(b, c.rAddr) } -func (wpc *bindPacketConn) LocalAddr() net.Addr { - if wpc.PacketConn.LocalAddr() == nil { +func (c *bindPacketConn) RemoteAddr() net.Addr { + return c.rAddr +} + +func (c *bindPacketConn) LocalAddr() net.Addr { + if c.EnhancePacketConn.LocalAddr() == nil { return &net.UDPAddr{IP: net.IPv4zero, Port: 0} } else { - return wpc.PacketConn.LocalAddr() + return c.EnhancePacketConn.LocalAddr() } } +func (c *bindPacketConn) Upstream() any { + return c.EnhancePacketConn +} + func NewBindPacketConn(pc net.PacketConn, rAddr net.Addr) net.Conn { return &bindPacketConn{ - PacketConn: pc, - rAddr: rAddr, + EnhancePacketConn: NewEnhancePacketConn(pc), + rAddr: rAddr, } } diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 2ff73c82..6da2d9d1 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -62,7 +62,7 @@ func (c *BufferedConn) Buffered() int { } func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { _, err = buffer.ReadOnceFrom(c.r) return } @@ -70,10 +70,11 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { } func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { length := c.r.Buffered() b, _ := c.r.Peek(length) _, _ = c.r.Discard(length) + c.r = nil // drop bufio.Reader to let gc can clean up its internal buf return buf.As(b) } return nil @@ -84,7 +85,7 @@ func (c *BufferedConn) Upstream() any { } func (c *BufferedConn) ReaderReplaceable() bool { - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { return false } return true diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go new file mode 100644 index 00000000..bcf2db9d --- /dev/null +++ b/common/net/deadline/packet.go @@ -0,0 +1,154 @@ +package deadline + +import ( + "net" + "os" + "runtime" + "time" + + "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/common/net/packet" +) + +type readResult struct { + data []byte + addr net.Addr + err error +} + +type NetPacketConn struct { + net.PacketConn + deadline atomic.TypedValue[time.Time] + pipeDeadline pipeDeadline + disablePipe atomic.Bool + inRead atomic.Bool + resultCh chan any +} + +func NewNetPacketConn(pc net.PacketConn) net.PacketConn { + npc := &NetPacketConn{ + PacketConn: pc, + pipeDeadline: makePipeDeadline(), + resultCh: make(chan any, 1), + } + npc.resultCh <- nil + if enhancePC, isEnhance := pc.(packet.EnhancePacketConn); isEnhance { + epc := &EnhancePacketConn{ + NetPacketConn: npc, + enhancePacketConn: enhancePacketConn{ + netPacketConn: npc, + enhancePacketConn: enhancePC, + }, + } + if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC { + return &EnhanceSingPacketConn{ + EnhancePacketConn: epc, + singPacketConn: singPacketConn{ + netPacketConn: npc, + singPacketConn: singPC, + }, + } + } + return epc + } + if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC { + return &SingPacketConn{ + NetPacketConn: npc, + singPacketConn: singPacketConn{ + netPacketConn: npc, + singPacketConn: singPC, + }, + } + } + return npc +} + +func (c *NetPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { +FOR: + for { + select { + case result := <-c.resultCh: + if result != nil { + if result, ok := result.(*readResult); ok { + n = copy(p, result.data) + addr = result.addr + err = result.err + c.resultCh <- nil // finish cache read + return + } + c.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.resultCh <- nil + break FOR + } + case <-c.pipeDeadline.wait(): + return 0, nil, os.ErrDeadlineExceeded + } + } + + if c.disablePipe.Load() { + return c.PacketConn.ReadFrom(p) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + n, addr, err = c.PacketConn.ReadFrom(p) + return + } + + <-c.resultCh + go c.pipeReadFrom(len(p)) + + return c.ReadFrom(p) +} + +func (c *NetPacketConn) pipeReadFrom(size int) { + buffer := make([]byte, size) + n, addr, err := c.PacketConn.ReadFrom(buffer) + buffer = buffer[:n] + result := &readResult{} + result.data = buffer + result.addr = addr + result.err = err + c.resultCh <- result +} + +func (c *NetPacketConn) SetReadDeadline(t time.Time) error { + if c.disablePipe.Load() { + return c.PacketConn.SetReadDeadline(t) + } else if c.inRead.Load() { + c.disablePipe.Store(true) + return c.PacketConn.SetReadDeadline(t) + } + c.deadline.Store(t) + c.pipeDeadline.set(t) + return nil +} + +func (c *NetPacketConn) ReaderReplaceable() bool { + select { + case result := <-c.resultCh: + c.resultCh <- result + if result != nil { + return false // cache reading + } else { + break + } + default: + return false // pipe reading + } + return c.disablePipe.Load() || c.deadline.Load().IsZero() +} + +func (c *NetPacketConn) WriterReplaceable() bool { + return true +} + +func (c *NetPacketConn) Upstream() any { + return c.PacketConn +} + +func (c *NetPacketConn) NeedAdditionalReadDeadline() bool { + return false +} diff --git a/common/net/deadline/packet_enhance.go b/common/net/deadline/packet_enhance.go new file mode 100644 index 00000000..5b7d767f --- /dev/null +++ b/common/net/deadline/packet_enhance.go @@ -0,0 +1,83 @@ +package deadline + +import ( + "net" + "os" + "runtime" + + "github.com/Dreamacro/clash/common/net/packet" +) + +type EnhancePacketConn struct { + *NetPacketConn + enhancePacketConn +} + +var _ packet.EnhancePacketConn = (*EnhancePacketConn)(nil) + +func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn { + return NewNetPacketConn(pc).(packet.EnhancePacketConn) +} + +type enhanceReadResult struct { + data []byte + put func() + addr net.Addr + err error +} + +type enhancePacketConn struct { + netPacketConn *NetPacketConn + enhancePacketConn packet.EnhancePacketConn +} + +func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*enhanceReadResult); ok { + data = result.data + put = result.put + addr = result.addr + err = result.err + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR + } + case <-c.netPacketConn.pipeDeadline.wait(): + return nil, nil, nil, os.ErrDeadlineExceeded + } + } + + if c.netPacketConn.disablePipe.Load() { + return c.enhancePacketConn.WaitReadFrom() + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + data, put, addr, err = c.enhancePacketConn.WaitReadFrom() + return + } + + <-c.netPacketConn.resultCh + go c.pipeWaitReadFrom() + + return c.WaitReadFrom() +} + +func (c *enhancePacketConn) pipeWaitReadFrom() { + data, put, addr, err := c.enhancePacketConn.WaitReadFrom() + result := &enhanceReadResult{} + result.data = data + result.put = put + result.addr = addr + result.err = err + c.netPacketConn.resultCh <- result +} diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go new file mode 100644 index 00000000..f41f3f5b --- /dev/null +++ b/common/net/deadline/packet_sing.go @@ -0,0 +1,177 @@ +package deadline + +import ( + "os" + "runtime" + + "github.com/Dreamacro/clash/common/net/packet" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type SingPacketConn struct { + *NetPacketConn + singPacketConn +} + +var _ packet.SingPacketConn = (*SingPacketConn)(nil) + +func NewSingPacketConn(pc packet.SingPacketConn) packet.SingPacketConn { + return NewNetPacketConn(pc).(packet.SingPacketConn) +} + +type EnhanceSingPacketConn struct { + *EnhancePacketConn + singPacketConn +} + +func NewEnhanceSingPacketConn(pc packet.EnhanceSingPacketConn) packet.EnhanceSingPacketConn { + return NewNetPacketConn(pc).(packet.EnhanceSingPacketConn) +} + +var _ packet.EnhanceSingPacketConn = (*EnhanceSingPacketConn)(nil) + +type singReadResult struct { + buffer *buf.Buffer + destination M.Socksaddr + err error +} + +type singPacketConn struct { + netPacketConn *NetPacketConn + singPacketConn packet.SingPacketConn +} + +func (c *singPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*singReadResult); ok { + destination = result.destination + err = result.err + n, _ := buffer.Write(result.buffer.Bytes()) + result.buffer.Advance(n) + if result.buffer.IsEmpty() { + result.buffer.Release() + } + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR + } + case <-c.netPacketConn.pipeDeadline.wait(): + return M.Socksaddr{}, os.ErrDeadlineExceeded + } + } + + if c.netPacketConn.disablePipe.Load() { + return c.singPacketConn.ReadPacket(buffer) + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + destination, err = c.singPacketConn.ReadPacket(buffer) + return + } + + <-c.netPacketConn.resultCh + go c.pipeReadPacket(buffer.FreeLen()) + + return c.ReadPacket(buffer) +} + +func (c *singPacketConn) pipeReadPacket(pLen int) { + buffer := buf.NewSize(pLen) + destination, err := c.singPacketConn.ReadPacket(buffer) + result := &singReadResult{} + result.destination = destination + result.err = err + c.netPacketConn.resultCh <- result +} + +func (c *singPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + return c.singPacketConn.WritePacket(buffer, destination) +} + +func (c *singPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) { + prw, isReadWaiter := bufio.CreatePacketReadWaiter(c.singPacketConn) + if isReadWaiter { + return &singPacketReadWaiter{ + netPacketConn: c.netPacketConn, + packetReadWaiter: prw, + }, true + } + return nil, false +} + +var _ N.PacketReadWaiter = (*singPacketReadWaiter)(nil) + +type singPacketReadWaiter struct { + netPacketConn *NetPacketConn + packetReadWaiter N.PacketReadWaiter +} + +type singWaitReadResult singReadResult + +func (c *singPacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) { + c.packetReadWaiter.InitializeReadWaiter(newBuffer) +} + +func (c *singPacketReadWaiter) WaitReadPacket() (destination M.Socksaddr, err error) { +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*singWaitReadResult); ok { + destination = result.destination + err = result.err + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR + } + case <-c.netPacketConn.pipeDeadline.wait(): + return M.Socksaddr{}, os.ErrDeadlineExceeded + } + } + + if c.netPacketConn.disablePipe.Load() { + return c.packetReadWaiter.WaitReadPacket() + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + destination, err = c.packetReadWaiter.WaitReadPacket() + return + } + + <-c.netPacketConn.resultCh + go c.pipeWaitReadPacket() + + return c.WaitReadPacket() +} + +func (c *singPacketReadWaiter) pipeWaitReadPacket() { + destination, err := c.packetReadWaiter.WaitReadPacket() + result := &singWaitReadResult{} + result.destination = destination + result.err = err + c.netPacketConn.resultCh <- result +} + +func (c *singPacketReadWaiter) Upstream() any { + return c.packetReadWaiter +} diff --git a/common/net/deadline/pipe.go b/common/net/deadline/pipe.go new file mode 100644 index 00000000..2cccfb42 --- /dev/null +++ b/common/net/deadline/pipe.go @@ -0,0 +1,84 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package deadline + +import ( + "sync" + "time" +) + +// pipeDeadline is an abstraction for handling timeouts. +type pipeDeadline struct { + mu sync.Mutex // Guards timer and cancel + timer *time.Timer + cancel chan struct{} // Must be non-nil +} + +func makePipeDeadline() pipeDeadline { + return pipeDeadline{cancel: make(chan struct{})} +} + +// set sets the point in time when the deadline will time out. +// A timeout event is signaled by closing the channel returned by waiter. +// Once a timeout has occurred, the deadline can be refreshed by specifying a +// t value in the future. +// +// A zero value for t prevents timeout. +func (d *pipeDeadline) set(t time.Time) { + d.mu.Lock() + defer d.mu.Unlock() + + if d.timer != nil && !d.timer.Stop() { + <-d.cancel // Wait for the timer callback to finish and close cancel + } + d.timer = nil + + // Time is zero, then there is no deadline. + closed := isClosedChan(d.cancel) + if t.IsZero() { + if closed { + d.cancel = make(chan struct{}) + } + return + } + + // Time in the future, setup a timer to cancel in the future. + if dur := time.Until(t); dur > 0 { + if closed { + d.cancel = make(chan struct{}) + } + d.timer = time.AfterFunc(dur, func() { + close(d.cancel) + }) + return + } + + // Time in the past, so close immediately. + if !closed { + close(d.cancel) + } +} + +// wait returns a channel that is closed when the deadline is exceeded. +func (d *pipeDeadline) wait() chan struct{} { + d.mu.Lock() + defer d.mu.Unlock() + return d.cancel +} + +func isClosedChan(c <-chan struct{}) bool { + select { + case <-c: + return true + default: + return false + } +} + +func makeFilledChan() chan struct{} { + ch := make(chan struct{}, 1) + ch <- struct{}{} + return ch +} diff --git a/common/net/packet.go b/common/net/packet.go new file mode 100644 index 00000000..fc562c42 --- /dev/null +++ b/common/net/packet.go @@ -0,0 +1,18 @@ +package net + +import ( + "github.com/Dreamacro/clash/common/net/deadline" + "github.com/Dreamacro/clash/common/net/packet" +) + +type EnhancePacketConn = packet.EnhancePacketConn +type WaitReadFrom = packet.WaitReadFrom + +var NewEnhancePacketConn = packet.NewEnhancePacketConn +var NewThreadSafePacketConn = packet.NewThreadSafePacketConn +var NewRefPacketConn = packet.NewRefPacketConn + +var NewDeadlineNetPacketConn = deadline.NewNetPacketConn +var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn +var NewDeadlineSingPacketConn = deadline.NewSingPacketConn +var NewDeadlineEnhanceSingPacketConn = deadline.NewEnhanceSingPacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go new file mode 100644 index 00000000..6c9542c1 --- /dev/null +++ b/common/net/packet/packet.go @@ -0,0 +1,77 @@ +package packet + +import ( + "net" + + "github.com/Dreamacro/clash/common/pool" +) + +type WaitReadFrom interface { + WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) +} + +type EnhancePacketConn interface { + net.PacketConn + WaitReadFrom +} + +func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { + if udpConn, isUDPConn := pc.(*net.UDPConn); isUDPConn { + return &enhanceUDPConn{UDPConn: udpConn} + } + if enhancePC, isEnhancePC := pc.(EnhancePacketConn); isEnhancePC { + return enhancePC + } + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return newEnhanceSingPacketConn(singPC) + } + return &enhancePacketConn{PacketConn: pc} +} + +type enhancePacketConn struct { + net.PacketConn +} + +func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + return waitReadFrom(c.PacketConn) +} + +func (c *enhancePacketConn) Upstream() any { + return c.PacketConn +} + +func (c *enhancePacketConn) WriterReplaceable() bool { + return true +} + +func (c *enhancePacketConn) ReaderReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) Upstream() any { + return c.UDPConn +} + +func (c *enhanceUDPConn) WriterReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) ReaderReplaceable() bool { + return true +} + +func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, err error) { + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readN int + readN, addr, err = pc.ReadFrom(readBuf) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + } + return +} diff --git a/common/net/packet/packet_posix.go b/common/net/packet/packet_posix.go new file mode 100644 index 00000000..2861482f --- /dev/null +++ b/common/net/packet/packet_posix.go @@ -0,0 +1,65 @@ +//go:build !windows + +package packet + +import ( + "net" + "strconv" + "syscall" + + "github.com/Dreamacro/clash/common/pool" +) + +type enhanceUDPConn struct { + *net.UDPConn + rawConn syscall.RawConn +} + +func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + if c.rawConn == nil { + c.rawConn, _ = c.UDPConn.SyscallConn() + } + var readErr error + err = c.rawConn.Read(func(fd uintptr) (done bool) { + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readFrom syscall.Sockaddr + var readN int + readN, _, _, readFrom, readErr = syscall.Recvmsg(int(fd), readBuf, nil, 0) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + data = nil + } + if readErr == syscall.EAGAIN { + return false + } + if readFrom != nil { + switch from := readFrom.(type) { + case *syscall.SockaddrInet4: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port} + case *syscall.SockaddrInet6: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)} + } + } + // udp should not convert readN == 0 to io.EOF + //if readN == 0 { + // readErr = io.EOF + //} + return true + }) + if err != nil { + return + } + if readErr != nil { + err = readErr + return + } + return +} diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go new file mode 100644 index 00000000..cfcf5ed0 --- /dev/null +++ b/common/net/packet/packet_sing.go @@ -0,0 +1,79 @@ +package packet + +import ( + "net" + + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type SingPacketConn = N.NetPacketConn + +type EnhanceSingPacketConn interface { + SingPacketConn + EnhancePacketConn +} + +type enhanceSingPacketConn struct { + SingPacketConn + packetReadWaiter N.PacketReadWaiter +} + +func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + var buff *buf.Buffer + var dest M.Socksaddr + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + if c.packetReadWaiter != nil { + c.packetReadWaiter.InitializeReadWaiter(newBuffer) + defer c.packetReadWaiter.InitializeReadWaiter(nil) + dest, err = c.packetReadWaiter.WaitReadPacket() + } else { + dest, err = c.SingPacketConn.ReadPacket(newBuffer()) + } + if dest.IsFqdn() { + addr = dest + } else { + addr = dest.UDPAddr() + } + if err != nil { + if buff != nil { + buff.Release() + } + return + } + if buff == nil { + return + } + if buff.IsEmpty() { + buff.Release() + return + } + data = buff.Bytes() + put = buff.Release + return +} + +func (c *enhanceSingPacketConn) Upstream() any { + return c.SingPacketConn +} + +func (c *enhanceSingPacketConn) WriterReplaceable() bool { + return true +} + +func (c *enhanceSingPacketConn) ReaderReplaceable() bool { + return true +} + +func newEnhanceSingPacketConn(conn SingPacketConn) *enhanceSingPacketConn { + epc := &enhanceSingPacketConn{SingPacketConn: conn} + if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn); isReadWaiter { + epc.packetReadWaiter = readWaiter + } + return epc +} diff --git a/common/net/packet/packet_windows.go b/common/net/packet/packet_windows.go new file mode 100644 index 00000000..cb4c518b --- /dev/null +++ b/common/net/packet/packet_windows.go @@ -0,0 +1,15 @@ +//go:build windows + +package packet + +import ( + "net" +) + +type enhanceUDPConn struct { + *net.UDPConn +} + +func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + return waitReadFrom(c.UDPConn) +} diff --git a/common/net/packet/ref.go b/common/net/packet/ref.go new file mode 100644 index 00000000..a562b2e2 --- /dev/null +++ b/common/net/packet/ref.go @@ -0,0 +1,75 @@ +package packet + +import ( + "net" + "runtime" + "time" +) + +type refPacketConn struct { + pc EnhancePacketConn + ref any +} + +func (c *refPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.WaitReadFrom() +} + +func (c *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.ReadFrom(p) +} + +func (c *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.WriteTo(p, addr) +} + +func (c *refPacketConn) Close() error { + defer runtime.KeepAlive(c.ref) + return c.pc.Close() +} + +func (c *refPacketConn) LocalAddr() net.Addr { + defer runtime.KeepAlive(c.ref) + return c.pc.LocalAddr() +} + +func (c *refPacketConn) SetDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetDeadline(t) +} + +func (c *refPacketConn) SetReadDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetReadDeadline(t) +} + +func (c *refPacketConn) SetWriteDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetWriteDeadline(t) +} + +func (c *refPacketConn) Upstream() any { + return c.pc +} + +func (c *refPacketConn) ReaderReplaceable() bool { // Relay() will handle reference + return true +} + +func (c *refPacketConn) WriterReplaceable() bool { // Relay() will handle reference + return true +} + +func NewRefPacketConn(pc net.PacketConn, ref any) EnhancePacketConn { + rPC := &refPacketConn{pc: NewEnhancePacketConn(pc), ref: ref} + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return &refSingPacketConn{ + refPacketConn: rPC, + singPacketConn: singPC, + } + } + return rPC +} diff --git a/common/net/packet/ref_sing.go b/common/net/packet/ref_sing.go new file mode 100644 index 00000000..2ca955fa --- /dev/null +++ b/common/net/packet/ref_sing.go @@ -0,0 +1,26 @@ +package packet + +import ( + "runtime" + + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type refSingPacketConn struct { + *refPacketConn + singPacketConn SingPacketConn +} + +var _ N.NetPacketConn = (*refSingPacketConn)(nil) + +func (c *refSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + defer runtime.KeepAlive(c.ref) + return c.singPacketConn.WritePacket(buffer, destination) +} + +func (c *refSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + defer runtime.KeepAlive(c.ref) + return c.singPacketConn.ReadPacket(buffer) +} diff --git a/common/net/packet/thread.go b/common/net/packet/thread.go new file mode 100644 index 00000000..14d64233 --- /dev/null +++ b/common/net/packet/thread.go @@ -0,0 +1,36 @@ +package packet + +import ( + "net" + "sync" +) + +type threadSafePacketConn struct { + EnhancePacketConn + access sync.Mutex +} + +func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { + c.access.Lock() + defer c.access.Unlock() + return c.EnhancePacketConn.WriteTo(b, addr) +} + +func (c *threadSafePacketConn) Upstream() any { + return c.EnhancePacketConn +} + +func (c *threadSafePacketConn) ReaderReplaceable() bool { + return true +} + +func NewThreadSafePacketConn(pc net.PacketConn) EnhancePacketConn { + tsPC := &threadSafePacketConn{EnhancePacketConn: NewEnhancePacketConn(pc)} + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return &threadSafeSingPacketConn{ + threadSafePacketConn: tsPC, + singPacketConn: singPC, + } + } + return tsPC +} diff --git a/common/net/packet/thread_sing.go b/common/net/packet/thread_sing.go new file mode 100644 index 00000000..0869a512 --- /dev/null +++ b/common/net/packet/thread_sing.go @@ -0,0 +1,24 @@ +package packet + +import ( + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type threadSafeSingPacketConn struct { + *threadSafePacketConn + singPacketConn SingPacketConn +} + +var _ N.NetPacketConn = (*threadSafeSingPacketConn)(nil) + +func (c *threadSafeSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + c.access.Lock() + defer c.access.Unlock() + return c.singPacketConn.WritePacket(buffer, destination) +} + +func (c *threadSafeSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + return c.singPacketConn.ReadPacket(buffer) +} diff --git a/common/net/refconn.go b/common/net/refconn.go index 537cb839..5caaebc8 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -80,47 +80,3 @@ var _ ExtendedConn = (*refConn)(nil) func NewRefConn(conn net.Conn, ref any) net.Conn { return &refConn{conn: NewExtendedConn(conn), ref: ref} } - -type refPacketConn struct { - pc net.PacketConn - ref any -} - -func (pc *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - defer runtime.KeepAlive(pc.ref) - return pc.pc.ReadFrom(p) -} - -func (pc *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - defer runtime.KeepAlive(pc.ref) - return pc.pc.WriteTo(p, addr) -} - -func (pc *refPacketConn) Close() error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.Close() -} - -func (pc *refPacketConn) LocalAddr() net.Addr { - defer runtime.KeepAlive(pc.ref) - return pc.pc.LocalAddr() -} - -func (pc *refPacketConn) SetDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetDeadline(t) -} - -func (pc *refPacketConn) SetReadDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetReadDeadline(t) -} - -func (pc *refPacketConn) SetWriteDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetWriteDeadline(t) -} - -func NewRefPacketConn(pc net.PacketConn, ref any) net.PacketConn { - return &refPacketConn{pc: pc, ref: ref} -} diff --git a/common/net/sing.go b/common/net/sing.go index 7eb92f03..c92008ba 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -23,10 +23,6 @@ func NewDeadlineConn(conn net.Conn) ExtendedConn { return deadline.NewFallbackConn(conn) } -func NewDeadlinePacketConn(pc net.PacketConn) net.PacketConn { - return deadline.NewFallbackPacketConn(bufio.NewPacketConn(pc)) -} - func NeedHandshake(conn any) bool { if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() { return true diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 09d5cced..4863d6ae 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -18,10 +18,11 @@ type tfoConn struct { } func (c *tfoConn) Dial(earlyData []byte) (err error) { - c.Conn, err = c.dialFn(c.ctx, earlyData) + conn, err := c.dialFn(c.ctx, earlyData) if err != nil { return } + c.Conn = conn c.dialed <- true return err } diff --git a/component/geodata/strmatcher/mph_matcher.go b/component/geodata/strmatcher/mph_matcher.go index 3c10cb49..8d8b0508 100644 --- a/component/geodata/strmatcher/mph_matcher.go +++ b/component/geodata/strmatcher/mph_matcher.go @@ -234,26 +234,26 @@ tail: case s == 0: case s < 4: h ^= uint64(*(*byte)(p)) - h ^= uint64(*(*byte)(add(p, s>>1))) << 8 - h ^= uint64(*(*byte)(add(p, s-1))) << 16 + h ^= uint64(*(*byte)(unsafe.Add(p, s>>1))) << 8 + h ^= uint64(*(*byte)(unsafe.Add(p, s-1))) << 16 h = rotl31(h*m1) * m2 case s <= 8: h ^= uint64(readUnaligned32(p)) - h ^= uint64(readUnaligned32(add(p, s-4))) << 32 + h ^= uint64(readUnaligned32(unsafe.Add(p, s-4))) << 32 h = rotl31(h*m1) * m2 case s <= 16: h ^= readUnaligned64(p) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-8)) + h ^= readUnaligned64(unsafe.Add(p, s-8)) h = rotl31(h*m1) * m2 case s <= 32: h ^= readUnaligned64(p) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, 8)) + h ^= readUnaligned64(unsafe.Add(p, 8)) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-16)) + h ^= readUnaligned64(unsafe.Add(p, s-16)) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-8)) + h ^= readUnaligned64(unsafe.Add(p, s-8)) h = rotl31(h*m1) * m2 default: v1 := h @@ -263,16 +263,16 @@ tail: for s >= 32 { v1 ^= readUnaligned64(p) v1 = rotl31(v1*m1) * m2 - p = add(p, 8) + p = unsafe.Add(p, 8) v2 ^= readUnaligned64(p) v2 = rotl31(v2*m2) * m3 - p = add(p, 8) + p = unsafe.Add(p, 8) v3 ^= readUnaligned64(p) v3 = rotl31(v3*m3) * m4 - p = add(p, 8) + p = unsafe.Add(p, 8) v4 ^= readUnaligned64(p) v4 = rotl31(v4*m4) * m1 - p = add(p, 8) + p = unsafe.Add(p, 8) s -= 32 } h = v1 ^ v2 ^ v3 ^ v4 @@ -285,10 +285,6 @@ tail: return uintptr(h) } -func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - func readUnaligned32(p unsafe.Pointer) uint32 { q := (*[4]byte)(p) return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 diff --git a/component/http/http.go b/component/http/http.go index ece7b442..bcede09f 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -53,8 +53,12 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - conn := inner.HandleTcp(address, "") - return conn, nil + if conn, err := inner.HandleTcp(address); err == nil { + return conn, nil + } else { + d := net.Dialer{} + return d.DialContext(ctx, network, address) + } }, TLSClientConfig: tls.GetDefaultTLSConfig(), } diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index fc5cb294..83010f96 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -71,7 +71,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { currentMeta := &C.Metadata{Type: C.INNER} - if err := currentMeta.SetRemoteAddress(address); err != nil { + if err := currentMeta.SetRemoteAddress(rAddrPort.String()); err != nil { return nil, err } return p.listenPacket(ctx, currentMeta) diff --git a/component/tls/config.go b/component/tls/config.go index b5b56591..6f808248 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -33,10 +33,22 @@ func AddCertificate(certificate string) error { } } +func initializeCertPool() { + var err error + certPool, err = x509.SystemCertPool() + if err != nil { + certPool = x509.NewCertPool() + } + for _, cert := range trustCerts { + certPool.AddCert(cert) + } +} + func ResetCertificate() { mutex.Lock() defer mutex.Unlock() trustCerts = nil + initializeCertPool() } func getCertPool() *x509.CertPool { @@ -49,12 +61,7 @@ func getCertPool() *x509.CertPool { if certPool != nil { return certPool } - certPool, err := x509.SystemCertPool() - if err == nil { - for _, cert := range trustCerts { - certPool.AddCert(cert) - } - } + initializeCertPool() } return certPool } diff --git a/component/tls/reality.go b/component/tls/reality.go index dd4f3af8..b8a7fa3a 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -141,7 +141,7 @@ var pOffset = utils.MustOK(reflect.TypeOf((*utls.UConn)(nil)).Elem().FieldByName func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { //p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") - certs := *(*[]*x509.Certificate)(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + pOffset)) + certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset)) if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { h := hmac.New(sha512.New, c.authKey) h.Write(pub) diff --git a/config/config.go b/config/config.go index 71f4087e..ff16ac11 100644 --- a/config/config.go +++ b/config/config.go @@ -841,7 +841,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback()&&!ipnet.IP.IsLinkLocalUnicast() { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() { if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { ips = append(ips, ip) } @@ -938,6 +938,8 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) case "quic": addr, err = hostWithDefaultPort(u.Host, "853") dnsNetType = "quic" // DNS over QUIC + case "system": + dnsNetType = "system" // System DNS default: return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) } @@ -972,6 +974,10 @@ func parsePureDNSServer(server string) string { return "udp://" + server } + if server == "system" { + return "system://" + } + if ip, err := netip.ParseAddr(server); err != nil { if strings.Contains(server, "://") { return server @@ -1142,6 +1148,9 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } // check default nameserver is pure ip addr for _, ns := range dnsCfg.DefaultNameserver { + if ns.Net == "system" { + continue + } host, _, err := net.SplitHostPort(ns.Addr) if err != nil || net.ParseIP(host) == nil { u, err := url.Parse(ns.Addr) diff --git a/constant/adapters.go b/constant/adapters.go index 2a2c68c1..12579685 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -81,7 +81,7 @@ type Conn interface { } type PacketConn interface { - net.PacketConn + N.EnhancePacketConn Connection // Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed // WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error) @@ -106,11 +106,11 @@ type ProxyAdapter interface { // // Examples: // conn, _ := net.DialContext(context.Background(), "tcp", "host:port") - // conn, _ = adapter.StreamConn(conn, metadata) + // conn, _ = adapter.StreamConnContext(context.Background(), conn, metadata) // // It returns a C.Conn with protocol which start with // a new session (if any) - StreamConn(c net.Conn, metadata *Metadata) (net.Conn, error) + StreamConnContext(ctx context.Context, c net.Conn, metadata *Metadata) (net.Conn, error) // DialContext return a C.Conn with protocol which // contains multiplexing-related reuse logic (if any) diff --git a/constant/metadata.go b/constant/metadata.go index 1c344d5d..edc58aec 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -133,6 +133,7 @@ type Metadata struct { InIP netip.Addr `json:"inboundIP"` InPort string `json:"inboundPort"` InName string `json:"inboundName"` + InUser string `json:"inboundUser"` Host string `json:"host"` DNSMode DNSMode `json:"dnsMode"` Uid uint32 `json:"uid"` @@ -205,15 +206,16 @@ func (m *Metadata) Pure() *Metadata { return m } +func (m *Metadata) AddrPort() netip.AddrPort { + port, _ := strconv.ParseUint(m.DstPort, 10, 16) + return netip.AddrPortFrom(m.DstIP.Unmap(), uint16(port)) +} + func (m *Metadata) UDPAddr() *net.UDPAddr { if m.NetWork != UDP || !m.DstIP.IsValid() { return nil } - port, _ := strconv.ParseUint(m.DstPort, 10, 16) - return &net.UDPAddr{ - IP: m.DstIP.AsSlice(), - Port: int(port), - } + return net.UDPAddrFromAddrPort(m.AddrPort()) } func (m *Metadata) String() string { diff --git a/constant/rule.go b/constant/rule.go index 28c629a0..906f3cef 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -14,12 +14,14 @@ const ( SrcPort DstPort InPort + InUser + InName + InType Process ProcessPath RuleSet Network Uid - INTYPE SubRules MATCH AND @@ -55,6 +57,12 @@ func (rt RuleType) String() string { return "DstPort" case InPort: return "InPort" + case InUser: + return "InUser" + case InName: + return "InName" + case InType: + return "InType" case Process: return "Process" case ProcessPath: @@ -67,8 +75,6 @@ func (rt RuleType) String() string { return "Network" case Uid: return "Uid" - case INTYPE: - return "InType" case SubRules: return "SubRules" case AND: diff --git a/dns/system.go b/dns/system.go new file mode 100644 index 00000000..f5ab0efb --- /dev/null +++ b/dns/system.go @@ -0,0 +1,23 @@ +package dns + +import ( + "net" +) + +func loadSystemResolver() (clients []dnsClient, err error) { + nameservers, err := dnsReadConfig() + if err != nil { + return + } + if len(nameservers) == 0 { + return + } + servers := make([]NameServer, 0, len(nameservers)) + for _, addr := range nameservers { + servers = append(servers, NameServer{ + Addr: net.JoinHostPort(addr, "53"), + Net: "udp", + }) + } + return transform(servers, nil), nil +} diff --git a/dns/system_posix.go b/dns/system_posix.go new file mode 100644 index 00000000..d486b4fb --- /dev/null +++ b/dns/system_posix.go @@ -0,0 +1,27 @@ +//go:build !windows + +package dns + +import ( + "fmt" + "os" + "regexp" +) + +var ( + // nameserver xxx.xxx.xxx.xxx + nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) +) + +func dnsReadConfig() (servers []string, err error) { + content, err := os.ReadFile("/etc/resolv.conf") + if err != nil { + err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) + return + } + for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { + addr := line[1] + servers = append(servers, addr) + } + return +} diff --git a/dns/system_windows.go b/dns/system_windows.go new file mode 100644 index 00000000..47c1ebaa --- /dev/null +++ b/dns/system_windows.go @@ -0,0 +1,77 @@ +//go:build windows + +package dns + +import ( + "net" + "os" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +func dnsReadConfig() (servers []string, err error) { + aas, err := adapterAddresses() + if err != nil { + return + } + for _, aa := range aas { + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { + sa, err := dns.Address.Sockaddr.Sockaddr() + if err != nil { + continue + } + var ip net.IP + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + ip = net.IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ip = make(net.IP, net.IPv6len) + copy(ip, sa.Addr[:]) + if ip[0] == 0xfe && ip[1] == 0xc0 { + // Ignore these fec0/10 ones. Windows seems to + // populate them as defaults on its misc rando + // interfaces. + continue + } + //continue + default: + // Unexpected type. + continue + } + servers = append(servers, ip.String()) + } + } + return +} + +// adapterAddresses returns a list of IP adapter and address +// structures. The structure contains an IP adapter and flattened +// multiple IP addresses including unicast, anycast and multicast +// addresses. +func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { + var b []byte + l := uint32(15000) // recommended initial size + for { + b = make([]byte, l) + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + if err == nil { + if l == 0 { + return nil, nil + } + break + } + if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + if l <= uint32(len(b)) { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + } + var aas []*windows.IpAdapterAddresses + for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { + aas = append(aas, aa) + } + return aas, nil +} diff --git a/dns/util.go b/dns/util.go index bfd2e9ed..d85deb17 100644 --- a/dns/util.go +++ b/dns/util.go @@ -79,6 +79,18 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { case "dhcp": ret = append(ret, newDHCPClient(s.Addr)) continue + case "system": + clients, err := loadSystemResolver() + if err != nil { + log.Errorln("[DNS:system] load system resolver failed: %s", err.Error()) + continue + } + if len(clients) == 0 { + log.Errorln("[DNS:system] no nameserver found in system") + continue + } + ret = append(ret, clients...) + continue case "quic": if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { ret = append(ret, doq) diff --git a/docs/config.yaml b/docs/config.yaml index 97bd40ec..4239abcf 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -77,32 +77,32 @@ tun: # auto-detect-interface: true # 自动识别出口网卡 # auto-route: true # 配置路由表 # mtu: 9000 # 最大传输单元 - # strict_route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 - inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + inet4-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 - inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + inet6-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 - "::/1" - "8000::/1" - # endpoint_independent_nat: false # 启用独立于端点的 NAT - # include_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route + # endpoint-independent-nat: false # 启用独立于端点的 NAT + # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route # - 0 - # include_uid_range: # 限制被路由的的用户范围 + # include-uid-range: # 限制被路由的的用户范围 # - 1000-99999 - # exclude_uid: # 排除路由的的用户 + # exclude-uid: # 排除路由的的用户 #- 1000 - # exclude_uid_range: # 排除路由的的用户范围 + # exclude-uid-range: # 排除路由的的用户范围 # - 1000-99999 # Android 用户和应用规则仅在 Android 下被支持 - # 并且需要 auto_route + # 并且需要 auto-route - # include_android_user: # 限制被路由的 Android 用户 + # include-android-user: # 限制被路由的 Android 用户 # - 0 # - 10 - # include_package: # 限制被路由的 Android 应用包名 + # include-package: # 限制被路由的 Android 应用包名 # - com.android.chrome - # exclude_package: # 排除被路由的 Android 应用包名 + # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin #ebpf配置 @@ -177,6 +177,7 @@ dns: - 8.8.8.8 - tls://1.12.12.12:853 - tls://223.5.5.5:853 + - system # append DNS server from system configuration. If not found, it would print an error log and skip. enhanced-mode: fake-ip # or redir-host fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 diff --git a/go.mod b/go.mod index 0d4a638e..b79f8e70 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.19 require ( github.com/3andne/restls-client-go v0.1.4 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/cilium/ebpf v0.9.3 + github.com/cilium/ebpf v0.10.0 github.com/coreos/go-iptables v0.6.0 - github.com/dlclark/regexp2 v1.7.0 + github.com/dlclark/regexp2 v1.9.0 github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 @@ -17,38 +17,40 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 github.com/jpillora/backoff v1.0.0 + github.com/klauspost/cpuid/v2 v2.0.12 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 - github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba - github.com/metacubex/sing-tun v0.1.4 + github.com/mdlayher/netlink v1.7.2 + github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca + github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a - github.com/miekg/dns v1.1.53 - github.com/mroth/weightedrand/v2 v2.0.0 + github.com/miekg/dns v1.1.54 + github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 - github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e + github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c + github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.3 + github.com/shirou/gopsutil/v3 v3.23.4 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 - github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 + github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 - go.etcd.io/bbolt v1.3.6 + go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.8.0 - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.9.0 - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.7.0 - google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d + golang.org/x/crypto v0.9.0 + golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 + golang.org/x/net v0.10.0 + golang.org/x/sync v0.2.0 + golang.org/x/sys v0.8.0 + google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 ) @@ -67,17 +69,15 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/mdlayher/socket v0.4.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect @@ -89,6 +89,7 @@ require ( github.com/quic-go/qtls-go1-20 v0.1.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect + github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -96,12 +97,15 @@ require ( github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/vishvananda/netns v0.0.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) + +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b + +replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 diff --git a/go.sum b/go.sum index 37cc84b1..11d98c03 100644 --- a/go.sum +++ b/go.sum @@ -14,15 +14,15 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc= -github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A= +github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= +github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI= +github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= @@ -32,7 +32,7 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= @@ -52,8 +52,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -82,34 +82,36 @@ github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4= -github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ= -github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= -github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw= -github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He8YwyK600lHAS1xxNsP4k/jnZ8zqQ34XjCGn925+Yk= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4 h1:OQDBNHjuPKrOprCiK+sLt97YQ0K6b9ZWmJB6z51ibZQ= -github.com/metacubex/sing-tun v0.1.4/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= +github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugFjoBjAkth89MHlKHRaMdo43tGQ3MOPVayQ= +github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I= +github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= +github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e h1:7QlJQl4S3F3YXn48fYxjymMw8HkXg9bl++hLi4ZRyCY= +github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e/go.mod h1:u9onX49LZPYuIPQ7SdM64Gnins8y5wg4Cn6ZYRSxWHU= +github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 h1:iRfcuztp7REfmOyasSlCL/pqNWfUDMTJ2CwbGpxpeks= +github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899/go.mod h1:RSt9rxGHllLdc5JUebkQwaqyWLx09Lqya37DlBe8CP8= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= -github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= -github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= +github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= @@ -138,21 +140,15 @@ github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1T github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= -github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzlnPxOpuv64jhjz3teIvccu3YMFX4fJI= -github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= +github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= -github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= -github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -163,9 +159,10 @@ github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2d github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.23.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= -github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= -github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= +github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= +github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= +github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= @@ -195,10 +192,10 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M= -github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= +github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -206,16 +203,16 @@ github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtb github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= +golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -224,39 +221,35 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -268,11 +261,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d h1:qp0AnQCvRCMlu9jBjtdbTaaEmThIgZOrbVyDEOcmKhQ= -google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 0a7c54f9..a58f224c 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -30,8 +30,9 @@ func upgrade(w http.ResponseWriter, r *http.Request) { err = updater.Update(execPath) if err != nil { + log.Warnln("%s", err) render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, newError(fmt.Sprintf("Upgrade: %s", err))) + render.JSON(w, r, newError(fmt.Sprintf("%s", err))) return } diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 3d80707a..90b14c27 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -8,6 +8,7 @@ import ( "io" "net/http" "os" + "os/exec" "path/filepath" "runtime" "strings" @@ -17,15 +18,16 @@ import ( clashHttp "github.com/Dreamacro/clash/component/http" "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/klauspost/cpuid/v2" ) // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go // Updater is the Clash.Meta updater. var ( - goarch string - goos string - goarm string - gomips string + goarm string + gomips string + amd64Compatible string workDir string @@ -45,6 +47,12 @@ var ( latestVersion string ) +func init() { + if runtime.GOARCH == "amd64" && cpuid.CPU.X64Level() < 3 { + amd64Compatible = "-compatible" + } +} + type updateError struct { Message string } @@ -59,8 +67,6 @@ func Update(execPath string) (err error) { mu.Lock() defer mu.Unlock() - goos = runtime.GOOS - goarch = runtime.GOARCH latestVersion, err = getLatestVersion() if err != nil { return err @@ -69,7 +75,7 @@ func Update(execPath string) (err error) { log.Infoln("current version %s, latest version %s", constant.Version, latestVersion) if latestVersion == constant.Version { - err := &updateError{Message: "Already using latest version"} + err := &updateError{Message: "already using latest version"} return err } @@ -128,12 +134,10 @@ func prepare(exePath string) (err error) { //log.Infoln(packageName) backupDir = filepath.Join(workDir, "meta-backup") - if goos == "windows" && goarch == "amd64" { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible.exe" - } else if goos == "linux" && goarch == "amd64" { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible" + if runtime.GOOS == "windows" { + updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" } else { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible } log.Infoln("updateExeName: %s ", updateExeName) @@ -198,7 +202,7 @@ func replace() error { var err error log.Infoln("replacing: %s to %s", updateExeName, currentExeName) - if goos == "windows" { + if runtime.GOOS == "windows" { // rename fails with "File in use" error err = copyFile(updateExeName, currentExeName) } else { @@ -430,17 +434,19 @@ func getLatestVersion() (version string, err error) { func updateDownloadURL() { var middle string - if goarch == "arm" && goarm != "" { - middle = fmt.Sprintf("-%s-%sv%s-%s", goos, goarch, goarm, latestVersion) - } else if isMIPS(goarch) && gomips != "" { - middle = fmt.Sprintf("-%s-%s-%s-%s", goos, goarch, gomips, latestVersion) - } else if goarch == "amd64" && (goos == "windows" || goos == "linux") { - middle = fmt.Sprintf("-%s-%s-compatible-%s", goos, goarch, latestVersion) + if runtime.GOARCH == "arm" && probeGoARM() { + //-linux-armv7-alpha-e552b54.gz + middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, goarm, latestVersion) + } else if runtime.GOARCH == "arm64" { + //-linux-arm64-alpha-e552b54.gz + middle = fmt.Sprintf("-%s-%s-%s", runtime.GOOS, runtime.GOARCH, latestVersion) + } else if isMIPS(runtime.GOARCH) && gomips != "" { + middle = fmt.Sprintf("-%s-%s-%s-%s", runtime.GOOS, runtime.GOARCH, gomips, latestVersion) } else { - middle = fmt.Sprintf("-%s-%s-%s", goos, goarch, latestVersion) + middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, amd64Compatible, latestVersion) } - if goos == "windows" { + if runtime.GOOS == "windows" { middle += ".zip" } else { middle += ".gz" @@ -462,3 +468,22 @@ func isMIPS(arch string) (ok bool) { return false } } + +// linux only +func probeGoARM() (ok bool) { + cmd := exec.Command("cat", "/proc/cpuinfo") + output, err := cmd.Output() + if err != nil { + log.Errorln("probe goarm error:%s", err) + return false + } + cpuInfo := string(output) + if strings.Contains(cpuInfo, "vfpv3") || strings.Contains(cpuInfo, "vfpv4") { + goarm = "v7" + } else if strings.Contains(cpuInfo, "vfp") { + goarm = "v6" + } else { + goarm = "v5" + } + return true +} diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index a7e38588..9ba87e2f 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -1,9 +1,11 @@ package inner import ( + "errors" + "net" + "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "net" ) var tcpIn chan<- C.ConnContext @@ -12,9 +14,13 @@ func New(in chan<- C.ConnContext) { tcpIn = in } -func HandleTcp(dst string, host string) net.Conn { +func HandleTcp(address string) (conn net.Conn, err error) { + if tcpIn == nil { + return nil, errors.New("tcp uninitialized") + } + // executor Parsed conn1, conn2 := net.Pipe() - context := inbound.NewInner(conn2, dst, host) + context := inbound.NewInner(conn2, address) tcpIn <- context - return conn1 + return conn1, nil } diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 6884b960..febf87c3 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -103,7 +103,7 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions conn = l.pickCipher.StreamConn(conn) conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly - target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) + target, err := socks5.ReadAddr0(conn) if err != nil { _ = conn.Close() return diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 3f058406..4efafa60 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -4,7 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" @@ -29,19 +29,20 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } sl := &UDPListener{l, false} - conn := pickCipher.PacketConn(l) + conn := pickCipher.PacketConn(N.NewEnhancePacketConn(l)) go func() { for { - buf := pool.Get(pool.RelayBufferSize) - n, remoteAddr, err := conn.ReadFrom(buf) + data, put, remoteAddr, err := conn.WaitReadFrom() if err != nil { - pool.Put(buf) + if put != nil { + put() + } if sl.closed { break } continue } - handleSocksUDP(conn, in, buf[:n], remoteAddr) + handleSocksUDP(conn, in, data, put, remoteAddr) } }() @@ -57,11 +58,13 @@ func (l *UDPListener) LocalAddr() net.Addr { return l.packetConn.LocalAddr() } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr) { +func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr) { tgtAddr := socks5.SplitAddr(buf) if tgtAddr == nil { // Unresolved UDP packet, return buffer to the pool - pool.Put(buf) + if put != nil { + put() + } return } target := socks5.ParseAddr(tgtAddr.String()) @@ -71,7 +74,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, ad pc: pc, rAddr: addr, payload: payload, - bufRef: buf, + put: put, } select { case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS): diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index 2e9fd003..c34c5cd0 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -6,7 +6,6 @@ import ( "net" "net/url" - "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/socks5" ) @@ -14,7 +13,7 @@ type packet struct { pc net.PacketConn rAddr net.Addr payload []byte - bufRef []byte + put func() } func (c *packet) Data() []byte { @@ -37,7 +36,9 @@ func (c *packet) LocalAddr() net.Addr { } func (c *packet) Drop() { - pool.Put(c.bufRef) + if c.put != nil { + c.put() + } } func (c *packet) InAddr() net.Addr { diff --git a/listener/sing/context.go b/listener/sing/context.go index f7aed851..a500e4a4 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -2,8 +2,11 @@ package sing import ( "context" + "golang.org/x/exp/slices" "github.com/Dreamacro/clash/adapter/inbound" + + "github.com/sagernet/sing/common/auth" ) type contextKey string @@ -22,3 +25,20 @@ func getAdditions(ctx context.Context) []inbound.Addition { } return nil } + +func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbound.Addition { + additionsCloned := false + if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { + additions = slices.Clone(additions) + additionsCloned = true + additions = append(additions, ctxAdditions...) + } + if user, ok := auth.UserFromContext[string](ctx); ok { + if !additionsCloned { + additions = slices.Clone(additions) + additionsCloned = true + } + additions = append(additions, inbound.WithInUser(user)) + } + return additions +} diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2ccdfe2d..c60bbe67 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,7 +3,6 @@ package sing import ( "context" "errors" - "golang.org/x/exp/slices" "net" "net/netip" "sync" @@ -18,6 +17,7 @@ import ( mux "github.com/sagernet/sing-mux" vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio/deadline" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -57,6 +57,14 @@ func (c *waitCloseConn) Upstream() any { return c.ExtendedConn } +func (c *waitCloseConn) ReaderReplaceable() bool { + return true +} + +func (c *waitCloseConn) WriterReplaceable() bool { + return true +} + func UpstreamMetadata(metadata M.Metadata) M.Metadata { return M.Metadata{ Source: metadata.Source, @@ -65,11 +73,6 @@ func UpstreamMetadata(metadata M.Metadata) M.Metadata { } func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { - additions := h.Additions - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additions = append(additions, ctxAdditions...) - } switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) @@ -94,15 +97,13 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) + h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...) return nil } func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { - additions := h.Additions - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additions = append(additions, ctxAdditions...) + if deadline.NeedAdditionalReadDeadline(conn) { + conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} @@ -112,11 +113,30 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } for { - buff := buf.NewPacket() // do not use stack buffer - dest, err := conn.ReadPacket(buff) + var ( + dest M.Socksaddr + err error + ) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if ShouldIgnorePacketError(err) { break } @@ -131,7 +151,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff: buff, } select { - case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): + case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...): default: } } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index c7e05bb5..1fa9a3ba 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -21,7 +21,7 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/metadata" + M "github.com/sagernet/sing/common/metadata" ) type Listener struct { @@ -92,19 +92,38 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C go func() { conn := bufio.NewPacketConn(ul) + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } for { - buff := buf.NewPacket() - remoteAddr, err := conn.ReadPacket(buff) + var ( + dest M.Socksaddr + err error + ) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if sl.closed { break } continue } - _ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{ + _ = sl.service.NewPacket(context.TODO(), conn, buff, M.Metadata{ Protocol: "shadowsocks", - Source: remoteAddr, + Source: dest, }) } }() @@ -170,9 +189,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) { func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) - err := l.service.NewConnection(ctx, conn, metadata.Metadata{ + err := l.service.NewConnection(ctx, conn, M.Metadata{ Protocol: "shadowsocks", - Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), + Source: M.ParseSocksaddr(conn.RemoteAddr().String()), }) if err != nil { _ = conn.Close() diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index dc33be91..88e3f6d6 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -17,6 +17,7 @@ import ( D "github.com/miekg/dns" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/network" ) @@ -108,20 +109,40 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - for { + + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { // safe size which is 1232 from https://dnsflagday.net/2020/. // so 2048 is enough - buff := buf.NewSize(2 * 1024) + buff = buf.NewSize(2 * 1024) + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } + for { + var ( + dest M.Socksaddr + err error + ) _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) - dest, err := conn.ReadPacket(buff) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if sing.ShouldIgnorePacketError(err) { break } return err } - go func() { + go func(buff *buf.Buffer) { ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() inData := buff.Bytes() @@ -146,7 +167,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. if err != nil { return } - }() + }(buff) // catch buff at goroutine create, avoid next loop change buff } return nil } diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 2a274f61..4967adc6 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -78,7 +78,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT }() conn, err := listenLocalConn(rAddr, lAddr, in, natTable) if err != nil { - log.Errorln("listenLocalConn failed with error: %s, packet loss", err.Error()) + log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local) return nil, err } natTable.AddLocalConn(local, remote, conn) diff --git a/rules/common/in_name.go b/rules/common/in_name.go new file mode 100644 index 00000000..1e2abe15 --- /dev/null +++ b/rules/common/in_name.go @@ -0,0 +1,49 @@ +package common + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + "strings" +) + +type InName struct { + *Base + names []string + adapter string + payload string +} + +func (u *InName) Match(metadata *C.Metadata) (bool, string) { + for _, name := range u.names { + if metadata.InName == name { + return true, u.adapter + } + } + return false, "" +} + +func (u *InName) RuleType() C.RuleType { + return C.InName +} + +func (u *InName) Adapter() string { + return u.adapter +} + +func (u *InName) Payload() string { + return u.payload +} + +func NewInName(iNames, adapter string) (*InName, error) { + names := strings.Split(iNames, "/") + if len(names) == 0 { + return nil, fmt.Errorf("in name couldn't be empty") + } + + return &InName{ + Base: &Base{}, + names: names, + adapter: adapter, + payload: iNames, + }, nil +} diff --git a/rules/common/in_type.go b/rules/common/in_type.go index 520c9594..453045d8 100644 --- a/rules/common/in_type.go +++ b/rules/common/in_type.go @@ -23,7 +23,7 @@ func (u *InType) Match(metadata *C.Metadata) (bool, string) { } func (u *InType) RuleType() C.RuleType { - return C.INTYPE + return C.InType } func (u *InType) Adapter() string { @@ -37,7 +37,7 @@ func (u *InType) Payload() string { func NewInType(iTypes, adapter string) (*InType, error) { types := strings.Split(iTypes, "/") if len(types) == 0 { - return nil, fmt.Errorf("in type could be empty") + return nil, fmt.Errorf("in type couldn't be empty") } tps, err := parseInTypes(types) diff --git a/rules/common/in_user.go b/rules/common/in_user.go new file mode 100644 index 00000000..24f4b2e5 --- /dev/null +++ b/rules/common/in_user.go @@ -0,0 +1,49 @@ +package common + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + "strings" +) + +type InUser struct { + *Base + users []string + adapter string + payload string +} + +func (u *InUser) Match(metadata *C.Metadata) (bool, string) { + for _, user := range u.users { + if metadata.InUser == user { + return true, u.adapter + } + } + return false, "" +} + +func (u *InUser) RuleType() C.RuleType { + return C.InUser +} + +func (u *InUser) Adapter() string { + return u.adapter +} + +func (u *InUser) Payload() string { + return u.payload +} + +func NewInUser(iUsers, adapter string) (*InUser, error) { + users := strings.Split(iUsers, "/") + if len(users) == 0 { + return nil, fmt.Errorf("in user couldn't be empty") + } + + return &InUser{ + Base: &Base{}, + users: users, + adapter: adapter, + payload: iUsers, + }, nil +} diff --git a/rules/parser.go b/rules/parser.go index 1a336225..df790bc3 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -47,6 +47,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] parsed, parseErr = RC.NewUid(payload, target) case "IN-TYPE": parsed, parseErr = RC.NewInType(payload, target) + case "IN-USER": + parsed, parseErr = RC.NewInUser(payload, target) + case "IN-NAME": + parsed, parseErr = RC.NewInName(payload, target) case "SUB-RULE": parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule) case "AND": diff --git a/test/go.mod b/test/go.mod index 6cbf50e8..1327f84f 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,26 +6,34 @@ require ( github.com/Dreamacro/clash v0.0.0 github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 - github.com/miekg/dns v1.1.50 - github.com/stretchr/testify v1.8.1 - golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e + github.com/miekg/dns v1.1.53 + github.com/stretchr/testify v1.8.2 + golang.org/x/net v0.9.0 ) replace github.com/Dreamacro/clash => ../ require ( - github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/3andne/restls-client-go v0.1.4 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/RyuaNerin/go-krypto v1.0.2 // indirect + github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/cilium/ebpf v0.9.3 // indirect github.com/coreos/go-iptables v0.6.0 // indirect - github.com/database64128/tfo-go/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/go-units v0.4.0 // indirect + github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect + github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect + github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect + github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/gofrs/uuid v4.3.1+incompatible // indirect + github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.0.1 // indirect @@ -33,53 +41,74 @@ require ( github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c // indirect - github.com/josharian/native v1.0.0 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 // indirect + github.com/josharian/native v1.1.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect + github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect - github.com/marten-seemann/qpack v0.3.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect - github.com/mdlayher/netlink v1.7.0 // indirect + github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e // indirect - github.com/metacubex/sing-shadowsocks v0.1.0 // indirect - github.com/metacubex/sing-tun v0.1.0 // indirect - github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c // indirect + github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect + github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 // indirect + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba // indirect + github.com/metacubex/sing-tun v0.1.4 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a // indirect github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/mroth/weightedrand/v2 v2.0.0 // indirect + github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/openacid/low v0.1.21 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/oschwald/geoip2-golang v1.8.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect + github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/qtls-go1-19 v0.2.1 // indirect + github.com/quic-go/qtls-go1-20 v0.1.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.1.0 // indirect - github.com/sagernet/sing-vmess v0.1.0 // indirect - github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c // indirect - github.com/samber/lo v1.35.0 // indirect + github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a // indirect + github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e // indirect + github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 // indirect + github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect + github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect + github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect + github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect + github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect + github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect + github.com/samber/lo v1.38.1 // indirect + github.com/shirou/gopsutil/v3 v3.23.4 // indirect + github.com/shoenig/go-m1cpu v0.1.5 // indirect + github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect + github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect + github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect + github.com/tklauser/go-sysconf v0.3.11 // indirect + github.com/tklauser/numcpus v0.6.0 // indirect + github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + github.com/zhangyunhao116/fastrand v0.3.0 // indirect + gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.6 // indirect - go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a // indirect - golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/mod v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.1.12 // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/tools v0.6.0 // indirect + google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.4.0 // indirect - gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/test/go.sum b/test/go.sum index 22e24a16..b6f03871 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,8 +1,17 @@ +github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= +github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= +github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -10,8 +19,6 @@ github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc= github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/database64128/tfo-go/v2 v2.0.2 h1:5rGgkJeLEKlNaqredfrPQNLnctn1b+1fq/8tdKdOzJg= -github.com/database64128/tfo-go/v2 v2.0.2/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -25,94 +32,100 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= +github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= +github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= +github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po= +github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg= +github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY= +github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= +github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= +github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= +github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c h1:OCFM4+DXTWfNlyeoddrTwdup/ztkGSyAMR2UGcPckNQ= -github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E= +github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= +github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= -github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g= -github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI= -github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE= -github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= -github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI= -github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4= +github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e h1:RnfC6+sShJ3biU2Q2wuh4FxZ8/3fp1QG+1zAfswVehA= -github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e/go.mod h1:7NPWVTLiX2Ss9q9gBNZaNHsPqZ3Tg/ApyrXxxUYbl78= -github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A= -github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= -github.com/metacubex/sing-tun v0.1.0 h1:iQj0+0WjJynSKAtfv87wOZlVKWl3w9RvkOSkVe9zuMg= -github.com/metacubex/sing-tun v0.1.0/go.mod h1:l4JyI6RTrlHLQz5vSakg+wxA+LwGVI0Mz5ZtlOv67dA= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c h1:VHtXDny/TNOF7YDT9d9Qkr+x6K1O4cejXLlyPUXDeXQ= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c/go.mod h1:fULJ451x1/XlpIhl+Oo+EPGKla9tFZaqT5dKLrZ+NvM= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= +github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= +github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw= +github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He8YwyK600lHAS1xxNsP4k/jnZ8zqQ34XjCGn925+Yk= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= +github.com/metacubex/sing-tun v0.1.4 h1:OQDBNHjuPKrOprCiK+sLt97YQ0K6b9ZWmJB6z51ibZQ= +github.com/metacubex/sing-tun v0.1.4/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= +github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= +github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= +github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= +github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g= github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= +github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= +github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= +github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= +github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= +github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs3U1+I= +github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -121,45 +134,78 @@ github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6 github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw= github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= +github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= +github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= +github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= -github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.0 h1:FGmaP2BVPYO2IyC/3R1DaQa/zr+kOKHRgWqrmOF+Gu8= -github.com/sagernet/sing v0.1.0/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4= -github.com/sagernet/sing-vmess v0.1.0 h1:x0tYBJRbVi7zVXpMEW45eApGpXIDs9ub3raglouAKMo= -github.com/sagernet/sing-vmess v0.1.0/go.mod h1:4lwj6EHrUlgRnKhbmtboGbt+wtl5+tHMv96Ez8LZArw= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c h1:qP3ZOHnjZalvqbjundbXiv/YrNlo3HOgrKc+S1QGs0U= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= -github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= -github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a h1:s2kkd/eR3mWGkYioknxhgQzG8uft4VRx9skhqxxeyVQ= +github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzlnPxOpuv64jhjz3teIvccu3YMFX4fJI= +github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 h1:0Dc1t9ao9EyvRil6l/950PLwND1qO1rgnxwbcctE8KE= +github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9/go.mod h1:Dpib342FFR68SZ3CSRYxk/zWbanAqRBrCxoLuda5I0A= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= +github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= +github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U= +github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= +github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= +github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= +github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= +github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= +github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= +github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= +github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= +github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= +github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= +github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU= +github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo= +github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= +github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= +github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= +github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= +github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M= @@ -167,40 +213,35 @@ github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8x github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= +github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= +gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= +gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -208,60 +249,47 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d h1:qp0AnQCvRCMlu9jBjtdbTaaEmThIgZOrbVyDEOcmKhQ= +google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -269,8 +297,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 36cf68f8..e98f7fb5 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -199,9 +199,12 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re if err != nil { return nil, err } - wrap.remoteAddr = pconn.RemoteAddr() + if tlsConfig == nil { + return pconn, nil + } + if len(Fingerprint) != 0 { if realityConfig == nil { if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { diff --git a/transport/shadowsocks/core/cipher.go b/transport/shadowsocks/core/cipher.go index 7f4f7f71..cd30360c 100644 --- a/transport/shadowsocks/core/cipher.go +++ b/transport/shadowsocks/core/cipher.go @@ -7,6 +7,7 @@ import ( "sort" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" ) @@ -21,7 +22,7 @@ type StreamConnCipher interface { } type PacketConnCipher interface { - PacketConn(net.PacketConn) net.PacketConn + PacketConn(N.EnhancePacketConn) N.EnhancePacketConn } // ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns). @@ -128,7 +129,7 @@ type AeadCipher struct { } func (aead *AeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) } -func (aead *AeadCipher) PacketConn(c net.PacketConn) net.PacketConn { +func (aead *AeadCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return shadowaead.NewPacketConn(c, aead) } @@ -139,7 +140,7 @@ type StreamCipher struct { } func (ciph *StreamCipher) StreamConn(c net.Conn) net.Conn { return shadowstream.NewConn(c, ciph) } -func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn { +func (ciph *StreamCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return shadowstream.NewPacketConn(c, ciph) } @@ -147,8 +148,8 @@ func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn { type dummy struct{} -func (dummy) StreamConn(c net.Conn) net.Conn { return c } -func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c } +func (dummy) StreamConn(c net.Conn) net.Conn { return c } +func (dummy) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } // key-derivation function from original Shadowsocks func Kdf(password string, keyLen int) []byte { diff --git a/transport/shadowsocks/shadowaead/packet.go b/transport/shadowsocks/shadowaead/packet.go index 7043ead7..e84ac570 100644 --- a/transport/shadowsocks/shadowaead/packet.go +++ b/transport/shadowsocks/shadowaead/packet.go @@ -6,6 +6,7 @@ import ( "io" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) @@ -57,15 +58,15 @@ func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) { } type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Cipher } const maxPacketSize = 64 * 1024 -// NewPacketConn wraps a net.PacketConn with cipher -func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn { - return &PacketConn{PacketConn: c, Cipher: ciph} +// NewPacketConn wraps an N.EnhancePacketConn with cipher +func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn { + return &PacketConn{EnhancePacketConn: c, Cipher: ciph} } // WriteTo encrypts b and write to addr using the embedded PacketConn. @@ -76,13 +77,13 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf, addr) + _, err = c.EnhancePacketConn.WriteTo(buf, addr) return len(b), err } // ReadFrom reads from the embedded PacketConn and decrypts into b. func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -93,3 +94,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, bb) return len(bb), addr, err } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = Unpack(data[c.Cipher.SaltSize():], data, c) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/shadowsocks/shadowstream/packet.go b/transport/shadowsocks/shadowstream/packet.go index 0b46dea1..f0bf43ef 100644 --- a/transport/shadowsocks/shadowstream/packet.go +++ b/transport/shadowsocks/shadowstream/packet.go @@ -6,6 +6,7 @@ import ( "io" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) @@ -43,13 +44,13 @@ func Unpack(dst, pkt []byte, s Cipher) ([]byte, error) { } type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Cipher } -// NewPacketConn wraps a net.PacketConn with stream cipher encryption/decryption. -func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn { - return &PacketConn{PacketConn: c, Cipher: ciph} +// NewPacketConn wraps an N.EnhancePacketConn with stream cipher encryption/decryption. +func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn { + return &PacketConn{EnhancePacketConn: c, Cipher: ciph} } const maxPacketSize = 64 * 1024 @@ -61,12 +62,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf, addr) + _, err = c.EnhancePacketConn.WriteTo(buf, addr) return len(b), err } func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -77,3 +78,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, bb) return len(bb), addr, err } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = Unpack(data[c.IVSize():], data, c) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/socks5/socks5.go b/transport/socks5/socks5.go index 7d4f11ae..6f95cce9 100644 --- a/transport/socks5/socks5.go +++ b/transport/socks5/socks5.go @@ -299,6 +299,50 @@ func ReadAddr(r io.Reader, b []byte) (Addr, error) { return nil, ErrAddressNotSupported } +func ReadAddr0(r io.Reader) (Addr, error) { + aType, err := ReadByte(r) // read 1st byte for address type + if err != nil { + return nil, err + } + + switch aType { + case AtypDomainName: + var domainLength byte + domainLength, err = ReadByte(r) // read 2nd byte for domain length + if err != nil { + return nil, err + } + b := make([]byte, 1+1+uint16(domainLength)+2) + _, err = io.ReadFull(r, b[2:]) + b[0] = aType + b[1] = domainLength + return b, err + case AtypIPv4: + var b [1 + net.IPv4len + 2]byte + _, err = io.ReadFull(r, b[1:]) + b[0] = aType + return b[:], err + case AtypIPv6: + var b [1 + net.IPv6len + 2]byte + _, err = io.ReadFull(r, b[1:]) + b[0] = aType + return b[:], err + } + + return nil, ErrAddressNotSupported +} + +func ReadByte(reader io.Reader) (byte, error) { + if br, isBr := reader.(io.ByteReader); isBr { + return br.ReadByte() + } + var b [1]byte + if _, err := io.ReadFull(reader, b[:]); err != nil { + return 0, err + } + return b[0], nil +} + // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. func SplitAddr(b []byte) Addr { addrLen := 1 diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go index 4de48151..e2f0e143 100644 --- a/transport/ssr/protocol/auth_aes128_sha1.go +++ b/transport/ssr/protocol/auth_aes128_sha1.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/ssr/tools" @@ -82,13 +83,13 @@ func (a *authAES128) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authAES128) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authAES128) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { p := &authAES128{ Base: a.Base, authAES128Function: a.authAES128Function, userData: a.userData, } - return &PacketConn{PacketConn: c, Protocol: p} + return &PacketConn{EnhancePacketConn: c, Protocol: p} } func (a *authAES128) Decode(dst, src *bytes.Buffer) error { diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 6b12ab9b..23efb390 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/shadowsocks/core" @@ -83,13 +84,13 @@ func (a *authChainA) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authChainA) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authChainA) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { p := &authChainA{ Base: a.Base, salt: a.salt, userData: a.userData, } - return &PacketConn{PacketConn: c, Protocol: p} + return &PacketConn{EnhancePacketConn: c, Protocol: p} } func (a *authChainA) Decode(dst, src *bytes.Buffer) error { diff --git a/transport/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go index 9e814ac2..26039181 100644 --- a/transport/ssr/protocol/auth_sha1_v4.go +++ b/transport/ssr/protocol/auth_sha1_v4.go @@ -7,6 +7,7 @@ import ( "hash/crc32" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/ssr/tools" @@ -35,7 +36,7 @@ func (a *authSHA1V4) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authSHA1V4) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authSHA1V4) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } diff --git a/transport/ssr/protocol/origin.go b/transport/ssr/protocol/origin.go index 80fdfa9a..52525a2f 100644 --- a/transport/ssr/protocol/origin.go +++ b/transport/ssr/protocol/origin.go @@ -3,6 +3,8 @@ package protocol import ( "bytes" "net" + + N "github.com/Dreamacro/clash/common/net" ) type origin struct{} @@ -13,7 +15,7 @@ func newOrigin(b *Base) Protocol { return &origin{} } func (o *origin) StreamConn(c net.Conn, iv []byte) net.Conn { return c } -func (o *origin) PacketConn(c net.PacketConn) net.PacketConn { return c } +func (o *origin) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } func (o *origin) Decode(dst, src *bytes.Buffer) error { dst.ReadFrom(src) diff --git a/transport/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go index 249db70a..988ff75d 100644 --- a/transport/ssr/protocol/packet.go +++ b/transport/ssr/protocol/packet.go @@ -3,11 +3,12 @@ package protocol import ( "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Protocol } @@ -18,12 +19,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf.Bytes(), addr) + _, err = c.EnhancePacketConn.WriteTo(buf.Bytes(), addr) return len(b), err } func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -34,3 +35,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, decoded) return len(decoded), addr, nil } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = c.DecodePacket(data) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go index 5b86ecb9..1c27da48 100644 --- a/transport/ssr/protocol/protocol.go +++ b/transport/ssr/protocol/protocol.go @@ -6,6 +6,8 @@ import ( "fmt" "net" + N "github.com/Dreamacro/clash/common/net" + "github.com/zhangyunhao116/fastrand" ) @@ -22,7 +24,7 @@ var ( type Protocol interface { StreamConn(net.Conn, []byte) net.Conn - PacketConn(net.PacketConn) net.PacketConn + PacketConn(N.EnhancePacketConn) N.EnhancePacketConn Decode(dst, src *bytes.Buffer) error Encode(buf *bytes.Buffer, b []byte) error DecodePacket([]byte) ([]byte, error) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 8eae8237..abe21f34 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -13,6 +13,7 @@ import ( "net/http" "sync" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" @@ -70,7 +71,7 @@ type Trojan struct { hexPassword []byte } -func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { +func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) { alpn := defaultALPN if len(t.option.ALPN) != 0 { alpn = t.option.ALPN @@ -149,7 +150,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } } -func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { +func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { alpn := defaultWebsocketALPN if len(t.option.ALPN) != 0 { alpn = t.option.ALPN @@ -162,7 +163,7 @@ func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) ServerName: t.option.ServerName, } - return vmess.StreamWebsocketConn(conn, &vmess.WebsocketConfig{ + return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{ Host: wsOptions.Host, Port: wsOptions.Port, Path: wsOptions.Path, @@ -303,6 +304,8 @@ func New(option *Option) *Trojan { return &Trojan{option, hexSha224([]byte(option.Password))} } +var _ N.EnhancePacketConn = (*PacketConn)(nil) + type PacketConn struct { net.Conn remain int @@ -350,6 +353,49 @@ func (pc *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return n, addr, nil } +func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + pc.mux.Lock() + defer pc.mux.Unlock() + + destination, err := socks5.ReadAddr0(pc.Conn) + if err != nil { + return nil, nil, nil, err + } + addr = destination.UDPAddr() + + data = pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(data) + } + + _, err = io.ReadFull(pc.Conn, data[:2+2]) // u16be length + CR LF + if err != nil { + if put != nil { + put() + } + return nil, nil, nil, err + } + length := binary.BigEndian.Uint16(data) + + if length > 0 { + data = data[:length] + _, err = io.ReadFull(pc.Conn, data) + if err != nil { + if put != nil { + put() + } + return nil, nil, nil, err + } + } else { + if put != nil { + put() + } + return nil, nil, addr, nil + } + + return +} + func hexSha224(data []byte) []byte { buf := make([]byte, 56) hash := sha256.New224() diff --git a/transport/tuic/client.go b/transport/tuic/client.go index af00da03..c18a9049 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -11,6 +11,7 @@ import ( "sync" "sync/atomic" "time" + "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" @@ -289,7 +290,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta return nil, err } - conn := &earlyConn{BufferedConn: N.NewBufferedConn(stream), RequestTimeout: t.RequestTimeout} + bufConn := N.NewBufferedConn(stream) + conn := &earlyConn{ExtendedConn: bufConn, bufConn: bufConn, RequestTimeout: t.RequestTimeout} if !t.FastOpen { err = conn.Response() if err != nil { @@ -300,9 +302,10 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta } type earlyConn struct { - *N.BufferedConn - resOnce sync.Once - resErr error + N.ExtendedConn // only expose standard N.ExtendedConn function to outside + bufConn *N.BufferedConn + resOnce sync.Once + resErr error RequestTimeout time.Duration } @@ -311,7 +314,7 @@ func (conn *earlyConn) response() error { if conn.RequestTimeout > 0 { _ = conn.SetReadDeadline(time.Now().Add(conn.RequestTimeout)) } - response, err := ReadResponse(conn) + response, err := ReadResponse(conn.bufConn) if err != nil { _ = conn.Close() return err @@ -336,7 +339,7 @@ func (conn *earlyConn) Read(b []byte) (n int, err error) { if err != nil { return 0, err } - return conn.BufferedConn.Read(b) + return conn.bufConn.Read(b) } func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { @@ -344,7 +347,19 @@ func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { if err != nil { return err } - return conn.BufferedConn.ReadBuffer(buffer) + return conn.bufConn.ReadBuffer(buffer) +} + +func (conn *earlyConn) Upstream() any { + return conn.bufConn +} + +func (conn *earlyConn) ReaderReplaceable() bool { + return atomic.LoadUint32((*uint32)(unsafe.Pointer(&conn.resOnce))) == 1 && conn.resErr == nil +} + +func (conn *earlyConn) WriterReplaceable() bool { + return true } func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 99164362..17368386 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -17,17 +17,12 @@ const ( InitialMaxDatagramSize = 1252 InitialPacketSizeIPv4 = 1252 InitialPacketSizeIPv6 = 1232 - InitialCongestionWindow = 10 + InitialCongestionWindow = 32 DefaultBBRMaxCongestionWindow = 10000 ) -const ( - initialMinCongestionWindow = 4 - minInitialPacketSize = 1200 -) - func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { - maxSize := congestion.ByteCount(minInitialPacketSize) + maxSize := congestion.ByteCount(1200) // If this is not a UDP address, we don't know anything about the MTU. // Use the minimum size of an Initial packet as the max packet size. if udpAddr, ok := addr.(*net.UDPAddr); ok { @@ -37,7 +32,7 @@ func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { maxSize = InitialPacketSizeIPv6 } } - return maxSize + return congestion.ByteCount(maxSize) } var ( @@ -45,8 +40,8 @@ var ( // Default initial rtt used before any samples are received. InitialRtt = 100 * time.Millisecond - // The gain used for the STARTUP, equal to 2/ln(2). - DefaultHighGain = 2.89 + // The gain used for the STARTUP, equal to 4*ln(2). + DefaultHighGain = 2.77 // The gain used in STARTUP after loss has been detected. // 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth @@ -281,7 +276,7 @@ func (b *bbrSender) maxCongestionWindow() congestion.ByteCount { } func (b *bbrSender) minCongestionWindow() congestion.ByteCount { - return b.maxDatagramSize * initialMinCongestionWindow + return b.maxDatagramSize * b.initialCongestionWindow } func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index 567f6ce5..f226746d 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -197,6 +197,21 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err return } +func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + if q.inputConn != nil { + var packet Packet + packet, err = ReadPacket(q.inputConn) + if err != nil { + return + } + data = packet.DATA + addr = packet.ADDR.UDPAddr() + } else { + err = net.ErrClosed + } + return +} + func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index a460eecc..472bb980 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -465,6 +465,11 @@ func NewAddress(metadata *C.Metadata) Address { } func NewAddressNetAddr(addr net.Addr) (Address, error) { + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { + if addrPort := addr.AddrPort(); addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName + return NewAddressAddrPort(addrPort), nil + } + } addrStr := addr.String() if addrPort, err := netip.ParseAddrPort(addrStr); err == nil { return NewAddressAddrPort(addrPort), nil diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 7c2c8a88..25483670 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -1,6 +1,7 @@ package obfs import ( + "context" "crypto/tls" "net" "net/http" @@ -22,7 +23,7 @@ type Option struct { } // NewV2rayObfs return a HTTPObfs -func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { +func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, error) { header := http.Header{} for k, v := range option.Headers { header.Add(k, v) @@ -57,7 +58,7 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { } var err error - conn, err = vmess.StreamWebsocketConn(conn, config) + conn, err = vmess.StreamWebsocketConn(ctx, conn, config) if err != nil { return nil, err } diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 6c3714e0..9e2e5e89 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -1,25 +1,18 @@ package vless import ( - "bytes" - "crypto/subtle" - gotls "crypto/tls" "encoding/binary" "errors" "fmt" "io" "net" - "reflect" "sync" - "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/vless/vision" "github.com/gofrs/uuid/v5" - utls "github.com/sagernet/utls" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) @@ -36,33 +29,10 @@ type Conn struct { handshakeMutex sync.Mutex needHandshake bool err error - - tlsConn net.Conn - input *bytes.Reader - rawInput *bytes.Buffer - - packetsToFilter int - isTLS bool - isTLS12orAbove bool - enableXTLS bool - cipher uint16 - remainingServerHello uint16 - readRemainingContent int - readRemainingPadding int - readProcess bool - readFilterUUID bool - readLastCommand byte - writeFilterApplicationData bool - writeDirect bool } func (vc *Conn) Read(b []byte) (int, error) { if vc.received { - if vc.readProcess { - buffer := buf.With(b) - err := vc.ReadBuffer(buffer) - return buffer.Len(), err - } return vc.ExtendedReader.Read(b) } @@ -70,106 +40,11 @@ func (vc *Conn) Read(b []byte) (int, error) { return 0, err } vc.received = true - return vc.Read(b) + return vc.ExtendedReader.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { if vc.received { - toRead := buffer.FreeBytes() - if vc.readRemainingContent > 0 { - if vc.readRemainingContent < buffer.FreeLen() { - toRead = toRead[:vc.readRemainingContent] - } - n, err := vc.ExtendedReader.Read(toRead) - buffer.Truncate(n) - vc.readRemainingContent -= n - vc.FilterTLS(toRead) - return err - } - if vc.readRemainingPadding > 0 { - _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) - if err != nil { - return err - } - vc.readRemainingPadding = 0 - } - if vc.readProcess { - switch vc.readLastCommand { - case commandPaddingContinue: - //if vc.isTLS || vc.packetsToFilter > 0 { - headerUUIDLen := 0 - if vc.readFilterUUID { - headerUUIDLen = uuid.Size - } - var header []byte - if need := headerUUIDLen + paddingHeaderLen; buffer.FreeLen() < need { - header = make([]byte, need) - } else { - header = buffer.FreeBytes()[:need] - } - _, err := io.ReadFull(vc.ExtendedReader, header) - if err != nil { - return err - } - pos := 0 - if vc.readFilterUUID { - vc.readFilterUUID = false - pos = uuid.Size - if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 { - err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", - uuid.FromBytesOrNil(header[:uuid.Size]).String()) - log.Errorln(err.Error()) - return err - } - } - vc.readLastCommand = header[pos] - vc.readRemainingContent = int(binary.BigEndian.Uint16(header[pos+1:])) - vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[pos+3:])) - log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", - vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) - return vc.ReadBuffer(buffer) - //} - case commandPaddingEnd: - vc.readProcess = false - return vc.ReadBuffer(buffer) - case commandPaddingDirect: - needReturn := false - if vc.input != nil { - _, err := buffer.ReadFrom(vc.input) - if err != nil { - return err - } - if vc.input.Len() == 0 { - needReturn = true - vc.input = nil - } else { // buffer is full - return nil - } - } - if vc.rawInput != nil { - _, err := buffer.ReadFrom(vc.rawInput) - if err != nil { - return err - } - needReturn = true - if vc.rawInput.Len() == 0 { - vc.rawInput = nil - } - } - if vc.input == nil && vc.rawInput == nil { - vc.readProcess = false - vc.ExtendedReader = N.NewExtendedReader(vc.Conn) - log.Debugln("XTLS Vision direct read start") - } - if needReturn { - return nil - } - default: - err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) - log.Debugln(err.Error()) - return err - } - } return vc.ExtendedReader.ReadBuffer(buffer) } @@ -177,7 +52,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { return err } vc.received = true - return vc.ReadBuffer(buffer) + return vc.ExtendedReader.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { @@ -200,18 +75,6 @@ func (vc *Conn) Write(p []byte) (int, error) { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - _buffer := buf.StackNew() - defer buf.KeepAlive(_buffer) - buffer := buf.Dup(_buffer) - defer buffer.Release() - buffer.Write(p) - err := vc.WriteBuffer(buffer) - if err != nil { - return 0, err - } - return len(p), nil - } return vc.ExtendedWriter.Write(p) } @@ -232,63 +95,6 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - buffer2 := ReshapeBuffer(buffer) - defer buffer2.Release() - vc.FilterTLS(buffer.Bytes()) - command := commandPaddingContinue - if !vc.isTLS { - command = commandPaddingEnd - - // disable XTLS - //vc.readProcess = false - vc.writeFilterApplicationData = false - vc.packetsToFilter = 0 - } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer, command, nil, vc.isTLS) - err := vc.ExtendedWriter.WriteBuffer(buffer) - if err != nil { - return err - } - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(5 * time.Millisecond) - } - if buffer2 != nil { - if vc.writeDirect || !vc.isTLS { - return vc.ExtendedWriter.WriteBuffer(buffer2) - } - vc.FilterTLS(buffer2.Bytes()) - command = commandPaddingContinue - if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer2, command, nil, vc.isTLS) - err = vc.ExtendedWriter.WriteBuffer(buffer2) - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(10 * time.Millisecond) - } - } - return err - } - /*if vc.writeDirect { - log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) - }*/ return vc.ExtendedWriter.WriteBuffer(buffer) } @@ -300,10 +106,9 @@ func (vc *Conn) sendRequest(p []byte) bool { return true } } - isVision := vc.IsXTLSVisionEnabled() var buffer *buf.Buffer - if isVision { + if vc.IsXTLSVisionEnabled() { _buffer := buf.StackNew() defer buf.KeepAlive(_buffer) buffer = buf.Dup(_buffer) @@ -350,50 +155,14 @@ func (vc *Conn) sendRequest(p []byte) bool { ) } - if isVision && !vc.dst.UDP && !vc.dst.Mux { - if len(p) == 0 { - WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id, vc.isTLS) - } else { - vc.FilterTLS(p) - //if vc.isTLS { - WriteWithPadding(buffer, p, commandPaddingContinue, vc.id, vc.isTLS) - //} else { - // buf.Must(buf.Error(buffer.Write(p))) - // - // // disable XTLS - // vc.readProcess = false - // vc.writeFilterApplicationData = false - // vc.packetsToFilter = 0 - //} - } - } else { - buf.Must(buf.Error(buffer.Write(p))) - } + buf.Must(buf.Error(buffer.Write(p))) _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) - if vc.err != nil { - return true - } - if isVision { - switch underlying := vc.tlsConn.(type) { - case *gotls.Conn: - if underlying.ConnectionState().Version != gotls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - case *utls.UConn: - if underlying.ConnectionState().Version != utls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - default: - vc.err = fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, vc.addons.Flow) - } - vc.tlsConn = nil - } return true } func (vc *Conn) recvResponse() error { - var buffer [1]byte + var buffer [2]byte _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) if vc.err != nil { return vc.err @@ -403,12 +172,7 @@ func (vc *Conn) recvResponse() error { return errors.New("unexpected response version") } - _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) - if vc.err != nil { - return vc.err - } - - length := int64(buffer[0]) + length := int64(buffer[1]) if length != 0 { // addon data length > 0 io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard } @@ -416,18 +180,8 @@ func (vc *Conn) recvResponse() error { return nil } -func (vc *Conn) FrontHeadroom() int { - if vc.IsXTLSVisionEnabled() { - return paddingHeaderLen - } - return 0 -} - func (vc *Conn) Upstream() any { - if vc.tlsConn == nil { - return vc.Conn - } - return vc.tlsConn + return vc.Conn } func (vc *Conn) NeedHandshake() bool { @@ -439,7 +193,7 @@ func (vc *Conn) IsXTLSVisionEnabled() bool { } // newConn return a Conn instance -func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { +func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { c := &Conn{ ExtendedReader: N.NewExtendedReader(conn), ExtendedWriter: N.NewExtendedWriter(conn), @@ -468,43 +222,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } case XRV: - c.packetsToFilter = 6 - c.readProcess = true - c.readFilterUUID = true - c.writeFilterApplicationData = true - c.addons = client.Addons - var t reflect.Type - var p uintptr - switch underlying := conn.(type) { - case *gotls.Conn: - //log.Debugln("type tls") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying).Elem() - p = uintptr(unsafe.Pointer(underlying)) - case *utls.UConn: - //log.Debugln("type *utls.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying.Conn).Elem() - p = uintptr(unsafe.Pointer(underlying.Conn)) - case *tlsC.UConn: - //log.Debugln("type *tlsC.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying.UConn - t = reflect.TypeOf(underlying.Conn).Elem() - //log.Debugln("t:%v", t) - p = uintptr(unsafe.Pointer(underlying.Conn)) - default: - return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) + visionConn, err := vision.NewConn(c, c.id) + if err != nil { + return nil, err } - i, _ := t.FieldByName("input") - r, _ := t.FieldByName("rawInput") - c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) - c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) - //if _, ok := c.Conn.(*net.TCPConn); !ok { - // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) - //} + c.addons = client.Addons + return visionConn, nil } } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go new file mode 100644 index 00000000..23721c0b --- /dev/null +++ b/transport/vless/vision/conn.go @@ -0,0 +1,304 @@ +package vision + +import ( + "bytes" + "crypto/subtle" + gotls "crypto/tls" + "encoding/binary" + "fmt" + "io" + "net" + + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/log" + + "github.com/gofrs/uuid/v5" + utls "github.com/sagernet/utls" +) + +var ( + _ N.ExtendedConn = (*Conn)(nil) +) + +type Conn struct { + net.Conn + N.ExtendedReader + N.ExtendedWriter + upstream net.Conn + userUUID *uuid.UUID + + tlsConn net.Conn + input *bytes.Reader + rawInput *bytes.Buffer + + needHandshake bool + packetsToFilter int + isTLS bool + isTLS12orAbove bool + enableXTLS bool + cipher uint16 + remainingServerHello uint16 + readRemainingContent int + readRemainingPadding int + readProcess bool + readFilterUUID bool + readLastCommand byte + writeFilterApplicationData bool + writeDirect bool +} + +func (vc *Conn) Read(b []byte) (int, error) { + if vc.readProcess { + buffer := buf.With(b) + err := vc.ReadBuffer(buffer) + return buffer.Len(), err + } + return vc.ExtendedReader.Read(b) +} + +func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { + toRead := buffer.FreeBytes() + if vc.readRemainingContent > 0 { + if vc.readRemainingContent < buffer.FreeLen() { + toRead = toRead[:vc.readRemainingContent] + } + n, err := vc.ExtendedReader.Read(toRead) + buffer.Truncate(n) + vc.readRemainingContent -= n + vc.FilterTLS(toRead) + return err + } + if vc.readRemainingPadding > 0 { + _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) + if err != nil { + return err + } + vc.readRemainingPadding = 0 + } + if vc.readProcess { + switch vc.readLastCommand { + case commandPaddingContinue: + //if vc.isTLS || vc.packetsToFilter > 0 { + headerUUIDLen := 0 + if vc.readFilterUUID { + headerUUIDLen = uuid.Size + } + var header []byte + if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need { + header = make([]byte, need) + } else { + header = buffer.FreeBytes()[:need] + } + _, err := io.ReadFull(vc.ExtendedReader, header) + if err != nil { + return err + } + if vc.readFilterUUID { + vc.readFilterUUID = false + if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", + uuid.FromBytesOrNil(header[:uuid.Size]).String()) + log.Errorln(err.Error()) + return err + } + header = header[uuid.Size:] + } + vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[3:])) + vc.readRemainingContent = int(binary.BigEndian.Uint16(header[1:])) + vc.readLastCommand = header[0] + log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", + vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) + return vc.ReadBuffer(buffer) + //} + case commandPaddingEnd: + vc.readProcess = false + return vc.ReadBuffer(buffer) + case commandPaddingDirect: + needReturn := false + if vc.input != nil { + _, err := buffer.ReadFrom(vc.input) + if err != nil { + return err + } + if vc.input.Len() == 0 { + needReturn = true + vc.input = nil + } else { // buffer is full + return nil + } + } + if vc.rawInput != nil { + _, err := buffer.ReadFrom(vc.rawInput) + if err != nil { + return err + } + needReturn = true + if vc.rawInput.Len() == 0 { + vc.rawInput = nil + } + } + if vc.input == nil && vc.rawInput == nil { + vc.readProcess = false + vc.ExtendedReader = N.NewExtendedReader(vc.Conn) + log.Debugln("XTLS Vision direct read start") + } + if needReturn { + return nil + } + default: + err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) + log.Debugln(err.Error()) + return err + } + } + return vc.ExtendedReader.ReadBuffer(buffer) +} + +func (vc *Conn) Write(p []byte) (int, error) { + if vc.writeFilterApplicationData { + _buffer := buf.StackNew() + defer buf.KeepAlive(_buffer) + buffer := buf.Dup(_buffer) + defer buffer.Release() + buffer.Write(p) + err := vc.WriteBuffer(buffer) + if err != nil { + return 0, err + } + return len(p), nil + } + return vc.ExtendedWriter.Write(p) +} + +func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { + if vc.needHandshake { + vc.needHandshake = false + if buffer.IsEmpty() { + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false) + } else { + vc.FilterTLS(buffer.Bytes()) + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS) + } + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + buffer.Release() + return err + } + switch underlying := vc.tlsConn.(type) { + case *gotls.Conn: + if underlying.ConnectionState().Version != gotls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + case *utls.UConn: + if underlying.ConnectionState().Version != utls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + } + vc.tlsConn = nil + return nil + } + + if vc.writeFilterApplicationData { + buffer2 := ReshapeBuffer(buffer) + defer buffer2.Release() + vc.FilterTLS(buffer.Bytes()) + command := commandPaddingContinue + if !vc.isTLS { + command = commandPaddingEnd + + // disable XTLS + //vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 + } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + return err + } + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(5 * time.Millisecond) + } + if buffer2 != nil { + if vc.writeDirect || !vc.isTLS { + return vc.ExtendedWriter.WriteBuffer(buffer2) + } + vc.FilterTLS(buffer2.Bytes()) + command = commandPaddingContinue + if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer2, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer2) + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(10 * time.Millisecond) + } + } + return err + } + /*if vc.writeDirect { + log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) + }*/ + return vc.ExtendedWriter.WriteBuffer(buffer) +} + +func (vc *Conn) FrontHeadroom() int { + if vc.readFilterUUID { + return PaddingHeaderLen + } + return PaddingHeaderLen - uuid.Size +} + +func (vc *Conn) NeedHandshake() bool { + return vc.needHandshake +} + +func (vc *Conn) Upstream() any { + if vc.writeDirect || + vc.readLastCommand == commandPaddingDirect { + return vc.Conn + } + return vc.upstream +} + +func (vc *Conn) ReaderPossiblyReplaceable() bool { + return vc.readProcess +} + +func (vc *Conn) ReaderReplaceable() bool { + if !vc.readProcess && + vc.readLastCommand == commandPaddingDirect { + return true + } + return false +} + +func (vc *Conn) WriterPossiblyReplaceable() bool { + return vc.writeFilterApplicationData +} + +func (vc *Conn) WriterReplaceable() bool { + if vc.writeDirect { + return true + } + return false +} diff --git a/transport/vless/filter.go b/transport/vless/vision/filter.go similarity index 99% rename from transport/vless/filter.go rename to transport/vless/vision/filter.go index f577be7a..e070de35 100644 --- a/transport/vless/filter.go +++ b/transport/vless/vision/filter.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" diff --git a/transport/vless/vision.go b/transport/vless/vision/padding.go similarity index 94% rename from transport/vless/vision.go rename to transport/vless/vision/padding.go index 5649dde4..d5a230d1 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision/padding.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" @@ -12,7 +12,7 @@ import ( ) const ( - paddingHeaderLen = 1 + 2 + 2 // =5 + PaddingHeaderLen = uuid.Size + 1 + 2 + 2 // =21 commandPaddingContinue byte = 0x00 commandPaddingEnd byte = 0x01 @@ -67,7 +67,7 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding } func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer { - if buffer.Len() <= buf.BufferSize-paddingHeaderLen { + if buffer.Len() <= buf.BufferSize-PaddingHeaderLen { return nil } cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart) diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go new file mode 100644 index 00000000..3b52dd4b --- /dev/null +++ b/transport/vless/vision/vision.go @@ -0,0 +1,70 @@ +// Package vision implements VLESS flow `xtls-rprx-vision` introduced by Xray-core. +package vision + +import ( + "bytes" + gotls "crypto/tls" + "errors" + "fmt" + "net" + "reflect" + "unsafe" + + N "github.com/Dreamacro/clash/common/net" + tlsC "github.com/Dreamacro/clash/component/tls" + + "github.com/gofrs/uuid/v5" + "github.com/sagernet/sing/common" + utls "github.com/sagernet/utls" +) + +var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") + +type connWithUpstream interface { + net.Conn + common.WithUpstream +} + +func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) { + c := &Conn{ + ExtendedReader: N.NewExtendedReader(conn), + ExtendedWriter: N.NewExtendedWriter(conn), + upstream: conn, + userUUID: userUUID, + packetsToFilter: 6, + needHandshake: true, + readProcess: true, + readFilterUUID: true, + writeFilterApplicationData: true, + } + var t reflect.Type + var p unsafe.Pointer + switch underlying := conn.Upstream().(type) { + case *gotls.Conn: + //log.Debugln("type tls") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + case *utls.UConn: + //log.Debugln("type *utls.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying.Conn).Elem() + p = unsafe.Pointer(underlying.Conn) + case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying.UConn + t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) + p = unsafe.Pointer(underlying.Conn) + default: + return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`) + } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) + c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) + return c, nil +} diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index 3a319568..071e6e8f 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -2,18 +2,12 @@ package vless import ( "context" - "errors" "net" tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" xtls "github.com/xtls/go" ) -var ( - ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") -) - type XTLSConfig struct { Host string SkipCertVerify bool @@ -21,7 +15,7 @@ type XTLSConfig struct { NextProtos []string } -func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { +func StreamXTLSConn(ctx context.Context, conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { xtlsConfig := &xtls.Config{ ServerName: cfg.Host, InsecureSkipVerify: cfg.SkipCertVerify, @@ -38,9 +32,6 @@ func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { xtlsConn := xtls.Client(conn, xtlsConfig) - // fix xtls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := xtlsConn.HandshakeContext(ctx) return xtlsConn, err } diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index f020d273..54813029 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -7,7 +7,6 @@ import ( "net" tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" ) type TLSConfig struct { @@ -19,7 +18,7 @@ type TLSConfig struct { Reality *tlsC.RealityConfig } -func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { +func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) { tlsConfig := &tls.Config{ ServerName: cfg.Host, InsecureSkipVerify: cfg.SkipCertVerify, @@ -39,15 +38,10 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { if cfg.Reality == nil { utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig) if valid { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) return utlsConn, err } } else { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality) } } @@ -57,9 +51,6 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { tlsConn := tls.Client(conn, tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - err := tlsConn.HandshakeContext(ctx) return tlsConn, err } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index e7335d84..a4ce99a9 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -194,17 +194,17 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { earlyDataBuf := bytes.NewBuffer(earlyData) if _, err := base64EarlyDataEncoder.Write(earlyDataBuf.Next(wsedc.config.MaxEarlyData)); err != nil { - return errors.New("failed to encode early data: " + err.Error()) + return fmt.Errorf("failed to encode early data: %w", err) } if errc := base64EarlyDataEncoder.Close(); errc != nil { - return errors.New("failed to encode early data tail: " + errc.Error()) + return fmt.Errorf("failed to encode early data tail: %w", errc) } var err error - if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, base64DataBuf); err != nil { + if wsedc.Conn, err = streamWebsocketConn(wsedc.ctx, wsedc.underlay, wsedc.config, base64DataBuf); err != nil { wsedc.Close() - return errors.New("failed to dial WebSocket: " + err.Error()) + return fmt.Errorf("failed to dial WebSocket: %w", err) } wsedc.dialed <- true @@ -340,7 +340,7 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co return N.NewDeadlineConn(conn), nil } -func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { +func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { dialer := &websocket.Dialer{ NetDial: func(network, addr string) (net.Conn, error) { @@ -396,13 +396,13 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf } } - wsConn, resp, err := dialer.Dial(uri.String(), headers) + wsConn, resp, err := dialer.DialContext(ctx, uri.String(), headers) if err != nil { - reason := err.Error() + reason := err if resp != nil { - reason = resp.Status + reason = errors.New(resp.Status) } - return nil, fmt.Errorf("dial %s error: %s", uri.Host, reason) + return nil, fmt.Errorf("dial %s error: %w", uri.Host, reason) } conn = &websocketConn{ @@ -417,7 +417,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf return N.NewDeadlineConn(conn), nil } -func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { +func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) (net.Conn, error) { if u, err := url.Parse(c.Path); err == nil { if q := u.Query(); q.Get("ed") != "" { if ed, err := strconv.Atoi(q.Get("ed")); err == nil { @@ -434,5 +434,5 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { return streamWebsocketWithEarlyDataConn(conn, c) } - return streamWebsocketConn(conn, c, nil) + return streamWebsocketConn(ctx, conn, c, nil) } diff --git a/tunnel/connection.go b/tunnel/connection.go index c64a5266..b130f79a 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -7,7 +7,6 @@ import ( "time" N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" ) @@ -27,34 +26,43 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata return nil } -func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, fAddr netip.Addr) { - buf := pool.Get(pool.UDPBufferSize) +func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) { defer func() { _ = pc.Close() closeAllLocalCoon(key) natTable.Delete(key) - _ = pool.Put(buf) }() for { _ = pc.SetReadDeadline(time.Now().Add(udpTimeout)) - n, from, err := pc.ReadFrom(buf) + data, put, from, err := pc.WaitReadFrom() if err != nil { return } - fromUDPAddr := from.(*net.UDPAddr) - _fromUDPAddr := *fromUDPAddr - fromUDPAddr = &_fromUDPAddr // make a copy - if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { - if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) { - fromUDPAddr.IP = fAddr.Unmap().AsSlice() - } else { - fromUDPAddr.IP = fromAddr.Unmap().AsSlice() + fromUDPAddr, isUDPAddr := from.(*net.UDPAddr) + if isUDPAddr { + _fromUDPAddr := *fromUDPAddr + fromUDPAddr = &_fromUDPAddr // make a copy + if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { + fromAddr = fromAddr.Unmap() + if fAddr.IsValid() && (oAddrPort.Addr() == fromAddr) { // oAddrPort was Unmapped + fromAddr = fAddr.Unmap() + } + fromUDPAddr.IP = fromAddr.AsSlice() + if fromAddr.Is4() { + fromUDPAddr.Zone = "" // only ipv6 can have the zone + } } + } else { + fromUDPAddr = net.UDPAddrFromAddrPort(oAddrPort) // oAddrPort was Unmapped + log.Warnln("server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", from, from, oAddrPort) } - _, err = packet.WriteBack(buf[:n], fromUDPAddr) + _, err = packet.WriteBack(data, fromUDPAddr) + if put != nil { + put() + } if err != nil { return } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 170cbc99..a2a921ac 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -186,6 +186,16 @@ func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { return n, addr, err } +func (ut *udpTracker) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = ut.PacketConn.WaitReadFrom() + download := int64(len(data)) + if ut.pushToManager { + ut.manager.PushDownloaded(download) + } + ut.DownloadTotal.Add(download) + return +} + func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) { n, err := ut.PacketConn.WriteTo(b, addr) upload := int64(n) @@ -201,6 +211,10 @@ func (ut *udpTracker) Close() error { return ut.PacketConn.Close() } +func (ut *udpTracker) Upstream() any { + return ut.PacketConn +} + func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker { metadata.RemoteDst = parseRemoteDestination(nil, conn) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index a4a473e9..4e00aca2 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -383,10 +383,10 @@ func handleUDPConn(packet C.PacketAdapter) { log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) } - oAddr := metadata.DstIP + oAddrPort := metadata.AddrPort() natTable.Set(key, pc) - go handleUDPToLocal(packet, pc, key, oAddr, fAddr) + go handleUDPToLocal(packet, pc, key, oAddrPort, fAddr) handle() }()