aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2025-02-14 13:39:34 -0500
committerXe Iaso <me@xeiaso.net>2025-02-14 13:39:34 -0500
commit1acc1602f2ff678c0e4bf49fa62345505ec0aa35 (patch)
treed2eec95941c9cd0a53f6de89cfde44222aa55940
parent17c44496aaa77e8d0a499db8c044cb42ab00086b (diff)
downloadx-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.json3
-rw-r--r--cmd/anubis/internal/config/config.go3
-rw-r--r--cmd/anubis/internal/dnsbl/dnsbl.go95
-rw-r--r--cmd/anubis/internal/dnsbl/dnsbl_test.go55
-rw-r--r--cmd/anubis/internal/dnsbl/droneblresponse_string.go54
-rw-r--r--cmd/anubis/main.go14
-rw-r--r--cmd/anubis/policy.go5
-rw-r--r--go.mod24
-rw-r--r--go.sum32
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
}
diff --git a/go.mod b/go.mod
index 898ecc2..bb60ab9 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 78d556e..e6a0eb1 100644
--- a/go.sum
+++ b/go.sum
@@ -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=