mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
Add common proxy utilities
This commit is contained in:
parent
6b0421db0d
commit
8b46e60553
4 changed files with 296 additions and 2 deletions
18
common/proxy/check.go
Normal file
18
common/proxy/check.go
Normal file
|
@ -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
|
||||
}
|
||||
}
|
253
common/proxy/client.go
Normal file
253
common/proxy/client.go
Normal file
|
@ -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
|
||||
}
|
6
go.mod
6
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
|
||||
)
|
||||
|
|
21
go.sum
21
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=
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue