aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShelikhoo <xiaokangwang@outlook.com>2023-10-18 16:23:31 +0100
committerShelikhoo <xiaokangwang@outlook.com>2023-10-24 17:42:46 +0100
commit8b46e60553b9de34df12079906f72559361ea20d (patch)
treeb50ebcb9965317ec21d01b1c3d3a20540dfa9c3a
parent6b0421db0d0f7f24fc0e1251a8a2803eeb06c5fe (diff)
downloadsnowflake-8b46e60553b9de34df12079906f72559361ea20d.tar.gz
snowflake-8b46e60553b9de34df12079906f72559361ea20d.zip
Add common proxy utilities
-rw-r--r--common/proxy/check.go18
-rw-r--r--common/proxy/client.go253
-rw-r--r--go.mod6
-rw-r--r--go.sum21
4 files changed, 296 insertions, 2 deletions
diff --git a/common/proxy/check.go b/common/proxy/check.go
new file mode 100644
index 0000000..797b3eb
--- /dev/null
+++ b/common/proxy/check.go
@@ -0,0 +1,18 @@
+package proxy
+
+import (
+ "errors"
+ "net/url"
+ "strings"
+)
+
+var errUnsupportedProxyType = errors.New("unsupported proxy type")
+
+func CheckProxyProtocolSupport(proxy *url.URL) error {
+ switch strings.ToLower(proxy.Scheme) {
+ case "socks5":
+ return nil
+ default:
+ return errUnsupportedProxyType
+ }
+}
diff --git a/common/proxy/client.go b/common/proxy/client.go
new file mode 100644
index 0000000..cd1bd98
--- /dev/null
+++ b/common/proxy/client.go
@@ -0,0 +1,253 @@
+package proxy
+
+import (
+ "context"
+ "errors"
+ "log"
+ "net"
+ "net/url"
+ "strconv"
+ "time"
+
+ "github.com/miekg/dns"
+ "github.com/pion/transport/v2"
+ "github.com/txthinking/socks5"
+)
+
+func NewSocks5UDPClient(addr *url.URL) SocksClient {
+ return SocksClient{addr: addr}
+}
+
+type SocksClient struct {
+ addr *url.URL
+}
+
+type SocksConn struct {
+ net.Conn
+ socks5Client *socks5.Client
+}
+
+func (s SocksConn) SetReadBuffer(bytes int) error {
+ return nil
+}
+
+func (s SocksConn) SetWriteBuffer(bytes int) error {
+ return nil
+}
+
+func (s SocksConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
+ var buf [2000]byte
+ n, err = s.Conn.Read(buf[:])
+ if err != nil {
+ return 0, nil, err
+ }
+ Datagram, err := socks5.NewDatagramFromBytes(buf[:n])
+ if err != nil {
+ return 0, nil, err
+ }
+ addr, err = net.ResolveUDPAddr("udp", Datagram.Address())
+ if err != nil {
+ return 0, nil, err
+ }
+ n = copy(b, Datagram.Data)
+ if n < len(Datagram.Data) {
+ return 0, nil, errors.New("short buffer")
+ }
+ return len(Datagram.Data), addr, nil
+}
+
+func (s SocksConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) {
+ panic("unimplemented")
+}
+
+func (s SocksConn) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
+
+ a, addrb, portb, err := socks5.ParseAddress(addr.String())
+ if err != nil {
+ return 0, err
+ }
+ packet := socks5.NewDatagram(a, addrb, portb, b)
+ _, err = s.Conn.Write(packet.Bytes())
+ if err != nil {
+ return 0, err
+ }
+ return len(b), nil
+}
+
+func (s SocksConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) {
+ panic("unimplemented")
+}
+
+func (sc *SocksClient) ListenPacket(network string, locAddr *net.UDPAddr) (transport.UDPConn, error) {
+ conn, err := sc.listenPacket()
+ if err != nil {
+ log.Println("[SOCKS5 Client Error] cannot listen packet", err)
+ }
+ return conn, err
+}
+
+func (sc *SocksClient) listenPacket() (transport.UDPConn, error) {
+ var username, password string
+ if sc.addr.User != nil {
+ username = sc.addr.User.Username()
+ password, _ = sc.addr.User.Password()
+ }
+ client, err := socks5.NewClient(
+ sc.addr.Host,
+ username, password, 300, 300)
+ if err != nil {
+ return nil, err
+ }
+
+ err = client.Negotiate(nil)
+ if err != nil {
+ return nil, err
+ }
+
+ udpRequest := socks5.NewRequest(socks5.CmdUDP, socks5.ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00})
+
+ reply, err := client.Request(udpRequest)
+ if err != nil {
+ return nil, err
+ }
+
+ udpServerAddr := socks5.ToAddress(reply.Atyp, reply.BndAddr, reply.BndPort)
+
+ conn, err := net.Dial("udp", udpServerAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ return &SocksConn{conn, client}, nil
+}
+
+func (s SocksConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
+ return s.WriteToUDP(p, addr.(*net.UDPAddr))
+}
+
+func (s SocksConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
+ return s.ReadFromUDP(p)
+}
+
+func (s SocksConn) Read(b []byte) (int, error) {
+ panic("implement me")
+}
+
+func (s SocksConn) RemoteAddr() net.Addr {
+ panic("implement me")
+}
+
+func (s SocksConn) Write(b []byte) (int, error) {
+ panic("implement me")
+}
+
+func (sc *SocksClient) ResolveUDPAddr(network string, address string) (*net.UDPAddr, error) {
+ dnsServer, err := net.ResolveUDPAddr("udp", "1.1.1.1:53")
+ if err != nil {
+ return nil, err
+ }
+ proxiedResolver := newDnsResolver(sc, dnsServer)
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ host, port, err := net.SplitHostPort(address)
+ if err != nil {
+ return nil, err
+ }
+ ip, err := proxiedResolver.lookupIPAddr(ctx, host, network == "udp6")
+ if err != nil {
+ return nil, err
+ }
+ if len(ip) <= 0 {
+ return nil, errors.New("cannot resolve hostname: NXDOMAIN")
+ }
+ switch network {
+ case "udp4":
+ var v4IPAddr []net.IPAddr
+ for _, v := range ip {
+ if v.IP.To4() != nil {
+ v4IPAddr = append(v4IPAddr, v)
+ }
+ }
+ ip = v4IPAddr
+ case "udp6":
+ var v6IPAddr []net.IPAddr
+ for _, v := range ip {
+ if v.IP.To4() == nil {
+ v6IPAddr = append(v6IPAddr, v)
+ }
+ }
+ ip = v6IPAddr
+ case "udp":
+ default:
+ return nil, errors.New("unknown network")
+ }
+
+ if len(ip) <= 0 {
+ return nil, errors.New("cannot resolve hostname: so suitable address")
+ }
+
+ portInInt, err := strconv.ParseInt(port, 10, 32)
+ return &net.UDPAddr{
+ IP: ip[0].IP,
+ Port: int(portInInt),
+ Zone: "",
+ }, nil
+}
+
+func newDnsResolver(sc *SocksClient,
+ serverAddress net.Addr) *dnsResolver {
+ return &dnsResolver{sc: sc, serverAddress: serverAddress}
+}
+
+type dnsResolver struct {
+ sc *SocksClient
+ serverAddress net.Addr
+}
+
+func (r *dnsResolver) lookupIPAddr(ctx context.Context, host string, ipv6 bool) ([]net.IPAddr, error) {
+ packetConn, err := r.sc.listenPacket()
+ if err != nil {
+ return nil, err
+ }
+ msg := new(dns.Msg)
+ if !ipv6 {
+ msg.SetQuestion(dns.Fqdn(host), dns.TypeA)
+ } else {
+ msg.SetQuestion(dns.Fqdn(host), dns.TypeAAAA)
+ }
+ encodedMsg, err := msg.Pack()
+ if err != nil {
+ log.Println(err.Error())
+ }
+ for i := 2; i >= 0; i-- {
+ _, err := packetConn.WriteTo(encodedMsg, r.serverAddress)
+ if err != nil {
+ log.Println(err.Error())
+ }
+ }
+ ctx, cancel := context.WithTimeout(ctx, time.Second)
+ defer cancel()
+ go func() {
+ <-ctx.Done()
+ packetConn.Close()
+ }()
+ var dataBuf [1600]byte
+ n, _, err := packetConn.ReadFrom(dataBuf[:])
+ if err != nil {
+ return nil, err
+ }
+ err = msg.Unpack(dataBuf[:n])
+ if err != nil {
+ return nil, err
+ }
+ var returnedIPs []net.IPAddr
+ for _, resp := range msg.Answer {
+ switch respTyped := resp.(type) {
+ case *dns.A:
+ returnedIPs = append(returnedIPs, net.IPAddr{IP: respTyped.A})
+ case *dns.AAAA:
+ returnedIPs = append(returnedIPs, net.IPAddr{IP: respTyped.AAAA})
+ }
+ }
+ return returnedIPs, nil
+}
diff --git a/go.mod b/go.mod
index f564bae..f97b3c9 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.21
require (
github.com/gorilla/websocket v1.5.0
+ github.com/miekg/dns v1.1.56
github.com/pion/ice/v2 v2.3.11
github.com/pion/sdp/v3 v3.0.6
github.com/pion/stun v0.6.1
@@ -14,6 +15,7 @@ require (
github.com/refraction-networking/utls v1.5.3
github.com/smartystreets/goconvey v1.8.1
github.com/stretchr/testify v1.8.4
+ github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301
github.com/xtaci/kcp-go/v5 v5.6.5
github.com/xtaci/smux v1.5.24
gitlab.torproject.org/tpo/anti-censorship/geoip v0.0.0-20210928150955-7ce4b3d98d01
@@ -40,6 +42,7 @@ require (
github.com/klauspost/reedsolomon v1.11.8 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/interceptor v0.1.19 // indirect
@@ -60,6 +63,9 @@ require (
github.com/templexxx/cpu v0.1.0 // indirect
github.com/templexxx/xorsimd v0.4.2 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
+ github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect
+ golang.org/x/mod v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
+ golang.org/x/tools v0.13.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 899e626..2913591 100644
--- a/go.sum
+++ b/go.sum
@@ -76,6 +76,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.1.51/go.mod h1:2Z9d3CP1LQWihRZUf29mQ19yDThaI4DAYzte2CaQW5c=
+github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
+github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -90,6 +93,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
@@ -177,6 +182,10 @@ github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUo
github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
+github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf h1:7PflaKRtU4np/epFxRXlFhlzLXZzKFrH5/I4so5Ove0=
+github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM=
+github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 h1:d/Wr/Vl/wiJHc3AHYbYs5I3PucJvRuw3SvbmlIRf+oM=
+github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301/go.mod h1:ntmMHL/xPq1WLeKiw8p/eRATaae6PiVRNipHFJxI8PM=
github.com/xtaci/kcp-go/v5 v5.6.5 h1:oxGZNobj3OddrLzwdJYnR/waNgwrL98u02u0DWNHE3k=
github.com/xtaci/kcp-go/v5 v5.6.5/go.mod h1:Qy3Zf2tWTdFdEs0E8JvhrX+39r5UDZoYac8anvud7/Q=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
@@ -207,7 +216,10 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -222,6 +234,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
@@ -239,6 +252,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -268,6 +283,7 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
@@ -296,9 +312,10 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
-golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
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=