diff options
| author | Xe Iaso <me@xeiaso.net> | 2025-02-14 13:39:34 -0500 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2025-02-14 13:39:34 -0500 |
| commit | 1acc1602f2ff678c0e4bf49fa62345505ec0aa35 (patch) | |
| tree | d2eec95941c9cd0a53f6de89cfde44222aa55940 | |
| parent | 17c44496aaa77e8d0a499db8c044cb42ab00086b (diff) | |
| download | x-1acc1602f2ff678c0e4bf49fa62345505ec0aa35.tar.xz x-1acc1602f2ff678c0e4bf49fa62345505ec0aa35.zip | |
cmd/anubis: enable DNSBL checking via dronebl
Signed-off-by: Xe Iaso <me@xeiaso.net>
| -rw-r--r-- | cmd/anubis/botPolicies.json | 3 | ||||
| -rw-r--r-- | cmd/anubis/internal/config/config.go | 3 | ||||
| -rw-r--r-- | cmd/anubis/internal/dnsbl/dnsbl.go | 95 | ||||
| -rw-r--r-- | cmd/anubis/internal/dnsbl/dnsbl_test.go | 55 | ||||
| -rw-r--r-- | cmd/anubis/internal/dnsbl/droneblresponse_string.go | 54 | ||||
| -rw-r--r-- | cmd/anubis/main.go | 14 | ||||
| -rw-r--r-- | cmd/anubis/policy.go | 5 | ||||
| -rw-r--r-- | go.mod | 24 | ||||
| -rw-r--r-- | go.sum | 32 |
9 files changed, 254 insertions, 31 deletions
diff --git a/cmd/anubis/botPolicies.json b/cmd/anubis/botPolicies.json index 8ca88e1..b90eba0 100644 --- a/cmd/anubis/botPolicies.json +++ b/cmd/anubis/botPolicies.json @@ -60,5 +60,6 @@ "user_agent_regex": "Mozilla", "action": "CHALLENGE" } - ] + ], + "dnsbl": true }
\ No newline at end of file diff --git a/cmd/anubis/internal/config/config.go b/cmd/anubis/internal/config/config.go index 7f986c1..b67db77 100644 --- a/cmd/anubis/internal/config/config.go +++ b/cmd/anubis/internal/config/config.go @@ -53,5 +53,6 @@ func (b Bot) Valid() error { } type Config struct { - Bots []Bot `json:"bots"` + Bots []Bot `json:"bots"` + DNSBL bool `json:"dnsbl"` } diff --git a/cmd/anubis/internal/dnsbl/dnsbl.go b/cmd/anubis/internal/dnsbl/dnsbl.go new file mode 100644 index 0000000..60edd5c --- /dev/null +++ b/cmd/anubis/internal/dnsbl/dnsbl.go @@ -0,0 +1,95 @@ +package dnsbl + +import ( + "errors" + "fmt" + "net" + "strings" +) + +//go:generate go tool golang.org/x/tools/cmd/stringer -type=DroneBLResponse + +type DroneBLResponse byte + +const ( + AllGood DroneBLResponse = 0 + IRCDrone DroneBLResponse = 3 + Bottler DroneBLResponse = 5 + UnknownSpambotOrDrone DroneBLResponse = 6 + DDOSDrone DroneBLResponse = 7 + SOCKSProxy DroneBLResponse = 8 + HTTPProxy DroneBLResponse = 9 + ProxyChain DroneBLResponse = 10 + OpenProxy DroneBLResponse = 11 + OpenDNSResolver DroneBLResponse = 12 + BruteForceAttackers DroneBLResponse = 13 + OpenWingateProxy DroneBLResponse = 14 + CompromisedRouter DroneBLResponse = 15 + AutoRootingWorms DroneBLResponse = 16 + AutoDetectedBotIP DroneBLResponse = 17 + Unknown DroneBLResponse = 255 +) + +func Reverse(ip net.IP) string { + if ip.To4() != nil { + return reverse4(ip) + } + + return reverse6(ip) +} + +func reverse4(ip net.IP) string { + splitAddress := strings.Split(ip.String(), ".") + + // swap first and last octet + splitAddress[0], splitAddress[3] = splitAddress[3], splitAddress[0] + // swap middle octets + splitAddress[1], splitAddress[2] = splitAddress[2], splitAddress[1] + + return strings.Join(splitAddress, ".") +} + +func reverse6(ip net.IP) string { + ipBytes := []byte(ip) + var sb strings.Builder + + for i := len(ipBytes) - 1; i >= 0; i-- { + // Split the byte into two nibbles + highNibble := ipBytes[i] >> 4 + lowNibble := ipBytes[i] & 0x0F + + // Append the nibbles in reversed order + sb.WriteString(fmt.Sprintf("%x.%x.", lowNibble, highNibble)) + } + + return sb.String()[:len(sb.String())-1] +} + +func Lookup(ipStr string) (DroneBLResponse, error) { + ip := net.ParseIP(ipStr) + if ip == nil { + return Unknown, errors.New("dnsbl: input is not an IP address") + } + + revIP := Reverse(ip) + ".dnsbl.dronebl.org" + + ips, err := net.LookupIP(revIP) + if err != nil { + var dnserr *net.DNSError + if errors.As(err, &dnserr) { + if dnserr.IsNotFound { + return AllGood, nil + } + } + + return Unknown, err + } + + if len(ips) != 0 { + for _, ip := range ips { + return DroneBLResponse(ip.To4()[3]), nil + } + } + + return UnknownSpambotOrDrone, nil +} diff --git a/cmd/anubis/internal/dnsbl/dnsbl_test.go b/cmd/anubis/internal/dnsbl/dnsbl_test.go new file mode 100644 index 0000000..9bcf0e7 --- /dev/null +++ b/cmd/anubis/internal/dnsbl/dnsbl_test.go @@ -0,0 +1,55 @@ +package dnsbl + +import ( + "fmt" + "net" + "testing" +) + +func TestReverse4(t *testing.T) { + cases := []struct { + inp, out string + }{ + {"1.2.3.4", "4.3.2.1"}, + } + + for _, cs := range cases { + t.Run(fmt.Sprintf("%s->%s", cs.inp, cs.out), func(t *testing.T) { + out := reverse4(net.ParseIP(cs.inp)) + + if out != cs.out { + t.Errorf("wanted %s\ngot: %s", cs.out, out) + } + }) + } +} + +func TestReverse6(t *testing.T) { + cases := []struct { + inp, out string + }{ + { + inp: "1234:5678:9ABC:DEF0:1234:5678:9ABC:DEF0", + out: "0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1", + }, + } + + for _, cs := range cases { + t.Run(fmt.Sprintf("%s->%s", cs.inp, cs.out), func(t *testing.T) { + out := reverse6(net.ParseIP(cs.inp)) + + if out != cs.out { + t.Errorf("wanted %s, got: %s", cs.out, out) + } + }) + } +} + +func TestLookup(t *testing.T) { + resp, err := Lookup("27.65.243.194") + if err != nil { + t.Fatalf("it broked: %v", err) + } + + t.Logf("response: %x", resp) +}
\ No newline at end of file diff --git a/cmd/anubis/internal/dnsbl/droneblresponse_string.go b/cmd/anubis/internal/dnsbl/droneblresponse_string.go new file mode 100644 index 0000000..5104dda --- /dev/null +++ b/cmd/anubis/internal/dnsbl/droneblresponse_string.go @@ -0,0 +1,54 @@ +// Code generated by "stringer -type=DroneBLResponse"; DO NOT EDIT. + +package dnsbl + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AllGood-0] + _ = x[IRCDrone-3] + _ = x[Bottler-5] + _ = x[UnknownSpambotOrDrone-6] + _ = x[DDOSDrone-7] + _ = x[SOCKSProxy-8] + _ = x[HTTPProxy-9] + _ = x[ProxyChain-10] + _ = x[OpenProxy-11] + _ = x[OpenDNSResolver-12] + _ = x[BruteForceAttackers-13] + _ = x[OpenWingateProxy-14] + _ = x[CompromisedRouter-15] + _ = x[AutoRootingWorms-16] + _ = x[AutoDetectedBotIP-17] + _ = x[Unknown-255] +} + +const ( + _DroneBLResponse_name_0 = "AllGood" + _DroneBLResponse_name_1 = "IRCDrone" + _DroneBLResponse_name_2 = "BottlerUnknownSpambotOrDroneDDOSDroneSOCKSProxyHTTPProxyProxyChainOpenProxyOpenDNSResolverBruteForceAttackersOpenWingateProxyCompromisedRouterAutoRootingWormsAutoDetectedBotIP" + _DroneBLResponse_name_3 = "Unknown" +) + +var ( + _DroneBLResponse_index_2 = [...]uint8{0, 7, 28, 37, 47, 56, 66, 75, 90, 109, 125, 142, 158, 175} +) + +func (i DroneBLResponse) String() string { + switch { + case i == 0: + return _DroneBLResponse_name_0 + case i == 3: + return _DroneBLResponse_name_1 + case 5 <= i && i <= 17: + i -= 5 + return _DroneBLResponse_name_2[_DroneBLResponse_index_2[i]:_DroneBLResponse_index_2[i+1]] + case i == 255: + return _DroneBLResponse_name_3 + default: + return "DroneBLResponse(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/cmd/anubis/main.go b/cmd/anubis/main.go index a15dba8..477fe50 100644 --- a/cmd/anubis/main.go +++ b/cmd/anubis/main.go @@ -30,6 +30,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" "within.website/x" "within.website/x/cmd/anubis/internal/config" + "within.website/x/cmd/anubis/internal/dnsbl" "within.website/x/internal" "within.website/x/xess" ) @@ -213,6 +214,19 @@ func (s *Server) maybeReverseProxy(w http.ResponseWriter, r *http.Request) { ) policyApplications.WithLabelValues(cr.Name, string(cr.Rule)).Add(1) + ip := r.Header.Get("X-Real-Ip") + + if s.policy.DNSBL && ip != "" { + resp, err := dnsbl.Lookup(ip) + if err != nil { + lg.Error("can't look up ip in dnsbl", "err", err) + } else { + lg.Info("DNSBL hit", "status", resp.String()) + templ.Handler(base("Oh noes!", errorPage(fmt.Sprintf("DroneBL reported an entry: %s, see https://dronebl.org/lookup?ip=%s", resp.String(), ip))), templ.WithStatus(http.StatusOK)).ServeHTTP(w, r) + return + } + } + switch cr.Rule { case config.RuleAllow: lg.Debug("allowing traffic to origin (explicit)") diff --git a/cmd/anubis/policy.go b/cmd/anubis/policy.go index 7d778c7..6e2241e 100644 --- a/cmd/anubis/policy.go +++ b/cmd/anubis/policy.go @@ -24,7 +24,8 @@ var ( type ParsedConfig struct { orig config.Config - Bots []Bot + Bots []Bot + DNSBL bool } type Bot struct { @@ -85,6 +86,8 @@ func parseConfig(fin io.Reader, fname string) (*ParsedConfig, error) { return nil, fmt.Errorf("errors validating policy config JSON %s: %w", fname, err) } + result.DNSBL = c.DNSBL + return result, nil } @@ -1,8 +1,6 @@ module within.website/x -go 1.23.3 - -toolchain go1.23.4 +go 1.24 require ( al.essio.dev/pkg/shellescape v1.5.1 @@ -69,13 +67,15 @@ require ( github.com/thoj/go-ircevent v0.0.0-20210723090443-73e444401d64 github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef github.com/twitchtv/twirp v8.1.3+incompatible + github.com/whyrusleeping/cbor-gen v0.1.3-0.20240904181319-8dc02b38228c github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 go.etcd.io/bbolt v1.4.0 go.jetpack.io/tyson v0.1.1 go4.org v0.0.0-20190313082347-94abd6928b1d - golang.org/x/crypto v0.32.0 + golang.org/x/crypto v0.33.0 golang.org/x/oauth2 v0.25.0 - golang.org/x/sync v0.10.0 + golang.org/x/sync v0.11.0 + golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 google.golang.org/grpc v1.70.0 gorm.io/gorm v1.25.12 gorm.io/plugin/prometheus v0.1.0 @@ -199,7 +199,6 @@ require ( github.com/valyala/fasthttp v1.58.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect - github.com/whyrusleeping/cbor-gen v0.1.3-0.20240904181319-8dc02b38228c // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect @@ -212,7 +211,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -261,11 +259,13 @@ require ( github.com/sendgrid/rest v2.6.9+incompatible // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/image v0.23.0 - golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.34.0 - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.35.0 + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.5.0 - golang.org/x/tools v0.29.0 + golang.org/x/tools v0.30.0 google.golang.org/protobuf v1.36.4 ) + +tool golang.org/x/tools/cmd/stringer @@ -953,8 +953,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -997,8 +997,8 @@ golang.org/x/mod v0.4.1/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/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1051,8 +1051,8 @@ golang.org/x/net v0.0.0-20220921203646-d300de134e69/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1093,8 +1093,8 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ 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/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1184,15 +1184,15 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1206,8 +1206,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1271,8 +1271,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= 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= |
