From 84e4677a94fdf90a543de2c132c1d48144e19730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 20 Aug 2022 10:38:12 +0800 Subject: [PATCH] Improve process searcher --- adapter/inbound.go | 8 +- common/process/searcher.go | 12 ++- common/process/searcher_android.go | 14 +-- common/process/searcher_darwin.go | 4 +- common/process/searcher_linux.go | 8 +- common/process/searcher_linux_shared.go | 136 ++++-------------------- common/process/searcher_windows.go | 4 +- common/process/searcher_with_name.go | 6 +- common/process/searcher_without_name.go | 6 +- go.mod | 2 +- go.sum | 4 +- inbound/default.go | 7 ++ inbound/hysteria.go | 1 + route/router.go | 8 +- test/go.mod | 2 +- test/go.sum | 4 +- 16 files changed, 77 insertions(+), 149 deletions(-) diff --git a/adapter/inbound.go b/adapter/inbound.go index 8119a37f..ab5fb771 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -29,14 +29,14 @@ type InboundContext struct { // cache + OriginDestination M.Socksaddr DomainStrategy dns.DomainStrategy SniffEnabled bool SniffOverrideDestination bool DestinationAddresses []netip.Addr - - SourceGeoIPCode string - GeoIPCode string - ProcessInfo *process.Info + SourceGeoIPCode string + GeoIPCode string + ProcessInfo *process.Info } type inboundContextKey struct{} diff --git a/common/process/searcher.go b/common/process/searcher.go index fa93807f..d6f67a0b 100644 --- a/common/process/searcher.go +++ b/common/process/searcher.go @@ -10,7 +10,7 @@ import ( ) type Searcher interface { - FindProcessInfo(ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) + FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) } var ErrNotFound = E.New("process not found") @@ -26,3 +26,13 @@ type Info struct { User string UserId int32 } + +func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + info, err := findProcessInfo(searcher, ctx, network, source, destination) + if err != nil { + if source.Addr().Is4In6() { + info, err = findProcessInfo(searcher, ctx, network, netip.AddrPortFrom(netip.AddrFrom4(source.Addr().As4()), source.Port()), destination) + } + } + return info, err +} diff --git a/common/process/searcher_android.go b/common/process/searcher_android.go index 0058c0c7..b8ef817a 100644 --- a/common/process/searcher_android.go +++ b/common/process/searcher_android.go @@ -17,22 +17,22 @@ func NewSearcher(config Config) (Searcher, error) { return &androidSearcher{config.PackageManager}, nil } -func (s *androidSearcher) FindProcessInfo(ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - _, uid, err := resolveSocketByNetlink(network, srcIP, srcPort) +func (s *androidSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + socket, err := resolveSocketByNetlink(network, source, destination) if err != nil { return nil, err } - if sharedPackage, loaded := s.packageManager.SharedPackageByID(uint32(uid)); loaded { + if sharedPackage, loaded := s.packageManager.SharedPackageByID(socket.UID); loaded { return &Info{ - UserId: uid, + UserId: int32(socket.UID), PackageName: sharedPackage, }, nil } - if packageName, loaded := s.packageManager.PackageByID(uint32(uid)); loaded { + if packageName, loaded := s.packageManager.PackageByID(socket.UID); loaded { return &Info{ - UserId: uid, + UserId: int32(socket.UID), PackageName: packageName, }, nil } - return &Info{UserId: uid}, nil + return &Info{UserId: int32(socket.UID)}, nil } diff --git a/common/process/searcher_darwin.go b/common/process/searcher_darwin.go index 2547ba89..3ddf30de 100644 --- a/common/process/searcher_darwin.go +++ b/common/process/searcher_darwin.go @@ -21,8 +21,8 @@ func NewSearcher(_ Config) (Searcher, error) { return &darwinSearcher{}, nil } -func (d *darwinSearcher) FindProcessInfo(ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - processName, err := findProcessName(network, srcIP, srcPort) +func (d *darwinSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + processName, err := findProcessName(network, source.Addr(), int(source.Port())) if err != nil { return nil, err } diff --git a/common/process/searcher_linux.go b/common/process/searcher_linux.go index f9bed9c8..3462740e 100644 --- a/common/process/searcher_linux.go +++ b/common/process/searcher_linux.go @@ -19,17 +19,17 @@ func NewSearcher(config Config) (Searcher, error) { return &linuxSearcher{config.Logger}, nil } -func (s *linuxSearcher) FindProcessInfo(ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - inode, uid, err := resolveSocketByNetlink(network, srcIP, srcPort) +func (s *linuxSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + socket, err := resolveSocketByNetlink(network, source, destination) if err != nil { return nil, err } - processPath, err := resolveProcessNameByProcSearch(inode, uid) + processPath, err := resolveProcessNameByProcSearch(socket.INode, socket.UID) if err != nil { s.logger.DebugContext(ctx, "find process path: ", err) } return &Info{ - UserId: uid, + UserId: int32(socket.UID), ProcessPath: processPath, }, nil } diff --git a/common/process/searcher_linux_shared.go b/common/process/searcher_linux_shared.go index a00d5075..1114c07d 100644 --- a/common/process/searcher_linux_shared.go +++ b/common/process/searcher_linux_shared.go @@ -6,7 +6,6 @@ import ( "bytes" "encoding/binary" "fmt" - "net" "net/netip" "os" "path" @@ -15,9 +14,7 @@ import ( "unicode" "unsafe" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/netlink" N "github.com/sagernet/sing/common/network" ) @@ -37,19 +34,9 @@ const ( pathProc = "/proc" ) -func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (inode int32, uid int32, err error) { - for attempts := 0; attempts < 3; attempts++ { - inode, uid, err = resolveSocketByNetlink0(network, ip, srcPort) - if err == nil { - return - } - } - return -} - -func resolveSocketByNetlink0(network string, ip netip.Addr, srcPort int) (inode int32, uid int32, err error) { - var family byte - var protocol byte +func resolveSocketByNetlink(network string, source netip.AddrPort, destination netip.AddrPort) (*netlink.Socket, error) { + var family uint8 + var protocol uint8 switch network { case N.NetworkTCP: @@ -57,114 +44,31 @@ func resolveSocketByNetlink0(network string, ip netip.Addr, srcPort int) (inode case N.NetworkUDP: protocol = syscall.IPPROTO_UDP default: - return 0, 0, os.ErrInvalid + return nil, os.ErrInvalid } - - if ip.Is4() { + if source.Addr().Is4() { family = syscall.AF_INET } else { family = syscall.AF_INET6 } - - req := packSocketDiagRequest(family, protocol, ip, uint16(srcPort)) - - socket, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_INET_DIAG) + sockets, err := netlink.SocketGet(family, protocol, source, netip.AddrPortFrom(netip.IPv6Unspecified(), 0)) + if err == nil { + sockets, err = netlink.SocketGet(family, protocol, source, destination) + } if err != nil { - return 0, 0, E.Cause(err, "dial netlink") + return nil, err } - defer syscall.Close(socket) - - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100}) - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100}) - - if err = syscall.Connect(socket, &syscall.SockaddrNetlink{ - Family: syscall.AF_NETLINK, - Pad: 0, - Pid: 0, - Groups: 0, - }); err != nil { - return 0, 0, err + if len(sockets) > 1 { + for _, socket := range sockets { + if socket.ID.DestinationPort == destination.Port() { + return socket, nil + } + } } - - if _, err = syscall.Write(socket, req); err != nil { - return 0, 0, E.Cause(err, "write netlink request") - } - - _buffer := buf.StackNew() - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - - n, err := syscall.Read(socket, buffer.FreeBytes()) - if err != nil { - return 0, 0, E.Cause(err, "read netlink response") - } - - buffer.Truncate(n) - - messages, err := syscall.ParseNetlinkMessage(buffer.Bytes()) - if err != nil { - return 0, 0, E.Cause(err, "parse netlink message") - } else if len(messages) == 0 { - return 0, 0, E.New("unexcepted netlink response") - } - - message := messages[0] - if message.Header.Type&syscall.NLMSG_ERROR != 0 { - return 0, 0, E.New("netlink message: NLMSG_ERROR") - } - - inode, uid = unpackSocketDiagResponse(&messages[0]) - if inode < 0 || uid < 0 { - return 0, 0, E.New("invalid inode(", inode, ") or uid(", uid, ")") - } - return + return sockets[0], nil } -func packSocketDiagRequest(family, protocol byte, source netip.Addr, sourcePort uint16) []byte { - s := make([]byte, 16) - copy(s, source.AsSlice()) - - buf := make([]byte, sizeOfSocketDiagRequest) - - nativeEndian.PutUint32(buf[0:4], sizeOfSocketDiagRequest) - nativeEndian.PutUint16(buf[4:6], socketDiagByFamily) - nativeEndian.PutUint16(buf[6:8], syscall.NLM_F_REQUEST|syscall.NLM_F_DUMP) - nativeEndian.PutUint32(buf[8:12], 0) - nativeEndian.PutUint32(buf[12:16], 0) - - buf[16] = family - buf[17] = protocol - buf[18] = 0 - buf[19] = 0 - nativeEndian.PutUint32(buf[20:24], 0xFFFFFFFF) - - binary.BigEndian.PutUint16(buf[24:26], sourcePort) - binary.BigEndian.PutUint16(buf[26:28], 0) - - copy(buf[28:44], s) - copy(buf[44:60], net.IPv6zero) - - nativeEndian.PutUint32(buf[60:64], 0) - nativeEndian.PutUint64(buf[64:72], 0xFFFFFFFFFFFFFFFF) - - return buf -} - -func unpackSocketDiagResponse(msg *syscall.NetlinkMessage) (inode, uid int32) { - if len(msg.Data) < 72 { - return 0, 0 - } - - data := msg.Data - - uid = int32(nativeEndian.Uint32(data[64:68])) - inode = int32(nativeEndian.Uint32(data[68:72])) - - return -} - -func resolveProcessNameByProcSearch(inode, uid int32) (string, error) { +func resolveProcessNameByProcSearch(inode, uid uint32) (string, error) { files, err := os.ReadDir(pathProc) if err != nil { return "", err @@ -182,7 +86,7 @@ func resolveProcessNameByProcSearch(inode, uid int32) (string, error) { if err != nil { return "", err } - if info.Sys().(*syscall.Stat_t).Uid != uint32(uid) { + if info.Sys().(*syscall.Stat_t).Uid != uid { continue } diff --git a/common/process/searcher_windows.go b/common/process/searcher_windows.go index f76c1105..f13b440e 100644 --- a/common/process/searcher_windows.go +++ b/common/process/searcher_windows.go @@ -63,8 +63,8 @@ func initWin32API() error { return nil } -func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - processName, err := findProcessName(network, srcIP, srcPort) +func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + processName, err := findProcessName(network, source.Addr(), int(source.Port())) if err != nil { return nil, err } diff --git a/common/process/searcher_with_name.go b/common/process/searcher_with_name.go index ed7ffffb..c7ac3c40 100644 --- a/common/process/searcher_with_name.go +++ b/common/process/searcher_with_name.go @@ -1,4 +1,4 @@ -//go:build cgo && linux && !android +//go:build linux && !android package process @@ -10,8 +10,8 @@ import ( F "github.com/sagernet/sing/common/format" ) -func FindProcessInfo(searcher Searcher, ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - info, err := searcher.FindProcessInfo(ctx, network, srcIP, srcPort) +func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + info, err := searcher.FindProcessInfo(ctx, network, source, destination) if err != nil { return nil, err } diff --git a/common/process/searcher_without_name.go b/common/process/searcher_without_name.go index c3d542e6..ffc56a7b 100644 --- a/common/process/searcher_without_name.go +++ b/common/process/searcher_without_name.go @@ -1,4 +1,4 @@ -//go:build !(cgo && linux && !android) +//go:build !linux || android package process @@ -7,6 +7,6 @@ import ( "net/netip" ) -func FindProcessInfo(searcher Searcher, ctx context.Context, network string, srcIP netip.Addr, srcPort int) (*Info, error) { - return searcher.FindProcessInfo(ctx, network, srcIP, srcPort) +func findProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) { + return searcher.FindProcessInfo(ctx, network, source, destination) } diff --git a/go.mod b/go.mod index 0effb982..cc9c2299 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible github.com/oschwald/maxminddb-golang v1.10.0 github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a + github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb github.com/sagernet/sing v0.0.0-20220819160035-717bc38fd35c github.com/sagernet/sing-dns v0.0.0-20220819010310-839eab1578c9 @@ -50,7 +51,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/sagernet/netlink v0.0.0-20220816152750-7a75378bd31a // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect go.uber.org/multierr v1.6.0 // indirect diff --git a/go.sum b/go.sum index 43f1d158..8ffb7aeb 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,8 @@ github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a h1:SE3Xn4GOQ+kx github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a/go.mod h1:Q+ZXyesnkjV5B70B1ixk65ecKrlJ2jz0atv3fPKsVVo= 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-20220816152750-7a75378bd31a h1:iNtsfGMenajBUGZ/1yAzl1v3p+t/7IJ/ilQXq9haRZ8= -github.com/sagernet/netlink v0.0.0-20220816152750-7a75378bd31a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e h1:0QsCfdXMXHprFCQDjyT2m/6Vnj5yvQUq1gG0ybjZ9Hk= +github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= diff --git a/inbound/default.go b/inbound/default.go index 063da67c..f5202c28 100644 --- a/inbound/default.go +++ b/inbound/default.go @@ -47,6 +47,7 @@ type myInboundAdapter struct { tcpListener *net.TCPListener udpConn *net.UDPConn + udpAddr M.Socksaddr packetAccess sync.RWMutex packetOutboundClosed chan struct{} packetOutbound chan *myInboundPacket @@ -84,6 +85,7 @@ func (a *myInboundAdapter) Start() error { return err } a.udpConn = udpConn + a.udpAddr = bindAddr a.packetOutboundClosed = make(chan struct{}) a.packetOutbound = make(chan *myInboundPacket) if a.oobPacketHandler != nil { @@ -164,6 +166,7 @@ func (a *myInboundAdapter) loopTCPIn() { metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.Network = N.NetworkTCP metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()) + metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr()) a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source) hErr := a.connHandler.NewConnection(ctx, conn, metadata) if hErr != nil { @@ -198,6 +201,7 @@ func (a *myInboundAdapter) loopUDPIn() { metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.Network = N.NetworkUDP metadata.Source = M.SocksaddrFromNetIP(addr) + metadata.OriginDestination = a.udpAddr err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata) if err != nil { a.newError(E.Cause(err, "process packet from ", metadata.Source)) @@ -230,6 +234,7 @@ func (a *myInboundAdapter) loopUDPOOBIn() { metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.Network = N.NetworkUDP metadata.Source = M.SocksaddrFromNetIP(addr) + metadata.OriginDestination = a.udpAddr err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata) if err != nil { a.newError(E.Cause(err, "process packet from ", metadata.Source)) @@ -256,6 +261,7 @@ func (a *myInboundAdapter) loopUDPInThreadSafe() { metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.Network = N.NetworkUDP metadata.Source = M.SocksaddrFromNetIP(addr) + metadata.OriginDestination = a.udpAddr err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata) if err != nil { buffer.Release() @@ -284,6 +290,7 @@ func (a *myInboundAdapter) loopUDPOOBInThreadSafe() { metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.Network = N.NetworkUDP metadata.Source = M.SocksaddrFromNetIP(addr) + metadata.OriginDestination = a.udpAddr err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata) if err != nil { buffer.Release() diff --git a/inbound/hysteria.go b/inbound/hysteria.go index 60ff71fa..bbcbf953 100644 --- a/inbound/hysteria.go +++ b/inbound/hysteria.go @@ -276,6 +276,7 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea metadata.SniffOverrideDestination = h.listenOptions.SniffOverrideDestination metadata.DomainStrategy = dns.DomainStrategy(h.listenOptions.DomainStrategy) metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()) + metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr()) metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port) if !request.UDP { h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) diff --git a/route/router.go b/route/router.go index 30d64909..6a854068 100644 --- a/route/router.go +++ b/route/router.go @@ -591,7 +591,13 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m func (r *Router) match(ctx context.Context, metadata *adapter.InboundContext, defaultOutbound adapter.Outbound) (adapter.Rule, adapter.Outbound) { if r.processSearcher != nil { - processInfo, err := process.FindProcessInfo(r.processSearcher, ctx, metadata.Network, metadata.Source.Addr, int(metadata.Source.Port)) + var originDestination netip.AddrPort + if metadata.OriginDestination.IsValid() { + originDestination = metadata.OriginDestination.AddrPort() + } else if metadata.Destination.IsIP() { + originDestination = metadata.Destination.AddrPort() + } + processInfo, err := process.FindProcessInfo(r.processSearcher, ctx, metadata.Network, metadata.Source.AddrPort(), originDestination) if err != nil { r.logger.DebugContext(ctx, "failed to search process: ", err) } else { diff --git a/test/go.mod b/test/go.mod index 182c63d8..91a15080 100644 --- a/test/go.mod +++ b/test/go.mod @@ -53,7 +53,7 @@ require ( github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/sagernet/netlink v0.0.0-20220816152750-7a75378bd31a // indirect + github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e // indirect github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect github.com/sagernet/sing-dns v0.0.0-20220819010310-839eab1578c9 // indirect github.com/sagernet/sing-tun v0.0.0-20220820022232-9e535150dbff // indirect diff --git a/test/go.sum b/test/go.sum index acf871e5..4289406f 100644 --- a/test/go.sum +++ b/test/go.sum @@ -112,8 +112,8 @@ github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a h1:SE3Xn4GOQ+kx github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a/go.mod h1:Q+ZXyesnkjV5B70B1ixk65ecKrlJ2jz0atv3fPKsVVo= 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-20220816152750-7a75378bd31a h1:iNtsfGMenajBUGZ/1yAzl1v3p+t/7IJ/ilQXq9haRZ8= -github.com/sagernet/netlink v0.0.0-20220816152750-7a75378bd31a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= +github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e h1:0QsCfdXMXHprFCQDjyT2m/6Vnj5yvQUq1gG0ybjZ9Hk= +github.com/sagernet/netlink v0.0.0-20220820040938-560ab95cda9e/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=