From 83323ca5504def8e2107f9b3d5a96620fc3cc124 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 16 Aug 2024 17:04:08 -0400 Subject: [PATCH 01/61] feat: initial implementation --- README.md | 77 ++++ acme/reader.go | 82 +++++ acme/setup.go | 87 +++++ acme/writer.go | 294 +++++++++++++++ client/challenge.go | 104 ++++++ cmd/e2e_test.go | 352 ++++++++++++++++++ cmd/main.go | 27 ++ go.mod | 221 +++++++++++ go.sum | 873 ++++++++++++++++++++++++++++++++++++++++++++ ipparser/plugin.go | 134 +++++++ 10 files changed, 2251 insertions(+) create mode 100644 acme/reader.go create mode 100644 acme/setup.go create mode 100644 acme/writer.go create mode 100644 client/challenge.go create mode 100644 cmd/e2e_test.go create mode 100644 cmd/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 ipparser/plugin.go diff --git a/README.md b/README.md index 8845420..2ddc31e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,80 @@ # p2p-forge > An Authoritative DNS server for distributing DNS subdomains to libp2p peers + +## Build + +`go build` will build the binary in your local directory + +## Install + +```console +$ go install github.com/ipshipyard/p2p-forge@latest +``` + +Will download using go mod, build and install the binary in your global Go binary directory (e.g. `~/go/bin`) + +### From source +`go install` will build and install the binary in your global Go binary directory (e.g. `~/go/bin`) + +## Usage + +### Handled DNS records + +There are 3 types of records handled for a given peer and forge (e.g. `.libp2p.direct`): +- ACME Challenges for a given peerID `_acme-challenge..libp2p.direct` +- A records for an IPv4 prefixed subdomain like `1-2-3-4..libp2p.direct` +- AAAA records for an IPv6 prefixed subdomain like `2001-db8--..libp2p.direct` + +#### IPv4 subdomain handling + +IPv4 handling is fairly straightforward, for a given IPv4 address `1.2.3.4` convert the `.`s into `-`s and the result +will be valid. + +#### IPv6 subdomain handling + +Due to the length of IPv6 addresses there are a number of different formats for describing IPv6 addresses. + +The addresses handled here are: +- For an address `A:B:C:D:1:2:3:4` convert the `:`s into `-`s and the result will be valid. +- Addresses of the form `A::C:D` can be converted either into their expanded form or into a condensed form by replacing +the `:`s with `-`s, like `A--C-D` +- When there is a `:` as the first or last character it must be converted to a 0 to comply with [rfc1123](https://datatracker.ietf.org/doc/html/rfc1123#section-2) +, so `::B:C:D` would become `0--B-C-D` and `1::` would become `1--0` + +Other address formats (e.g. the dual IPv6/IPv4 format) are not supported + +### Submitting Challenge Records + +To claim a domain name like `.libp2p.direct` requires: +1. The private key corresponding to the given peerID +2. A publicly reachable libp2p endpoint with one of the following libp2p transport configurations: + - QUIC-v1 + - TCP or WS or WSS, Yamux, TLS or Noise + - WebTransport + - Note: The [Identify protocol](https://github.com/libp2p/specs/tree/master/identify) (`/ipfs/id/1.0.0`) + - Other transports are under consideration (e.g. HTTP), if they are of interest please file an issue + +To set an ACME challenge send an HTTP request to the server (for libp2p.direct this is registration.libp2p.direct) +```shell +curl -X POST "https://registration.libp2p.direct/v1//_acme-challenge" \ +-H "Authorization: Bearer ." +-H "Content-Type: application/json" \ +-d '{ + "value": "your_acme_challenge_token", + "addresses": "[your_multiaddrs, comma_separated]" +}' +``` + +Where the signature is a base64 encoding of the signature for a [libp2p signed envelope](https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md) +where: +- The domain separation string is "peer-forge-domain-challenge" +- The payload type is the ASCII string "/peer-forge-domain-challenge" +- The payload bytes are the contents of the body of the request + +If the public key is not extractable from the peerID then after the signature add a `.` followed by the base64 encoded +public key in the libp2p public key format. + +Note: Per the [peerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids) the peerIDs with +extractable public keys are those that are encoded as fewer than 42 bytes (i.e. Ed25519 and Secp256k1), which means the +others (i.e. RSA and ECDSA) require the public keys to be in the Authorization header. \ No newline at end of file diff --git a/acme/reader.go b/acme/reader.go new file mode 100644 index 0000000..36972be --- /dev/null +++ b/acme/reader.go @@ -0,0 +1,82 @@ +package acme + +import ( + "context" + "strings" + "time" + + "github.com/coredns/coredns/plugin" + "github.com/ipfs/go-datastore" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/miekg/dns" +) + +type acmeReader struct { + Next plugin.Handler + ForgeDomain string + Datastore datastore.Datastore +} + +const ttl = 1 * time.Hour + +// ServeDNS implements the plugin.Handler interface. +func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + var answers []dns.RR + for _, q := range r.Question { + if q.Qtype != dns.TypeTXT && q.Qtype != dns.TypeANY { + continue + } + + subdomain := strings.TrimSuffix(q.Name, "."+p.ForgeDomain+".") + if len(subdomain) == len(q.Name) || len(subdomain) == 0 { + continue + } + + domainSegments := strings.Split(subdomain, ".") + if len(domainSegments) != 2 { + continue + } + + peerIDStr := domainSegments[1] + peerID, err := peer.Decode(peerIDStr) + if err != nil { + continue + } + + const acmeSubdomain = "_acme-challenge" + prefix := domainSegments[0] + if prefix != acmeSubdomain { + continue + } + + val, err := p.Datastore.Get(ctx, datastore.NewKey(peerID.String())) + if err != nil { + continue + } + + answers = append(answers, &dns.TXT{ + Hdr: dns.RR_Header{ + Name: dns.Fqdn(q.Name), + Rrtype: dns.TypeTXT, + Class: dns.ClassINET, + Ttl: uint32(ttl.Seconds()), + }, + Txt: []string{string(val)}, + }) + } + + if len(answers) > 0 { + var m dns.Msg + m.SetReply(r) + m.Authoritative = true + m.Answer = answers + w.WriteMsg(&m) + return dns.RcodeSuccess, nil + } + + // Call next plugin (if any). + return plugin.NextOrFailure(p.Name(), p.Next, ctx, w, r) +} + +// Name implements the Handler interface. +func (p acmeReader) Name() string { return pluginName } diff --git a/acme/setup.go b/acme/setup.go new file mode 100644 index 0000000..a2b8445 --- /dev/null +++ b/acme/setup.go @@ -0,0 +1,87 @@ +package acme + +import ( + "fmt" + "github.com/coredns/caddy" + "github.com/coredns/coredns/core/dnsserver" + "github.com/coredns/coredns/plugin" + "github.com/ipfs/go-datastore" + + badger4 "github.com/ipfs/go-ds-badger4" + + "github.com/aws/aws-sdk-go/aws/session" + ddbv1 "github.com/aws/aws-sdk-go/service/dynamodb" + ddbds "github.com/ipfs/go-ds-dynamodb" +) + +const pluginName = "acme" + +func init() { plugin.Register(pluginName, setup) } + +func setup(c *caddy.Controller) error { + reader, writer, err := parse(c) + if err != nil { + return plugin.Error(pluginName, err) + } + + c.OnStartup(writer.OnStartup) + c.OnRestart(writer.OnReload) + c.OnFinalShutdown(writer.OnFinalShutdown) + c.OnRestartFailed(writer.OnStartup) + + // Add the read portion of the plugin to CoreDNS, so Servers can use it in their plugin chain. + // The write portion is not *really* a plugin just a separate webserver running. + dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { + return reader + }) + + return nil +} + +func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { + var forgeDomain string + var httpListenAddr string + var databaseType string + + // Parse the configuration from the Corefile + c.Next() + args := c.RemainingArgs() + if len(args) < 3 { + return nil, nil, fmt.Errorf("invalid arguments") + } + + forgeDomain = args[0] + httpListenAddr = args[1] + databaseType = args[2] + + var ds datastore.TTLDatastore + + switch databaseType { + case "dynamo": + ddbClient := ddbv1.New(session.Must(session.NewSession())) + ds = ddbds.New(ddbClient, "foo") + case "badger": + if len(args) != 4 { + return nil, nil, fmt.Errorf("need to pass a path for the Badger configuration") + } + dbPath := args[3] + var err error + ds, err = badger4.NewDatastore(dbPath, nil) + if err != nil { + return nil, nil, err + } + default: + return nil, nil, fmt.Errorf("unknown database type: %s", databaseType) + } + + writer := &acmeWriter{ + Addr: httpListenAddr, + Datastore: ds, + } + reader := &acmeReader{ + ForgeDomain: forgeDomain, + Datastore: ds, + } + + return reader, writer, nil +} diff --git a/acme/writer.go b/acme/writer.go new file mode 100644 index 0000000..f5e7e2c --- /dev/null +++ b/acme/writer.go @@ -0,0 +1,294 @@ +package acme + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "net/http" + "strings" + "time" + + clog "github.com/coredns/coredns/plugin/pkg/log" + "github.com/coredns/coredns/plugin/pkg/reuseport" + + "github.com/gorilla/mux" + + "github.com/ipfs/go-datastore" + pool "github.com/libp2p/go-buffer-pool" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-varint" +) + +var log = clog.NewWithPlugin(pluginName) + +// acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. +type acmeWriter struct { + Addr string + + Datastore datastore.TTLDatastore + + ln net.Listener + nlSetup bool + mux *mux.Router +} + +func (c *acmeWriter) OnStartup() error { + if c.Addr == "" { + c.Addr = ":8080" + } + + var err error + + ln, err := reuseport.Listen("tcp", c.Addr) + if err != nil { + return err + } + + c.ln = ln + + c.mux = mux.NewRouter() + c.nlSetup = true + + c.mux.HandleFunc("/v1/{peerID}/_acme-challenge", func(w http.ResponseWriter, r *http.Request) { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte("must pass an authorization header")) + return + } + + vars := mux.Vars(r) + peerIDStr, peerIDFound := vars["peerID"] + if !peerIDFound { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("peerID not found in request URL")) + return + } + peerID, err := peer.Decode(peerIDStr) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("invalid peer ID")) + return + } + + pk, err := peerID.ExtractPublicKey() + if err != nil && errors.Is(err, peer.ErrNoPublicKey) { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(fmt.Sprintf("unable to extract public key from peer ID: %s", err.Error()))) + return + } + + body, err := io.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(fmt.Sprintf("error reading body: %s", err))) + return + } + + authComponents := strings.Split(authHeader, ".") + if pk == nil { + if len(authComponents) != 2 { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("must pass both a signature and public key if the public key cannot be extracted from the peerID")) + return + } + base64EncodedPubKey := authComponents[1] + encodedPubKey, err := base64.StdEncoding.DecodeString(base64EncodedPubKey) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("could not decode public key")) + return + } + pk, err = crypto.UnmarshalPublicKey(encodedPubKey) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("could not unmarshal public key")) + return + } + + calculatedID, err := peer.IDFromPublicKey(pk) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("could not calculate peerID from public key")) + return + } + + if calculatedID != peerID { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte("calculated peer ID does not match the passed peerID")) + return + } + } else { + if len(authComponents) != 1 { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("when the peerID can be extracted from the public key only the signature should be in the authorization header")) + return + } + } + + base64EncodedSignature := authComponents[0] + signature, err := base64.StdEncoding.DecodeString(base64EncodedSignature) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(fmt.Sprintf("error decoding signature: %s", err))) + } + + unsigned := makeUnsigned(signatureDomainString, signaturePayloadType, body) + defer pool.Put(unsigned) + + verified, err := pk.Verify(unsigned, signature) + if !verified { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte("invalid signature")) + return + } + + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(fmt.Sprintf("error verifying signature: %s", err))) + return + } + + typedBody := &requestBody{} + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(typedBody); err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(fmt.Sprintf("error decoding body: %s", err))) + return + } + + // Value must be a base64url encoding of a SHA256 digest per https://datatracker.ietf.org/doc/html/rfc8555/#section-8.4 + decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(fmt.Sprintf("error decoding value as base64url: %s", err))) + return + } + + if len(decodedValue) != 32 { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("value is not a base64url of a SHA256 digest")) + return + } + + if err := testAddresses(r.Context(), peerID, typedBody.Addresses); err != nil { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(fmt.Sprintf("error testing addresses: %s", err))) + return + } + + const ttl = time.Hour + err = c.Datastore.PutWithTTL(r.Context(), datastore.NewKey(peerID.String()), []byte(typedBody.Value), ttl) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(fmt.Sprintf("error storing value: %s", err))) + return + } + w.WriteHeader(http.StatusOK) + }).Methods("POST") + + go func() { http.Serve(c.ln, c.mux) }() + + return nil +} + +func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { + h, err := libp2p.New(libp2p.NoListenAddrs, libp2p.DisableRelay()) + if err != nil { + return err + } + + var mas []multiaddr.Multiaddr + for _, addr := range addrs { + ma, err := multiaddr.NewMultiaddr(addr) + if err != nil { + return err + } + mas = append(mas, ma) + } + + err = h.Connect(ctx, peer.AddrInfo{ID: p, Addrs: mas}) + if err != nil { + return err + } + + // TODO: Do we need to listen on the identify event instead? + // TODO: Where do we want to record this information if anywhere? + var agentVersion string + if v, err := h.Peerstore().Get(p, "AgentVersion"); err == nil { + if vs, ok := v.(string); ok { + agentVersion = vs + } + } + log.Debugf("connected to peer %s - UserAgent: %s", p, agentVersion) + return nil +} + +type requestBody struct { + Value string `json:"value"` + Addresses []string `json:"addresses"` +} + +const signatureDomainString = "peer-forge-domain-challenge" + +var signaturePayloadType []byte = []byte("/peer-forge-domain-challenge") + +// makeUnsigned is a helper function that prepares a buffer to sign or verify. +// It returns a byte slice from a pool. The caller MUST return this slice to the +// pool. +func makeUnsigned(domain string, payloadType []byte, payload []byte) []byte { + var ( + fields = [][]byte{[]byte(domain), payloadType, payload} + + // fields are prefixed with their length as an unsigned varint. we + // compute the lengths before allocating the sig buffer, so we know how + // much space to add for the lengths + flen = make([][]byte, len(fields)) + size = 0 + ) + + for i, f := range fields { + l := len(f) + flen[i] = varint.ToUvarint(uint64(l)) + size += l + len(flen[i]) + } + + b := pool.Get(size) + + var s int + for i, f := range fields { + s += copy(b[s:], flen[i]) + s += copy(b[s:], f) + } + + return b[:s] +} + +func (c *acmeWriter) OnFinalShutdown() error { + if !c.nlSetup { + return nil + } + + c.ln.Close() + c.nlSetup = false + return nil +} + +func (c *acmeWriter) OnReload() error { + if !c.nlSetup { + return nil + } + + c.ln.Close() + c.nlSetup = false + return nil +} diff --git a/client/challenge.go b/client/challenge.go new file mode 100644 index 0000000..69e644b --- /dev/null +++ b/client/challenge.go @@ -0,0 +1,104 @@ +package client + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/record" + "github.com/libp2p/go-libp2p/core/record/pb" + "github.com/multiformats/go-multiaddr" + "google.golang.org/protobuf/proto" +) + +// SendChallenge submits a challenge to the DNS server for the given peerID. +// It requires the corresponding private key and a list of multiaddresses that the peerID is listening on using +// publicly reachable IP addresses. +func SendChallenge(ctx context.Context, baseURL string, peerID peer.ID, privKey crypto.PrivKey, challenge string, addrs []multiaddr.Multiaddr) error { + maStrs := make([]string, len(addrs)) + for i, addr := range addrs { + maStrs[i] = addr.String() + } + var requestBody = &requestRecord{ + Value: challenge, + Addresses: maStrs, + } + + env, err := record.Seal(requestBody, privKey) + if err != nil { + return err + } + envBytes, err := env.Marshal() + if err != nil { + return err + } + + var pbEnv pb.Envelope + if err := proto.Unmarshal(envBytes, &pbEnv); err != nil { + return err + } + authHeader := base64.StdEncoding.EncodeToString(pbEnv.Signature) + pk, err := peerID.ExtractPublicKey() + if err != nil && errors.Is(err, peer.ErrNoPublicKey) { + return err + } + if pk == nil { + pk = env.PublicKey + pkBytes, err := crypto.MarshalPublicKey(pk) + if err != nil { + return err + } + base64EncodedPk := base64.StdEncoding.EncodeToString(pkBytes) + authHeader += "." + base64EncodedPk + } + + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/%s/_acme-challenge", baseURL, peerID), bytes.NewReader(pbEnv.Payload)) + if err != nil { + return err + } + req.Header.Add("Authorization", authHeader) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + respBody, _ := io.ReadAll(resp.Body) + return fmt.Errorf("%s : %s", resp.Status, respBody) + } + return nil +} + +type requestRecord struct { + Value string `json:"value"` + Addresses []string `json:"addresses"` +} + +func (r *requestRecord) Domain() string { + return "peer-forge-domain-challenge" +} + +func (r *requestRecord) Codec() []byte { + return []byte("/peer-forge-domain-challenge") +} + +func (r *requestRecord) MarshalRecord() ([]byte, error) { + out, err := json.Marshal(r) + if err != nil { + return nil, err + } + return out, nil +} + +func (r *requestRecord) UnmarshalRecord(bytes []byte) error { + return json.Unmarshal(bytes, r) +} + +var _ record.Record = (*requestRecord)(nil) diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go new file mode 100644 index 0000000..3b70d87 --- /dev/null +++ b/cmd/e2e_test.go @@ -0,0 +1,352 @@ +package main + +import ( + "context" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "errors" + "fmt" + "net" + "os" + "testing" + + "github.com/coredns/caddy" + "github.com/coredns/coredns/core/dnsserver" + "github.com/ipshipyard/p2p-forge/client" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/miekg/dns" + "github.com/multiformats/go-multibase" + + _ "github.com/coredns/coredns/core/plugin" // Load all managed plugins in github.com/coredns/coredns. + _ "github.com/ipshipyard/p2p-forge/acme" + _ "github.com/ipshipyard/p2p-forge/ipparser" +) + +const forge = "libp2p.direct" + +var dnsServerAddress string +var httpPort int + +func TestMain(m *testing.M) { + tmpDir, err := os.MkdirTemp("", "p2p-forge") + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + defer os.RemoveAll(tmpDir) + + tmpListener, err := net.Listen("tcp", ":0") + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + httpPort = tmpListener.Addr().(*net.TCPAddr).Port + if err := tmpListener.Close(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + dnsserver.Directives = []string{ + "log", + "whoami", + "startup", + "shutdown", + "ipparser", + "acme", + } + + corefile := fmt.Sprintf(`.:0 { + log + ipparser %s + acme %s :%d badger %s + }`, forge, forge, httpPort, tmpDir) + + instance, err := caddy.Start(NewInput(corefile)) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + + dnsServerAddress = instance.Servers()[0].LocalAddr().String() + + m.Run() + + errs := instance.ShutdownCallbacks() + err = errors.Join(errs...) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + if err := instance.Stop(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + instance.Wait() +} + +func TestSetACMEChallenge(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + sk, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + + h, err := libp2p.New(libp2p.Identity(sk)) + if err != nil { + t.Fatal(err) + } + + testDigest := sha256.Sum256([]byte("test")) + testChallenge := base64.RawURLEncoding.EncodeToString(testDigest[:]) + + if err := client.SendChallenge(ctx, fmt.Sprintf("http://127.0.0.1:%d", httpPort), h.ID(), sk, testChallenge, h.Addrs()); err != nil { + t.Fatal(err) + } + + peerIDb36, err := peer.ToCid(h.ID()).StringOfBase(multibase.Base36) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + m.Question = make([]dns.Question, 1) + m.Question[0] = dns.Question{Qclass: dns.ClassINET, Name: fmt.Sprintf("_acme-challenge.%s.%s.", peerIDb36, forge), Qtype: dns.TypeTXT} + + r, err := dns.Exchange(m, dnsServerAddress) + if err != nil { + t.Fatalf("Could not send message: %s", err) + } + if r.Rcode != dns.RcodeSuccess || len(r.Answer) == 0 { + t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) + } + expectedAnswer := fmt.Sprintf(`%s 3600 IN TXT "%s"`, m.Question[0].Name, testChallenge) + if r.Answer[0].String() != expectedAnswer { + t.Fatalf("Expected %s reply, got %s", expectedAnswer, r.Answer[0].String()) + } +} + +func TestIPv4Lookup(t *testing.T) { + _, pk, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + peerID, err := peer.IDFromPublicKey(pk) + if err != nil { + t.Fatal(err) + } + peerIDb36, err := peer.ToCid(peerID).StringOfBase(multibase.Base36) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + qtype uint16 + subdomain string + expectedSuccess bool + expectedAddress string + }{ + { + name: "IPv4-A", + qtype: dns.TypeA, + subdomain: "1-2-3-4", + expectedSuccess: true, + expectedAddress: "1.2.3.4", + }, + { + name: "IPv4-ANY", + qtype: dns.TypeANY, + subdomain: "11-222-33-4", + expectedSuccess: true, + expectedAddress: "11.222.33.4", + }, + { + name: "IPv4-AAAA", + qtype: dns.TypeAAAA, + subdomain: "1-2-3-4", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "InvalidIPv4_1-2-3-4-5", + qtype: dns.TypeANY, + subdomain: "1-2-3-4-5", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "InvalidIPv4_1-2-3", + qtype: dns.TypeANY, + subdomain: "1-2-3", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "InvalidIPv4_1-2-3-444", + qtype: dns.TypeANY, + subdomain: "1-2-3-444", + expectedSuccess: false, + expectedAddress: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := new(dns.Msg) + m.Question = make([]dns.Question, 1) + m.Question[0] = dns.Question{Qclass: dns.ClassINET, Name: fmt.Sprintf("%s.%s.%s.", tt.subdomain, peerIDb36, forge), Qtype: tt.qtype} + + r, err := dns.Exchange(m, dnsServerAddress) + if err != nil { + t.Fatalf("Could not send message: %s", err) + } + + if !tt.expectedSuccess { + if r.Rcode != dns.RcodeServerFailure || len(r.Answer) != 0 { + t.Fatalf("Expected failed reply, got %s and answers %+v", dns.RcodeToString[r.Rcode], r.Answer) + } + return + } + + if r.Rcode != dns.RcodeSuccess || len(r.Answer) == 0 { + t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) + } + expectedAnswer := fmt.Sprintf(`%s 3600 IN A %s`, m.Question[0].Name, tt.expectedAddress) + if r.Answer[0].String() != expectedAnswer { + t.Fatalf("Expected %s reply, got %s", expectedAnswer, r.Answer[0].String()) + } + }) + } +} + +func TestIPv6Lookup(t *testing.T) { + _, pk, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + peerID, err := peer.IDFromPublicKey(pk) + if err != nil { + t.Fatal(err) + } + peerIDb36, err := peer.ToCid(peerID).StringOfBase(multibase.Base36) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + qtype uint16 + subdomain string + expectedSuccess bool + expectedAddress string + }{ + { + name: "A", + qtype: dns.TypeA, + subdomain: "0--1", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "ANY", + qtype: dns.TypeANY, + subdomain: "1234-5678-90AB-CDEF-1-22-33-444", + expectedSuccess: true, + expectedAddress: "1234:5678:90ab:cdef:1:22:33:444", + }, + { + name: "AAAA", + qtype: dns.TypeAAAA, + subdomain: "0--1", + expectedSuccess: true, + expectedAddress: "::1", + }, + { + name: "Invalid_Starting0", + qtype: dns.TypeANY, + subdomain: "--1", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "Invalid_Ending0", + qtype: dns.TypeANY, + subdomain: "0--", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "InvalidIPv6_IPv4Combo", + qtype: dns.TypeANY, + subdomain: "0--1.2.3.4", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "Invalid_TooSmall", + qtype: dns.TypeANY, + subdomain: "1-2-3-4-5-6-7", + expectedSuccess: false, + expectedAddress: "", + }, + { + name: "Invalid_TooBig", + qtype: dns.TypeANY, + subdomain: "1-2-3-4-5-6-7-8-9", + expectedSuccess: false, + expectedAddress: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := new(dns.Msg) + m.Question = make([]dns.Question, 1) + m.Question[0] = dns.Question{Qclass: dns.ClassINET, Name: fmt.Sprintf("%s.%s.%s.", tt.subdomain, peerIDb36, forge), Qtype: tt.qtype} + + r, err := dns.Exchange(m, dnsServerAddress) + if err != nil { + t.Fatalf("Could not send message: %s", err) + } + + if !tt.expectedSuccess { + if r.Rcode != dns.RcodeServerFailure || len(r.Answer) != 0 { + t.Fatalf("Expected failed reply, got %s and answers %+v", dns.RcodeToString[r.Rcode], r.Answer) + } + return + } + + if r.Rcode != dns.RcodeSuccess || len(r.Answer) == 0 { + t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) + } + expectedAnswer := fmt.Sprintf(`%s 3600 IN AAAA %s`, m.Question[0].Name, tt.expectedAddress) + if r.Answer[0].String() != expectedAnswer { + t.Fatalf("Expected %s reply, got %s", expectedAnswer, r.Answer[0].String()) + } + }) + } +} + +// Input implements the caddy.Input interface and acts as an easy way to use a string as a Corefile. +type Input struct { + corefile []byte +} + +// NewInput returns a pointer to Input, containing the corefile string as input. +func NewInput(corefile string) *Input { + return &Input{corefile: []byte(corefile)} +} + +// Body implements the Input interface. +func (i *Input) Body() []byte { return i.corefile } + +// Path implements the Input interface. +func (i *Input) Path() string { return "Corefile" } + +// ServerType implements the Input interface. +func (i *Input) ServerType() string { return "dns" } diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..cb59451 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,27 @@ +package main + +import ( + _ "github.com/coredns/coredns/core/plugin" // Load all managed plugins in github.com/coredns/coredns. + _ "github.com/ipshipyard/p2p-forge/acme" + _ "github.com/ipshipyard/p2p-forge/ipparser" + + "github.com/coredns/coredns/core/dnsserver" + "github.com/coredns/coredns/coremain" +) + +var directives = []string{ + "log", + "whoami", + "startup", + "shutdown", + "ipparser", + "acme", +} + +func init() { + dnsserver.Directives = directives +} + +func main() { + coremain.Run() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ab423be --- /dev/null +++ b/go.mod @@ -0,0 +1,221 @@ +module github.com/ipshipyard/p2p-forge + +go 1.22 + +require ( + github.com/aws/aws-sdk-go v1.51.25 + github.com/coredns/caddy v1.1.1 + github.com/coredns/coredns v1.11.3 + github.com/gorilla/mux v1.8.1 + github.com/ipfs/go-datastore v0.6.0 + github.com/ipfs/go-ds-badger4 v0.1.5 + github.com/ipfs/go-ds-dynamodb v0.1.1 + github.com/libp2p/go-buffer-pool v0.1.0 + github.com/libp2p/go-libp2p v0.36.1 + github.com/miekg/dns v1.1.61 + github.com/multiformats/go-multiaddr v0.13.0 + github.com/multiformats/go-multibase v0.2.0 + github.com/multiformats/go-varint v0.0.7 + google.golang.org/protobuf v1.34.2 +) + +require ( + cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.29 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.2.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/DataDog/appsec-internal-go v1.5.0 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.1 // indirect + github.com/DataDog/datadog-go/v5 v5.3.0 // indirect + github.com/DataDog/go-libddwaf/v2 v2.3.2 // indirect + github.com/DataDog/go-tuf v1.0.2-0.5.2 // indirect + github.com/DataDog/sketches-go v1.4.2 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/antonmedv/expr v1.15.5 // indirect + github.com/apparentlymart/go-cidr v1.1.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/coreos/go-semver v0.3.0 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/dgraph-io/badger/v4 v4.2.0 // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/dnstap/golang-dnstap v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/ebitengine/purego v0.6.0-alpha.5 // indirect + github.com/elastic/gosigar v0.14.3 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/farsightsec/golang-framestream v0.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect + github.com/flynn/noise v1.1.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/glog v1.2.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/flatbuffers v1.12.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 // indirect + github.com/ipfs/go-cid v0.4.1 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect + github.com/jbenet/goprocess v0.1.4 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/koron/go-ssdp v0.0.4 // indirect + github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect + github.com/libp2p/go-msgio v0.3.0 // indirect + github.com/libp2p/go-nat v0.2.0 // indirect + github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.1.0 // indirect + github.com/multiformats/go-base36 v0.2.0 // indirect + github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multicodec v0.9.0 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/onsi/ginkgo/v2 v2.19.1 // indirect + github.com/opencontainers/runtime-spec v1.2.0 // indirect + github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 // indirect + github.com/openzipkin/zipkin-go v0.4.2 // indirect + github.com/oschwald/geoip2-golang v1.9.0 // indirect + github.com/oschwald/maxminddb-golang v1.11.0 // indirect + github.com/outcaste-io/ristretto v0.2.3 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/philhofer/fwd v1.1.2 // indirect + github.com/pion/datachannel v1.5.8 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/ice/v2 v2.3.32 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.8 // indirect + github.com/pion/sctp v1.8.20 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.20 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.9 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.50 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/quic-go v0.45.2 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect + github.com/raulk/go-watchdog v1.3.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/tinylib/msgp v1.1.8 // indirect + github.com/wlynxg/anet v0.0.3 // indirect + go.etcd.io/etcd/api/v3 v3.5.12 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect + go.etcd.io/etcd/client/v3 v3.5.12 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/dig v1.17.1 // indirect + go.uber.org/fx v1.22.1 // indirect + go.uber.org/mock v0.4.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.23.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.172.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.63.2 // indirect + gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.3 // indirect + k8s.io/apimachinery v0.29.3 // indirect + k8s.io/client-go v0.29.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + lukechampine.com/blake3 v1.3.0 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c5655e7 --- /dev/null +++ b/go.sum @@ -0,0 +1,873 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.22 h1:/GblQdIudfEM3AWWZ0mrYJQSd7JS4S/Mbzh6F0ov0Xc= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 h1:0W/yGmFdTIT77fvdlGZ0LMISoLHFJ7Tx4U0yeB+uFs4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.2.0 h1:nQOZzFCudTh+TvquAtCRjM01VEYx85e9qbwt5ncW4L8= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DataDog/appsec-internal-go v1.5.0 h1:8kS5zSx5T49uZ8dZTdT19QVAvC/B8ByyZdhQKYQWHno= +github.com/DataDog/appsec-internal-go v1.5.0/go.mod h1:pEp8gjfNLtEOmz+iZqC8bXhu0h4k7NUsW/qiQb34k1U= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0 h1:bUMSNsw1iofWiju9yc1f+kBd33E3hMJtq9GuU602Iy8= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.48.0/go.mod h1:HzySONXnAgSmIQfL6gOv9hWprKJkx8CicuXuUbmgWfo= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.1 h1:5nE6N3JSs2IG3xzMthNFhXfOaXlrsdgqmJ73lndFf8c= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.48.1/go.mod h1:Vc+snp0Bey4MrrJyiV2tVxxJb6BmLomPvN1RgAvjGaQ= +github.com/DataDog/datadog-go/v5 v5.3.0 h1:2q2qjFOb3RwAZNU+ez27ZVDwErJv5/VpbBPprz7Z+s8= +github.com/DataDog/datadog-go/v5 v5.3.0/go.mod h1:XRDJk1pTc00gm+ZDiBKsjh7oOOtJfYfglVCmFb8C2+Q= +github.com/DataDog/go-libddwaf/v2 v2.3.2 h1:pdi9xjWW57IpOpTeOyPuNveEDFLmmInsHDeuZk3TY34= +github.com/DataDog/go-libddwaf/v2 v2.3.2/go.mod h1:gsCdoijYQfj8ce/T2bEDNPZFIYnmHluAgVDpuQOWMZE= +github.com/DataDog/go-tuf v1.0.2-0.5.2 h1:EeZr937eKAWPxJ26IykAdWA4A0jQXJgkhUjqEI/w7+I= +github.com/DataDog/go-tuf v1.0.2-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= +github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= +github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= +github.com/DataDog/sketches-go v1.4.2 h1:gppNudE9d19cQ98RYABOetxIhpTCl4m7CnbRZjvVA/o= +github.com/DataDog/sketches-go v1.4.2/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra7H1KMgpgkLk= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antonmedv/expr v1.15.5 h1:y0Iz3cEwmpRz5/r3w4qQR0MfIqJGdGM1zbhD/v0G5Vg= +github.com/antonmedv/expr v1.15.5/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= +github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= +github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/aws/aws-sdk-go v1.43.1/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.51.25 h1:DjTT8mtmsachhV6yrXR8+yhnG6120dazr720nopRsls= +github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= +github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= +github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= +github.com/coredns/coredns v1.11.3 h1:8RjnpZc42db5th84/QJKH2i137ecJdzZK1HJwhetSPk= +github.com/coredns/coredns v1.11.3/go.mod h1:lqFkDsHjEUdY7LJ75Nib3lwqJGip6ewWOqNIf8OavIQ= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= +github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/dnstap/golang-dnstap v0.4.0 h1:KRHBoURygdGtBjDI2w4HifJfMAhhOqDuktAokaSa234= +github.com/dnstap/golang-dnstap v0.4.0/go.mod h1:FqsSdH58NAmkAvKcpyxht7i4FoBjKu8E4JUPt8ipSUs= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/ebitengine/purego v0.6.0-alpha.5 h1:EYID3JOAdmQ4SNZYJHu9V6IqOeRQDBYxqKAg9PyoHFY= +github.com/ebitengine/purego v0.6.0-alpha.5/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo= +github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA= +github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 h1:w66aaP3c6SIQ0pi3QH1Tb4AMO3aWoEPxd1CNvLphbkA= +github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9/go.mod h1:BaIJzjD2ZnHmx2acPF6XfGLPzNCMiBbMRqJr+8/8uRI= +github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= +github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger4 v0.1.5 h1:MwrTsIUJIqH/ChuDdUOzxwxMxHx/Li1ECoSCKsCUxiA= +github.com/ipfs/go-ds-badger4 v0.1.5/go.mod h1:LUU2FbhNdmhAbJmMeoahVRbe4GsduAODSJHWJJh2Vo4= +github.com/ipfs/go-ds-dynamodb v0.1.1 h1:636i0Gl8j9wuKfw4gZKTH/fOch5WLWDu0OYrlBTE/0g= +github.com/ipfs/go-ds-dynamodb v0.1.1/go.mod h1:JG3C8nDcZMer7hKUVDT1wKY9LdD7TAX0psPSC7R/BrE= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= +github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= +github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= +github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= +github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= +github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= +github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= +github.com/libp2p/go-libp2p v0.36.1 h1:piAHesy0/8ifBEBUS8HF2m7ywR5vnktUFv00dTsVKcs= +github.com/libp2p/go-libp2p v0.36.1/go.mod h1:vHzel3CpRB+vS11fIjZSJAU4ALvieKV9VZHC9VerHj8= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= +github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= +github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= +github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= +github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= +github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= +github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= +github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +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/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= +github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= +github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= +github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= +github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= +github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10Siffyepr6SvlKbUsjH5JpNCRi8= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= +github.com/openzipkin/zipkin-go v0.4.2/go.mod h1:ZeVkFjuuBiSy13y8vpSDCjMi9GoI3hPpCJSBx/EYFhY= +github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= +github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= +github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= +github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= +github.com/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0= +github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= +github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= +github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.32 h1:VwE/uEeqiMm0zUWpdt1DJtnqEkj3UjEbhX92/CurtWI= +github.com/pion/ice/v2 v2.3.32/go.mod h1:8fac0+qftclGy1tYd/nfwfHC729BLaxtVqMdMVCAVPU= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.8 h1:EtYFHI0rpUEjT/RMnGfb1vdJhbYmPG77szD72uUnSxs= +github.com/pion/rtp v1.8.8/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.20 h1:sOc3lkV/tQaP57ZUEXIMdM2V92IIB2ia5v/ygnBxaEg= +github.com/pion/sctp v1.8.20/go.mod h1:oTxw8i5m+WbDHZJL/xUpe6CPIn1Y0GIKKwTLF4h53H8= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= +github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.8/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v2 v2.2.9 h1:WEDygVovkJlV2CCunM9KS2kds+kcl7zdIefQA5y/nkE= +github.com/pion/transport/v2 v2.2.9/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.6 h1:k1mQU06bmmX143qSWgXFqSH1KUJceQvIUuVH/K5ELWw= +github.com/pion/transport/v3 v3.0.6/go.mod h1:HvJr2N/JwNJAfipsRleqwFoR3t/pWyHeZUs89v3+t5s= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.50 h1:C/rwL2mBfCxHv6tlLzDAO3krJpQXfVx8A8WHnGJ2j34= +github.com/pion/webrtc/v3 v3.2.50/go.mod h1:dytYYoSBy7ZUWhJMbndx9UckgYvzNAfL7xgVnrIKxqo= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/quic-go v0.45.2 h1:DfqBmqjb4ExSdxRIb/+qXhPC+7k6+DUNZha4oeiC9fY= +github.com/quic-go/quic-go v0.45.2/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= +github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= +github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= +github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg= +github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= +go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= +go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= +go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= +go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys= +go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/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.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +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= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.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.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +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= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +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= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/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.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk= +google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 h1:jeZxE4ZlfAc+R0zO5TEmJBwOLet3NThsOfYJeSQg1x0= +gopkg.in/DataDog/dd-trace-go.v1 v1.62.0/go.mod h1:YTvYkk3PTsfw0OWrRFxV/IQ5Gy4nZ5TRvxTAP3JcIzs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/gotraceui v0.2.0 h1:dmNsfQ9Vl3GwbiVD7Z8d/osC6WtGGrasyrC2suc4ZIQ= +honnef.co/go/gotraceui v0.2.0/go.mod h1:qHo4/W75cA3bX0QQoSvDjbJa4R8mAyyFjbWAj63XElc= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/ipparser/plugin.go b/ipparser/plugin.go new file mode 100644 index 0000000..a9f6731 --- /dev/null +++ b/ipparser/plugin.go @@ -0,0 +1,134 @@ +package ipparser + +import ( + "context" + "net" + "strings" + "time" + + "github.com/coredns/caddy" + "github.com/coredns/coredns/core/dnsserver" + "github.com/coredns/coredns/plugin" + "github.com/miekg/dns" + + "github.com/libp2p/go-libp2p/core/peer" +) + +const pluginName = "ipparser" + +func init() { plugin.Register(pluginName, setup) } + +func setup(c *caddy.Controller) error { + c.Next() + + var forgeDomain string + if c.NextArg() { + forgeDomain = c.Val() + } + if c.NextArg() { + // If there was another token, return an error, because we don't have any configuration. + // Any errors returned from this setup function should be wrapped with plugin.Error, so we + // can present a slightly nicer error message to the user. + return plugin.Error(pluginName, c.ArgErr()) + } + + // Add the Plugin to CoreDNS, so Servers can use it in their plugin chain. + dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { + return ipParser{Next: next, ForgeDomain: forgeDomain} + }) + + return nil +} + +type ipParser struct { + Next plugin.Handler + ForgeDomain string +} + +const ttl = 1 * time.Hour + +// ServeDNS implements the plugin.Handler interface. +func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { + var answers []dns.RR + for _, q := range r.Question { + if q.Qtype != dns.TypeA && q.Qtype != dns.TypeAAAA && q.Qtype != dns.TypeANY { + continue + } + + subdomain := strings.TrimSuffix(q.Name, "."+p.ForgeDomain+".") + if len(subdomain) == len(q.Name) || len(subdomain) == 0 { + continue + } + + domainSegments := strings.Split(subdomain, ".") + if len(domainSegments) != 2 { + continue + } + + peerIDStr := domainSegments[1] + _, err := peer.Decode(peerIDStr) + if err != nil { + continue + } + + prefix := domainSegments[0] + segments := strings.Split(prefix, "-") + if len(segments) == 4 && (q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY) { + ipStr := strings.Join(segments, ".") + ip := net.ParseIP(ipStr) + if ip == nil { + continue + } + answers = append(answers, &dns.A{ + Hdr: dns.RR_Header{ + Name: dns.Fqdn(q.Name), + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: uint32(ttl.Seconds()), + }, + A: ip, + }) + continue + } + + if !(q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY) { + continue + } + + // - is not a valid first or last character https://datatracker.ietf.org/doc/html/rfc1123#section-2 + if prefix[0] == '-' || prefix[len(prefix)-1] == '-' { + continue + } + + prefixAsIpv6 := strings.Join(segments, ":") + ip := net.ParseIP(prefixAsIpv6) + if ip == nil { + continue + } + + answers = append(answers, &dns.AAAA{ + Hdr: dns.RR_Header{ + Name: dns.Fqdn(q.Name), + Rrtype: dns.TypeAAAA, + Class: dns.ClassINET, + Ttl: uint32(ttl.Seconds()), + }, + AAAA: ip, + }) + } + + if len(answers) > 0 { + var m dns.Msg + m.SetReply(r) + m.Authoritative = true + m.Answer = answers + w.WriteMsg(&m) + return dns.RcodeSuccess, nil + } + + // Call next plugin (if any). + return plugin.NextOrFailure(p.Name(), p.Next, ctx, w, r) +} + +// Name implements the Handler interface. +func (p ipParser) Name() string { return pluginName } From 0ddd505efdbf861ed5f270a289e4394523d824af Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 16 Aug 2024 17:11:06 -0400 Subject: [PATCH 02/61] ci: add workflows --- .github/workflows/go-check.yml | 18 ++++++++++++++++++ .github/workflows/go-test-config.json | 3 +++ .github/workflows/go-test.yml | 22 ++++++++++++++++++++++ .github/workflows/release-check.yml | 19 +++++++++++++++++++ .github/workflows/releaser.yml | 17 +++++++++++++++++ .github/workflows/tagpush.yml | 18 ++++++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 .github/workflows/go-check.yml create mode 100644 .github/workflows/go-test-config.json create mode 100644 .github/workflows/go-test.yml create mode 100644 .github/workflows/release-check.yml create mode 100644 .github/workflows/releaser.yml create mode 100644 .github/workflows/tagpush.yml diff --git a/.github/workflows/go-check.yml b/.github/workflows/go-check.yml new file mode 100644 index 0000000..232775d --- /dev/null +++ b/.github/workflows/go-check.yml @@ -0,0 +1,18 @@ +name: Go Checks + +on: + pull_request: + push: + branches: ["main"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + go-check: + uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 diff --git a/.github/workflows/go-test-config.json b/.github/workflows/go-test-config.json new file mode 100644 index 0000000..699fa72 --- /dev/null +++ b/.github/workflows/go-test-config.json @@ -0,0 +1,3 @@ +{ + "skip32bit": true +} diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml new file mode 100644 index 0000000..7af2d4f --- /dev/null +++ b/.github/workflows/go-test.yml @@ -0,0 +1,22 @@ +name: Go Test + +on: + pull_request: + push: + branches: ["main"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + go-test: + uses: ipdxco/unified-github-workflows/.github/workflows/go-test.yml@v1.0 + with: + go-versions: '["this"]' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml new file mode 100644 index 0000000..0b5ff60 --- /dev/null +++ b/.github/workflows/release-check.yml @@ -0,0 +1,19 @@ +name: Release Checker + +on: + pull_request_target: + paths: [ 'version.json' ] + types: [ opened, synchronize, reopened, labeled, unlabeled ] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release-check: + uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml new file mode 100644 index 0000000..2ebdbed --- /dev/null +++ b/.github/workflows/releaser.yml @@ -0,0 +1,17 @@ +name: Releaser + +on: + push: + paths: [ 'version.json' ] + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: true + +jobs: + releaser: + uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 diff --git a/.github/workflows/tagpush.yml b/.github/workflows/tagpush.yml new file mode 100644 index 0000000..5ef3fb9 --- /dev/null +++ b/.github/workflows/tagpush.yml @@ -0,0 +1,18 @@ +name: Tag Push Checker + +on: + push: + tags: + - v* + +permissions: + contents: read + issues: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + releaser: + uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 From 6566eb546ed45adc6426a5a851da7f1f8445a690 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 22 Aug 2024 11:10:50 -0400 Subject: [PATCH 03/61] feat: add acme client hook for libp2p --- client/acme.go | 284 +++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 7 +- go.sum | 15 +++ 3 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 client/acme.go diff --git a/client/acme.go b/client/acme.go new file mode 100644 index 0000000..90d8c91 --- /dev/null +++ b/client/acme.go @@ -0,0 +1,284 @@ +package client + +import ( + "context" + "crypto/x509" + "fmt" + "net" + "strings" + "sync" + "time" + + "github.com/caddyserver/certmagic" + logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" + "github.com/libp2p/go-libp2p/core/peer" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/tcp" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" + libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" + "github.com/mholt/acmez/v2" + "github.com/mholt/acmez/v2/acme" + "github.com/multiformats/go-multiaddr" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/multiformats/go-multibase" +) + +var log = logging.Logger("p2p-forge/client") + +type P2PForgeCertMgr struct { + forgeDomain string + forgeRegistrationEndpoint string + cfg *certmagic.Config + h *hostWrapper +} + +type hostWrapper struct { + host.Host +} + +type hostCloseWrapper struct { + host.Host + closeFn func() error +} + +func (h hostCloseWrapper) Close() error { + return h.closeFn() +} + +func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool, onCertLoaded func(), allowPrivateForgeAddrs bool, opts ...libp2p.Option) (host.Host, error) { + certMgr := NewP2PForgeCertMgt(forgeDomain, forgeRegistrationEndpoint, caEndpoint, userEmail, trustedRoots) + tlsCfg := certMgr.cfg.TLSConfig() + tlsCfg.NextProtos = nil // remove the ACME ALPN + + var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) + + var h host.Host + var mx sync.RWMutex + // TODO: Option passing mechanism here isn't respectful of which transports the user wants to support or the addresses they want to listen on + hTmp, err := libp2p.New(libp2p.ChainOptions(libp2p.ChainOptions(opts...), + libp2p.DefaultListenAddrs, + libp2p.ListenAddrStrings([]string{ // TODO: Grab these addresses from a TCP listener and share the ports + fmt.Sprintf("/ip4/0.0.0.0/tcp/0/tls/sni/*.%s/ws", forgeDomain), + fmt.Sprintf("/ip6/::/tcp/0/tls/sni/*.%s/ws", forgeDomain), + }...), + libp2p.Transport(tcp.NewTCPTransport), + libp2p.Transport(libp2pquic.NewTransport), + libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(tlsCfg)), + libp2p.Transport(libp2pwebtransport.New), + libp2p.Transport(libp2pwebrtc.New), + libp2p.AddrsFactory(func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + mx.RLock() + if h == nil { + mx.RUnlock() + return multiaddrs + } + mx.RUnlock() + + retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) + for i, a := range multiaddrs { + if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { + retAddrs[i] = a + continue + } + + // We expect the address to be of the form: /ipX//tcp//tls/sni/*./ws + // We'll then replace the * with the IP address + withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) + if withoutForgeWSS.Equal(a) { + retAddrs[i] = a + continue + } + + index := 0 + var escapedIPStr string + var ipMaStr string + var tcpPortStr string + multiaddr.ForEach(withoutForgeWSS, func(c multiaddr.Component) bool { + switch index { + case 0: + switch c.Protocol().Code { + case multiaddr.P_IP4: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ".", "-") + case multiaddr.P_IP6: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ":", "-") + if escapedIPStr[0] == '-' { + escapedIPStr = "0" + escapedIPStr + } + if escapedIPStr[len(escapedIPStr)-1] == '-' { + escapedIPStr = escapedIPStr + "0" + } + default: + return false + } + case 1: + if c.Protocol().Code != multiaddr.P_TCP { + return false + } + tcpPortStr = c.Value() + default: + index++ + return false + } + index++ + return true + }) + if index != 2 || escapedIPStr == "" || tcpPortStr == "" { + retAddrs[i] = a + continue + } + + pidStr := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) + + newMaStr := fmt.Sprintf("%s/tcp/%s/tls/sni/%s.%s.%s/ws", ipMaStr, tcpPortStr, escapedIPStr, pidStr, forgeDomain) + newMA, err := multiaddr.NewMultiaddr(newMaStr) + if err != nil { + log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) + retAddrs[i] = a + continue + } + retAddrs[i] = newMA + } + return retAddrs + }), + )) + if err != nil { + return nil, err + } + mx.Lock() + h = hTmp + mx.Unlock() + + ctx, cancel := context.WithCancel(context.Background()) + if err := certMgr.Run(ctx, h); err != nil { + cancel() + return nil, err + } + + w := &hostCloseWrapper{Host: h, closeFn: func() error { + cancel() + err := h.Close() + return err + }} + + if onCertLoaded != nil { + pidStr := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) + certName := fmt.Sprintf("*.%s.%s", pidStr, forgeDomain) + _ = certName + certMgr.cfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { + if event == "cached_managed_cert" { + sans, ok := data["sans"] + if !ok { + return nil + } + sanList, ok := sans.([]string) + if !ok { + return nil + } + for _, san := range sanList { + if san == certName { + onCertLoaded() + } + } + return nil + } + return nil + } + } + + return w, nil +} + +func isRelayAddr(a multiaddr.Multiaddr) bool { + found := false + multiaddr.ForEach(a, func(c multiaddr.Component) bool { + found = c.Protocol().Code == multiaddr.P_CIRCUIT + return !found + }) + return found +} + +var publicCIDR6 = "2000::/3" +var public6 *net.IPNet + +func init() { + _, public6, _ = net.ParseCIDR(publicCIDR6) +} + +// isPublicAddr follows the logic of manet.IsPublicAddr, except it uses +// a stricter definition of "public" for ipv6: namely "is it in 2000::/3"? +func isPublicAddr(a multiaddr.Multiaddr) bool { + ip, err := manet.ToIP(a) + if err != nil { + return false + } + if ip.To4() != nil { + return !inAddrRange(ip, manet.Private4) && !inAddrRange(ip, manet.Unroutable4) + } + + return public6.Contains(ip) +} + +func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { + for _, ipnet := range ipnets { + if ipnet.Contains(ip) { + return true + } + } + + return false +} + +func NewP2PForgeCertMgt(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool) *P2PForgeCertMgr { + cfg := certmagic.NewDefault() + cfg.Storage = &certmagic.FileStorage{Path: "foo"} + h := &hostWrapper{} + myACME := certmagic.NewACMEIssuer(cfg, certmagic.ACMEIssuer{ // TODO: UX around user passed emails + agreement + CA: caEndpoint, // TODO: Switch to real CA by default + Email: userEmail, + Agreed: true, + DNS01Solver: &dns01P2PForgeSolver{forgeRegistrationEndpoint, h}, + TrustedRoots: trustedRoots, + }) + cfg.Issuers = []certmagic.Issuer{myACME} + return &P2PForgeCertMgr{forgeDomain, forgeRegistrationEndpoint, cfg, h} +} + +func (m *P2PForgeCertMgr) Run(ctx context.Context, h host.Host) error { + m.h.Host = h + pb36 := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) + + if err := m.cfg.ManageAsync(ctx, []string{fmt.Sprintf("*.%s.%s", pb36, m.forgeDomain)}); err != nil { + return err + } + return nil +} + +type dns01P2PForgeSolver struct { + forge string + host host.Host +} + +func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge) error { + // TODO: query the authoritative DNS + time.Sleep(time.Second * 5) + return nil +} + +func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { + return SendChallenge(ctx, d.forge, d.host.ID(), d.host.Peerstore().PrivKey(d.host.ID()), challenge.DNS01KeyAuthorization(), d.host.Addrs()) +} + +func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error { + //TODO: Should we implement this, or is doing delete and Last-Writer-Wins enough? + return nil +} + +var _ acmez.Solver = (*dns01P2PForgeSolver)(nil) +var _ acmez.Waiter = (*dns01P2PForgeSolver)(nil) diff --git a/go.mod b/go.mod index ab423be..9548365 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,17 @@ go 1.22 require ( github.com/aws/aws-sdk-go v1.51.25 + github.com/caddyserver/certmagic v0.21.3 github.com/coredns/caddy v1.1.1 github.com/coredns/coredns v1.11.3 github.com/gorilla/mux v1.8.1 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger4 v0.1.5 github.com/ipfs/go-ds-dynamodb v0.1.1 + github.com/ipfs/go-log/v2 v2.5.1 github.com/libp2p/go-buffer-pool v0.1.0 github.com/libp2p/go-libp2p v0.36.1 + github.com/mholt/acmez/v2 v2.0.1 github.com/miekg/dns v1.1.61 github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multibase v0.2.0 @@ -43,6 +46,7 @@ require ( github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/caddyserver/zerossl v0.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect @@ -95,7 +99,6 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 // indirect github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect @@ -105,6 +108,7 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/koron/go-ssdp v0.0.4 // indirect + github.com/libdns/libdns v0.2.2 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect @@ -174,6 +178,7 @@ require ( github.com/stretchr/testify v1.9.0 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/wlynxg/anet v0.0.3 // indirect + github.com/zeebo/blake3 v0.2.3 // indirect go.etcd.io/etcd/api/v3 v3.5.12 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect go.etcd.io/etcd/client/v3 v3.5.12 // indirect diff --git a/go.sum b/go.sum index c5655e7..920aa81 100644 --- a/go.sum +++ b/go.sum @@ -71,6 +71,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= +github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI= +github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= +github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -297,6 +301,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= @@ -311,6 +316,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= @@ -343,6 +350,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= +github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -562,6 +571,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= +github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= +github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= From d1a0b6e9eb8acf7a6f65d581f5662386e73642a2 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 28 Aug 2024 13:23:27 -0400 Subject: [PATCH 04/61] test: add more complete e2e testing --- cmd/e2e_test.go | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 +- go.sum | 7 ++ 3 files changed, 177 insertions(+), 1 deletion(-) diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 3b70d87..9459fad 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -2,14 +2,28 @@ package main import ( "context" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" "crypto/sha256" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" "encoding/base64" + "encoding/pem" "errors" "fmt" + libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" + "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" + "log" + "math/big" "net" + "net/http" "os" + "strings" "testing" + "time" "github.com/coredns/caddy" "github.com/coredns/coredns/core/dnsserver" @@ -23,6 +37,11 @@ import ( _ "github.com/coredns/coredns/core/plugin" // Load all managed plugins in github.com/coredns/coredns. _ "github.com/ipshipyard/p2p-forge/acme" _ "github.com/ipshipyard/p2p-forge/ipparser" + + pebbleCA "github.com/letsencrypt/pebble/v2/ca" + pebbleDB "github.com/letsencrypt/pebble/v2/db" + pebbleVA "github.com/letsencrypt/pebble/v2/va" + pebbleWFE "github.com/letsencrypt/pebble/v2/wfe" ) const forge = "libp2p.direct" @@ -332,6 +351,153 @@ func TestIPv6Lookup(t *testing.T) { } } +func TestLibp2pACMEE2E(t *testing.T) { + db := pebbleDB.NewMemoryStore() + logger := log.New(os.Stdout, "", 0) + ca := pebbleCA.New(logger, db, "", 0, 1, 0) + va := pebbleVA.New(logger, 0, 0, false, dnsServerAddress, db) + + wfeImpl := pebbleWFE.New(logger, db, va, ca, false, false, 3, 5) + muxHandler := wfeImpl.Handler() + + acmeHTTPListener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + defer acmeHTTPListener.Close() + + // Generate the self-signed certificate and private key + certPEM, privPEM, err := generateSelfSignedCert("127.0.0.1") + if err != nil { + log.Fatalf("Failed to generate self-signed certificate: %v", err) + } + + // Load the certificate and key into tls.Certificate + cert, err := tls.X509KeyPair(certPEM, privPEM) + if err != nil { + log.Fatalf("Failed to load key pair: %v", err) + } + + // Create a TLS configuration with the certificate + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + + // Wrap the listener with TLS + acmeHTTPListener = tls.NewListener(acmeHTTPListener, tlsConfig) + + go func() { + http.Serve(acmeHTTPListener, muxHandler) + }() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cas := x509.NewCertPool() + cas.AppendCertsFromPEM(certPEM) + + acmeEndpoint := fmt.Sprintf("https://%s%s", acmeHTTPListener.Addr(), pebbleWFE.DirectoryPath) + certLoaded := make(chan bool, 1) + h, err := client.NewHostWithP2PForge(forge, fmt.Sprintf("http://127.0.0.1:%d", httpPort), acmeEndpoint, "foo@bar.com", cas, func() { + certLoaded <- true + }, true) + if err != nil { + t.Fatal(err) + } + + cp := x509.NewCertPool() + cp.AddCert(ca.GetRootCert(0).Cert) + tlsCfgWithTestCA := &tls.Config{RootCAs: cp} + + localDnsResolver, err := madns.NewResolver(madns.WithDefaultResolver(&net.Resolver{ + PreferGo: true, + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { + d := net.Dialer{ + Timeout: time.Second * 5, // Set a timeout for the connection + } + return d.DialContext(ctx, network, dnsServerAddress) + }, + })) + if err != nil { + t.Fatal(err) + } + customResolver, err := madns.NewResolver(madns.WithDomainResolver("libp2p.direct.", localDnsResolver)) + if err != nil { + t.Fatal(err) + } + + h2, err := libp2p.New(libp2p.Transport(libp2pws.New, libp2pws.WithTLSClientConfig(tlsCfgWithTestCA)), + libp2p.MultiaddrResolver(customResolver)) + if err != nil { + t.Fatal(err) + } + + var dialAddr multiaddr.Multiaddr + hAddrs := h.Addrs() + for _, addr := range hAddrs { + as := addr.String() + if strings.Contains(as, "p2p-circuit") { + continue + } + if strings.Contains(as, "libp2p.direct/ws") { + dialAddr = addr + break + } + } + if dialAddr == nil { + t.Fatalf("no valid wss addresses: %v", hAddrs) + } + + select { + case <-certLoaded: + case <-time.After(time.Second * 30): + t.Fatal("timed out waiting for certificate") + } + + if err := h2.Connect(ctx, peer.AddrInfo{ID: h.ID(), Addrs: []multiaddr.Multiaddr{dialAddr}}); err != nil { + t.Fatal(err) + } +} + +func generateSelfSignedCert(ipAddr string) ([]byte, []byte, error) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, err + } + + serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + if err != nil { + return nil, nil, err + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"My Organization"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), // Valid for 1 year + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + IPAddresses: []net.IP{net.ParseIP(ipAddr)}, + } + + certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return nil, nil, err + } + + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) + privDER, err := x509.MarshalECPrivateKey(priv) + if err != nil { + return nil, nil, err + } + privPEM := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: privDER}) + + return certPEM, privPEM, nil +} + // Input implements the caddy.Input interface and acts as an easy way to use a string as a Corefile. type Input struct { corefile []byte diff --git a/go.mod b/go.mod index 9548365..ec6a7c7 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,13 @@ require ( github.com/ipfs/go-ds-badger4 v0.1.5 github.com/ipfs/go-ds-dynamodb v0.1.1 github.com/ipfs/go-log/v2 v2.5.1 + github.com/letsencrypt/pebble/v2 v2.6.0 github.com/libp2p/go-buffer-pool v0.1.0 github.com/libp2p/go-libp2p v0.36.1 github.com/mholt/acmez/v2 v2.0.1 github.com/miekg/dns v1.1.61 github.com/multiformats/go-multiaddr v0.13.0 + github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-varint v0.0.7 google.golang.org/protobuf v1.34.2 @@ -68,6 +70,7 @@ require ( github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -108,6 +111,7 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/koron/go-ssdp v0.0.4 // indirect + github.com/letsencrypt/challtestsrv v1.3.2 // indirect github.com/libdns/libdns v0.2.2 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect @@ -129,7 +133,6 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect diff --git a/go.sum b/go.sum index 920aa81..eeccb62 100644 --- a/go.sum +++ b/go.sum @@ -151,6 +151,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= +github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -316,6 +318,10 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/letsencrypt/challtestsrv v1.3.2 h1:pIDLBCLXR3B1DLmOmkkqg29qVa7DDozBnsOpL9PxmAY= +github.com/letsencrypt/challtestsrv v1.3.2/go.mod h1:Ur4e4FvELUXLGhkMztHOsPIsvGxD/kzSJninOrkM+zc= +github.com/letsencrypt/pebble/v2 v2.6.0 h1:7xetaJ4YaesUnWWeRGSs3UHOwyfX4I4sfOfDrkvnhNw= +github.com/letsencrypt/pebble/v2 v2.6.0/go.mod h1:SID2E75Cx6sQ9AXFkdzhLdQ6S1zhRUbw08Cgu7GJLSk= github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= @@ -355,6 +361,7 @@ github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGo github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= From c7e589213e626050671dff7b1e8c6efff4a62861 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 29 Aug 2024 15:56:39 -0400 Subject: [PATCH 05/61] fix: add HTTP 2 and 1.1 ALPNs --- client/acme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/acme.go b/client/acme.go index 90d8c91..6b064cd 100644 --- a/client/acme.go +++ b/client/acme.go @@ -51,7 +51,7 @@ func (h hostCloseWrapper) Close() error { func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool, onCertLoaded func(), allowPrivateForgeAddrs bool, opts ...libp2p.Option) (host.Host, error) { certMgr := NewP2PForgeCertMgt(forgeDomain, forgeRegistrationEndpoint, caEndpoint, userEmail, trustedRoots) tlsCfg := certMgr.cfg.TLSConfig() - tlsCfg.NextProtos = nil // remove the ACME ALPN + tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) From bc873f68e33509e7070052807a2073983ef3b01a Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 30 Aug 2024 13:03:49 -0400 Subject: [PATCH 06/61] chore: update go-libp2p --- go.mod | 8 ++++---- go.sum | 17 ++++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index ec6a7c7..1eec860 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 github.com/libp2p/go-buffer-pool v0.1.0 - github.com/libp2p/go-libp2p v0.36.1 + github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa github.com/mholt/acmez/v2 v2.0.1 github.com/miekg/dns v1.1.61 github.com/multiformats/go-multiaddr v0.13.0 @@ -151,7 +151,7 @@ require ( github.com/philhofer/fwd v1.1.2 // indirect github.com/pion/datachannel v1.5.8 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/ice/v2 v2.3.32 // indirect + github.com/pion/ice/v2 v2.3.34 // indirect github.com/pion/interceptor v0.1.29 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect @@ -162,9 +162,9 @@ require ( github.com/pion/sdp/v3 v3.0.9 // indirect github.com/pion/srtp/v2 v2.0.20 // indirect github.com/pion/stun v0.6.1 // indirect - github.com/pion/transport/v2 v2.2.9 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.50 // indirect + github.com/pion/webrtc/v3 v3.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.19.1 // indirect diff --git a/go.sum b/go.sum index eeccb62..ebf920e 100644 --- a/go.sum +++ b/go.sum @@ -328,8 +328,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.36.1 h1:piAHesy0/8ifBEBUS8HF2m7ywR5vnktUFv00dTsVKcs= -github.com/libp2p/go-libp2p v0.36.1/go.mod h1:vHzel3CpRB+vS11fIjZSJAU4ALvieKV9VZHC9VerHj8= +github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa h1:fpHzZMdrj/X7HrqoD1yPY56YTlIlX7l3d0sSraekjJQ= +github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -444,8 +444,8 @@ github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.32 h1:VwE/uEeqiMm0zUWpdt1DJtnqEkj3UjEbhX92/CurtWI= -github.com/pion/ice/v2 v2.3.32/go.mod h1:8fac0+qftclGy1tYd/nfwfHC729BLaxtVqMdMVCAVPU= +github.com/pion/ice/v2 v2.3.34 h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM= +github.com/pion/ice/v2 v2.3.34/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -471,17 +471,16 @@ github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/ github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.8/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v2 v2.2.9 h1:WEDygVovkJlV2CCunM9KS2kds+kcl7zdIefQA5y/nkE= -github.com/pion/transport/v2 v2.2.9/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.6 h1:k1mQU06bmmX143qSWgXFqSH1KUJceQvIUuVH/K5ELWw= github.com/pion/transport/v3 v3.0.6/go.mod h1:HvJr2N/JwNJAfipsRleqwFoR3t/pWyHeZUs89v3+t5s= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.50 h1:C/rwL2mBfCxHv6tlLzDAO3krJpQXfVx8A8WHnGJ2j34= -github.com/pion/webrtc/v3 v3.2.50/go.mod h1:dytYYoSBy7ZUWhJMbndx9UckgYvzNAfL7xgVnrIKxqo= +github.com/pion/webrtc/v3 v3.3.0 h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I= +github.com/pion/webrtc/v3 v3.3.0/go.mod h1:hVmrDJvwhEertRWObeb1xzulzHGeVUoPlWvxdGzcfU0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= From 4b96c4af973661b34927a700cbc3610cf2ea74a7 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 Sep 2024 12:13:07 -0400 Subject: [PATCH 07/61] chore: switch from net.ParseIP to netip.ParseAddr --- ipparser/plugin.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipparser/plugin.go b/ipparser/plugin.go index a9f6731..7d010c7 100644 --- a/ipparser/plugin.go +++ b/ipparser/plugin.go @@ -2,7 +2,7 @@ package ipparser import ( "context" - "net" + "net/netip" "strings" "time" @@ -75,8 +75,8 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg segments := strings.Split(prefix, "-") if len(segments) == 4 && (q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY) { ipStr := strings.Join(segments, ".") - ip := net.ParseIP(ipStr) - if ip == nil { + ip, err := netip.ParseAddr(ipStr) + if err != nil { continue } answers = append(answers, &dns.A{ @@ -86,7 +86,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg Class: dns.ClassINET, Ttl: uint32(ttl.Seconds()), }, - A: ip, + A: ip.AsSlice(), }) continue } @@ -101,8 +101,8 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg } prefixAsIpv6 := strings.Join(segments, ":") - ip := net.ParseIP(prefixAsIpv6) - if ip == nil { + ip, err := netip.ParseAddr(prefixAsIpv6) + if err != nil { continue } @@ -113,7 +113,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg Class: dns.ClassINET, Ttl: uint32(ttl.Seconds()), }, - AAAA: ip, + AAAA: ip.AsSlice(), }) } From 5f36c1ad4ec1dd2d6b67c42c9b649f53b736782a Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 Sep 2024 12:22:16 -0400 Subject: [PATCH 08/61] fix: explicitly close test hosts --- acme/writer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/acme/writer.go b/acme/writer.go index f5e7e2c..5305910 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -206,6 +206,7 @@ func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { if err != nil { return err } + defer h.Close() var mas []multiaddr.Multiaddr for _, addr := range addrs { From 77c93306de65ccc3d55b374739b5ce30c492c48a Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 Sep 2024 12:53:58 -0400 Subject: [PATCH 09/61] fix: rename constructor to NewP2PForgeCertMgr --- client/acme.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/acme.go b/client/acme.go index 6b064cd..67f8cfc 100644 --- a/client/acme.go +++ b/client/acme.go @@ -49,7 +49,7 @@ func (h hostCloseWrapper) Close() error { } func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool, onCertLoaded func(), allowPrivateForgeAddrs bool, opts ...libp2p.Option) (host.Host, error) { - certMgr := NewP2PForgeCertMgt(forgeDomain, forgeRegistrationEndpoint, caEndpoint, userEmail, trustedRoots) + certMgr := NewP2PForgeCertMgr(forgeDomain, forgeRegistrationEndpoint, caEndpoint, userEmail, trustedRoots) tlsCfg := certMgr.cfg.TLSConfig() tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs @@ -235,7 +235,7 @@ func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { return false } -func NewP2PForgeCertMgt(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool) *P2PForgeCertMgr { +func NewP2PForgeCertMgr(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool) *P2PForgeCertMgr { cfg := certmagic.NewDefault() cfg.Storage = &certmagic.FileStorage{Path: "foo"} h := &hostWrapper{} From 999ba3cbf175844af0dc872b4fcc3b09fd575a80 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 Sep 2024 16:50:13 -0400 Subject: [PATCH 10/61] feat: add options --- client/acme.go | 168 +++++++++++++++++++++++++++++++++++++++++++----- cmd/e2e_test.go | 9 ++- 2 files changed, 158 insertions(+), 19 deletions(-) diff --git a/client/acme.go b/client/acme.go index 67f8cfc..fad4bcc 100644 --- a/client/acme.go +++ b/client/acme.go @@ -48,17 +48,66 @@ func (h hostCloseWrapper) Close() error { return h.closeFn() } -func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool, onCertLoaded func(), allowPrivateForgeAddrs bool, opts ...libp2p.Option) (host.Host, error) { - certMgr := NewP2PForgeCertMgr(forgeDomain, forgeRegistrationEndpoint, caEndpoint, userEmail, trustedRoots) +type P2PForgeHostConfig struct { + certMgrOpts []P2PForgeCertMgrOptions + onCertLoaded func() + allowPrivateForgeAddrs bool + libp2pOpts []libp2p.Option +} + +type P2PForgeHostOptions func(*P2PForgeHostConfig) error + +func WithP2PForgeCertMgrOptions(opts ...P2PForgeCertMgrOptions) P2PForgeHostOptions { + return func(h *P2PForgeHostConfig) error { + h.certMgrOpts = append(h.certMgrOpts, opts...) + return nil + } +} + +func WithLibp2pOptions(opts ...libp2p.Option) P2PForgeHostOptions { + return func(h *P2PForgeHostConfig) error { + h.libp2pOpts = append(h.libp2pOpts, opts...) + return nil + } +} + +func WithOnCertLoaded(fn func()) P2PForgeHostOptions { + return func(h *P2PForgeHostConfig) error { + h.onCertLoaded = fn + return nil + } +} + +// WithAllowPrivateForgeAddrs is meant for testing +func WithAllowPrivateForgeAddrs() P2PForgeHostOptions { + return func(h *P2PForgeHostConfig) error { + h.allowPrivateForgeAddrs = true + return nil + } +} + +func NewHostWithP2PForge(opts ...P2PForgeHostOptions) (host.Host, error) { + cfg := &P2PForgeHostConfig{} + for _, opt := range opts { + if err := opt(cfg); err != nil { + return nil, err + } + } + + certMgr, err := NewP2PForgeCertMgr(cfg.certMgrOpts...) + if err != nil { + return nil, err + } tlsCfg := certMgr.cfg.TLSConfig() tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs + forgeDomain := certMgr.forgeDomain var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) var h host.Host var mx sync.RWMutex // TODO: Option passing mechanism here isn't respectful of which transports the user wants to support or the addresses they want to listen on - hTmp, err := libp2p.New(libp2p.ChainOptions(libp2p.ChainOptions(opts...), + hTmp, err := libp2p.New(libp2p.ChainOptions(libp2p.ChainOptions(cfg.libp2pOpts...), libp2p.DefaultListenAddrs, libp2p.ListenAddrStrings([]string{ // TODO: Grab these addresses from a TCP listener and share the ports fmt.Sprintf("/ip4/0.0.0.0/tcp/0/tls/sni/*.%s/ws", forgeDomain), @@ -79,7 +128,7 @@ func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, c retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) for i, a := range multiaddrs { - if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { + if isRelayAddr(a) || (!cfg.allowPrivateForgeAddrs && isPublicAddr(a)) { retAddrs[i] = a continue } @@ -167,7 +216,7 @@ func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, c return err }} - if onCertLoaded != nil { + if cfg.onCertLoaded != nil { pidStr := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) certName := fmt.Sprintf("*.%s.%s", pidStr, forgeDomain) _ = certName @@ -183,7 +232,7 @@ func NewHostWithP2PForge(forgeDomain string, forgeRegistrationEndpoint string, c } for _, san := range sanList { if san == certName { - onCertLoaded() + cfg.onCertLoaded() } } return nil @@ -235,19 +284,106 @@ func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { return false } -func NewP2PForgeCertMgr(forgeDomain string, forgeRegistrationEndpoint string, caEndpoint string, userEmail string, trustedRoots *x509.CertPool) *P2PForgeCertMgr { - cfg := certmagic.NewDefault() - cfg.Storage = &certmagic.FileStorage{Path: "foo"} +type P2PForgeCertMgrConfig struct { + forgeDomain string + forgeRegistrationEndpoint string + caEndpoint string + userEmail string + trustedRoots *x509.CertPool + storage certmagic.Storage +} + +type P2PForgeCertMgrOptions func(*P2PForgeCertMgrConfig) error + +func WithForgeDomain(domain string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.forgeDomain = domain + return nil + } +} + +func WithForgeRegistrationEndpoint(endpoint string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.forgeRegistrationEndpoint = endpoint + return nil + } +} + +func WithCAEndpoint(caEndpoint string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.caEndpoint = caEndpoint + return nil + } +} + +func WithCertificateStorage(storage certmagic.Storage) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.storage = storage + return nil + } +} + +func WithUserEmail(email string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.userEmail = email + return nil + } +} + +// WithTrustedRoots is meant for testing +func WithTrustedRoots(trustedRoots *x509.CertPool) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.trustedRoots = trustedRoots + return nil + } +} + +// NewP2PForgeCertMgr handles the creation and management of certificates that are automatically granted by a forge +// to a libp2p host. +// +// Calling this function signifies your acceptance to +// the CA's Subscriber Agreement and/or Terms of Service. Let's Encrypt is the default CA. +func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error) { + mgrCfg := &P2PForgeCertMgrConfig{} + for _, opt := range opts { + if err := opt(mgrCfg); err != nil { + return nil, err + } + } + + const libp2pDirectName = "libp2p.direct" + const libp2pDirectRegistrationEndpoint = "https://registration.libp2p.direct" + if mgrCfg.forgeDomain == "" { + mgrCfg.forgeDomain = "libp2p.direct" + } + if mgrCfg.caEndpoint == "" { + mgrCfg.caEndpoint = certmagic.LetsEncryptProductionCA + } + if mgrCfg.forgeRegistrationEndpoint == "" { + if mgrCfg.forgeDomain == libp2pDirectName { + mgrCfg.forgeRegistrationEndpoint = libp2pDirectRegistrationEndpoint + } else { + return nil, fmt.Errorf("must specify the forge registration endpoint if using a non-default forge") + } + } + const defaultStorageLocation = "p2p-forge-certs" + if mgrCfg.storage == nil { + mgrCfg.storage = &certmagic.FileStorage{Path: defaultStorageLocation} + } + + certCfg := certmagic.NewDefault() + certCfg.Storage = mgrCfg.storage h := &hostWrapper{} - myACME := certmagic.NewACMEIssuer(cfg, certmagic.ACMEIssuer{ // TODO: UX around user passed emails + agreement - CA: caEndpoint, // TODO: Switch to real CA by default - Email: userEmail, + + myACME := certmagic.NewACMEIssuer(certCfg, certmagic.ACMEIssuer{ // TODO: UX around user passed emails + agreement + CA: mgrCfg.caEndpoint, + Email: mgrCfg.userEmail, Agreed: true, - DNS01Solver: &dns01P2PForgeSolver{forgeRegistrationEndpoint, h}, - TrustedRoots: trustedRoots, + DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, h}, + TrustedRoots: mgrCfg.trustedRoots, }) - cfg.Issuers = []certmagic.Issuer{myACME} - return &P2PForgeCertMgr{forgeDomain, forgeRegistrationEndpoint, cfg, h} + certCfg.Issuers = []certmagic.Issuer{myACME} + return &P2PForgeCertMgr{mgrCfg.forgeDomain, mgrCfg.forgeRegistrationEndpoint, certCfg, h}, nil } func (m *P2PForgeCertMgr) Run(ctx context.Context, h host.Host) error { diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 9459fad..ff6ad93 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -398,9 +398,12 @@ func TestLibp2pACMEE2E(t *testing.T) { acmeEndpoint := fmt.Sprintf("https://%s%s", acmeHTTPListener.Addr(), pebbleWFE.DirectoryPath) certLoaded := make(chan bool, 1) - h, err := client.NewHostWithP2PForge(forge, fmt.Sprintf("http://127.0.0.1:%d", httpPort), acmeEndpoint, "foo@bar.com", cas, func() { - certLoaded <- true - }, true) + h, err := client.NewHostWithP2PForge( + client.WithP2PForgeCertMgrOptions(client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas)), + client.WithOnCertLoaded(func() { + certLoaded <- true + }), + client.WithAllowPrivateForgeAddrs()) if err != nil { t.Fatal(err) } From fab0c5ba50f3e7b996b3722de1867013dcda58f7 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 Sep 2024 15:29:50 -0400 Subject: [PATCH 11/61] feat: switch to http peerID auth --- README.md | 15 +--- acme/writer.go | 204 ++++++++++---------------------------------- client/acme.go | 2 +- client/challenge.go | 77 +++-------------- cmd/e2e_test.go | 2 +- go.mod | 8 +- go.sum | 4 +- 7 files changed, 68 insertions(+), 244 deletions(-) diff --git a/README.md b/README.md index 2ddc31e..1c6a66a 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ To claim a domain name like `.libp2p.direct` requires: To set an ACME challenge send an HTTP request to the server (for libp2p.direct this is registration.libp2p.direct) ```shell curl -X POST "https://registration.libp2p.direct/v1//_acme-challenge" \ --H "Authorization: Bearer ." +-H "Authorization: libp2p-PeerID bearer=\"\"" -H "Content-Type: application/json" \ -d '{ "value": "your_acme_challenge_token", @@ -66,15 +66,4 @@ curl -X POST "https://registration.libp2p.direct/v1//_acme-challenge" \ }' ``` -Where the signature is a base64 encoding of the signature for a [libp2p signed envelope](https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md) -where: -- The domain separation string is "peer-forge-domain-challenge" -- The payload type is the ASCII string "/peer-forge-domain-challenge" -- The payload bytes are the contents of the body of the request - -If the public key is not extractable from the peerID then after the signature add a `.` followed by the base64 encoded -public key in the libp2p public key format. - -Note: Per the [peerID spec](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#peer-ids) the peerIDs with -extractable public keys are those that are encoded as fewer than 42 bytes (i.e. Ed25519 and Secp256k1), which means the -others (i.e. RSA and ECDSA) require the public keys to be in the Authorization header. \ No newline at end of file +Where the bearer token is derived via the [libp2p HTTP PeerID Auth Specification](https://github.com/libp2p/specs/pull/564). \ No newline at end of file diff --git a/acme/writer.go b/acme/writer.go index 5305910..a08187f 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -3,14 +3,13 @@ package acme import ( "bytes" "context" + "crypto/rand" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "net" "net/http" - "strings" "time" clog "github.com/coredns/coredns/plugin/pkg/log" @@ -19,12 +18,11 @@ import ( "github.com/gorilla/mux" "github.com/ipfs/go-datastore" - pool "github.com/libp2p/go-buffer-pool" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" "github.com/multiformats/go-multiaddr" - "github.com/multiformats/go-varint" ) var log = clog.NewWithPlugin(pluginName) @@ -57,144 +55,67 @@ func (c *acmeWriter) OnStartup() error { c.mux = mux.NewRouter() c.nlSetup = true - c.mux.HandleFunc("/v1/{peerID}/_acme-challenge", func(w http.ResponseWriter, r *http.Request) { - authHeader := r.Header.Get("Authorization") - if authHeader == "" { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte("must pass an authorization header")) - return - } - - vars := mux.Vars(r) - peerIDStr, peerIDFound := vars["peerID"] - if !peerIDFound { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte("peerID not found in request URL")) - return - } - peerID, err := peer.Decode(peerIDStr) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("invalid peer ID")) - return - } - - pk, err := peerID.ExtractPublicKey() - if err != nil && errors.Is(err, peer.ErrNoPublicKey) { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(fmt.Sprintf("unable to extract public key from peer ID: %s", err.Error()))) - return - } - - body, err := io.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(fmt.Sprintf("error reading body: %s", err))) - return - } - - authComponents := strings.Split(authHeader, ".") - if pk == nil { - if len(authComponents) != 2 { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("must pass both a signature and public key if the public key cannot be extracted from the peerID")) - return - } - base64EncodedPubKey := authComponents[1] - encodedPubKey, err := base64.StdEncoding.DecodeString(base64EncodedPubKey) + // server side secret key and peerID not particularly relevant, so we can generate new ones as needed + sk, _, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + return err + } + authPeer := &httppeeridauth.ServerPeerIDAuth{ + PrivKey: sk, + TokenTTL: time.Hour, + InsecureNoTLS: true, // TODO: figure out how we want to handle TLS termination for this service + ValidHostnameFn: func(s string) bool { + return true + }, + Next: func(peerID peer.ID, w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("could not decode public key")) + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(fmt.Sprintf("error reading body: %s", err))) return } - pk, err = crypto.UnmarshalPublicKey(encodedPubKey) - if err != nil { + + typedBody := &requestBody{} + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(typedBody); err != nil { w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("could not unmarshal public key")) + _, _ = w.Write([]byte(fmt.Sprintf("error decoding body: %s", err))) return } - calculatedID, err := peer.IDFromPublicKey(pk) + // Value must be a base64url encoding of a SHA256 digest per https://datatracker.ietf.org/doc/html/rfc8555/#section-8.4 + decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte("could not calculate peerID from public key")) + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte(fmt.Sprintf("error decoding value as base64url: %s", err))) return } - if calculatedID != peerID { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte("calculated peer ID does not match the passed peerID")) + if len(decodedValue) != 32 { + w.WriteHeader(http.StatusBadRequest) + _, _ = w.Write([]byte("value is not a base64url of a SHA256 digest")) return } - } else { - if len(authComponents) != 1 { + + if err := testAddresses(r.Context(), peerID, typedBody.Addresses); err != nil { w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("when the peerID can be extracted from the public key only the signature should be in the authorization header")) + _, _ = w.Write([]byte(fmt.Sprintf("error testing addresses: %s", err))) return } - } - base64EncodedSignature := authComponents[0] - signature, err := base64.StdEncoding.DecodeString(base64EncodedSignature) - if err != nil { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(fmt.Sprintf("error decoding signature: %s", err))) - } - - unsigned := makeUnsigned(signatureDomainString, signaturePayloadType, body) - defer pool.Put(unsigned) - - verified, err := pk.Verify(unsigned, signature) - if !verified { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte("invalid signature")) - return - } - - if err != nil { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write([]byte(fmt.Sprintf("error verifying signature: %s", err))) - return - } - - typedBody := &requestBody{} - decoder := json.NewDecoder(bytes.NewReader(body)) - decoder.DisallowUnknownFields() - if err := decoder.Decode(typedBody); err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(fmt.Sprintf("error decoding body: %s", err))) - return - } - - // Value must be a base64url encoding of a SHA256 digest per https://datatracker.ietf.org/doc/html/rfc8555/#section-8.4 - decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(fmt.Sprintf("error decoding value as base64url: %s", err))) - return - } - - if len(decodedValue) != 32 { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("value is not a base64url of a SHA256 digest")) - return - } - - if err := testAddresses(r.Context(), peerID, typedBody.Addresses); err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte(fmt.Sprintf("error testing addresses: %s", err))) - return - } + const ttl = time.Hour + err = c.Datastore.PutWithTTL(r.Context(), datastore.NewKey(peerID.String()), []byte(typedBody.Value), ttl) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte(fmt.Sprintf("error storing value: %s", err))) + return + } + w.WriteHeader(http.StatusOK) + }, + } - const ttl = time.Hour - err = c.Datastore.PutWithTTL(r.Context(), datastore.NewKey(peerID.String()), []byte(typedBody.Value), ttl) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write([]byte(fmt.Sprintf("error storing value: %s", err))) - return - } - w.WriteHeader(http.StatusOK) - }).Methods("POST") + c.mux.Handle("/v1/_acme-challenge", authPeer).Methods("POST") go func() { http.Serve(c.ln, c.mux) }() @@ -239,41 +160,6 @@ type requestBody struct { Addresses []string `json:"addresses"` } -const signatureDomainString = "peer-forge-domain-challenge" - -var signaturePayloadType []byte = []byte("/peer-forge-domain-challenge") - -// makeUnsigned is a helper function that prepares a buffer to sign or verify. -// It returns a byte slice from a pool. The caller MUST return this slice to the -// pool. -func makeUnsigned(domain string, payloadType []byte, payload []byte) []byte { - var ( - fields = [][]byte{[]byte(domain), payloadType, payload} - - // fields are prefixed with their length as an unsigned varint. we - // compute the lengths before allocating the sig buffer, so we know how - // much space to add for the lengths - flen = make([][]byte, len(fields)) - size = 0 - ) - - for i, f := range fields { - l := len(f) - flen[i] = varint.ToUvarint(uint64(l)) - size += l + len(flen[i]) - } - - b := pool.Get(size) - - var s int - for i, f := range fields { - s += copy(b[s:], flen[i]) - s += copy(b[s:], f) - } - - return b[:s] -} - func (c *acmeWriter) OnFinalShutdown() error { if !c.nlSetup { return nil diff --git a/client/acme.go b/client/acme.go index fad4bcc..81a07b4 100644 --- a/client/acme.go +++ b/client/acme.go @@ -408,7 +408,7 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge } func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { - return SendChallenge(ctx, d.forge, d.host.ID(), d.host.Peerstore().PrivKey(d.host.ID()), challenge.DNS01KeyAuthorization(), d.host.Addrs()) + return SendChallenge(ctx, d.forge, d.host.Peerstore().PrivKey(d.host.ID()), challenge.DNS01KeyAuthorization(), d.host.Addrs()) } func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error { diff --git a/client/challenge.go b/client/challenge.go index 69e644b..f947075 100644 --- a/client/challenge.go +++ b/client/challenge.go @@ -3,69 +3,45 @@ package client import ( "bytes" "context" - "encoding/base64" "encoding/json" - "errors" "fmt" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" "io" "net/http" "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/record" - "github.com/libp2p/go-libp2p/core/record/pb" "github.com/multiformats/go-multiaddr" - "google.golang.org/protobuf/proto" ) // SendChallenge submits a challenge to the DNS server for the given peerID. // It requires the corresponding private key and a list of multiaddresses that the peerID is listening on using // publicly reachable IP addresses. -func SendChallenge(ctx context.Context, baseURL string, peerID peer.ID, privKey crypto.PrivKey, challenge string, addrs []multiaddr.Multiaddr) error { +func SendChallenge(ctx context.Context, baseURL string, privKey crypto.PrivKey, challenge string, addrs []multiaddr.Multiaddr) error { maStrs := make([]string, len(addrs)) for i, addr := range addrs { maStrs[i] = addr.String() } - var requestBody = &requestRecord{ + + body, err := json.Marshal(&struct { + Value string `json:"value"` + Addresses []string `json:"addresses"` + }{ Value: challenge, Addresses: maStrs, - } - - env, err := record.Seal(requestBody, privKey) - if err != nil { - return err - } - envBytes, err := env.Marshal() + }) if err != nil { return err } - var pbEnv pb.Envelope - if err := proto.Unmarshal(envBytes, &pbEnv); err != nil { - return err - } - authHeader := base64.StdEncoding.EncodeToString(pbEnv.Signature) - pk, err := peerID.ExtractPublicKey() - if err != nil && errors.Is(err, peer.ErrNoPublicKey) { - return err - } - if pk == nil { - pk = env.PublicKey - pkBytes, err := crypto.MarshalPublicKey(pk) - if err != nil { - return err - } - base64EncodedPk := base64.StdEncoding.EncodeToString(pkBytes) - authHeader += "." + base64EncodedPk - } - - req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/%s/_acme-challenge", baseURL, peerID), bytes.NewReader(pbEnv.Payload)) + req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/_acme-challenge", baseURL), bytes.NewReader(body)) if err != nil { return err } - req.Header.Add("Authorization", authHeader) - resp, err := http.DefaultClient.Do(req) + client := &httppeeridauth.ClientPeerIDAuth{PrivKey: privKey} + _, resp, err := client.AuthenticatedDo(http.DefaultClient, func() *http.Request { + return req + }) if err != nil { return err } @@ -75,30 +51,3 @@ func SendChallenge(ctx context.Context, baseURL string, peerID peer.ID, privKey } return nil } - -type requestRecord struct { - Value string `json:"value"` - Addresses []string `json:"addresses"` -} - -func (r *requestRecord) Domain() string { - return "peer-forge-domain-challenge" -} - -func (r *requestRecord) Codec() []byte { - return []byte("/peer-forge-domain-challenge") -} - -func (r *requestRecord) MarshalRecord() ([]byte, error) { - out, err := json.Marshal(r) - if err != nil { - return nil, err - } - return out, nil -} - -func (r *requestRecord) UnmarshalRecord(bytes []byte) error { - return json.Unmarshal(bytes, r) -} - -var _ record.Record = (*requestRecord)(nil) diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index ff6ad93..79b31e8 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -123,7 +123,7 @@ func TestSetACMEChallenge(t *testing.T) { testDigest := sha256.Sum256([]byte("test")) testChallenge := base64.RawURLEncoding.EncodeToString(testDigest[:]) - if err := client.SendChallenge(ctx, fmt.Sprintf("http://127.0.0.1:%d", httpPort), h.ID(), sk, testChallenge, h.Addrs()); err != nil { + if err := client.SendChallenge(ctx, fmt.Sprintf("http://127.0.0.1:%d", httpPort), sk, testChallenge, h.Addrs()); err != nil { t.Fatal(err) } diff --git a/go.mod b/go.mod index 1eec860..493b20c 100644 --- a/go.mod +++ b/go.mod @@ -13,15 +13,12 @@ require ( github.com/ipfs/go-ds-dynamodb v0.1.1 github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 - github.com/libp2p/go-buffer-pool v0.1.0 - github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa + github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897 github.com/mholt/acmez/v2 v2.0.1 github.com/miekg/dns v1.1.61 github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.2.0 - github.com/multiformats/go-varint v0.0.7 - google.golang.org/protobuf v1.34.2 ) require ( @@ -113,6 +110,7 @@ require ( github.com/koron/go-ssdp v0.0.4 // indirect github.com/letsencrypt/challtestsrv v1.3.2 // indirect github.com/libdns/libdns v0.2.2 // indirect + github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect @@ -137,6 +135,7 @@ require ( github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/ginkgo/v2 v2.19.1 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect @@ -212,6 +211,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.63.2 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index ebf920e..d757a93 100644 --- a/go.sum +++ b/go.sum @@ -328,8 +328,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa h1:fpHzZMdrj/X7HrqoD1yPY56YTlIlX7l3d0sSraekjJQ= -github.com/libp2p/go-libp2p v0.36.3-0.20240830152458-d55bed5f78fa/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= +github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897 h1:OCIXsMBv93Db1pVVOM95wlyr0oUf8XE6pFktd6nhFu0= +github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= From 308b83a433a397dc5bc2326b4276a1f76eb5799d Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 Sep 2024 15:57:52 -0400 Subject: [PATCH 12/61] chore: tidy up dependency imports --- cmd/e2e_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 79b31e8..4334fa2 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -13,9 +13,6 @@ import ( "encoding/pem" "errors" "fmt" - libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" - "github.com/multiformats/go-multiaddr" - madns "github.com/multiformats/go-multiaddr-dns" "log" "math/big" "net" @@ -31,7 +28,10 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" "github.com/miekg/dns" + "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" "github.com/multiformats/go-multibase" _ "github.com/coredns/coredns/core/plugin" // Load all managed plugins in github.com/coredns/coredns. From 00b6c7c84fd62c44fa84958d848703063cf8f6e9 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 Sep 2024 21:51:46 -0400 Subject: [PATCH 13/61] docs: add more clarification that base64url does not include padding --- acme/writer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/acme/writer.go b/acme/writer.go index a08187f..27375f1 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -85,6 +85,7 @@ func (c *acmeWriter) OnStartup() error { } // Value must be a base64url encoding of a SHA256 digest per https://datatracker.ietf.org/doc/html/rfc8555/#section-8.4 + // It MUST NOT contain any characters outside the base64url alphabet, including padding characters ("="). decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) if err != nil { w.WriteHeader(http.StatusBadRequest) From f4b98ac89984835194497a405dc25066d666dc3f Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 Sep 2024 21:59:05 -0400 Subject: [PATCH 14/61] docs: clarify requirements for libp2p clients requesting certs --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1c6a66a..02b0db2 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,13 @@ Other address formats (e.g. the dual IPv6/IPv4 format) are not supported To claim a domain name like `.libp2p.direct` requires: 1. The private key corresponding to the given peerID -2. A publicly reachable libp2p endpoint with one of the following libp2p transport configurations: - - QUIC-v1 - - TCP or WS or WSS, Yamux, TLS or Noise - - WebTransport - - Note: The [Identify protocol](https://github.com/libp2p/specs/tree/master/identify) (`/ipfs/id/1.0.0`) - - Other transports are under consideration (e.g. HTTP), if they are of interest please file an issue +2. A publicly reachable libp2p endpoint with + - one of the following libp2p transport configurations: + - QUIC-v1 + - TCP or WS or WSS, Yamux, TLS or Noise + - WebTransport + - Other transports are under consideration (e.g. HTTP), if they are of interest please file an issue + - the [Identify protocol](https://github.com/libp2p/specs/tree/master/identify) (`/ipfs/id/1.0.0`) To set an ACME challenge send an HTTP request to the server (for libp2p.direct this is registration.libp2p.direct) ```shell From 66744f1c8b15aa954ddf1c87a9565d7e0c4036e8 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 5 Sep 2024 03:22:06 -0400 Subject: [PATCH 15/61] feat: allow TLS termination and certificate management for registration endpoint --- acme/setup.go | 9 +++---- acme/writer.go | 63 +++++++++++++++++++++++++++++++++++++------------ cmd/e2e_test.go | 2 +- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/acme/setup.go b/acme/setup.go index a2b8445..5ce6e4b 100644 --- a/acme/setup.go +++ b/acme/setup.go @@ -6,7 +6,6 @@ import ( "github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/plugin" "github.com/ipfs/go-datastore" - badger4 "github.com/ipfs/go-ds-badger4" "github.com/aws/aws-sdk-go/aws/session" @@ -52,7 +51,8 @@ func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { forgeDomain = args[0] httpListenAddr = args[1] - databaseType = args[2] + httpDomain := args[2] + databaseType = args[3] var ds datastore.TTLDatastore @@ -61,10 +61,10 @@ func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { ddbClient := ddbv1.New(session.Must(session.NewSession())) ds = ddbds.New(ddbClient, "foo") case "badger": - if len(args) != 4 { + if len(args) != 5 { return nil, nil, fmt.Errorf("need to pass a path for the Badger configuration") } - dbPath := args[3] + dbPath := args[4] var err error ds, err = badger4.NewDatastore(dbPath, nil) if err != nil { @@ -76,6 +76,7 @@ func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { writer := &acmeWriter{ Addr: httpListenAddr, + Domain: httpDomain, Datastore: ds, } reader := &acmeReader{ diff --git a/acme/writer.go b/acme/writer.go index 27375f1..c183382 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -4,17 +4,21 @@ import ( "bytes" "context" "crypto/rand" + "crypto/tls" "encoding/base64" "encoding/json" "fmt" "io" "net" "net/http" + "strings" "time" clog "github.com/coredns/coredns/plugin/pkg/log" "github.com/coredns/coredns/plugin/pkg/reuseport" + "github.com/caddyserver/certmagic" + "github.com/gorilla/mux" "github.com/ipfs/go-datastore" @@ -29,27 +33,47 @@ var log = clog.NewWithPlugin(pluginName) // acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. type acmeWriter struct { - Addr string + Addr string + Domain string Datastore datastore.TTLDatastore - ln net.Listener - nlSetup bool - mux *mux.Router + ln net.Listener + nlSetup bool + closeCertMgr func() + mux *mux.Router } func (c *acmeWriter) OnStartup() error { - if c.Addr == "" { - c.Addr = ":8080" - } - - var err error + domainName := c.Domain ln, err := reuseport.Listen("tcp", c.Addr) if err != nil { return err } + if domainName != "localhost" { + certCfg := certmagic.NewDefault() + certCfg.Storage = &certmagic.FileStorage{Path: fmt.Sprintf("%s-certs", strings.Replace(domainName, ".", "_", -1))} + myACME := certmagic.NewACMEIssuer(certCfg, certmagic.ACMEIssuer{ + CA: certmagic.LetsEncryptProductionCA, // TODO: Add a way to set the email and/or CA + Agreed: true, + }) + certCfg.Issuers = []certmagic.Issuer{myACME} + + tlsConfig := certCfg.TLSConfig() + tlsConfig.NextProtos = append([]string{"h2", "http/1.1"}, tlsConfig.NextProtos...) + + ctx, cancel := context.WithCancel(context.Background()) + if err := certCfg.ManageAsync(ctx, []string{domainName}); err != nil { + cancel() + return err + } + c.closeCertMgr = cancel + + ln = tls.NewListener(ln, tlsConfig) + } + c.ln = ln c.mux = mux.NewRouter() @@ -61,12 +85,8 @@ func (c *acmeWriter) OnStartup() error { return err } authPeer := &httppeeridauth.ServerPeerIDAuth{ - PrivKey: sk, - TokenTTL: time.Hour, - InsecureNoTLS: true, // TODO: figure out how we want to handle TLS termination for this service - ValidHostnameFn: func(s string) bool { - return true - }, + PrivKey: sk, + TokenTTL: time.Hour, Next: func(peerID peer.ID, w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { @@ -116,6 +136,13 @@ func (c *acmeWriter) OnStartup() error { }, } + if domainName == "localhost" { + authPeer.InsecureNoTLS = true + authPeer.ValidHostnameFn = func(s string) bool { // TODO: should enable separate checking of host headers even with no TLS termination + return true + } + } + c.mux.Handle("/v1/_acme-challenge", authPeer).Methods("POST") go func() { http.Serve(c.ln, c.mux) }() @@ -167,6 +194,9 @@ func (c *acmeWriter) OnFinalShutdown() error { } c.ln.Close() + if c.closeCertMgr != nil { + c.closeCertMgr() + } c.nlSetup = false return nil } @@ -177,6 +207,9 @@ func (c *acmeWriter) OnReload() error { } c.ln.Close() + if c.closeCertMgr != nil { + c.closeCertMgr() + } c.nlSetup = false return nil } diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 4334fa2..2ea60c9 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -81,7 +81,7 @@ func TestMain(m *testing.M) { corefile := fmt.Sprintf(`.:0 { log ipparser %s - acme %s :%d badger %s + acme %s :%d localhost badger %s }`, forge, forge, httpPort, tmpDir) instance, err := caddy.Start(NewInput(corefile)) From e03e370b08fbc2595050fe56125a59b1b30db6e6 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Fri, 6 Sep 2024 15:11:39 -0700 Subject: [PATCH 16/61] Update go-libp2p http peer id auth --- acme/writer.go | 2 +- client/challenge.go | 7 +++---- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/acme/writer.go b/acme/writer.go index c183382..de0152a 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -137,7 +137,7 @@ func (c *acmeWriter) OnStartup() error { } if domainName == "localhost" { - authPeer.InsecureNoTLS = true + authPeer.NoTLS = true authPeer.ValidHostnameFn = func(s string) bool { // TODO: should enable separate checking of host headers even with no TLS termination return true } diff --git a/client/challenge.go b/client/challenge.go index f947075..62c5155 100644 --- a/client/challenge.go +++ b/client/challenge.go @@ -5,10 +5,11 @@ import ( "context" "encoding/json" "fmt" - httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" "io" "net/http" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + "github.com/libp2p/go-libp2p/core/crypto" "github.com/multiformats/go-multiaddr" ) @@ -39,9 +40,7 @@ func SendChallenge(ctx context.Context, baseURL string, privKey crypto.PrivKey, } client := &httppeeridauth.ClientPeerIDAuth{PrivKey: privKey} - _, resp, err := client.AuthenticatedDo(http.DefaultClient, func() *http.Request { - return req - }) + _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) if err != nil { return err } diff --git a/go.mod b/go.mod index 493b20c..b67a477 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/ipfs/go-ds-dynamodb v0.1.1 github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 - github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897 + github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c github.com/mholt/acmez/v2 v2.0.1 github.com/miekg/dns v1.1.61 github.com/multiformats/go-multiaddr v0.13.0 diff --git a/go.sum b/go.sum index d757a93..0ab38f6 100644 --- a/go.sum +++ b/go.sum @@ -328,8 +328,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897 h1:OCIXsMBv93Db1pVVOM95wlyr0oUf8XE6pFktd6nhFu0= -github.com/libp2p/go-libp2p v0.36.3-0.20240903225031-fbcede220897/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= +github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c h1:OAkpXwVI5odbKc4SUf/ds8Ohn20uf4jQHT88cql2Jms= +github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= From 26046dfd2abe49f1256f064c2971bcbd1b9a5422 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 6 Sep 2024 19:06:40 -0400 Subject: [PATCH 17/61] feat: change syntax for Corefile, and add ability to declare external TLS termination for the registration domain --- acme/setup.go | 129 +++++++++++++++++++++++++++++++++----------- acme/writer.go | 19 ++++--- client/acme.go | 42 +++++++++++++-- client/challenge.go | 38 ++++++++----- cmd/e2e_test.go | 30 +++++++++-- 5 files changed, 196 insertions(+), 62 deletions(-) diff --git a/acme/setup.go b/acme/setup.go index 5ce6e4b..4d55927 100644 --- a/acme/setup.go +++ b/acme/setup.go @@ -2,14 +2,18 @@ package acme import ( "fmt" + "strconv" + "strings" + "github.com/coredns/caddy" "github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/plugin" - "github.com/ipfs/go-datastore" - badger4 "github.com/ipfs/go-ds-badger4" "github.com/aws/aws-sdk-go/aws/session" ddbv1 "github.com/aws/aws-sdk-go/service/dynamodb" + + "github.com/ipfs/go-datastore" + badger4 "github.com/ipfs/go-ds-badger4" ddbds "github.com/ipfs/go-ds-dynamodb" ) @@ -37,47 +41,108 @@ func setup(c *caddy.Controller) error { return nil } +// parse Parses the configuration from the Corefile func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { + /* + Syntax is: + acme { + [registration-domain [listen-address=
] [external-tls=] + [database-type [...database-args]] + } + + Databases: + - dynamo + - badger + */ + var forgeDomain string + var forgeRegistrationDomain string + var externalTLS bool var httpListenAddr string - var databaseType string + var ds datastore.TTLDatastore - // Parse the configuration from the Corefile - c.Next() - args := c.RemainingArgs() - if len(args) < 3 { - return nil, nil, fmt.Errorf("invalid arguments") - } + for c.Next() { + args := c.RemainingArgs() - forgeDomain = args[0] - httpListenAddr = args[1] - httpDomain := args[2] - databaseType = args[3] + switch len(args) { + case 0: + return nil, nil, c.ArgErr() + case 1: + forgeDomain = args[0] + default: + return nil, nil, c.ArgErr() + } - var ds datastore.TTLDatastore + for c.NextBlock() { + switch c.Val() { + case "registration-domain": + args := c.RemainingArgs() + if len(args) > 3 || len(args) == 0 { + return nil, nil, c.ArgErr() + } - switch databaseType { - case "dynamo": - ddbClient := ddbv1.New(session.Must(session.NewSession())) - ds = ddbds.New(ddbClient, "foo") - case "badger": - if len(args) != 5 { - return nil, nil, fmt.Errorf("need to pass a path for the Badger configuration") - } - dbPath := args[4] - var err error - ds, err = badger4.NewDatastore(dbPath, nil) - if err != nil { - return nil, nil, err + forgeRegistrationDomain = args[0] + for i := 1; i < len(args); i++ { + nextArg := args[i] + argKV := strings.Split(nextArg, "=") + if len(argKV) != 2 { + return nil, nil, c.ArgErr() + } + k, v := argKV[0], argKV[1] + switch k { + case "listen-address": + httpListenAddr = v + case "external-tls": + externalTLSString := v + var err error + externalTLS, err = strconv.ParseBool(externalTLSString) + if err != nil { + return nil, nil, c.ArgErr() + } + default: + return nil, nil, c.ArgErr() + } + } + case "database-type": + args := c.RemainingArgs() + if len(args) == 0 { + return nil, nil, c.ArgErr() + } + databaseType := args[0] + args = args[1:] + + switch databaseType { + case "dynamo": + if len(args) != 1 { + return nil, nil, c.ArgErr() + } + + ddbClient := ddbv1.New(session.Must(session.NewSession())) + ds = ddbds.New(ddbClient, args[0]) + case "badger": + if len(args) != 1 { + return nil, nil, fmt.Errorf("need to pass a path for the Badger configuration") + } + dbPath := args[0] + var err error + ds, err = badger4.NewDatastore(dbPath, nil) + if err != nil { + return nil, nil, err + } + default: + return nil, nil, fmt.Errorf("unknown database type: %s", databaseType) + } + default: + return nil, nil, c.ArgErr() + } } - default: - return nil, nil, fmt.Errorf("unknown database type: %s", databaseType) } writer := &acmeWriter{ - Addr: httpListenAddr, - Domain: httpDomain, - Datastore: ds, + Addr: httpListenAddr, + Domain: forgeRegistrationDomain, + Datastore: ds, + ExternalTLS: externalTLS, } reader := &acmeReader{ ForgeDomain: forgeDomain, diff --git a/acme/writer.go b/acme/writer.go index de0152a..7055d01 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -33,8 +33,9 @@ var log = clog.NewWithPlugin(pluginName) // acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. type acmeWriter struct { - Addr string - Domain string + Addr string + Domain string + ExternalTLS bool Datastore datastore.TTLDatastore @@ -45,16 +46,14 @@ type acmeWriter struct { } func (c *acmeWriter) OnStartup() error { - domainName := c.Domain - ln, err := reuseport.Listen("tcp", c.Addr) if err != nil { return err } - if domainName != "localhost" { + if !c.ExternalTLS { certCfg := certmagic.NewDefault() - certCfg.Storage = &certmagic.FileStorage{Path: fmt.Sprintf("%s-certs", strings.Replace(domainName, ".", "_", -1))} + certCfg.Storage = &certmagic.FileStorage{Path: fmt.Sprintf("%s-certs", strings.Replace(c.Domain, ".", "_", -1))} myACME := certmagic.NewACMEIssuer(certCfg, certmagic.ACMEIssuer{ CA: certmagic.LetsEncryptProductionCA, // TODO: Add a way to set the email and/or CA Agreed: true, @@ -65,7 +64,7 @@ func (c *acmeWriter) OnStartup() error { tlsConfig.NextProtos = append([]string{"h2", "http/1.1"}, tlsConfig.NextProtos...) ctx, cancel := context.WithCancel(context.Background()) - if err := certCfg.ManageAsync(ctx, []string{domainName}); err != nil { + if err := certCfg.ManageAsync(ctx, []string{c.Domain}); err != nil { cancel() return err } @@ -136,10 +135,10 @@ func (c *acmeWriter) OnStartup() error { }, } - if domainName == "localhost" { + if c.ExternalTLS { authPeer.NoTLS = true - authPeer.ValidHostnameFn = func(s string) bool { // TODO: should enable separate checking of host headers even with no TLS termination - return true + authPeer.ValidHostnameFn = func(s string) bool { + return s == c.Domain } } diff --git a/client/acme.go b/client/acme.go index 81a07b4..4483d8e 100644 --- a/client/acme.go +++ b/client/acme.go @@ -4,7 +4,10 @@ import ( "context" "crypto/x509" "fmt" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + "io" "net" + "net/http" "strings" "sync" "time" @@ -291,6 +294,7 @@ type P2PForgeCertMgrConfig struct { userEmail string trustedRoots *x509.CertPool storage certmagic.Storage + modifyForgeRequest func(r *http.Request) error } type P2PForgeCertMgrOptions func(*P2PForgeCertMgrConfig) error @@ -330,6 +334,15 @@ func WithUserEmail(email string) P2PForgeCertMgrOptions { } } +// WithModifiedForgeRequest enables modifying how the ACME DNS challenges are sent to the forge, such as to enable +// custom HTTP headers, etc. +func WithModifiedForgeRequest(fn func(req *http.Request) error) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.modifyForgeRequest = fn + return nil + } +} + // WithTrustedRoots is meant for testing func WithTrustedRoots(trustedRoots *x509.CertPool) P2PForgeCertMgrOptions { return func(config *P2PForgeCertMgrConfig) error { @@ -366,6 +379,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error return nil, fmt.Errorf("must specify the forge registration endpoint if using a non-default forge") } } + const defaultStorageLocation = "p2p-forge-certs" if mgrCfg.storage == nil { mgrCfg.storage = &certmagic.FileStorage{Path: defaultStorageLocation} @@ -379,7 +393,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error CA: mgrCfg.caEndpoint, Email: mgrCfg.userEmail, Agreed: true, - DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, h}, + DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, h, mgrCfg.modifyForgeRequest}, TrustedRoots: mgrCfg.trustedRoots, }) certCfg.Issuers = []certmagic.Issuer{myACME} @@ -397,8 +411,9 @@ func (m *P2PForgeCertMgr) Run(ctx context.Context, h host.Host) error { } type dns01P2PForgeSolver struct { - forge string - host host.Host + forge string + host host.Host + modifyForgeRequest func(r *http.Request) error } func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge) error { @@ -408,7 +423,26 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge } func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { - return SendChallenge(ctx, d.forge, d.host.Peerstore().PrivKey(d.host.ID()), challenge.DNS01KeyAuthorization(), d.host.Addrs()) + req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), d.host.Addrs()) + if err != nil { + return err + } + if d.modifyForgeRequest != nil { + if err := d.modifyForgeRequest(req); err != nil { + return err + } + } + + client := &httppeeridauth.ClientPeerIDAuth{PrivKey: d.host.Peerstore().PrivKey(d.host.ID())} + _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + respBody, _ := io.ReadAll(resp.Body) + return fmt.Errorf("%s : %s", resp.Status, respBody) + } + return nil } func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challenge) error { diff --git a/client/challenge.go b/client/challenge.go index 62c5155..2908e90 100644 --- a/client/challenge.go +++ b/client/challenge.go @@ -18,6 +18,29 @@ import ( // It requires the corresponding private key and a list of multiaddresses that the peerID is listening on using // publicly reachable IP addresses. func SendChallenge(ctx context.Context, baseURL string, privKey crypto.PrivKey, challenge string, addrs []multiaddr.Multiaddr) error { + req, err := ChallengeRequest(ctx, baseURL, challenge, addrs) + if err != nil { + return err + } + + client := &httppeeridauth.ClientPeerIDAuth{PrivKey: privKey} + _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + respBody, _ := io.ReadAll(resp.Body) + return fmt.Errorf("%s : %s", resp.Status, respBody) + } + return nil +} + +// ChallengeRequest creates an HTTP Request object for submitting an ACME challenge to the DNS server for a given peerID. +// Construction of the request requires a list of multiaddresses that the peerID is listening on using +// publicly reachable IP addresses. +// +// Sending the request to the DNS server requires performing HTTP PeerID Authentication for the corresponding peerID +func ChallengeRequest(ctx context.Context, baseURL string, challenge string, addrs []multiaddr.Multiaddr) (*http.Request, error) { maStrs := make([]string, len(addrs)) for i, addr := range addrs { maStrs[i] = addr.String() @@ -31,22 +54,13 @@ func SendChallenge(ctx context.Context, baseURL string, privKey crypto.PrivKey, Addresses: maStrs, }) if err != nil { - return err + return nil, err } req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/v1/_acme-challenge", baseURL), bytes.NewReader(body)) if err != nil { - return err + return nil, err } - client := &httppeeridauth.ClientPeerIDAuth{PrivKey: privKey} - _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) - if err != nil { - return err - } - if resp.StatusCode != http.StatusOK { - respBody, _ := io.ReadAll(resp.Body) - return fmt.Errorf("%s : %s", resp.Status, respBody) - } - return nil + return req, nil } diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 2ea60c9..9fbebfb 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -13,6 +13,7 @@ import ( "encoding/pem" "errors" "fmt" + "io" "log" "math/big" "net" @@ -28,6 +29,7 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" "github.com/miekg/dns" "github.com/multiformats/go-multiaddr" @@ -45,6 +47,7 @@ import ( ) const forge = "libp2p.direct" +const forgeRegistration = "registration.libp2p.direct" var dnsServerAddress string var httpPort int @@ -81,8 +84,11 @@ func TestMain(m *testing.M) { corefile := fmt.Sprintf(`.:0 { log ipparser %s - acme %s :%d localhost badger %s - }`, forge, forge, httpPort, tmpDir) + acme %s { + registration-domain %s listen-address=:%d external-tls=true + database-type badger %s + } + }`, forge, forge, forgeRegistration, httpPort, tmpDir) instance, err := caddy.Start(NewInput(corefile)) if err != nil { @@ -123,9 +129,21 @@ func TestSetACMEChallenge(t *testing.T) { testDigest := sha256.Sum256([]byte("test")) testChallenge := base64.RawURLEncoding.EncodeToString(testDigest[:]) - if err := client.SendChallenge(ctx, fmt.Sprintf("http://127.0.0.1:%d", httpPort), sk, testChallenge, h.Addrs()); err != nil { + req, err := client.ChallengeRequest(ctx, fmt.Sprintf("http://127.0.0.1:%d", httpPort), testChallenge, h.Addrs()) + if err != nil { + t.Fatal(err) + } + req.Host = forgeRegistration + + peerHTTPClient := &httppeeridauth.ClientPeerIDAuth{PrivKey: sk} + _, resp, err := peerHTTPClient.AuthenticatedDo(http.DefaultClient, req) + if err != nil { t.Fatal(err) } + if resp.StatusCode != http.StatusOK { + respBody, _ := io.ReadAll(resp.Body) + t.Fatal(fmt.Errorf("%s : %s", resp.Status, respBody)) + } peerIDb36, err := peer.ToCid(h.ID()).StringOfBase(multibase.Base36) if err != nil { @@ -399,7 +417,11 @@ func TestLibp2pACMEE2E(t *testing.T) { acmeEndpoint := fmt.Sprintf("https://%s%s", acmeHTTPListener.Addr(), pebbleWFE.DirectoryPath) certLoaded := make(chan bool, 1) h, err := client.NewHostWithP2PForge( - client.WithP2PForgeCertMgrOptions(client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas)), + client.WithP2PForgeCertMgrOptions(client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas), + client.WithModifiedForgeRequest(func(req *http.Request) error { + req.Host = forgeRegistration + return nil + })), client.WithOnCertLoaded(func() { certLoaded <- true }), From f2942d80bccaf5304c20c65e6c3e8aeaaebc59bc Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 9 Sep 2024 16:08:37 -0400 Subject: [PATCH 18/61] docs: add Corefile config docs --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index 02b0db2..0e1087d 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,59 @@ Will download using go mod, build and install the binary in your global Go binar ## Usage +### Configuration + +This binary is based on [CoreDNS](https://github.com/coredns/coredns) which is itself based on Caddy. +To run the binary create a file `Corefile` following the syntax listed in the CoreDNS documentation. + +This binary introduces two additional plugins: +- `ipparser` which handles returning A and AAAA records for domains like `..libp2p.direct` +- `acme` which handles reading and writing DNS acme challenges for domains like `_acme-challenge..libp2p.direct` + +#### ipparser Syntax + +~~~ +ipparser FORGE_DOMAIN +~~~ + +**FORGE_DOMAIN** the domain of the forge (e.g. libp2p.direct) + +#### acme Syntax + +~~~ +acme FORGE_DOMAIN { + [registration-domain REGISTRATION_DOMAIN [listen-address=ADDRESS] [external-tls=true|false] + [database-type DB_TYPE [...DB_ARGS]] +} +~~~ + +- **FORGE_DOMAIN** the domain of the forge (e.g. libp2p.direct) +- **REGISTRATION_DOMAIN** the domain used by clients to send requests for setting ACME challenges (e.g. registration.libp2p.direct) + - **ADDRESS** is the address and port for the internal HTTP server to listen on (e.g. :1234), defaults to `:443`. + - external-tls should be set to true if the TLS termination (and validation of the registration domain name) will happen externally or should be handled locally, defaults to false +- **DB_TYPE** is the type of the backing database used for storing the ACME challenges. Options include: + - dynamo TABLE_NAME (where all credentials are set via AWS' standard environment variables) + - badger DB_PATH + +### Example + +Below is a basic example of starting a DNS server that handles the IP based domain names as well as ACME challenges. +It does the following: +- Handles IP-based names and ACME challenges for the libp2p.direct forge +- Sets up a standard HTTPS listener for registration.libp2p.direct to handle setting ACME challenges +- Uses dynamo as a backend for ACME challenges + +``` corefile +. { + log + ipparser libp2p.direct + acme libp2p.direct { + registration-domain registration.libp2p.direct listen-address=:443 external-tls=false + database-type dynamo mytable + } +} +``` + ### Handled DNS records There are 3 types of records handled for a given peer and forge (e.g. `.libp2p.direct`): From c34b6bb2ea33c55f2d0943cb0301022da45afb66 Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 9 Sep 2024 17:50:45 -0700 Subject: [PATCH 19/61] Split Cert mgr apart from libp2p Host --- client/acme.go | 407 ++++++++++++++++++++++-------------------------- cmd/e2e_test.go | 40 ++++- 2 files changed, 219 insertions(+), 228 deletions(-) diff --git a/client/acme.go b/client/acme.go index 4483d8e..e2fcc07 100644 --- a/client/acme.go +++ b/client/acme.go @@ -4,7 +4,6 @@ import ( "context" "crypto/x509" "fmt" - httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" "io" "net" "net/http" @@ -12,16 +11,16 @@ import ( "sync" "time" + httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + "go.uber.org/fx" + "github.com/caddyserver/certmagic" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" - libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" - "github.com/libp2p/go-libp2p/p2p/transport/tcp" - libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + "github.com/libp2p/go-libp2p/p2p/transport/websocket" libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" - libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" "github.com/mholt/acmez/v2" "github.com/mholt/acmez/v2/acme" "github.com/multiformats/go-multiaddr" @@ -32,221 +31,35 @@ import ( var log = logging.Logger("p2p-forge/client") type P2PForgeCertMgr struct { + ctx context.Context + cancel func() forgeDomain string forgeRegistrationEndpoint string + provideHost func(host.Host) + hostFn func() host.Host cfg *certmagic.Config - h *hostWrapper -} - -type hostWrapper struct { - host.Host -} - -type hostCloseWrapper struct { - host.Host - closeFn func() error -} - -func (h hostCloseWrapper) Close() error { - return h.closeFn() } type P2PForgeHostConfig struct { certMgrOpts []P2PForgeCertMgrOptions - onCertLoaded func() allowPrivateForgeAddrs bool - libp2pOpts []libp2p.Option } -type P2PForgeHostOptions func(*P2PForgeHostConfig) error +type P2PForgeHostOptions func(*P2PForgeHostConfig) func WithP2PForgeCertMgrOptions(opts ...P2PForgeCertMgrOptions) P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) error { + return func(h *P2PForgeHostConfig) { h.certMgrOpts = append(h.certMgrOpts, opts...) - return nil - } -} - -func WithLibp2pOptions(opts ...libp2p.Option) P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) error { - h.libp2pOpts = append(h.libp2pOpts, opts...) - return nil - } -} - -func WithOnCertLoaded(fn func()) P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) error { - h.onCertLoaded = fn - return nil } } // WithAllowPrivateForgeAddrs is meant for testing func WithAllowPrivateForgeAddrs() P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) error { + return func(h *P2PForgeHostConfig) { h.allowPrivateForgeAddrs = true - return nil } } -func NewHostWithP2PForge(opts ...P2PForgeHostOptions) (host.Host, error) { - cfg := &P2PForgeHostConfig{} - for _, opt := range opts { - if err := opt(cfg); err != nil { - return nil, err - } - } - - certMgr, err := NewP2PForgeCertMgr(cfg.certMgrOpts...) - if err != nil { - return nil, err - } - tlsCfg := certMgr.cfg.TLSConfig() - tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs - forgeDomain := certMgr.forgeDomain - - var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) - - var h host.Host - var mx sync.RWMutex - // TODO: Option passing mechanism here isn't respectful of which transports the user wants to support or the addresses they want to listen on - hTmp, err := libp2p.New(libp2p.ChainOptions(libp2p.ChainOptions(cfg.libp2pOpts...), - libp2p.DefaultListenAddrs, - libp2p.ListenAddrStrings([]string{ // TODO: Grab these addresses from a TCP listener and share the ports - fmt.Sprintf("/ip4/0.0.0.0/tcp/0/tls/sni/*.%s/ws", forgeDomain), - fmt.Sprintf("/ip6/::/tcp/0/tls/sni/*.%s/ws", forgeDomain), - }...), - libp2p.Transport(tcp.NewTCPTransport), - libp2p.Transport(libp2pquic.NewTransport), - libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(tlsCfg)), - libp2p.Transport(libp2pwebtransport.New), - libp2p.Transport(libp2pwebrtc.New), - libp2p.AddrsFactory(func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { - mx.RLock() - if h == nil { - mx.RUnlock() - return multiaddrs - } - mx.RUnlock() - - retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) - for i, a := range multiaddrs { - if isRelayAddr(a) || (!cfg.allowPrivateForgeAddrs && isPublicAddr(a)) { - retAddrs[i] = a - continue - } - - // We expect the address to be of the form: /ipX//tcp//tls/sni/*./ws - // We'll then replace the * with the IP address - withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) - if withoutForgeWSS.Equal(a) { - retAddrs[i] = a - continue - } - - index := 0 - var escapedIPStr string - var ipMaStr string - var tcpPortStr string - multiaddr.ForEach(withoutForgeWSS, func(c multiaddr.Component) bool { - switch index { - case 0: - switch c.Protocol().Code { - case multiaddr.P_IP4: - ipMaStr = c.String() - ipAddr := c.Value() - escapedIPStr = strings.ReplaceAll(ipAddr, ".", "-") - case multiaddr.P_IP6: - ipMaStr = c.String() - ipAddr := c.Value() - escapedIPStr = strings.ReplaceAll(ipAddr, ":", "-") - if escapedIPStr[0] == '-' { - escapedIPStr = "0" + escapedIPStr - } - if escapedIPStr[len(escapedIPStr)-1] == '-' { - escapedIPStr = escapedIPStr + "0" - } - default: - return false - } - case 1: - if c.Protocol().Code != multiaddr.P_TCP { - return false - } - tcpPortStr = c.Value() - default: - index++ - return false - } - index++ - return true - }) - if index != 2 || escapedIPStr == "" || tcpPortStr == "" { - retAddrs[i] = a - continue - } - - pidStr := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) - - newMaStr := fmt.Sprintf("%s/tcp/%s/tls/sni/%s.%s.%s/ws", ipMaStr, tcpPortStr, escapedIPStr, pidStr, forgeDomain) - newMA, err := multiaddr.NewMultiaddr(newMaStr) - if err != nil { - log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) - retAddrs[i] = a - continue - } - retAddrs[i] = newMA - } - return retAddrs - }), - )) - if err != nil { - return nil, err - } - mx.Lock() - h = hTmp - mx.Unlock() - - ctx, cancel := context.WithCancel(context.Background()) - if err := certMgr.Run(ctx, h); err != nil { - cancel() - return nil, err - } - - w := &hostCloseWrapper{Host: h, closeFn: func() error { - cancel() - err := h.Close() - return err - }} - - if cfg.onCertLoaded != nil { - pidStr := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) - certName := fmt.Sprintf("*.%s.%s", pidStr, forgeDomain) - _ = certName - certMgr.cfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { - if event == "cached_managed_cert" { - sans, ok := data["sans"] - if !ok { - return nil - } - sanList, ok := sans.([]string) - if !ok { - return nil - } - for _, san := range sanList { - if san == certName { - cfg.onCertLoaded() - } - } - return nil - } - return nil - } - } - - return w, nil -} - func isRelayAddr(a multiaddr.Multiaddr) bool { found := false multiaddr.ForEach(a, func(c multiaddr.Component) bool { @@ -256,25 +69,18 @@ func isRelayAddr(a multiaddr.Multiaddr) bool { return found } -var publicCIDR6 = "2000::/3" -var public6 *net.IPNet - -func init() { - _, public6, _ = net.ParseCIDR(publicCIDR6) -} - // isPublicAddr follows the logic of manet.IsPublicAddr, except it uses -// a stricter definition of "public" for ipv6: namely "is it in 2000::/3"? +// a stricter definition of "public" for ipv6 by excluding nat64 addresses. func isPublicAddr(a multiaddr.Multiaddr) bool { ip, err := manet.ToIP(a) if err != nil { return false } if ip.To4() != nil { - return !inAddrRange(ip, manet.Private4) && !inAddrRange(ip, manet.Unroutable4) + return manet.IsPublicAddr(a) } - return public6.Contains(ip) + return manet.IsPublicAddr(a) && !manet.IsNAT64IPv4ConvertedIPv6Addr(a) } func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { @@ -295,10 +101,18 @@ type P2PForgeCertMgrConfig struct { trustedRoots *x509.CertPool storage certmagic.Storage modifyForgeRequest func(r *http.Request) error + onCertLoaded func() } type P2PForgeCertMgrOptions func(*P2PForgeCertMgrConfig) error +func WithOnCertLoaded(fn func()) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.onCertLoaded = fn + return nil + } +} + func WithForgeDomain(domain string) P2PForgeCertMgrOptions { return func(config *P2PForgeCertMgrConfig) error { config.forgeDomain = domain @@ -387,32 +201,110 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error certCfg := certmagic.NewDefault() certCfg.Storage = mgrCfg.storage - h := &hostWrapper{} + hostChan := make(chan host.Host, 1) + provideHost := func(host host.Host) { hostChan <- host } + hostVal := sync.OnceValue(func() host.Host { + return <-hostChan + }) myACME := certmagic.NewACMEIssuer(certCfg, certmagic.ACMEIssuer{ // TODO: UX around user passed emails + agreement CA: mgrCfg.caEndpoint, Email: mgrCfg.userEmail, Agreed: true, - DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, h, mgrCfg.modifyForgeRequest}, + DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, hostVal, mgrCfg.modifyForgeRequest}, TrustedRoots: mgrCfg.trustedRoots, }) certCfg.Issuers = []certmagic.Issuer{myACME} - return &P2PForgeCertMgr{mgrCfg.forgeDomain, mgrCfg.forgeRegistrationEndpoint, certCfg, h}, nil + + if mgrCfg.onCertLoaded != nil { + certCfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { + if event == "cached_managed_cert" { + sans, ok := data["sans"] + if !ok { + return nil + } + sanList, ok := sans.([]string) + if !ok { + return nil + } + peerID := hostVal().ID() + pidStr := peer.ToCid(peerID).Encode(multibase.MustNewEncoder(multibase.Base36)) + certName := fmt.Sprintf("*.%s.%s", pidStr, mgrCfg.forgeDomain) + for _, san := range sanList { + if san == certName { + mgrCfg.onCertLoaded() + } + } + return nil + } + return nil + } + } + + return &P2PForgeCertMgr{ + forgeDomain: mgrCfg.forgeDomain, + forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, + provideHost: provideHost, + hostFn: hostVal, + cfg: certCfg, + }, nil } -func (m *P2PForgeCertMgr) Run(ctx context.Context, h host.Host) error { - m.h.Host = h - pb36 := peer.ToCid(h.ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) +func (m *P2PForgeCertMgr) Start() error { + m.ctx, m.cancel = context.WithCancel(context.Background()) + go func() { + pb36 := peer.ToCid(m.hostFn().ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) - if err := m.cfg.ManageAsync(ctx, []string{fmt.Sprintf("*.%s.%s", pb36, m.forgeDomain)}); err != nil { - return err - } + if err := m.cfg.ManageAsync(m.ctx, []string{fmt.Sprintf("*.%s.%s", pb36, m.forgeDomain)}); err != nil { + log.Error(err) + } + }() return nil } +func (m *P2PForgeCertMgr) Stop() { + m.cancel() +} + +// WebSocketTransport returns a libp2p.Option that enables the WebSocket +// transport for libp2p hosts with a TLS config managed by the P2PForgeCertMgr. +func (m *P2PForgeCertMgr) WebSocketTransport(opts ...websocket.Option) libp2p.Option { + tlsCfg := m.cfg.TLSConfig() + tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs + return libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(tlsCfg)) +} + +func (m *P2PForgeCertMgr) AddrStrings(opts ...websocket.Option) []string { + return []string{fmt.Sprintf("/ip4/0.0.0.0/tcp/0/tls/sni/*.%s/ws", m.forgeDomain), + fmt.Sprintf("/ip6/::/tcp/0/tls/sni/*.%s/ws", m.forgeDomain), + } +} + +func (m *P2PForgeCertMgr) Libp2pOptions(opts ...P2PForgeHostOptions) libp2p.Option { + cfg := &P2PForgeHostConfig{} + for _, opt := range opts { + opt(cfg) + } + + tlsCfg := m.cfg.TLSConfig() + tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs + forgeDomain := m.forgeDomain + + var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) + return libp2p.ChainOptions( + libp2p.AddrsFactory(addrFactoryFn(func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent)), + // If we had an Fx option we could do this: + libp2p.WithFxOption( + fx.Invoke(func(host host.Host) { + m.provideHost(host) + }), + ), + ) +} + type dns01P2PForgeSolver struct { forge string - host host.Host + hostVal func() host.Host modifyForgeRequest func(r *http.Request) error } @@ -423,7 +315,8 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge } func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { - req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), d.host.Addrs()) + host := d.hostVal() + req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), host.Addrs()) if err != nil { return err } @@ -433,7 +326,7 @@ func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challe } } - client := &httppeeridauth.ClientPeerIDAuth{PrivKey: d.host.Peerstore().PrivKey(d.host.ID())} + client := &httppeeridauth.ClientPeerIDAuth{PrivKey: host.Peerstore().PrivKey(host.ID())} _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) if err != nil { return err @@ -452,3 +345,77 @@ func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challe var _ acmez.Solver = (*dns01P2PForgeSolver)(nil) var _ acmez.Waiter = (*dns01P2PForgeSolver)(nil) + +func addrFactoryFn(peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr) func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + return func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) + for i, a := range multiaddrs { + if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { + retAddrs[i] = a + continue + } + + // We expect the address to be of the form: /ipX//tcp//tls/sni/*./ws + // We'll then replace the * with the IP address + withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) + if withoutForgeWSS.Equal(a) { + retAddrs[i] = a + continue + } + + index := 0 + var escapedIPStr string + var ipMaStr string + var tcpPortStr string + multiaddr.ForEach(withoutForgeWSS, func(c multiaddr.Component) bool { + switch index { + case 0: + switch c.Protocol().Code { + case multiaddr.P_IP4: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ".", "-") + case multiaddr.P_IP6: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ":", "-") + if escapedIPStr[0] == '-' { + escapedIPStr = "0" + escapedIPStr + } + if escapedIPStr[len(escapedIPStr)-1] == '-' { + escapedIPStr = escapedIPStr + "0" + } + default: + return false + } + case 1: + if c.Protocol().Code != multiaddr.P_TCP { + return false + } + tcpPortStr = c.Value() + default: + index++ + return false + } + index++ + return true + }) + if index != 2 || escapedIPStr == "" || tcpPortStr == "" { + retAddrs[i] = a + continue + } + + pidStr := peer.ToCid(peerIDFn()).Encode(multibase.MustNewEncoder(multibase.Base36)) + + newMaStr := fmt.Sprintf("%s/tcp/%s/tls/sni/%s.%s.%s/ws", ipMaStr, tcpPortStr, escapedIPStr, pidStr, forgeDomain) + newMA, err := multiaddr.NewMultiaddr(newMaStr) + if err != nil { + log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) + retAddrs[i] = a + continue + } + retAddrs[i] = newMA + } + return retAddrs + } +} diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 9fbebfb..f877c15 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -30,7 +30,11 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" + "github.com/libp2p/go-libp2p/p2p/transport/tcp" + libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" + libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" "github.com/miekg/dns" "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" @@ -416,16 +420,36 @@ func TestLibp2pACMEE2E(t *testing.T) { acmeEndpoint := fmt.Sprintf("https://%s%s", acmeHTTPListener.Addr(), pebbleWFE.DirectoryPath) certLoaded := make(chan bool, 1) - h, err := client.NewHostWithP2PForge( - client.WithP2PForgeCertMgrOptions(client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas), - client.WithModifiedForgeRequest(func(req *http.Request) error { - req.Host = forgeRegistration - return nil - })), + + certMgr, err := client.NewP2PForgeCertMgr( + client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas), + client.WithModifiedForgeRequest(func(req *http.Request) error { + req.Host = forgeRegistration + return nil + }), client.WithOnCertLoaded(func() { certLoaded <- true - }), - client.WithAllowPrivateForgeAddrs()) + })) + if err != nil { + t.Fatal(err) + } + certMgr.Start() + defer certMgr.Stop() + + h, err := libp2p.New(libp2p.ChainOptions( + libp2p.DefaultListenAddrs, + libp2p.Transport(tcp.NewTCPTransport), + libp2p.Transport(libp2pquic.NewTransport), + libp2p.Transport(libp2pwebtransport.New), + libp2p.Transport(libp2pwebrtc.New), + + libp2p.ListenAddrStrings( + certMgr.AddrStrings()..., // TODO reuse tcp port for ws + ), + certMgr.WebSocketTransport(), + // Sets up any options taht the cert manager needs + certMgr.Libp2pOptions(client.WithAllowPrivateForgeAddrs()), + )) if err != nil { t.Fatal(err) } From f4940513f44f7a2def3a55f7460be145c47be75a Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 9 Sep 2024 19:14:46 -0700 Subject: [PATCH 20/61] Don't require fx option --- client/acme.go | 45 ++++++++++++++++++++++++++------------------- cmd/e2e_test.go | 3 ++- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/client/acme.go b/client/acme.go index e2fcc07..fdd9d5c 100644 --- a/client/acme.go +++ b/client/acme.go @@ -12,7 +12,6 @@ import ( "time" httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" - "go.uber.org/fx" "github.com/caddyserver/certmagic" logging "github.com/ipfs/go-log/v2" @@ -35,8 +34,9 @@ type P2PForgeCertMgr struct { cancel func() forgeDomain string forgeRegistrationEndpoint string - provideHost func(host.Host) + ProvideHost func(host.Host) hostFn func() host.Host + hasHost func() bool cfg *certmagic.Config } @@ -203,7 +203,17 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error certCfg.Storage = mgrCfg.storage hostChan := make(chan host.Host, 1) provideHost := func(host host.Host) { hostChan <- host } - hostVal := sync.OnceValue(func() host.Host { + hasHostChan := make(chan struct{}) + hasHostFn := func() bool { + select { + case <-hasHostChan: + return true + default: + return false + } + } + hostFn := sync.OnceValue(func() host.Host { + defer close(hasHostChan) return <-hostChan }) @@ -211,7 +221,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error CA: mgrCfg.caEndpoint, Email: mgrCfg.userEmail, Agreed: true, - DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, hostVal, mgrCfg.modifyForgeRequest}, + DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, hostFn, mgrCfg.modifyForgeRequest}, TrustedRoots: mgrCfg.trustedRoots, }) certCfg.Issuers = []certmagic.Issuer{myACME} @@ -227,7 +237,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error if !ok { return nil } - peerID := hostVal().ID() + peerID := hostFn().ID() pidStr := peer.ToCid(peerID).Encode(multibase.MustNewEncoder(multibase.Base36)) certName := fmt.Sprintf("*.%s.%s", pidStr, mgrCfg.forgeDomain) for _, san := range sanList { @@ -244,8 +254,9 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error return &P2PForgeCertMgr{ forgeDomain: mgrCfg.forgeDomain, forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, - provideHost: provideHost, - hostFn: hostVal, + ProvideHost: provideHost, + hostFn: hostFn, + hasHost: hasHostFn, cfg: certCfg, }, nil } @@ -291,20 +302,13 @@ func (m *P2PForgeCertMgr) Libp2pOptions(opts ...P2PForgeHostOptions) libp2p.Opti forgeDomain := m.forgeDomain var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) - return libp2p.ChainOptions( - libp2p.AddrsFactory(addrFactoryFn(func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent)), - // If we had an Fx option we could do this: - libp2p.WithFxOption( - fx.Invoke(func(host host.Host) { - m.provideHost(host) - }), - ), - ) + return libp2p.AddrsFactory(addrFactoryFn(m.hasHost, func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent)) + } type dns01P2PForgeSolver struct { forge string - hostVal func() host.Host + hostFn func() host.Host modifyForgeRequest func(r *http.Request) error } @@ -315,7 +319,7 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge } func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { - host := d.hostVal() + host := d.hostFn() req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), host.Addrs()) if err != nil { return err @@ -346,8 +350,11 @@ func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challe var _ acmez.Solver = (*dns01P2PForgeSolver)(nil) var _ acmez.Waiter = (*dns01P2PForgeSolver)(nil) -func addrFactoryFn(peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr) func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { +func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr) func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { return func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + if !hasPeerID() { + return multiaddrs + } retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) for i, a := range multiaddrs { if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index f877c15..5e42524 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -447,12 +447,13 @@ func TestLibp2pACMEE2E(t *testing.T) { certMgr.AddrStrings()..., // TODO reuse tcp port for ws ), certMgr.WebSocketTransport(), - // Sets up any options taht the cert manager needs + // Sets up any options that the cert manager needs certMgr.Libp2pOptions(client.WithAllowPrivateForgeAddrs()), )) if err != nil { t.Fatal(err) } + certMgr.ProvideHost(h) cp := x509.NewCertPool() cp.AddCert(ca.GetRootCert(0).Cert) From c6feb2ae1f25987c039e09d333b2e985202a27db Mon Sep 17 00:00:00 2001 From: Marco Munizaga Date: Mon, 9 Sep 2024 19:30:31 -0700 Subject: [PATCH 21/61] Fix check --- client/acme.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/acme.go b/client/acme.go index fdd9d5c..ead8a90 100644 --- a/client/acme.go +++ b/client/acme.go @@ -18,7 +18,6 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/p2p/transport/websocket" libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" "github.com/mholt/acmez/v2" "github.com/mholt/acmez/v2/acme" @@ -279,13 +278,13 @@ func (m *P2PForgeCertMgr) Stop() { // WebSocketTransport returns a libp2p.Option that enables the WebSocket // transport for libp2p hosts with a TLS config managed by the P2PForgeCertMgr. -func (m *P2PForgeCertMgr) WebSocketTransport(opts ...websocket.Option) libp2p.Option { +func (m *P2PForgeCertMgr) WebSocketTransport(opts ...libp2pws.Option) libp2p.Option { tlsCfg := m.cfg.TLSConfig() tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs return libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(tlsCfg)) } -func (m *P2PForgeCertMgr) AddrStrings(opts ...websocket.Option) []string { +func (m *P2PForgeCertMgr) AddrStrings() []string { return []string{fmt.Sprintf("/ip4/0.0.0.0/tcp/0/tls/sni/*.%s/ws", m.forgeDomain), fmt.Sprintf("/ip6/::/tcp/0/tls/sni/*.%s/ws", m.forgeDomain), } From 1e262a8e5dc8c058bbb6fa5736936150b8883eb0 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 10 Sep 2024 22:30:32 -0400 Subject: [PATCH 22/61] feat: expose tls.Config explicitly rather than as a WebSocket option --- client/acme.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/client/acme.go b/client/acme.go index ead8a90..bec6f1f 100644 --- a/client/acme.go +++ b/client/acme.go @@ -2,6 +2,7 @@ package client import ( "context" + "crypto/tls" "crypto/x509" "fmt" "io" @@ -18,7 +19,6 @@ import ( "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" - libp2pws "github.com/libp2p/go-libp2p/p2p/transport/websocket" "github.com/mholt/acmez/v2" "github.com/mholt/acmez/v2/acme" "github.com/multiformats/go-multiaddr" @@ -276,12 +276,11 @@ func (m *P2PForgeCertMgr) Stop() { m.cancel() } -// WebSocketTransport returns a libp2p.Option that enables the WebSocket -// transport for libp2p hosts with a TLS config managed by the P2PForgeCertMgr. -func (m *P2PForgeCertMgr) WebSocketTransport(opts ...libp2pws.Option) libp2p.Option { +// TLSConfig returns a tls.Config that managed by the P2PForgeCertMgr +func (m *P2PForgeCertMgr) TLSConfig() *tls.Config { tlsCfg := m.cfg.TLSConfig() - tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs - return libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(tlsCfg)) + tlsCfg.NextProtos = nil // remove the ACME ALPN + return tlsCfg } func (m *P2PForgeCertMgr) AddrStrings() []string { From c55d539ed67bffe581dca25f5a38754fb44d59dc Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 10 Sep 2024 22:34:23 -0400 Subject: [PATCH 23/61] feat: expose an AddrsFactory function explicitly rather than as a libp2p.Option --- client/acme.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/acme.go b/client/acme.go index bec6f1f..8115ae6 100644 --- a/client/acme.go +++ b/client/acme.go @@ -16,7 +16,7 @@ import ( "github.com/caddyserver/certmagic" logging "github.com/ipfs/go-log/v2" - "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/config" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/mholt/acmez/v2" @@ -289,7 +289,10 @@ func (m *P2PForgeCertMgr) AddrStrings() []string { } } -func (m *P2PForgeCertMgr) Libp2pOptions(opts ...P2PForgeHostOptions) libp2p.Option { +// AddressFactory returns a function that rewrites a set of forge managed multiaddresses. +// This should be used with the libp2p.AddrsFactory option to ensure that a libp2p host with forge managed addresses +// only announces those that are active and valid. +func (m *P2PForgeCertMgr) AddressFactory(opts ...P2PForgeHostOptions) config.AddrsFactory { cfg := &P2PForgeHostConfig{} for _, opt := range opts { opt(cfg) @@ -300,8 +303,7 @@ func (m *P2PForgeCertMgr) Libp2pOptions(opts ...P2PForgeHostOptions) libp2p.Opti forgeDomain := m.forgeDomain var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) - return libp2p.AddrsFactory(addrFactoryFn(m.hasHost, func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent)) - + return addrFactoryFn(m.hasHost, func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent) } type dns01P2PForgeSolver struct { From 2d2f576a9ded31882521f3efbbe221a7fb938948 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 00:20:04 -0400 Subject: [PATCH 24/61] chore: update go-ds-dynamodb --- go.mod | 6 +++--- go.sum | 30 ++++++------------------------ 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index b67a477..6282302 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,14 @@ module github.com/ipshipyard/p2p-forge go 1.22 require ( - github.com/aws/aws-sdk-go v1.51.25 + github.com/aws/aws-sdk-go v1.55.5 github.com/caddyserver/certmagic v0.21.3 github.com/coredns/caddy v1.1.1 github.com/coredns/coredns v1.11.3 github.com/gorilla/mux v1.8.1 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger4 v0.1.5 - github.com/ipfs/go-ds-dynamodb v0.1.1 + github.com/ipfs/go-ds-dynamodb v0.2.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c @@ -201,7 +201,7 @@ require ( golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect diff --git a/go.sum b/go.sum index 0ab38f6..4158a19 100644 --- a/go.sum +++ b/go.sum @@ -59,9 +59,8 @@ github.com/antonmedv/expr v1.15.5 h1:y0Iz3cEwmpRz5/r3w4qQR0MfIqJGdGM1zbhD/v0G5Vg github.com/antonmedv/expr v1.15.5/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/aws/aws-sdk-go v1.43.1/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= -github.com/aws/aws-sdk-go v1.51.25 h1:DjTT8mtmsachhV6yrXR8+yhnG6120dazr720nopRsls= -github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -231,7 +230,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -267,17 +265,14 @@ github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9 h1:w66aaP3c6 github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9/go.mod h1:BaIJzjD2ZnHmx2acPF6XfGLPzNCMiBbMRqJr+8/8uRI= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger4 v0.1.5 h1:MwrTsIUJIqH/ChuDdUOzxwxMxHx/Li1ECoSCKsCUxiA= github.com/ipfs/go-ds-badger4 v0.1.5/go.mod h1:LUU2FbhNdmhAbJmMeoahVRbe4GsduAODSJHWJJh2Vo4= -github.com/ipfs/go-ds-dynamodb v0.1.1 h1:636i0Gl8j9wuKfw4gZKTH/fOch5WLWDu0OYrlBTE/0g= -github.com/ipfs/go-ds-dynamodb v0.1.1/go.mod h1:JG3C8nDcZMer7hKUVDT1wKY9LdD7TAX0psPSC7R/BrE= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-ds-dynamodb v0.2.0 h1:chGlVv19fh86ep35KbBcS+iCL9sc9gJbJToU22ON1wY= +github.com/ipfs/go-ds-dynamodb v0.2.0/go.mod h1:tWx1vVUuMUNXqT/C//bFXF7JdD4Ma0aAtE4XW1dcp+A= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -309,7 +304,6 @@ github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -510,7 +504,6 @@ github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtB github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -600,7 +593,6 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -614,11 +606,9 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= @@ -627,7 +617,6 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -651,7 +640,6 @@ 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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -680,7 +668,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -741,8 +728,8 @@ 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.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -777,9 +764,6 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -849,7 +833,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -869,7 +852,6 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= From e91c9c0b0afd4c15f87fb3fac7598c881205bf0c Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 03:22:21 -0400 Subject: [PATCH 25/61] ws option --- client/acme.go | 14 +++++++------- cmd/e2e_test.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/acme.go b/client/acme.go index 8115ae6..4cc845c 100644 --- a/client/acme.go +++ b/client/acme.go @@ -355,10 +355,10 @@ func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain s if !hasPeerID() { return multiaddrs } - retAddrs := make([]multiaddr.Multiaddr, len(multiaddrs)) - for i, a := range multiaddrs { + retAddrs := make([]multiaddr.Multiaddr, 0, len(multiaddrs)) + for _, a := range multiaddrs { if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { - retAddrs[i] = a + retAddrs = append(retAddrs, a) continue } @@ -366,7 +366,7 @@ func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain s // We'll then replace the * with the IP address withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) if withoutForgeWSS.Equal(a) { - retAddrs[i] = a + retAddrs = append(retAddrs, a) continue } @@ -408,7 +408,7 @@ func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain s return true }) if index != 2 || escapedIPStr == "" || tcpPortStr == "" { - retAddrs[i] = a + retAddrs = append(retAddrs, a) continue } @@ -418,10 +418,10 @@ func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain s newMA, err := multiaddr.NewMultiaddr(newMaStr) if err != nil { log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) - retAddrs[i] = a + retAddrs = append(retAddrs, a) continue } - retAddrs[i] = newMA + retAddrs = append(retAddrs, newMA) } return retAddrs } diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 5e42524..b94ded1 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -446,7 +446,7 @@ func TestLibp2pACMEE2E(t *testing.T) { libp2p.ListenAddrStrings( certMgr.AddrStrings()..., // TODO reuse tcp port for ws ), - certMgr.WebSocketTransport(), + libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(certMgr.TLSConfig())), // Sets up any options that the cert manager needs certMgr.Libp2pOptions(client.WithAllowPrivateForgeAddrs()), )) From 0d9c6f8f7d825a3cd6069b62f2ee1ce2de924a03 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 03:22:46 -0400 Subject: [PATCH 26/61] addrsfactory option --- cmd/e2e_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index b94ded1..1e415b1 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -447,8 +447,7 @@ func TestLibp2pACMEE2E(t *testing.T) { certMgr.AddrStrings()..., // TODO reuse tcp port for ws ), libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(certMgr.TLSConfig())), - // Sets up any options that the cert manager needs - certMgr.Libp2pOptions(client.WithAllowPrivateForgeAddrs()), + libp2p.AddrsFactory(certMgr.AddressFactory(client.WithAllowPrivateForgeAddrs())), )) if err != nil { t.Fatal(err) From 9779c7c5f0e36330693b79bf7cbc6c4afa3b0b94 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 15:17:02 -0400 Subject: [PATCH 27/61] feat: only expose forge addresses once we have certificates available --- client/acme.go | 176 ++++++++++++++++++++++++++++-------------------- cmd/e2e_test.go | 12 ++-- 2 files changed, 110 insertions(+), 78 deletions(-) diff --git a/client/acme.go b/client/acme.go index 4cc845c..23cffa1 100644 --- a/client/acme.go +++ b/client/acme.go @@ -37,6 +37,9 @@ type P2PForgeCertMgr struct { hostFn func() host.Host hasHost func() bool cfg *certmagic.Config + + hasCert bool // tracking if we've received a certificate + certCheckMx sync.RWMutex } type P2PForgeHostConfig struct { @@ -225,6 +228,15 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error }) certCfg.Issuers = []certmagic.Issuer{myACME} + mgr := &P2PForgeCertMgr{ + forgeDomain: mgrCfg.forgeDomain, + forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, + ProvideHost: provideHost, + hostFn: hostFn, + hasHost: hasHostFn, + cfg: certCfg, + } + if mgrCfg.onCertLoaded != nil { certCfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { if event == "cached_managed_cert" { @@ -241,6 +253,12 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error certName := fmt.Sprintf("*.%s.%s", pidStr, mgrCfg.forgeDomain) for _, san := range sanList { if san == certName { + // When the certificate is loaded mark that it has been so we know we are good to use the domain name + // TODO: This won't handle if the cert expires and cannot get renewed + mgr.certCheckMx.Lock() + mgr.hasCert = true + mgr.certCheckMx.Unlock() + // Execute user function for on certificate load mgrCfg.onCertLoaded() } } @@ -250,14 +268,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error } } - return &P2PForgeCertMgr{ - forgeDomain: mgrCfg.forgeDomain, - forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, - ProvideHost: provideHost, - hostFn: hostFn, - hasHost: hasHostFn, - cfg: certCfg, - }, nil + return mgr, nil } func (m *P2PForgeCertMgr) Start() error { @@ -300,10 +311,26 @@ func (m *P2PForgeCertMgr) AddressFactory(opts ...P2PForgeHostOptions) config.Add tlsCfg := m.cfg.TLSConfig() tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs - forgeDomain := m.forgeDomain - var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", forgeDomain)) - return addrFactoryFn(m.hasHost, func() peer.ID { return m.hostFn().ID() }, forgeDomain, cfg.allowPrivateForgeAddrs, p2pForgeWssComponent) + return m.createAddrsFactory(cfg.allowPrivateForgeAddrs) +} + +func (m *P2PForgeCertMgr) createAddrsFactory(allowPrivateForgeAddrs bool) config.AddrsFactory { + var p2pForgeWssComponent = multiaddr.StringCast(fmt.Sprintf("/tls/sni/*.%s/ws", m.forgeDomain)) + + return func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + var skipForgeAddrs bool + if !m.hasHost() { + skipForgeAddrs = true + } + m.certCheckMx.RLock() + if !m.hasCert { + skipForgeAddrs = true + } + m.certCheckMx.RUnlock() + + return addrFactoryFn(skipForgeAddrs, func() peer.ID { return m.hostFn().ID() }, m.forgeDomain, allowPrivateForgeAddrs, p2pForgeWssComponent, multiaddrs) + } } type dns01P2PForgeSolver struct { @@ -350,79 +377,84 @@ func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challe var _ acmez.Solver = (*dns01P2PForgeSolver)(nil) var _ acmez.Waiter = (*dns01P2PForgeSolver)(nil) -func addrFactoryFn(hasPeerID func() bool, peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr) func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { - return func(multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { - if !hasPeerID() { - return multiaddrs +func addrFactoryFn(skipForgeAddrs bool, peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr, multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { + retAddrs := make([]multiaddr.Multiaddr, 0, len(multiaddrs)) + for _, a := range multiaddrs { + if isRelayAddr(a) { + retAddrs = append(retAddrs, a) + continue } - retAddrs := make([]multiaddr.Multiaddr, 0, len(multiaddrs)) - for _, a := range multiaddrs { - if isRelayAddr(a) || (!allowPrivateForgeAddrs && isPublicAddr(a)) { - retAddrs = append(retAddrs, a) - continue - } - // We expect the address to be of the form: /ipX//tcp//tls/sni/*./ws - // We'll then replace the * with the IP address - withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) - if withoutForgeWSS.Equal(a) { - retAddrs = append(retAddrs, a) - continue - } + // We expect the address to be of the form: /ipX//tcp//tls/sni/*./ws + // We'll then replace the * with the IP address + withoutForgeWSS := a.Decapsulate(p2pForgeWssComponent) + if withoutForgeWSS.Equal(a) { + retAddrs = append(retAddrs, a) + continue + } - index := 0 - var escapedIPStr string - var ipMaStr string - var tcpPortStr string - multiaddr.ForEach(withoutForgeWSS, func(c multiaddr.Component) bool { - switch index { - case 0: - switch c.Protocol().Code { - case multiaddr.P_IP4: - ipMaStr = c.String() - ipAddr := c.Value() - escapedIPStr = strings.ReplaceAll(ipAddr, ".", "-") - case multiaddr.P_IP6: - ipMaStr = c.String() - ipAddr := c.Value() - escapedIPStr = strings.ReplaceAll(ipAddr, ":", "-") - if escapedIPStr[0] == '-' { - escapedIPStr = "0" + escapedIPStr - } - if escapedIPStr[len(escapedIPStr)-1] == '-' { - escapedIPStr = escapedIPStr + "0" - } - default: - return false + index := 0 + var escapedIPStr string + var ipMaStr string + var tcpPortStr string + multiaddr.ForEach(withoutForgeWSS, func(c multiaddr.Component) bool { + switch index { + case 0: + switch c.Protocol().Code { + case multiaddr.P_IP4: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ".", "-") + case multiaddr.P_IP6: + ipMaStr = c.String() + ipAddr := c.Value() + escapedIPStr = strings.ReplaceAll(ipAddr, ":", "-") + if escapedIPStr[0] == '-' { + escapedIPStr = "0" + escapedIPStr } - case 1: - if c.Protocol().Code != multiaddr.P_TCP { - return false + if escapedIPStr[len(escapedIPStr)-1] == '-' { + escapedIPStr = escapedIPStr + "0" } - tcpPortStr = c.Value() default: - index++ return false } + case 1: + if c.Protocol().Code != multiaddr.P_TCP { + return false + } + tcpPortStr = c.Value() + default: index++ - return true - }) - if index != 2 || escapedIPStr == "" || tcpPortStr == "" { - retAddrs = append(retAddrs, a) - continue + return false } + index++ + return true + }) + if index != 2 || escapedIPStr == "" || tcpPortStr == "" { + retAddrs = append(retAddrs, a) + continue + } - pidStr := peer.ToCid(peerIDFn()).Encode(multibase.MustNewEncoder(multibase.Base36)) + // It looks like it's a valid forge address, now figure out if we skip these forge addresses + if skipForgeAddrs { + continue + } - newMaStr := fmt.Sprintf("%s/tcp/%s/tls/sni/%s.%s.%s/ws", ipMaStr, tcpPortStr, escapedIPStr, pidStr, forgeDomain) - newMA, err := multiaddr.NewMultiaddr(newMaStr) - if err != nil { - log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) - retAddrs = append(retAddrs, a) - continue - } - retAddrs = append(retAddrs, newMA) + // don't return non-public forge addresses unless explicitly opted in + if !allowPrivateForgeAddrs && !isPublicAddr(a) { + continue + } + + pidStr := peer.ToCid(peerIDFn()).Encode(multibase.MustNewEncoder(multibase.Base36)) + + newMaStr := fmt.Sprintf("%s/tcp/%s/tls/sni/%s.%s.%s/ws", ipMaStr, tcpPortStr, escapedIPStr, pidStr, forgeDomain) + newMA, err := multiaddr.NewMultiaddr(newMaStr) + if err != nil { + log.Errorf("error creating new multiaddr from %q: %s", newMaStr, err.Error()) + retAddrs = append(retAddrs, a) + continue } - return retAddrs + retAddrs = append(retAddrs, newMA) } + return retAddrs } diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 1e415b1..303c1b4 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -481,6 +481,12 @@ func TestLibp2pACMEE2E(t *testing.T) { t.Fatal(err) } + select { + case <-certLoaded: + case <-time.After(time.Second * 30): + t.Fatal("timed out waiting for certificate") + } + var dialAddr multiaddr.Multiaddr hAddrs := h.Addrs() for _, addr := range hAddrs { @@ -497,12 +503,6 @@ func TestLibp2pACMEE2E(t *testing.T) { t.Fatalf("no valid wss addresses: %v", hAddrs) } - select { - case <-certLoaded: - case <-time.After(time.Second * 30): - t.Fatal("timed out waiting for certificate") - } - if err := h2.Connect(ctx, peer.AddrInfo{ID: h.ID(), Addrs: []multiaddr.Multiaddr{dialAddr}}); err != nil { t.Fatal(err) } From 4c9dc3e29f4584a908107368aeeae441c9c0d45f Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 15:17:26 -0400 Subject: [PATCH 28/61] fix: return an error if we can't write out the DNS response message --- acme/reader.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/acme/reader.go b/acme/reader.go index 36972be..499b3b2 100644 --- a/acme/reader.go +++ b/acme/reader.go @@ -70,7 +70,10 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M m.SetReply(r) m.Authoritative = true m.Answer = answers - w.WriteMsg(&m) + err := w.WriteMsg(&m) + if err != nil { + return dns.RcodeServerFailure, err + } return dns.RcodeSuccess, nil } From 65b05b8c3966a041bb6580659c8476363428b719 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 16:14:50 -0400 Subject: [PATCH 29/61] feat: add Forge-Authorization header as a guard on setting ACME challenges --- acme/writer.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/acme/writer.go b/acme/writer.go index 7055d01..65e5ce3 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -11,6 +11,7 @@ import ( "io" "net" "net/http" + "os" "strings" "time" @@ -31,6 +32,9 @@ import ( var log = clog.NewWithPlugin(pluginName) +const authEnvVar = "FORGE_ACCESS_TOKEN" +const authForgeHeader = "Forge-Authorization" + // acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. type acmeWriter struct { Addr string @@ -43,6 +47,8 @@ type acmeWriter struct { nlSetup bool closeCertMgr func() mux *mux.Router + + forgeAuthKey string } func (c *acmeWriter) OnStartup() error { @@ -73,6 +79,10 @@ func (c *acmeWriter) OnStartup() error { ln = tls.NewListener(ln, tlsConfig) } + authKey, found := os.LookupEnv(authEnvVar) + if found { + c.forgeAuthKey = authKey + } c.ln = ln c.mux = mux.NewRouter() @@ -87,6 +97,14 @@ func (c *acmeWriter) OnStartup() error { PrivKey: sk, TokenTTL: time.Hour, Next: func(peerID peer.ID, w http.ResponseWriter, r *http.Request) { + if c.forgeAuthKey != "" { + auth := r.Header.Get(authForgeHeader) + if c.forgeAuthKey != auth { + w.WriteHeader(http.StatusForbidden) + return + } + } + body, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusInternalServerError) From 02e34f097756a6321acc1ecce2fd2c3a734b2b03 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 18:07:56 -0400 Subject: [PATCH 30/61] chore: remove unused code --- client/acme.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/client/acme.go b/client/acme.go index 23cffa1..b1c0b9e 100644 --- a/client/acme.go +++ b/client/acme.go @@ -6,7 +6,6 @@ import ( "crypto/x509" "fmt" "io" - "net" "net/http" "strings" "sync" @@ -85,16 +84,6 @@ func isPublicAddr(a multiaddr.Multiaddr) bool { return manet.IsPublicAddr(a) && !manet.IsNAT64IPv4ConvertedIPv6Addr(a) } -func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool { - for _, ipnet := range ipnets { - if ipnet.Contains(ip) { - return true - } - } - - return false -} - type P2PForgeCertMgrConfig struct { forgeDomain string forgeRegistrationEndpoint string From db86cf21603fd058530db83b27e91115d90ab5da Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Sep 2024 22:21:14 -0400 Subject: [PATCH 31/61] feat: enable use of all default plugins --- cmd/main.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index cb59451..ed0b3bf 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,17 +9,13 @@ import ( "github.com/coredns/coredns/coremain" ) -var directives = []string{ - "log", - "whoami", - "startup", - "shutdown", +var customDirectives = []string{ "ipparser", "acme", } func init() { - dnsserver.Directives = directives + dnsserver.Directives = append(dnsserver.Directives, customDirectives...) } func main() { From 2020f9ca84c7a20a4fb7b11cf660d6d1424a023c Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 12 Sep 2024 15:28:17 -0400 Subject: [PATCH 32/61] feat: client only sends the forge public addresses --- client/acme.go | 116 ++++++++++++++++++++++++++---------------------- cmd/e2e_test.go | 3 +- 2 files changed, 65 insertions(+), 54 deletions(-) diff --git a/client/acme.go b/client/acme.go index b1c0b9e..3fe7cb4 100644 --- a/client/acme.go +++ b/client/acme.go @@ -28,39 +28,20 @@ import ( var log = logging.Logger("p2p-forge/client") type P2PForgeCertMgr struct { - ctx context.Context - cancel func() - forgeDomain string - forgeRegistrationEndpoint string - ProvideHost func(host.Host) - hostFn func() host.Host - hasHost func() bool - cfg *certmagic.Config + ctx context.Context + cancel func() + forgeDomain string + forgeRegistrationEndpoint string + ProvideHost func(host.Host) + hostFn func() host.Host + hasHost func() bool + cfg *certmagic.Config + allowPrivateForgeAddresses bool hasCert bool // tracking if we've received a certificate certCheckMx sync.RWMutex } -type P2PForgeHostConfig struct { - certMgrOpts []P2PForgeCertMgrOptions - allowPrivateForgeAddrs bool -} - -type P2PForgeHostOptions func(*P2PForgeHostConfig) - -func WithP2PForgeCertMgrOptions(opts ...P2PForgeCertMgrOptions) P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) { - h.certMgrOpts = append(h.certMgrOpts, opts...) - } -} - -// WithAllowPrivateForgeAddrs is meant for testing -func WithAllowPrivateForgeAddrs() P2PForgeHostOptions { - return func(h *P2PForgeHostConfig) { - h.allowPrivateForgeAddrs = true - } -} - func isRelayAddr(a multiaddr.Multiaddr) bool { found := false multiaddr.ForEach(a, func(c multiaddr.Component) bool { @@ -85,14 +66,15 @@ func isPublicAddr(a multiaddr.Multiaddr) bool { } type P2PForgeCertMgrConfig struct { - forgeDomain string - forgeRegistrationEndpoint string - caEndpoint string - userEmail string - trustedRoots *x509.CertPool - storage certmagic.Storage - modifyForgeRequest func(r *http.Request) error - onCertLoaded func() + forgeDomain string + forgeRegistrationEndpoint string + caEndpoint string + userEmail string + trustedRoots *x509.CertPool + storage certmagic.Storage + modifyForgeRequest func(r *http.Request) error + onCertLoaded func() + allowPrivateForgeAddresses bool } type P2PForgeCertMgrOptions func(*P2PForgeCertMgrConfig) error @@ -156,6 +138,14 @@ func WithTrustedRoots(trustedRoots *x509.CertPool) P2PForgeCertMgrOptions { } } +// WithAllowPrivateForgeAddrs is meant for testing +func WithAllowPrivateForgeAddrs() P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.allowPrivateForgeAddresses = true + return nil + } +} + // NewP2PForgeCertMgr handles the creation and management of certificates that are automatically granted by a forge // to a libp2p host. // @@ -209,10 +199,15 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error }) myACME := certmagic.NewACMEIssuer(certCfg, certmagic.ACMEIssuer{ // TODO: UX around user passed emails + agreement - CA: mgrCfg.caEndpoint, - Email: mgrCfg.userEmail, - Agreed: true, - DNS01Solver: &dns01P2PForgeSolver{mgrCfg.forgeRegistrationEndpoint, hostFn, mgrCfg.modifyForgeRequest}, + CA: mgrCfg.caEndpoint, + Email: mgrCfg.userEmail, + Agreed: true, + DNS01Solver: &dns01P2PForgeSolver{ + forge: mgrCfg.forgeRegistrationEndpoint, + hostFn: hostFn, + modifyForgeRequest: mgrCfg.modifyForgeRequest, + allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, + }, TrustedRoots: mgrCfg.trustedRoots, }) certCfg.Issuers = []certmagic.Issuer{myACME} @@ -292,16 +287,11 @@ func (m *P2PForgeCertMgr) AddrStrings() []string { // AddressFactory returns a function that rewrites a set of forge managed multiaddresses. // This should be used with the libp2p.AddrsFactory option to ensure that a libp2p host with forge managed addresses // only announces those that are active and valid. -func (m *P2PForgeCertMgr) AddressFactory(opts ...P2PForgeHostOptions) config.AddrsFactory { - cfg := &P2PForgeHostConfig{} - for _, opt := range opts { - opt(cfg) - } - +func (m *P2PForgeCertMgr) AddressFactory() config.AddrsFactory { tlsCfg := m.cfg.TLSConfig() tlsCfg.NextProtos = []string{"h2", "http/1.1"} // remove the ACME ALPN and set the HTTP 1.1 and 2 ALPNs - return m.createAddrsFactory(cfg.allowPrivateForgeAddrs) + return m.createAddrsFactory(m.allowPrivateForgeAddresses) } func (m *P2PForgeCertMgr) createAddrsFactory(allowPrivateForgeAddrs bool) config.AddrsFactory { @@ -323,9 +313,10 @@ func (m *P2PForgeCertMgr) createAddrsFactory(allowPrivateForgeAddrs bool) config } type dns01P2PForgeSolver struct { - forge string - hostFn func() host.Host - modifyForgeRequest func(r *http.Request) error + forge string + hostFn func() host.Host + modifyForgeRequest func(r *http.Request) error + allowPrivateForgeAddresses bool } func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge) error { @@ -335,8 +326,27 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge } func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error { - host := d.hostFn() - req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), host.Addrs()) + h := d.hostFn() + addrs := h.Addrs() + var advertisedAddrs []multiaddr.Multiaddr + + if !d.allowPrivateForgeAddresses { + var publicAddrs []multiaddr.Multiaddr + for _, addr := range addrs { + if isPublicAddr(addr) { + publicAddrs = append(publicAddrs, addr) + } + } + + if len(publicAddrs) == 0 { + return fmt.Errorf("no public address found") + } + advertisedAddrs = publicAddrs + } else { + advertisedAddrs = addrs + } + + req, err := ChallengeRequest(ctx, d.forge, challenge.DNS01KeyAuthorization(), advertisedAddrs) if err != nil { return err } @@ -346,7 +356,7 @@ func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challe } } - client := &httppeeridauth.ClientPeerIDAuth{PrivKey: host.Peerstore().PrivKey(host.ID())} + client := &httppeeridauth.ClientPeerIDAuth{PrivKey: h.Peerstore().PrivKey(h.ID())} _, resp, err := client.AuthenticatedDo(http.DefaultClient, req) if err != nil { return err diff --git a/cmd/e2e_test.go b/cmd/e2e_test.go index 303c1b4..0a4dc76 100644 --- a/cmd/e2e_test.go +++ b/cmd/e2e_test.go @@ -427,6 +427,7 @@ func TestLibp2pACMEE2E(t *testing.T) { req.Host = forgeRegistration return nil }), + client.WithAllowPrivateForgeAddrs(), client.WithOnCertLoaded(func() { certLoaded <- true })) @@ -447,7 +448,7 @@ func TestLibp2pACMEE2E(t *testing.T) { certMgr.AddrStrings()..., // TODO reuse tcp port for ws ), libp2p.Transport(libp2pws.New, libp2pws.WithTLSConfig(certMgr.TLSConfig())), - libp2p.AddrsFactory(certMgr.AddressFactory(client.WithAllowPrivateForgeAddrs())), + libp2p.AddrsFactory(certMgr.AddressFactory()), )) if err != nil { t.Fatal(err) From 6fff08eea8b5a59475bec6e165b5c5d1b394328f Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 13 Sep 2024 02:09:53 -0400 Subject: [PATCH 33/61] fix: return server fail if failed to write response --- ipparser/plugin.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ipparser/plugin.go b/ipparser/plugin.go index 7d010c7..29f8c8a 100644 --- a/ipparser/plugin.go +++ b/ipparser/plugin.go @@ -122,7 +122,10 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg m.SetReply(r) m.Authoritative = true m.Answer = answers - w.WriteMsg(&m) + err := w.WriteMsg(&m) + if err != nil { + return dns.RcodeServerFailure, err + } return dns.RcodeSuccess, nil } From 6b008c390e63af098c0459f585f563aff818dc2e Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 13 Sep 2024 18:09:03 -0400 Subject: [PATCH 34/61] fix: propagate WithAllowPrivateForgeAddrs correctly --- client/acme.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client/acme.go b/client/acme.go index 3fe7cb4..23cdcc9 100644 --- a/client/acme.go +++ b/client/acme.go @@ -213,12 +213,13 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error certCfg.Issuers = []certmagic.Issuer{myACME} mgr := &P2PForgeCertMgr{ - forgeDomain: mgrCfg.forgeDomain, - forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, - ProvideHost: provideHost, - hostFn: hostFn, - hasHost: hasHostFn, - cfg: certCfg, + forgeDomain: mgrCfg.forgeDomain, + forgeRegistrationEndpoint: mgrCfg.forgeRegistrationEndpoint, + ProvideHost: provideHost, + hostFn: hostFn, + hasHost: hasHostFn, + cfg: certCfg, + allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, } if mgrCfg.onCertLoaded != nil { From 39a53084cf4ef1b4debb64c8100e01035393e60e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 13 Sep 2024 23:29:38 +0200 Subject: [PATCH 35/61] fix: apply p2pforge before file plugin this allows us to handle acme and a records before looking into a static zone file --- cmd/main.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index ed0b3bf..5859ced 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,15 +7,31 @@ import ( "github.com/coredns/coredns/core/dnsserver" "github.com/coredns/coredns/coremain" + clog "github.com/coredns/coredns/plugin/pkg/log" ) -var customDirectives = []string{ +var p2pForgeDirectives = []string{ "ipparser", "acme", } func init() { - dnsserver.Directives = append(dnsserver.Directives, customDirectives...) + // Add custom plugins before 'file' to ensure our dynamic + // code is executed before static records loaded via 'file' which does not + // support fallthrough + // https://github.com/coredns/coredns/blob/v1.11.3/plugin.cfg + // https://github.com/coredns/coredns/issues/3601 + for i, d := range dnsserver.Directives { + if d == "file" { + ds := make([]string, 0, len(dnsserver.Directives)+len(p2pForgeDirectives)) + ds = append(ds, dnsserver.Directives[:i]...) + ds = append(ds, p2pForgeDirectives...) + ds = append(ds, dnsserver.Directives[i:]...) + dnsserver.Directives = ds + break + } + } + clog.Debugf("updated directives: %v", dnsserver.Directives) } func main() { From b06ddb08eca34495688de034c14ab33ad0af48ed Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 14 Sep 2024 02:32:21 +0200 Subject: [PATCH 36/61] refactor: p2p-forge cli and docker support - cleans up the way it is built, adds version tracking for stdout - includes Corefile and zone examples - Dockerfile - updated readme --- .github/docker/entrypoint.sh | 18 ++++++++ .github/docker/get-docker-tags.sh | 55 ++++++++++++++++++++++++ .github/workflows/docker.yml | 69 +++++++++++++++++++++++++++++++ .gitignore | 4 ++ Corefile | 6 +++ Dockerfile | 59 ++++++++++++++++++++++++++ README.md | 27 ++++++++++-- cmd/e2e_test.go => e2e_test.go | 0 cmd/main.go => main.go | 3 ++ version.go | 51 +++++++++++++++++++++++ version.json | 3 ++ zones/libp2p.direct | 33 +++++++++++++++ 12 files changed, 324 insertions(+), 4 deletions(-) create mode 100755 .github/docker/entrypoint.sh create mode 100755 .github/docker/get-docker-tags.sh create mode 100644 .github/workflows/docker.yml create mode 100644 .gitignore create mode 100644 Corefile create mode 100644 Dockerfile rename cmd/e2e_test.go => e2e_test.go (100%) rename cmd/main.go => main.go (94%) create mode 100644 version.go create mode 100644 version.json create mode 100644 zones/libp2p.direct diff --git a/.github/docker/entrypoint.sh b/.github/docker/entrypoint.sh new file mode 100755 index 0000000..1fe7be6 --- /dev/null +++ b/.github/docker/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e +user=p2pforge + +if [ -n "$DOCKER_DEBUG" ]; then + set -x +fi + +if [ `id -u` -eq 0 ]; then + echo "Changing user to $user" + exec su-exec "$user" "$0" $@ +fi + +# Only supported user can get here +p2p-forge --version + +exec p2p-forge $@ diff --git a/.github/docker/get-docker-tags.sh b/.github/docker/get-docker-tags.sh new file mode 100755 index 0000000..a230d21 --- /dev/null +++ b/.github/docker/get-docker-tags.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# get-docker-tags.sh produces Docker tags for the current build +# +# Usage: +# ./get-docker-tags.sh [git tag name] +# +# Example: +# +# # get tag for the main branch +# ./get-docker-tags.sh $(date -u +%F) testingsha main +# +# # get tag for a release tag +# ./get-docker-tags.sh $(date -u +%F) testingsha release v0.5.0 +# +# # Serving suggestion in CI +# ./get-docker-tags.sh $(date -u +%F) "$CI_SHA1" "$CI_BRANCH" "$CI_TAG" +# +set -euo pipefail + +if [[ $# -lt 1 ]] ; then + echo 'At least 1 arg required.' + echo 'Usage:' + echo './get-docker-tags.sh [git commit sha1] [git branch name] [git tag name]' + exit 1 +fi + +BUILD_NUM=$1 +GIT_SHA1=${2:-$(git rev-parse HEAD)} +GIT_SHA1_SHORT=$(echo "$GIT_SHA1" | cut -c 1-7) +GIT_BRANCH=${3:-$(git symbolic-ref -q --short HEAD || echo "unknown")} +GIT_TAG=${4:-$(git describe --tags --exact-match 2> /dev/null || echo "")} + +IMAGE_NAME=${IMAGE_NAME:-ipshipyard/p2p-forge} + +echoImageName () { + local IMAGE_TAG=$1 + echo "$IMAGE_NAME:$IMAGE_TAG" +} + +if [[ $GIT_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc ]]; then + echoImageName "$GIT_TAG" + +elif [[ $GIT_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echoImageName "$GIT_TAG" + echoImageName "latest" + +elif [ "$GIT_BRANCH" = "main" ] || [ "$GIT_BRANCH" = "staging" ]; then + echoImageName "${GIT_BRANCH}-${BUILD_NUM}-${GIT_SHA1_SHORT}" + echoImageName "${GIT_BRANCH}-latest" + +else + echo "Nothing to do. No docker tag defined for branch: $GIT_BRANCH, tag: $GIT_TAG" + +fi diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..8fd6068 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,69 @@ +name: Create and publish a Docker image + +on: + workflow_dispatch: + push: + branches: ['main', 'staging'] + tags: ['v*'] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Get tags + id: tags + env: + IMAGE_NAME: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + run: | + echo "value<> $GITHUB_OUTPUT + ./.github/docker/get-docker-tags.sh "$(date -u +%F)" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + shell: bash + - name: Build Docker image and publish to Docker Hub + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm/v7,linux/arm64/v8 + context: . + push: true + file: ./Dockerfile + tags: "${{ steps.tags.outputs.value }}" + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache to limit growth + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fdf6350 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +cmd/db.* +cmd/Corefile +cmd/cmd +p2p-forge diff --git a/Corefile b/Corefile new file mode 100644 index 0000000..c76a70c --- /dev/null +++ b/Corefile @@ -0,0 +1,6 @@ +libp2p.direct { + log + errors + ipparser libp2p.direct + file zones/libp2p.direct +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a18b284 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,59 @@ +FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.22-bookworm AS builder + +LABEL org.opencontainers.image.source=https://github.com/ipshipyard/p2p-forge +LABEL org.opencontainers.image.documentation=https://github.com/ipshipyard/p2p-forge#docker +LABEL org.opencontainers.image.description="An Authoritative DNS server for distributing DNS subdomains to libp2p peers" +# TODO: decide license: LABEL org.opencontainers.image.licenses=MIT+APACHE_2.0 + + +# This builds p2p-forge + +ARG TARGETPLATFORM TARGETOS TARGETARCH + +ENV GOPATH="/go" +ENV SRC_PATH="$GOPATH/src/github.com/ipshipyard/p2p-forge" +ENV GO111MODULE=on +ENV GOPROXY="https://proxy.golang.org" + +COPY go.* $SRC_PATH/ +WORKDIR $SRC_PATH +RUN go mod download + +COPY . $SRC_PATH +RUN git config --global --add safe.directory /go/src/github.com/ipshipyard/p2p-forge + +RUN --mount=target=. \ + --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg \ + CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o $GOPATH/bin/p2p-forge + +#------------------------------------------------------ +FROM debian:bookworm-slim + +# Instal binaries for $TARGETARCH +RUN apt-get update && \ + apt-get install --no-install-recommends -y tini ca-certificates libcap2-bin && \ + rm -rf /var/lib/apt/lists/* + +ENV GOPATH="/go" +ENV SRC_PATH="$GOPATH/src/github.com/ipshipyard/p2p-forge" +ENV P2P_FORGE_PATH="/p2p-forge" + +COPY --from=builder $GOPATH/bin/p2p-forge /usr/local/bin/p2p-forge +COPY --from=builder $SRC_PATH/.github/docker/entrypoint.sh /usr/local/bin/entrypoint.sh + +# TODO: for now we bundle configuration, but can be customized by +# mounting custom files on top of ones from image +COPY --from=builder $SRC_PATH/Corefile $P2P_FORGE_PATH/Corefile +COPY --from=builder $SRC_PATH/zones $P2P_FORGE_PATH/zones + +RUN mkdir -p $P2P_FORGE_PATH && \ + useradd -d $P2P_FORGE_PATH -u 1000 -G users p2pforge && \ + chown p2pforge:users $P2P_FORGE_PATH && \ + setcap cap_net_bind_service=+ep /usr/local/bin/p2p-forge + +VOLUME $P2P_FORGE_PATH +WORKDIR $P2P_FORGE_PATH +USER p2pforge +EXPOSE 53 53/udp +ENTRYPOINT ["tini", "--", "/usr/local/bin/entrypoint.sh"] diff --git a/README.md b/README.md index 0e1087d..cbb1fdb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Build -`go build` will build the binary in your local directory +`go build` will build the `p2p-forge` binary in your local directory ## Install @@ -15,15 +15,34 @@ $ go install github.com/ipshipyard/p2p-forge@latest Will download using go mod, build and install the binary in your global Go binary directory (e.g. `~/go/bin`) ### From source -`go install` will build and install the binary in your global Go binary directory (e.g. `~/go/bin`) + +`go install` will build and install the `p2p-forge` binary in your global Go binary directory (e.g. `~/go/bin`) ## Usage +### Local testing + +Build and run on custom port: + +```console +$ ./p2p-forge -dns.port 5353 +$ docker build -t p2p-forge . && docker run --rm -it --net=host p2p-forge -dns.port 5353 +``` + +Test with `dig`: + +```console +$ dig A 1-2-3-4.k51qzi5uqu5dlwfht6wwy7lp4z35bgytksvp5sg53fdhcocmirjepowgifkxqd.libp2p.direct @localhost -p 5353 +1.2.3.4 +``` + ### Configuration This binary is based on [CoreDNS](https://github.com/coredns/coredns) which is itself based on Caddy. To run the binary create a file `Corefile` following the syntax listed in the CoreDNS documentation. +A custom configuration can be passed via `./p2p-forge -conf Corefile.example` + This binary introduces two additional plugins: - `ipparser` which handles returning A and AAAA records for domains like `..libp2p.direct` - `acme` which handles reading and writing DNS acme challenges for domains like `_acme-challenge..libp2p.direct` @@ -64,7 +83,7 @@ It does the following: ``` corefile . { log - ipparser libp2p.direct + ipparser libp2p.direct acme libp2p.direct { registration-domain registration.libp2p.direct listen-address=:443 external-tls=false database-type dynamo mytable @@ -120,4 +139,4 @@ curl -X POST "https://registration.libp2p.direct/v1//_acme-challenge" \ }' ``` -Where the bearer token is derived via the [libp2p HTTP PeerID Auth Specification](https://github.com/libp2p/specs/pull/564). \ No newline at end of file +Where the bearer token is derived via the [libp2p HTTP PeerID Auth Specification](https://github.com/libp2p/specs/pull/564). diff --git a/cmd/e2e_test.go b/e2e_test.go similarity index 100% rename from cmd/e2e_test.go rename to e2e_test.go diff --git a/cmd/main.go b/main.go similarity index 94% rename from cmd/main.go rename to main.go index 5859ced..6153329 100644 --- a/cmd/main.go +++ b/main.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + _ "github.com/coredns/coredns/core/plugin" // Load all managed plugins in github.com/coredns/coredns. _ "github.com/ipshipyard/p2p-forge/acme" _ "github.com/ipshipyard/p2p-forge/ipparser" @@ -35,5 +37,6 @@ func init() { } func main() { + fmt.Printf("%s %s\n", name, version) // always print version coremain.Run() } diff --git a/version.go b/version.go new file mode 100644 index 0000000..ba26997 --- /dev/null +++ b/version.go @@ -0,0 +1,51 @@ +package main + +import ( + _ "embed" + "encoding/json" + "fmt" + "runtime/debug" + "time" +) + +//go:embed version.json +var versionJSON []byte + +var name = "p2p-forge" +var version = buildVersion() + +//var userAgent = name + "/" + version + +func buildVersion() string { + // Read version from embedded JSON file. + var verMap map[string]string + json.Unmarshal(versionJSON, &verMap) + release := verMap["version"] + + var revision string + var day string + var dirty bool + + info, ok := debug.ReadBuildInfo() + if !ok { + return release + " dev-build" + } + for _, kv := range info.Settings { + switch kv.Key { + case "vcs.revision": + revision = kv.Value[:7] + case "vcs.time": + t, _ := time.Parse(time.RFC3339, kv.Value) + day = t.UTC().Format("2006-01-02") + case "vcs.modified": + dirty = kv.Value == "true" + } + } + if dirty { + revision += "-dirty" + } + if revision != "" { + return fmt.Sprintf("%s %s-%s", release, day, revision) + } + return release + " dev-build" +} diff --git a/version.json b/version.json new file mode 100644 index 0000000..a3903b1 --- /dev/null +++ b/version.json @@ -0,0 +1,3 @@ +{ + "version": "v1.6.0" +} diff --git a/zones/libp2p.direct b/zones/libp2p.direct new file mode 100644 index 0000000..1e92192 --- /dev/null +++ b/zones/libp2p.direct @@ -0,0 +1,33 @@ +;; SOA Records +libp2p.direct. 300 IN SOA ns1.libp2p.direct. domains.ipshipyard.com. 2047792117 10000 2400 604800 300 + +;; DNS Service +libp2p.direct. 86400 IN NS ns1.libp2p.direct. +libp2p.direct. 86400 IN NS ns2.libp2p.direct. +libp2p.direct. 300 IN NS ns1-40-160-8-207.nip.io. ; TODO: alias for ns1/ns2 under different tld +libp2p.direct. 300 IN NS ns2-15-204-28-76.nip.io. ; TODO: replace with additonal instances + +ns1.libp2p.direct. 86400 IN A 40.160.8.207 +ns1.libp2p.direct. 86400 IN AAAA 2604:2dc0:101:100::265 + +ns2.libp2p.direct. 86400 IN A 15.204.28.76 +ns2.libp2p.direct. 86400 IN AAAA 2604:2dc0:202:200::64e + +;; TLS Provider +libp2p.direct. IN CAA 0 issue "letsencrypt.org" + +;; HTTP Service +libp2p.direct. 300 IN CNAME ns1.libp2p.direct. +registration.libp2p.direct. 300 IN CNAME ns1.libp2p.direct. + +;; PSL Records +_psl.libp2p.direct. 86400 IN TXT "https://github.com/publicsuffix/list/pull/2084" +_psl.libp2p.direct. 86400 IN TXT "https://github.com/publicsuffix/list/pull/2105" + +;; Email blocking +libp2p.direct. 86400 IN MX 0 . +libp2p.direct. 86400 IN TXT "v=spf1 -all" +_dmarc.libp2p.direct. 86400 IN TXT "v=DMARC1;p=reject;sp=reject;adkim=s;aspf=s" +*._domainkey.libp2p.direct. 86400 IN TXT "v=DKIM1; p=" + +; vim: ts=2 sw=2 et : From c9b535f8e56657a0ac5799e1d4eafaba382dda2a Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 14 Sep 2024 04:21:01 +0200 Subject: [PATCH 37/61] chore: reset version.json --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index a3903b1..81e3567 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v1.6.0" + "version": "v0.0.1" } From 50119434e9895637a25f81c7f83795d5d4bce4b8 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 16 Sep 2024 16:31:29 +0200 Subject: [PATCH 38/61] chore: switch SOA to ns1.p2p-forge.dwebops.net --- zones/libp2p.direct | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/zones/libp2p.direct b/zones/libp2p.direct index 1e92192..ef88137 100644 --- a/zones/libp2p.direct +++ b/zones/libp2p.direct @@ -1,11 +1,20 @@ +$TTL 300 +$ORIGIN libp2p.direct. + ;; SOA Records -libp2p.direct. 300 IN SOA ns1.libp2p.direct. domains.ipshipyard.com. 2047792117 10000 2400 604800 300 +@ 600 IN SOA ns1.p2p-forge.dwebops.net. domains.ipshipyard.com. ( + 2024091601 ; serial + 10000 ; refresh + 2400 ; retry + 604800 ; expire + 300 ; minimum + ) ;; DNS Service libp2p.direct. 86400 IN NS ns1.libp2p.direct. libp2p.direct. 86400 IN NS ns2.libp2p.direct. -libp2p.direct. 300 IN NS ns1-40-160-8-207.nip.io. ; TODO: alias for ns1/ns2 under different tld -libp2p.direct. 300 IN NS ns2-15-204-28-76.nip.io. ; TODO: replace with additonal instances +libp2p.direct. 86400 IN NS ns1.p2p-forge.dwebops.net. +libp2p.direct. 86400 IN NS ns2.p2p-forge.dwebops.net. ns1.libp2p.direct. 86400 IN A 40.160.8.207 ns1.libp2p.direct. 86400 IN AAAA 2604:2dc0:101:100::265 From d25be74c65189e75e962c5f93b4e6870e889fb44 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 16 Sep 2024 20:56:22 +0200 Subject: [PATCH 39/61] chore: simplify zone and bump soa ttl --- zones/libp2p.direct | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zones/libp2p.direct b/zones/libp2p.direct index ef88137..9d9783a 100644 --- a/zones/libp2p.direct +++ b/zones/libp2p.direct @@ -2,9 +2,9 @@ $TTL 300 $ORIGIN libp2p.direct. ;; SOA Records -@ 600 IN SOA ns1.p2p-forge.dwebops.net. domains.ipshipyard.com. ( - 2024091601 ; serial - 10000 ; refresh +@ 86400 IN SOA ns1.p2p-forge.dwebops.net. domains.ipshipyard.com. ( + 2024091603 ; serial + 86400 ; refresh 2400 ; retry 604800 ; expire 300 ; minimum @@ -26,8 +26,8 @@ ns2.libp2p.direct. 86400 IN AAAA 2604:2dc0:202:200::64e libp2p.direct. IN CAA 0 issue "letsencrypt.org" ;; HTTP Service -libp2p.direct. 300 IN CNAME ns1.libp2p.direct. -registration.libp2p.direct. 300 IN CNAME ns1.libp2p.direct. +libp2p.direct. 3600 IN A 40.160.8.207 +registration.libp2p.direct. 3600 IN A 40.160.8.207 ;; PSL Records _psl.libp2p.direct. 86400 IN TXT "https://github.com/publicsuffix/list/pull/2084" From ae0139ef07ef1879454db08a51ca9a4ded04e6b0 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 16 Sep 2024 21:06:52 +0200 Subject: [PATCH 40/61] fix: block ANY queries https://datatracker.ietf.org/doc/html/rfc8482 --- Corefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Corefile b/Corefile index c76a70c..77ceab7 100644 --- a/Corefile +++ b/Corefile @@ -1,6 +1,7 @@ libp2p.direct { log errors + any # RFC 8482 ipparser libp2p.direct file zones/libp2p.direct } From eef177025d8f7e5f30eafe890ebb224e4cb64ff9 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 16 Sep 2024 16:04:40 -0400 Subject: [PATCH 41/61] tmp(acme-writer): force use of authentication env var --- acme/writer.go | 4 ++++ e2e_test.go | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/acme/writer.go b/acme/writer.go index 65e5ce3..abc72e6 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -82,7 +82,11 @@ func (c *acmeWriter) OnStartup() error { authKey, found := os.LookupEnv(authEnvVar) if found { c.forgeAuthKey = authKey + } else { + // TODO: Remove when ready for rollout + return fmt.Errorf("environment variable %s not found", authEnvVar) } + c.ln = ln c.mux = mux.NewRouter() diff --git a/e2e_test.go b/e2e_test.go index 0a4dc76..a9d6804 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -53,6 +53,10 @@ import ( const forge = "libp2p.direct" const forgeRegistration = "registration.libp2p.direct" +const authEnvVar = "FORGE_ACCESS_TOKEN" +const authToken = "testToken" +const authForgeHeader = "Forge-Authorization" + var dnsServerAddress string var httpPort int @@ -63,6 +67,11 @@ func TestMain(m *testing.M) { os.Exit(1) } + if err := os.Setenv(authEnvVar, authToken); err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + defer os.RemoveAll(tmpDir) tmpListener, err := net.Listen("tcp", ":0") @@ -138,6 +147,7 @@ func TestSetACMEChallenge(t *testing.T) { t.Fatal(err) } req.Host = forgeRegistration + req.Header.Set(authForgeHeader, authToken) peerHTTPClient := &httppeeridauth.ClientPeerIDAuth{PrivKey: sk} _, resp, err := peerHTTPClient.AuthenticatedDo(http.DefaultClient, req) @@ -425,6 +435,7 @@ func TestLibp2pACMEE2E(t *testing.T) { client.WithForgeDomain(forge), client.WithForgeRegistrationEndpoint(fmt.Sprintf("http://127.0.0.1:%d", httpPort)), client.WithCAEndpoint(acmeEndpoint), client.WithTrustedRoots(cas), client.WithModifiedForgeRequest(func(req *http.Request) error { req.Host = forgeRegistration + req.Header.Set(authForgeHeader, authToken) return nil }), client.WithAllowPrivateForgeAddrs(), From 7fd1cfb9986ad13c073a9a2ed4ce07213f4b5c5b Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 16 Sep 2024 16:29:25 -0400 Subject: [PATCH 42/61] fix(acme-reader): handle subsequent plugins correctly --- acme/setup.go | 1 + 1 file changed, 1 insertion(+) diff --git a/acme/setup.go b/acme/setup.go index 4d55927..b375365 100644 --- a/acme/setup.go +++ b/acme/setup.go @@ -35,6 +35,7 @@ func setup(c *caddy.Controller) error { // Add the read portion of the plugin to CoreDNS, so Servers can use it in their plugin chain. // The write portion is not *really* a plugin just a separate webserver running. dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { + reader.Next = next return reader }) From a0ee13f9e4edc12b71b4d1f3449d3ea3f66b7c0c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 17 Sep 2024 20:18:24 +0200 Subject: [PATCH 43/61] chore: switch soa to ns1.libp2p.direct glue records are fixed, bumping serial to see if it helps with resolution at 8.8.8.8 --- zones/libp2p.direct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zones/libp2p.direct b/zones/libp2p.direct index 9d9783a..f3d64ab 100644 --- a/zones/libp2p.direct +++ b/zones/libp2p.direct @@ -2,8 +2,8 @@ $TTL 300 $ORIGIN libp2p.direct. ;; SOA Records -@ 86400 IN SOA ns1.p2p-forge.dwebops.net. domains.ipshipyard.com. ( - 2024091603 ; serial +@ 86400 IN SOA ns1.libp2p.direct. domains.ipshipyard.com. ( + 2024091701 ; serial 86400 ; refresh 2400 ; retry 604800 ; expire From 709fad73213cc346d07795d613e92bda0181015a Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 17 Sep 2024 20:32:32 +0200 Subject: [PATCH 44/61] chore: separate ip4 from ip6 glue records are ip4-only, this is just making sure we remove any inconsistencies that could make google dns refuse resolution --- zones/libp2p.direct | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zones/libp2p.direct b/zones/libp2p.direct index f3d64ab..9c8efd5 100644 --- a/zones/libp2p.direct +++ b/zones/libp2p.direct @@ -3,7 +3,7 @@ $ORIGIN libp2p.direct. ;; SOA Records @ 86400 IN SOA ns1.libp2p.direct. domains.ipshipyard.com. ( - 2024091701 ; serial + 2024091702 ; serial 86400 ; refresh 2400 ; retry 604800 ; expire @@ -17,10 +17,10 @@ libp2p.direct. 86400 IN NS ns1.p2p-forge.dwebops.ne libp2p.direct. 86400 IN NS ns2.p2p-forge.dwebops.net. ns1.libp2p.direct. 86400 IN A 40.160.8.207 -ns1.libp2p.direct. 86400 IN AAAA 2604:2dc0:101:100::265 +;ns1.p2p-forge.dwebops.net. 86400 IN AAAA 2604:2dc0:101:100::265 ns2.libp2p.direct. 86400 IN A 15.204.28.76 -ns2.libp2p.direct. 86400 IN AAAA 2604:2dc0:202:200::64e +;ns2.p2p-forge.dwebops.net. 86400 IN AAAA 2604:2dc0:202:200::64e ;; TLS Provider libp2p.direct. IN CAA 0 issue "letsencrypt.org" From f9d8f0779f2567845a66b369e3ec0ec99b4ca6d7 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 18 Sep 2024 00:20:44 -0400 Subject: [PATCH 45/61] respond with no answer but a successful query on peerID.forge and valid ip.peerID.forge --- e2e_test.go | 120 +++++++++++++++++++++++++++++++++++++++++++-- ipparser/plugin.go | 35 ++++++++----- 2 files changed, 139 insertions(+), 16 deletions(-) diff --git a/e2e_test.go b/e2e_test.go index a9d6804..0aefc4a 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -126,6 +126,102 @@ func TestMain(m *testing.M) { instance.Wait() } +// Need to handle .forgeDomain to return NODATA rather than NXDOMAIN per https://datatracker.ietf.org/doc/html/rfc8020 +func TestRFC8020(t *testing.T) { + _, pk, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + peerID, err := peer.IDFromPublicKey(pk) + if err != nil { + t.Fatal(err) + } + peerIDb36, err := peer.ToCid(peerID).StringOfBase(multibase.Base36) + if err != nil { + t.Fatal(err) + } + + m := new(dns.Msg) + m.Question = make([]dns.Question, 1) + m.Question[0] = dns.Question{Qclass: dns.ClassINET, Name: fmt.Sprintf("%s.%s.", peerIDb36, forge), Qtype: dns.TypeTXT} + + r, err := dns.Exchange(m, dnsServerAddress) + if err != nil { + t.Fatalf("Could not send message: %s", err) + } + if r.Rcode != dns.RcodeSuccess { + t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) + } + if len(r.Answer) != 0 { + t.Fatalf("expected no answers got %+v", r.Answer) + } +} + +// For valid subdomains (e.g. ..forgeDomain) even though only A or AAAA records might be supported +// we should return a successful lookup with no answer rather than erroring +func TestIPSubdomainsNonExistentRecords(t *testing.T) { + _, pk, err := crypto.GenerateEd25519Key(rand.Reader) + if err != nil { + t.Fatal(err) + } + peerID, err := peer.IDFromPublicKey(pk) + if err != nil { + t.Fatal(err) + } + peerIDb36, err := peer.ToCid(peerID).StringOfBase(multibase.Base36) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + subdomain string + qtype uint16 + }{ + { + name: "AAAA_ipv4.peerID.forge", + subdomain: "1-2-3-4", + qtype: dns.TypeAAAA, + }, + { + name: "TXT_ipv4.peerID.forge", + subdomain: "1-2-3-4", + qtype: dns.TypeTXT, + }, + { + name: "A_ipv6.peerID.forge", + subdomain: "1234-5678-90AB-CDEF-1-22-33-444", + qtype: dns.TypeA, + }, + { + name: "TXT_ipv6.peerID.forge", + subdomain: "1234-5678-90AB-CDEF-1-22-33-444", + qtype: dns.TypeTXT, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + domain := fmt.Sprintf("%s.%s.%s.", tt.subdomain, peerIDb36, forge) + m := new(dns.Msg) + m.Question = make([]dns.Question, 1) + m.Question[0] = dns.Question{Qclass: dns.ClassINET, Name: domain, Qtype: tt.qtype} + + r, err := dns.Exchange(m, dnsServerAddress) + if err != nil { + t.Fatalf("Could not send message: %s", err) + } + if r.Rcode != dns.RcodeSuccess { + t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) + } + if len(r.Answer) != 0 { + t.Fatalf("expected no answers got %+v", r.Answer) + } + return + }) + } +} + func TestSetACMEChallenge(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -220,7 +316,7 @@ func TestIPv4Lookup(t *testing.T) { name: "IPv4-AAAA", qtype: dns.TypeAAAA, subdomain: "1-2-3-4", - expectedSuccess: false, + expectedSuccess: true, expectedAddress: "", }, { @@ -264,9 +360,17 @@ func TestIPv4Lookup(t *testing.T) { return } - if r.Rcode != dns.RcodeSuccess || len(r.Answer) == 0 { + if r.Rcode != dns.RcodeSuccess { t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) } + + if len(r.Answer) == 0 { + if tt.expectedAddress != "" { + t.Fatal("Expected an address but got none") + } + return + } + expectedAnswer := fmt.Sprintf(`%s 3600 IN A %s`, m.Question[0].Name, tt.expectedAddress) if r.Answer[0].String() != expectedAnswer { t.Fatalf("Expected %s reply, got %s", expectedAnswer, r.Answer[0].String()) @@ -300,7 +404,7 @@ func TestIPv6Lookup(t *testing.T) { name: "A", qtype: dns.TypeA, subdomain: "0--1", - expectedSuccess: false, + expectedSuccess: true, expectedAddress: "", }, { @@ -372,9 +476,17 @@ func TestIPv6Lookup(t *testing.T) { return } - if r.Rcode != dns.RcodeSuccess || len(r.Answer) == 0 { + if r.Rcode != dns.RcodeSuccess { t.Fatalf("Expected successful reply, got %s", dns.RcodeToString[r.Rcode]) } + + if len(r.Answer) == 0 { + if tt.expectedAddress != "" { + t.Fatal("Expected an address but got none") + } + return + } + expectedAnswer := fmt.Sprintf(`%s 3600 IN AAAA %s`, m.Question[0].Name, tt.expectedAddress) if r.Answer[0].String() != expectedAnswer { t.Fatalf("Expected %s reply, got %s", expectedAnswer, r.Answer[0].String()) diff --git a/ipparser/plugin.go b/ipparser/plugin.go index 29f8c8a..e922ee0 100644 --- a/ipparser/plugin.go +++ b/ipparser/plugin.go @@ -50,35 +50,45 @@ const ttl = 1 * time.Hour // ServeDNS implements the plugin.Handler interface. func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { var answers []dns.RR + containsNODATAResponse := false for _, q := range r.Question { - if q.Qtype != dns.TypeA && q.Qtype != dns.TypeAAAA && q.Qtype != dns.TypeANY { - continue - } - subdomain := strings.TrimSuffix(q.Name, "."+p.ForgeDomain+".") if len(subdomain) == len(q.Name) || len(subdomain) == 0 { continue } domainSegments := strings.Split(subdomain, ".") - if len(domainSegments) != 2 { + if len(domainSegments) > 2 { continue } - peerIDStr := domainSegments[1] + peerIDStr := domainSegments[len(domainSegments)-1] _, err := peer.Decode(peerIDStr) if err != nil { continue } + // Need to handle .forgeDomain to return NODATA rather than NXDOMAIN per https://datatracker.ietf.org/doc/html/rfc8020 + if len(domainSegments) == 1 { + containsNODATAResponse = true + continue + } + prefix := domainSegments[0] segments := strings.Split(prefix, "-") - if len(segments) == 4 && (q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY) { + if len(segments) == 4 { ipStr := strings.Join(segments, ".") ip, err := netip.ParseAddr(ipStr) if err != nil { continue } + + // Need to handle ..forgeDomain to return NODATA rather than NXDOMAIN per https://datatracker.ietf.org/doc/html/rfc8020 + if !(q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY) { + containsNODATAResponse = true + continue + } + answers = append(answers, &dns.A{ Hdr: dns.RR_Header{ Name: dns.Fqdn(q.Name), @@ -91,10 +101,6 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg continue } - if !(q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY) { - continue - } - // - is not a valid first or last character https://datatracker.ietf.org/doc/html/rfc1123#section-2 if prefix[0] == '-' || prefix[len(prefix)-1] == '-' { continue @@ -106,6 +112,11 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg continue } + if !(q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY) { + containsNODATAResponse = true + continue + } + answers = append(answers, &dns.AAAA{ Hdr: dns.RR_Header{ Name: dns.Fqdn(q.Name), @@ -117,7 +128,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg }) } - if len(answers) > 0 { + if len(answers) > 0 || containsNODATAResponse { var m dns.Msg m.SetReply(r) m.Authoritative = true From d060dacea2c489e920c8f222298295bb2800bd1b Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 18 Sep 2024 01:06:46 -0400 Subject: [PATCH 46/61] fix: normalize DNS names to lowercase --- acme/reader.go | 5 +++-- acme/setup.go | 4 ++-- ipparser/plugin.go | 7 ++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/acme/reader.go b/acme/reader.go index 499b3b2..00ff7ae 100644 --- a/acme/reader.go +++ b/acme/reader.go @@ -27,8 +27,9 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M continue } - subdomain := strings.TrimSuffix(q.Name, "."+p.ForgeDomain+".") - if len(subdomain) == len(q.Name) || len(subdomain) == 0 { + normalizedName := strings.ToLower(q.Name) + subdomain := strings.TrimSuffix(normalizedName, "."+p.ForgeDomain+".") + if len(subdomain) == len(normalizedName) || len(subdomain) == 0 { continue } diff --git a/acme/setup.go b/acme/setup.go index b375365..dcc0d55 100644 --- a/acme/setup.go +++ b/acme/setup.go @@ -69,7 +69,7 @@ func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { case 0: return nil, nil, c.ArgErr() case 1: - forgeDomain = args[0] + forgeDomain = strings.ToLower(args[0]) default: return nil, nil, c.ArgErr() } @@ -82,7 +82,7 @@ func parse(c *caddy.Controller) (*acmeReader, *acmeWriter, error) { return nil, nil, c.ArgErr() } - forgeRegistrationDomain = args[0] + forgeRegistrationDomain = strings.ToLower(args[0]) for i := 1; i < len(args); i++ { nextArg := args[i] argKV := strings.Split(nextArg, "=") diff --git a/ipparser/plugin.go b/ipparser/plugin.go index e922ee0..e17a55c 100644 --- a/ipparser/plugin.go +++ b/ipparser/plugin.go @@ -34,7 +34,7 @@ func setup(c *caddy.Controller) error { // Add the Plugin to CoreDNS, so Servers can use it in their plugin chain. dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { - return ipParser{Next: next, ForgeDomain: forgeDomain} + return ipParser{Next: next, ForgeDomain: strings.ToLower(forgeDomain)} }) return nil @@ -52,8 +52,9 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg var answers []dns.RR containsNODATAResponse := false for _, q := range r.Question { - subdomain := strings.TrimSuffix(q.Name, "."+p.ForgeDomain+".") - if len(subdomain) == len(q.Name) || len(subdomain) == 0 { + normalizedName := strings.ToLower(q.Name) + subdomain := strings.TrimSuffix(normalizedName, "."+p.ForgeDomain+".") + if len(subdomain) == len(normalizedName) || len(subdomain) == 0 { continue } From 4c9cc8ae02f8fc9cb713a82cbd8ef4067932fccf Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 18 Sep 2024 01:34:30 -0400 Subject: [PATCH 47/61] respond with no answer but a successful query on _acme-challenge.peerID.forge --- acme/reader.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/acme/reader.go b/acme/reader.go index 00ff7ae..3494d31 100644 --- a/acme/reader.go +++ b/acme/reader.go @@ -22,11 +22,8 @@ const ttl = 1 * time.Hour // ServeDNS implements the plugin.Handler interface. func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { var answers []dns.RR + containsNODATAResponse := false for _, q := range r.Question { - if q.Qtype != dns.TypeTXT && q.Qtype != dns.TypeANY { - continue - } - normalizedName := strings.ToLower(q.Name) subdomain := strings.TrimSuffix(normalizedName, "."+p.ForgeDomain+".") if len(subdomain) == len(normalizedName) || len(subdomain) == 0 { @@ -50,8 +47,14 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M continue } + if q.Qtype != dns.TypeTXT && q.Qtype != dns.TypeANY { + containsNODATAResponse = true + continue + } + val, err := p.Datastore.Get(ctx, datastore.NewKey(peerID.String())) if err != nil { + containsNODATAResponse = true continue } @@ -66,7 +69,7 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M }) } - if len(answers) > 0 { + if len(answers) > 0 || containsNODATAResponse { var m dns.Msg m.SetReply(r) m.Authoritative = true From 587c7fa8763a7bc19d69a58eb56a53d23029236c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 18 Sep 2024 23:02:55 +0200 Subject: [PATCH 48/61] fix: escape arbitrary bytes before writing to log --- acme/writer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/writer.go b/acme/writer.go index abc72e6..3c6225b 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -200,7 +200,7 @@ func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { agentVersion = vs } } - log.Debugf("connected to peer %s - UserAgent: %s", p, agentVersion) + log.Debugf("connected to peer %s - UserAgent: %q", p, agentVersion) return nil } From dbeb701d58c30fcd7ebe1e1eedf6ddb1789762c6 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 18 Sep 2024 17:40:12 -0400 Subject: [PATCH 49/61] fix(client): handle when our certificate is loaded even if no custom user functions are executing --- client/acme.go | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/client/acme.go b/client/acme.go index 23cdcc9..2cef5ad 100644 --- a/client/acme.go +++ b/client/acme.go @@ -222,35 +222,35 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, } - if mgrCfg.onCertLoaded != nil { - certCfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { - if event == "cached_managed_cert" { - sans, ok := data["sans"] - if !ok { - return nil - } - sanList, ok := sans.([]string) - if !ok { - return nil - } - peerID := hostFn().ID() - pidStr := peer.ToCid(peerID).Encode(multibase.MustNewEncoder(multibase.Base36)) - certName := fmt.Sprintf("*.%s.%s", pidStr, mgrCfg.forgeDomain) - for _, san := range sanList { - if san == certName { - // When the certificate is loaded mark that it has been so we know we are good to use the domain name - // TODO: This won't handle if the cert expires and cannot get renewed - mgr.certCheckMx.Lock() - mgr.hasCert = true - mgr.certCheckMx.Unlock() - // Execute user function for on certificate load + certCfg.OnEvent = func(ctx context.Context, event string, data map[string]any) error { + if event == "cached_managed_cert" { + sans, ok := data["sans"] + if !ok { + return nil + } + sanList, ok := sans.([]string) + if !ok { + return nil + } + peerID := hostFn().ID() + pidStr := peer.ToCid(peerID).Encode(multibase.MustNewEncoder(multibase.Base36)) + certName := fmt.Sprintf("*.%s.%s", pidStr, mgrCfg.forgeDomain) + for _, san := range sanList { + if san == certName { + // When the certificate is loaded mark that it has been so we know we are good to use the domain name + // TODO: This won't handle if the cert expires and cannot get renewed + mgr.certCheckMx.Lock() + mgr.hasCert = true + mgr.certCheckMx.Unlock() + // Execute user function for on certificate load + if mgrCfg.onCertLoaded != nil { mgrCfg.onCertLoaded() } } - return nil } return nil } + return nil } return mgr, nil From 2ecd19ac95e16461d9e19ff63e02d57411aa2cef Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 19 Sep 2024 00:04:46 +0200 Subject: [PATCH 50/61] refactor: expose client defaults this allows us to avoid hardcoding them in Kubo --- client/acme.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/client/acme.go b/client/acme.go index 2cef5ad..be10839 100644 --- a/client/acme.go +++ b/client/acme.go @@ -27,6 +27,12 @@ import ( var log = logging.Logger("p2p-forge/client") +const ( + DefaultForgeDomain = "libp2p.direct" + DefaultForgeEndpoint = "https://registration.libp2p.direct" + DefaultCAEndpoint = certmagic.LetsEncryptProductionCA +) + type P2PForgeCertMgr struct { ctx context.Context cancel func() @@ -159,17 +165,15 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error } } - const libp2pDirectName = "libp2p.direct" - const libp2pDirectRegistrationEndpoint = "https://registration.libp2p.direct" if mgrCfg.forgeDomain == "" { mgrCfg.forgeDomain = "libp2p.direct" } if mgrCfg.caEndpoint == "" { - mgrCfg.caEndpoint = certmagic.LetsEncryptProductionCA + mgrCfg.caEndpoint = DefaultCAEndpoint } if mgrCfg.forgeRegistrationEndpoint == "" { - if mgrCfg.forgeDomain == libp2pDirectName { - mgrCfg.forgeRegistrationEndpoint = libp2pDirectRegistrationEndpoint + if mgrCfg.forgeDomain == DefaultForgeDomain { + mgrCfg.forgeRegistrationEndpoint = DefaultForgeEndpoint } else { return nil, fmt.Errorf("must specify the forge registration endpoint if using a non-default forge") } From 11dda24e7e87df3b2f9b9c6c906008d883940b8e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 20 Sep 2024 20:14:15 +0200 Subject: [PATCH 51/61] feat(client): WithUserAgent + WithForgeAuth --- acme/writer.go | 10 ++++---- client/acme.go | 52 ++++++++++++++++++++++++++++++++++------ client/defaults.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++ e2e_test.go | 4 ++-- 4 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 client/defaults.go diff --git a/acme/writer.go b/acme/writer.go index 3c6225b..9dbf774 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -17,6 +17,7 @@ import ( clog "github.com/coredns/coredns/plugin/pkg/log" "github.com/coredns/coredns/plugin/pkg/reuseport" + "github.com/ipshipyard/p2p-forge/client" "github.com/caddyserver/certmagic" @@ -32,9 +33,6 @@ import ( var log = clog.NewWithPlugin(pluginName) -const authEnvVar = "FORGE_ACCESS_TOKEN" -const authForgeHeader = "Forge-Authorization" - // acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. type acmeWriter struct { Addr string @@ -79,12 +77,12 @@ func (c *acmeWriter) OnStartup() error { ln = tls.NewListener(ln, tlsConfig) } - authKey, found := os.LookupEnv(authEnvVar) + authKey, found := os.LookupEnv(client.ForgeAuthEnv) if found { c.forgeAuthKey = authKey } else { // TODO: Remove when ready for rollout - return fmt.Errorf("environment variable %s not found", authEnvVar) + return fmt.Errorf("environment variable %s not found", client.ForgeAuthEnv) } c.ln = ln @@ -102,7 +100,7 @@ func (c *acmeWriter) OnStartup() error { TokenTTL: time.Hour, Next: func(peerID peer.ID, w http.ResponseWriter, r *http.Request) { if c.forgeAuthKey != "" { - auth := r.Header.Get(authForgeHeader) + auth := r.Header.Get(client.ForgeAuthHeader) if c.forgeAuthKey != auth { w.WriteHeader(http.StatusForbidden) return diff --git a/client/acme.go b/client/acme.go index be10839..19c482d 100644 --- a/client/acme.go +++ b/client/acme.go @@ -27,12 +27,6 @@ import ( var log = logging.Logger("p2p-forge/client") -const ( - DefaultForgeDomain = "libp2p.direct" - DefaultForgeEndpoint = "https://registration.libp2p.direct" - DefaultCAEndpoint = certmagic.LetsEncryptProductionCA -) - type P2PForgeCertMgr struct { ctx context.Context cancel func() @@ -74,8 +68,10 @@ func isPublicAddr(a multiaddr.Multiaddr) bool { type P2PForgeCertMgrConfig struct { forgeDomain string forgeRegistrationEndpoint string + forgeAuth string caEndpoint string userEmail string + userAgent string trustedRoots *x509.CertPool storage certmagic.Storage modifyForgeRequest func(r *http.Request) error @@ -127,6 +123,32 @@ func WithUserEmail(email string) P2PForgeCertMgrOptions { } } +// WithForgeAuth sets optional secret be sent with requests to the forge +// registration endpoint. +func WithForgeAuth(forgeAuth string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.forgeAuth = forgeAuth + return nil + } +} + +// WithUserAgent sets custom User-Agent sent to the forge. +func WithUserAgent(userAgent string) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.userAgent = userAgent + return nil + } +} + +/* +// WithHTTPClient sets a custom HTTP Client to be used when talking to registration endpoint. +func WithHTTPClient(h httpClient) error { + return func(config *P2PForgeCertMgrConfig) error { + return nil + } +} +*/ + // WithModifiedForgeRequest enables modifying how the ACME DNS challenges are sent to the forge, such as to enable // custom HTTP headers, etc. func WithModifiedForgeRequest(fn func(req *http.Request) error) P2PForgeCertMgrOptions { @@ -166,7 +188,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error } if mgrCfg.forgeDomain == "" { - mgrCfg.forgeDomain = "libp2p.direct" + mgrCfg.forgeDomain = DefaultForgeDomain } if mgrCfg.caEndpoint == "" { mgrCfg.caEndpoint = DefaultCAEndpoint @@ -208,8 +230,10 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error Agreed: true, DNS01Solver: &dns01P2PForgeSolver{ forge: mgrCfg.forgeRegistrationEndpoint, + forgeAuth: mgrCfg.forgeAuth, hostFn: hostFn, modifyForgeRequest: mgrCfg.modifyForgeRequest, + userAgent: mgrCfg.userAgent, allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, }, TrustedRoots: mgrCfg.trustedRoots, @@ -319,8 +343,10 @@ func (m *P2PForgeCertMgr) createAddrsFactory(allowPrivateForgeAddrs bool) config type dns01P2PForgeSolver struct { forge string + forgeAuth string hostFn func() host.Host modifyForgeRequest func(r *http.Request) error + userAgent string allowPrivateForgeAddresses bool } @@ -355,6 +381,18 @@ func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challe if err != nil { return err } + + // Add forge auth header if set + if d.forgeAuth != "" { + req.Header.Set(ForgeAuthHeader, d.forgeAuth) + } + + // Always include User-Agent header + if d.userAgent == "" { + d.userAgent = defaultUserAgent + } + req.Header.Set("User-Agent", d.userAgent) + if d.modifyForgeRequest != nil { if err := d.modifyForgeRequest(req); err != nil { return err diff --git a/client/defaults.go b/client/defaults.go new file mode 100644 index 0000000..fb7f301 --- /dev/null +++ b/client/defaults.go @@ -0,0 +1,59 @@ +package client + +import ( + "reflect" + "runtime/debug" + + "github.com/caddyserver/certmagic" +) + +const ( + DefaultForgeDomain = "libp2p.direct" + DefaultForgeEndpoint = "https://registration.libp2p.direct" + DefaultCAEndpoint = certmagic.LetsEncryptProductionCA + DefaultCATestEndpoint = certmagic.LetsEncryptStagingCA + + // ForgeAuthEnv is optional environment variable that defines optional + // secret that limits access to registration endpoint + ForgeAuthEnv = "FORGE_ACCESS_TOKEN" + + // ForgeAuthHeader optional HTTP header that client should include when + // talking to a limited access registration endpoint + ForgeAuthHeader = "Forge-Authorization" +) + +// defaultUserAgent is used as a fallback to inform HTTP server which library +// version sent a request +var defaultUserAgent = moduleVersion() + +// importPath is the canonical import path that allows us to identify +// official client builds vs modified forks, and use that info in User-Agent header. +var importPath = getImportPath() + +// getImportPath returns the path that library consumers would have in go.mod +func getImportPath() string { + return reflect.ValueOf(P2PForgeCertMgr{}).Type().PkgPath() +} + +// moduleVersion returns a useful user agent version string allowing us to +// identify requests coming from official releases of this module vs forks. +func moduleVersion() (ua string) { + ua = importPath + var module *debug.Module + if bi, ok := debug.ReadBuildInfo(); ok { + // If debug.ReadBuildInfo was successful, we can read Version by finding + // this client in the dependency list of the app that has it in go.mod + for _, dep := range bi.Deps { + if dep.Path == importPath { + module = dep + break + } + } + if module != nil { + ua += "@" + module.Version + return + } + ua += "@unknown" + } + return +} diff --git a/e2e_test.go b/e2e_test.go index 0aefc4a..476f0bc 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -53,9 +53,9 @@ import ( const forge = "libp2p.direct" const forgeRegistration = "registration.libp2p.direct" -const authEnvVar = "FORGE_ACCESS_TOKEN" +const authEnvVar = client.ForgeAuthEnv const authToken = "testToken" -const authForgeHeader = "Forge-Authorization" +const authForgeHeader = client.ForgeAuthHeader var dnsServerAddress string var httpPort int From 4db6b559e960d4850014d74ef19c3e92e92f8176 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 25 Sep 2024 01:36:48 +0200 Subject: [PATCH 52/61] feat: prometheus metrics + docs registration one is commented for now, as we should measure failures as well as success. docs in docs/METRICS.md --- Corefile | 1 + Dockerfile | 2 ++ acme/metrics.go | 40 +++++++++++++++++++++++++++++++++++ acme/reader.go | 3 +++ acme/writer.go | 51 ++++++++++++++++++++++++++++++++++++++------- docs/METRICS.md | 28 +++++++++++++++++++++++++ ipparser/metrics.go | 26 +++++++++++++++++++++++ ipparser/plugin.go | 5 +++++ 8 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 acme/metrics.go create mode 100644 docs/METRICS.md create mode 100644 ipparser/metrics.go diff --git a/Corefile b/Corefile index 77ceab7..e7008c5 100644 --- a/Corefile +++ b/Corefile @@ -2,6 +2,7 @@ libp2p.direct { log errors any # RFC 8482 + prometheus localhost:9253 ipparser libp2p.direct file zones/libp2p.direct } diff --git a/Dockerfile b/Dockerfile index a18b284..32c0253 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,4 +56,6 @@ VOLUME $P2P_FORGE_PATH WORKDIR $P2P_FORGE_PATH USER p2pforge EXPOSE 53 53/udp +EXPOSE 443 +EXPOSE 9253 ENTRYPOINT ["tini", "--", "/usr/local/bin/entrypoint.sh"] diff --git a/acme/metrics.go b/acme/metrics.go new file mode 100644 index 0000000..740a560 --- /dev/null +++ b/acme/metrics.go @@ -0,0 +1,40 @@ +package acme + +import ( + "strconv" + + "github.com/coredns/coredns/plugin" + "github.com/miekg/dns" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + /* TODO + registrationRequestCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: plugin.Namespace, + Subsystem: "forge_" + pluginName, + Name: "registrations_total", + Help: "Counter of ACME DNS-01 broker registration requests made to this p2p-forge instance.", + }, []string{"status"}) + */ + dns01ResponseCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: plugin.Namespace, + Subsystem: "forge_" + pluginName, + Name: "dns01_responses_total", + Help: "The count of DNS-01 TXT responses generated by p2p-forge plugin.", + }, []string{"type"}) + peerProbeCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: plugin.Namespace, + Subsystem: "forge_" + pluginName, + Name: "libp2p_probe_total", + Help: "The count of libp2p probes performed before accepting registration by p2p-forge plugin.", + }, []string{"result", "agent"}) +) + +func dnsToString(dnsType uint16) string { + if str, ok := dns.TypeToString[dnsType]; ok { + return str + } + return strconv.Itoa(int(dnsType)) +} diff --git a/acme/reader.go b/acme/reader.go index 3494d31..3e6eb41 100644 --- a/acme/reader.go +++ b/acme/reader.go @@ -49,12 +49,14 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M if q.Qtype != dns.TypeTXT && q.Qtype != dns.TypeANY { containsNODATAResponse = true + dns01ResponseCount.WithLabelValues("NODATA-" + dnsToString(q.Qtype)).Add(1) continue } val, err := p.Datastore.Get(ctx, datastore.NewKey(peerID.String())) if err != nil { containsNODATAResponse = true + dns01ResponseCount.WithLabelValues("NODATA-TXT").Add(1) continue } @@ -67,6 +69,7 @@ func (p acmeReader) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M }, Txt: []string{string(val)}, }) + dns01ResponseCount.WithLabelValues("TXT").Add(1) } if len(answers) > 0 || containsNODATAResponse { diff --git a/acme/writer.go b/acme/writer.go index 9dbf774..343b17c 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -95,6 +95,7 @@ func (c *acmeWriter) OnStartup() error { if err != nil { return err } + authPeer := &httppeeridauth.ServerPeerIDAuth{ PrivKey: sk, TokenTTL: time.Hour, @@ -102,14 +103,14 @@ func (c *acmeWriter) OnStartup() error { if c.forgeAuthKey != "" { auth := r.Header.Get(client.ForgeAuthHeader) if c.forgeAuthKey != auth { - w.WriteHeader(http.StatusForbidden) + writeStatusHeader(w, http.StatusForbidden) return } } body, err := io.ReadAll(r.Body) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + writeStatusHeader(w, http.StatusInternalServerError) _, _ = w.Write([]byte(fmt.Sprintf("error reading body: %s", err))) return } @@ -118,7 +119,7 @@ func (c *acmeWriter) OnStartup() error { decoder := json.NewDecoder(bytes.NewReader(body)) decoder.DisallowUnknownFields() if err := decoder.Decode(typedBody); err != nil { - w.WriteHeader(http.StatusBadRequest) + writeStatusHeader(w, http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error decoding body: %s", err))) return } @@ -127,19 +128,19 @@ func (c *acmeWriter) OnStartup() error { // It MUST NOT contain any characters outside the base64url alphabet, including padding characters ("="). decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) if err != nil { - w.WriteHeader(http.StatusBadRequest) + writeStatusHeader(w, http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error decoding value as base64url: %s", err))) return } if len(decodedValue) != 32 { - w.WriteHeader(http.StatusBadRequest) + writeStatusHeader(w, http.StatusBadRequest) _, _ = w.Write([]byte("value is not a base64url of a SHA256 digest")) return } if err := testAddresses(r.Context(), peerID, typedBody.Addresses); err != nil { - w.WriteHeader(http.StatusBadRequest) + writeStatusHeader(w, http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error testing addresses: %s", err))) return } @@ -147,11 +148,11 @@ func (c *acmeWriter) OnStartup() error { const ttl = time.Hour err = c.Datastore.PutWithTTL(r.Context(), datastore.NewKey(peerID.String()), []byte(typedBody.Value), ttl) if err != nil { - w.WriteHeader(http.StatusInternalServerError) + writeStatusHeader(w, http.StatusInternalServerError) _, _ = w.Write([]byte(fmt.Sprintf("error storing value: %s", err))) return } - w.WriteHeader(http.StatusOK) + writeStatusHeader(w, http.StatusOK) }, } @@ -169,9 +170,20 @@ func (c *acmeWriter) OnStartup() error { return nil } +func writeStatusHeader(w http.ResponseWriter, statusCode int) { + + // TODO registrationRequestCount.WithLabelValues(strconv.Itoa(statusCode)).Add(1) + // TODO: make sure registrationRequestCount is updated on invalid requests + // correctly. Right now we are unable to detect when libp2p's httppeeridauth.ServerPeerIDAuth + // fails, the metric in writeStatusHeader is not being bumped + + w.WriteHeader(statusCode) +} + func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { h, err := libp2p.New(libp2p.NoListenAddrs, libp2p.DisableRelay()) if err != nil { + peerProbeCount.WithLabelValues("error", "unknown").Add(1) return err } defer h.Close() @@ -180,6 +192,7 @@ func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { for _, addr := range addrs { ma, err := multiaddr.NewMultiaddr(addr) if err != nil { + peerProbeCount.WithLabelValues("error", "unknown").Add(1) return err } mas = append(mas, ma) @@ -187,6 +200,7 @@ func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { err = h.Connect(ctx, peer.AddrInfo{ID: p, Addrs: mas}) if err != nil { + peerProbeCount.WithLabelValues("error", "unknown").Add(1) return err } @@ -199,9 +213,30 @@ func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { } } log.Debugf("connected to peer %s - UserAgent: %q", p, agentVersion) + peerProbeCount.WithLabelValues("ok", agentType(agentVersion)).Add(1) return nil } +// agentType returns bound cardinality agent label for metrics. +// libp2p clients can set agent version to arbitrary strings, +// and the metric labels have to have a bound cardinality +func agentType(agentVersion string) string { + if strings.HasPrefix(agentVersion, "kubo/") { + return "kubo" + } + if strings.HasPrefix(agentVersion, "helia/") { + return "helia" + } + // TODO: revisit once js0libp2p cleans up default user agents to something unique and not "libp2p/" + if strings.HasPrefix(agentVersion, "libp2p/") || strings.HasPrefix(agentVersion, "js-libp2p/") { + return "js-libp2p" + } + if strings.Contains(agentVersion, "go-libp2p") { + return "go-libp2p" + } + return "other" +} + type requestBody struct { Value string `json:"value"` Addresses []string `json:"addresses"` diff --git a/docs/METRICS.md b/docs/METRICS.md new file mode 100644 index 0000000..ed34108 --- /dev/null +++ b/docs/METRICS.md @@ -0,0 +1,28 @@ +## p2p-forge metrics + +Prometheus endpoint is exposed at `http://localhost:9253/metrics` + +It includes default [Prometheus Glient metrics](https://prometheus.io/docs/guides/go-application/) + [CoreDNS](#coredns) + [p2p-forge](#forge-metrics)-specific listed below. + +### Forge metrics + +- `coredns_forge_ipparser_requests_total{type}` - dynamic DNS `A`/`AAAA` responses generated by `ipparser` plugin for `ip.peerid.domain` and `peerid.domain`, including `NODATA-*` ones. +- `coredns_forge_acme_dns01_responses_total{type}` - DNS `TXT` responses generated by `acme` plugin for DNS-01 challenge at `_acme-challenge.peerid.domain`, including `NODATA-*` ones. +- `coredns_forge_acme_registrations_total{status}` - registration API responses generated by `acme` plugin when a client attempts to register DNS-01 challenge for their PeerID at `_acme-challenge.peerid.domain`. +- `coredns_forge_acme_libp2p_probe_total{result, agent}` - libp2p probe results `acme` plugin when testing connectivity before accepting DNS-01 challenge for a PeerID. `status` is either `ok` or `error` and `agent` value is limited to well known agents, `other` and `unknown`. + +### CoreDNS metrics + +In addition to the default Go metrics exported by the [Prometheus Go client](https://prometheus.io/docs/guides/go-application/), the following metrics are exported: + +- `coredns_build_info{version, revision, goversion}` - info about CoreDNS itself. +- `coredns_panics_total{}` - total number of panics. +- `coredns_dns_requests_total{server, zone, view, proto, family, type}` - total query count. +- `coredns_dns_request_duration_seconds{server, zone, view, type}` - duration to process each query. +- `coredns_dns_request_size_bytes{server, zone, view, proto}` - size of the request in bytes. +- `coredns_dns_do_requests_total{server, view, zone}` - queries that have the DO bit set +- `coredns_dns_response_size_bytes{server, zone, view, proto}` - response size in bytes. +- `coredns_dns_responses_total{server, zone, view, rcode, plugin}` - response per zone, rcode and plugin. +- `coredns_dns_https_responses_total{server, status}` - responses per server and http status code. +- `coredns_dns_quic_responses_total{server, status}` - responses per server and QUIC application code. +- `coredns_plugin_enabled{server, zone, view, name}` - indicates whether a plugin is enabled on per server, zone and view basis. diff --git a/ipparser/metrics.go b/ipparser/metrics.go new file mode 100644 index 0000000..45c8f55 --- /dev/null +++ b/ipparser/metrics.go @@ -0,0 +1,26 @@ +package ipparser + +import ( + "strconv" + + "github.com/coredns/coredns/plugin" + "github.com/miekg/dns" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +var ( + dynamicResponseCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Namespace: plugin.Namespace, + Subsystem: "forge_" + pluginName, + Name: "responses_total", + Help: "The count of dynamic A/AAAA DNS responses generated by p2p-forge.", + }, []string{"type"}) +) + +func dnsToString(dnsType uint16) string { + if str, ok := dns.TypeToString[dnsType]; ok { + return str + } + return strconv.Itoa(int(dnsType)) +} diff --git a/ipparser/plugin.go b/ipparser/plugin.go index e17a55c..c4618da 100644 --- a/ipparser/plugin.go +++ b/ipparser/plugin.go @@ -72,6 +72,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg // Need to handle .forgeDomain to return NODATA rather than NXDOMAIN per https://datatracker.ietf.org/doc/html/rfc8020 if len(domainSegments) == 1 { containsNODATAResponse = true + dynamicResponseCount.WithLabelValues("NODATA-PEERID-" + dnsToString(q.Qtype)).Add(1) continue } @@ -87,6 +88,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg // Need to handle ..forgeDomain to return NODATA rather than NXDOMAIN per https://datatracker.ietf.org/doc/html/rfc8020 if !(q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY) { containsNODATAResponse = true + dynamicResponseCount.WithLabelValues("NODATA-" + dnsToString(q.Qtype)).Add(1) continue } @@ -99,6 +101,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg }, A: ip.AsSlice(), }) + dynamicResponseCount.WithLabelValues("A").Add(1) continue } @@ -115,6 +118,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg if !(q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY) { containsNODATAResponse = true + dynamicResponseCount.WithLabelValues("NODATA-" + dnsToString(q.Qtype)).Add(1) continue } @@ -127,6 +131,7 @@ func (p ipParser) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg }, AAAA: ip.AsSlice(), }) + dynamicResponseCount.WithLabelValues("AAAA").Add(1) } if len(answers) > 0 || containsNODATAResponse { From 65145f8de005022bd46952b462b1c02d2a775057 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 11 Oct 2024 23:26:33 +0200 Subject: [PATCH 53/61] feat(metrics): forge_acme_registrations_total This enables `coredns_forge_acme_registrations_total{status}` which tracks number of request per response code, including ones that failed libp2pPeerIDAuth Also, switched to go-libp2p from main branch with http auth. --- acme/metrics.go | 2 -- acme/writer.go | 59 ++++++++++++++++++++++++++++----------------- go.mod | 31 ++++++++++++------------ go.sum | 64 +++++++++++++++++++++++-------------------------- 4 files changed, 82 insertions(+), 74 deletions(-) diff --git a/acme/metrics.go b/acme/metrics.go index 740a560..e693358 100644 --- a/acme/metrics.go +++ b/acme/metrics.go @@ -10,14 +10,12 @@ import ( ) var ( - /* TODO registrationRequestCount = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: plugin.Namespace, Subsystem: "forge_" + pluginName, Name: "registrations_total", Help: "Counter of ACME DNS-01 broker registration requests made to this p2p-forge instance.", }, []string{"status"}) - */ dns01ResponseCount = promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: plugin.Namespace, Subsystem: "forge_" + pluginName, diff --git a/acme/writer.go b/acme/writer.go index 343b17c..03b6f47 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -12,17 +12,17 @@ import ( "net" "net/http" "os" + "strconv" "strings" "time" clog "github.com/coredns/coredns/plugin/pkg/log" "github.com/coredns/coredns/plugin/pkg/reuseport" + "github.com/felixge/httpsnoop" "github.com/ipshipyard/p2p-forge/client" "github.com/caddyserver/certmagic" - "github.com/gorilla/mux" - "github.com/ipfs/go-datastore" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" @@ -33,6 +33,8 @@ import ( var log = clog.NewWithPlugin(pluginName) +const registrationApiPath = "/v1/_acme-challenge" + // acmeWriter implements writing of ACME Challenge DNS records by exporting an HTTP endpoint. type acmeWriter struct { Addr string @@ -44,7 +46,8 @@ type acmeWriter struct { ln net.Listener nlSetup bool closeCertMgr func() - mux *mux.Router + + handler http.Handler forgeAuthKey string } @@ -87,7 +90,7 @@ func (c *acmeWriter) OnStartup() error { c.ln = ln - c.mux = mux.NewRouter() + mux := http.NewServeMux() c.nlSetup = true // server side secret key and peerID not particularly relevant, so we can generate new ones as needed @@ -100,17 +103,23 @@ func (c *acmeWriter) OnStartup() error { PrivKey: sk, TokenTTL: time.Hour, Next: func(peerID peer.ID, w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintln(w, "400 Bad Request: Only POST method is allowed.") + return + } if c.forgeAuthKey != "" { auth := r.Header.Get(client.ForgeAuthHeader) if c.forgeAuthKey != auth { - writeStatusHeader(w, http.StatusForbidden) + w.WriteHeader(http.StatusForbidden) + fmt.Fprintf(w, "403 Forbidden: Missing %s header.", client.ForgeAuthHeader) return } } body, err := io.ReadAll(r.Body) if err != nil { - writeStatusHeader(w, http.StatusInternalServerError) + w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte(fmt.Sprintf("error reading body: %s", err))) return } @@ -119,7 +128,7 @@ func (c *acmeWriter) OnStartup() error { decoder := json.NewDecoder(bytes.NewReader(body)) decoder.DisallowUnknownFields() if err := decoder.Decode(typedBody); err != nil { - writeStatusHeader(w, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error decoding body: %s", err))) return } @@ -128,19 +137,19 @@ func (c *acmeWriter) OnStartup() error { // It MUST NOT contain any characters outside the base64url alphabet, including padding characters ("="). decodedValue, err := base64.RawURLEncoding.DecodeString(typedBody.Value) if err != nil { - writeStatusHeader(w, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error decoding value as base64url: %s", err))) return } if len(decodedValue) != 32 { - writeStatusHeader(w, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte("value is not a base64url of a SHA256 digest")) return } if err := testAddresses(r.Context(), peerID, typedBody.Addresses); err != nil { - writeStatusHeader(w, http.StatusBadRequest) + w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(fmt.Sprintf("error testing addresses: %s", err))) return } @@ -148,11 +157,11 @@ func (c *acmeWriter) OnStartup() error { const ttl = time.Hour err = c.Datastore.PutWithTTL(r.Context(), datastore.NewKey(peerID.String()), []byte(typedBody.Value), ttl) if err != nil { - writeStatusHeader(w, http.StatusInternalServerError) + w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte(fmt.Sprintf("error storing value: %s", err))) return } - writeStatusHeader(w, http.StatusOK) + w.WriteHeader(http.StatusOK) }, } @@ -163,21 +172,27 @@ func (c *acmeWriter) OnStartup() error { } } - c.mux.Handle("/v1/_acme-challenge", authPeer).Methods("POST") + // register handlers + mux.Handle(registrationApiPath, authPeer) + + // wrap handler in metrics meter + c.handler = withRequestMetrics(mux) - go func() { http.Serve(c.ln, c.mux) }() + go func() { + log.Infof("Registration HTTP API (%s) listener at %s", registrationApiPath, c.ln.Addr().String()) + http.Serve(c.ln, c.handler) + }() return nil } -func writeStatusHeader(w http.ResponseWriter, statusCode int) { - - // TODO registrationRequestCount.WithLabelValues(strconv.Itoa(statusCode)).Add(1) - // TODO: make sure registrationRequestCount is updated on invalid requests - // correctly. Right now we are unable to detect when libp2p's httppeeridauth.ServerPeerIDAuth - // fails, the metric in writeStatusHeader is not being bumped - - w.WriteHeader(statusCode) +func withRequestMetrics(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + m := httpsnoop.CaptureMetrics(next, w, r) + registrationRequestCount.WithLabelValues(strconv.Itoa(m.Code)).Add(1) + // TODO: decide if we keep below logger + log.Infof("%s %s (status=%d dt=%s ua=%q)", r.Method, r.URL, m.Code, m.Duration, r.UserAgent()) + }) } func testAddresses(ctx context.Context, p peer.ID, addrs []string) error { diff --git a/go.mod b/go.mod index 6282302..bacae04 100644 --- a/go.mod +++ b/go.mod @@ -4,21 +4,22 @@ go 1.22 require ( github.com/aws/aws-sdk-go v1.55.5 - github.com/caddyserver/certmagic v0.21.3 + github.com/caddyserver/certmagic v0.21.4 github.com/coredns/caddy v1.1.1 github.com/coredns/coredns v1.11.3 - github.com/gorilla/mux v1.8.1 + github.com/felixge/httpsnoop v1.0.4 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger4 v0.1.5 github.com/ipfs/go-ds-dynamodb v0.2.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 - github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c - github.com/mholt/acmez/v2 v2.0.1 - github.com/miekg/dns v1.1.61 + github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d + github.com/mholt/acmez/v2 v2.0.3 + github.com/miekg/dns v1.1.62 github.com/multiformats/go-multiaddr v0.13.0 - github.com/multiformats/go-multiaddr-dns v0.3.1 + github.com/multiformats/go-multiaddr-dns v0.4.0 github.com/multiformats/go-multibase v0.2.0 + github.com/prometheus/client_golang v1.20.4 ) require ( @@ -63,7 +64,6 @@ require ( github.com/elastic/gosigar v0.14.3 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/farsightsec/golang-framestream v0.3.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -166,12 +166,11 @@ require ( github.com/pion/webrtc/v3 v3.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.45.2 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.47.0 // indirect github.com/quic-go/webtransport-go v0.8.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect @@ -180,7 +179,7 @@ require ( github.com/stretchr/testify v1.9.0 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/wlynxg/anet v0.0.3 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/etcd/api/v3 v3.5.12 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect go.etcd.io/etcd/client/v3 v3.5.12 // indirect @@ -195,15 +194,15 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.25.0 // indirect + golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.7.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.23.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index 4158a19..a08bb4a 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0= -github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI= +github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0= +github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -244,8 +244,6 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0 github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -298,7 +296,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= @@ -312,6 +309,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/letsencrypt/challtestsrv v1.3.2 h1:pIDLBCLXR3B1DLmOmkkqg29qVa7DDozBnsOpL9PxmAY= github.com/letsencrypt/challtestsrv v1.3.2/go.mod h1:Ur4e4FvELUXLGhkMztHOsPIsvGxD/kzSJninOrkM+zc= github.com/letsencrypt/pebble/v2 v2.6.0 h1:7xetaJ4YaesUnWWeRGSs3UHOwyfX4I4sfOfDrkvnhNw= @@ -322,8 +321,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c h1:OAkpXwVI5odbKc4SUf/ds8Ohn20uf4jQHT88cql2Jms= -github.com/libp2p/go-libp2p v0.36.3-0.20240909195832-fbc0ac8f743c/go.mod h1:4Y5vFyCUiJuluEPmpnKYf6WFx5ViKPUYs/ixe9ANFZ8= +github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d h1:xAUGH+UOC6gfcL7GIeMos0B8RJvCHcfhxiykmGiqSm8= +github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d/go.mod h1:TTwkIltN7SS41Lljqp+kuI8iKp/0iyqExGinvx5PWJg= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -350,14 +349,13 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/mholt/acmez/v2 v2.0.1 h1:3/3N0u1pLjMK4sNEAFSI+bcvzbPhRpY383sy1kLHJ6k= -github.com/mholt/acmez/v2 v2.0.1/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U= +github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw= +github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -384,11 +382,10 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr-dns v0.4.0 h1:P76EJ3qzBXpUXZ3twdCDx/kvagMsNo0LMFXpyms/zgU= +github.com/multiformats/go-multiaddr-dns v0.4.0/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= @@ -400,7 +397,6 @@ github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7B github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -482,8 +478,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -494,10 +490,10 @@ github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65 github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.45.2 h1:DfqBmqjb4ExSdxRIb/+qXhPC+7k6+DUNZha4oeiC9fY= -github.com/quic-go/quic-go v0.45.2/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= +github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= @@ -572,8 +568,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= @@ -629,8 +625,8 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -675,8 +671,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -694,8 +690,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -738,8 +734,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= 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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -750,8 +746,8 @@ 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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= From d6c1f74f5c89e9369ab2827dcfb3fd96fc640f53 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 19 Oct 2024 00:13:31 +0200 Subject: [PATCH 54/61] feat: WithLogger(log *zap.SugaredLogger) allows consumers like Kubo to adjust logger NOTE: certmagic.DefaultACME.Logger and certmagic.Default.Logger are used before we are able to set custom logger, so consumer likely will want to set them to the same one. We don't override upstream defaults in case application uses multiple instances, and some of them are not related to p2p-forge. --- .gitignore | 2 ++ client/acme.go | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index fdf6350..f1552d3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ cmd/db.* cmd/Corefile cmd/cmd p2p-forge +p2p-forge-certs/ +badger.libp2p-direct-challenges/ diff --git a/client/acme.go b/client/acme.go index 19c482d..158e2cd 100644 --- a/client/acme.go +++ b/client/acme.go @@ -12,6 +12,7 @@ import ( "time" httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + "go.uber.org/zap" "github.com/caddyserver/certmagic" logging "github.com/ipfs/go-log/v2" @@ -25,8 +26,6 @@ import ( "github.com/multiformats/go-multibase" ) -var log = logging.Logger("p2p-forge/client") - type P2PForgeCertMgr struct { ctx context.Context cancel func() @@ -36,6 +35,7 @@ type P2PForgeCertMgr struct { hostFn func() host.Host hasHost func() bool cfg *certmagic.Config + log *zap.SugaredLogger allowPrivateForgeAddresses bool hasCert bool // tracking if we've received a certificate @@ -76,6 +76,7 @@ type P2PForgeCertMgrConfig struct { storage certmagic.Storage modifyForgeRequest func(r *http.Request) error onCertLoaded func() + log *zap.SugaredLogger allowPrivateForgeAddresses bool } @@ -174,6 +175,13 @@ func WithAllowPrivateForgeAddrs() P2PForgeCertMgrOptions { } } +func WithLogger(log *zap.SugaredLogger) P2PForgeCertMgrOptions { + return func(config *P2PForgeCertMgrConfig) error { + config.log = log + return nil + } +} + // NewP2PForgeCertMgr handles the creation and management of certificates that are automatically granted by a forge // to a libp2p host. // @@ -187,6 +195,9 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error } } + if mgrCfg.log == nil { + mgrCfg.log = logging.Logger("p2p-forge/client").Desugar().Sugar() + } if mgrCfg.forgeDomain == "" { mgrCfg.forgeDomain = DefaultForgeDomain } @@ -208,6 +219,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error certCfg := certmagic.NewDefault() certCfg.Storage = mgrCfg.storage + certCfg.Logger = mgrCfg.log.Desugar() hostChan := make(chan host.Host, 1) provideHost := func(host host.Host) { hostChan <- host } hasHostChan := make(chan struct{}) @@ -247,6 +259,7 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error hostFn: hostFn, hasHost: hasHostFn, cfg: certCfg, + log: mgrCfg.log, allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, } @@ -290,7 +303,7 @@ func (m *P2PForgeCertMgr) Start() error { pb36 := peer.ToCid(m.hostFn().ID()).Encode(multibase.MustNewEncoder(multibase.Base36)) if err := m.cfg.ManageAsync(m.ctx, []string{fmt.Sprintf("*.%s.%s", pb36, m.forgeDomain)}); err != nil { - log.Error(err) + m.log.Error(err) } }() return nil @@ -337,7 +350,7 @@ func (m *P2PForgeCertMgr) createAddrsFactory(allowPrivateForgeAddrs bool) config } m.certCheckMx.RUnlock() - return addrFactoryFn(skipForgeAddrs, func() peer.ID { return m.hostFn().ID() }, m.forgeDomain, allowPrivateForgeAddrs, p2pForgeWssComponent, multiaddrs) + return addrFactoryFn(skipForgeAddrs, func() peer.ID { return m.hostFn().ID() }, m.forgeDomain, allowPrivateForgeAddrs, p2pForgeWssComponent, multiaddrs, m.log) } } @@ -419,7 +432,7 @@ func (d *dns01P2PForgeSolver) CleanUp(ctx context.Context, challenge acme.Challe var _ acmez.Solver = (*dns01P2PForgeSolver)(nil) var _ acmez.Waiter = (*dns01P2PForgeSolver)(nil) -func addrFactoryFn(skipForgeAddrs bool, peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr, multiaddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr { +func addrFactoryFn(skipForgeAddrs bool, peerIDFn func() peer.ID, forgeDomain string, allowPrivateForgeAddrs bool, p2pForgeWssComponent multiaddr.Multiaddr, multiaddrs []multiaddr.Multiaddr, log *zap.SugaredLogger) []multiaddr.Multiaddr { retAddrs := make([]multiaddr.Multiaddr, 0, len(multiaddrs)) for _, a := range multiaddrs { if isRelayAddr(a) { From 97f25adc255c9c147c5537491066e4ceb8b17e20 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 00:17:41 +0100 Subject: [PATCH 55/61] chore: go-libp2p v0.37.0 and go 1.23 --- Dockerfile | 2 +- go.mod | 62 +++++++++++++-------------- go.sum | 123 +++++++++++++++++++++++++++-------------------------- 3 files changed, 94 insertions(+), 93 deletions(-) diff --git a/Dockerfile b/Dockerfile index 32c0253..1db72f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.22-bookworm AS builder +FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.23-bookworm AS builder LABEL org.opencontainers.image.source=https://github.com/ipshipyard/p2p-forge LABEL org.opencontainers.image.documentation=https://github.com/ipshipyard/p2p-forge#docker diff --git a/go.mod b/go.mod index bacae04..996f770 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ipshipyard/p2p-forge -go 1.22 +go 1.23 require ( github.com/aws/aws-sdk-go v1.55.5 @@ -13,13 +13,14 @@ require ( github.com/ipfs/go-ds-dynamodb v0.2.0 github.com/ipfs/go-log/v2 v2.5.1 github.com/letsencrypt/pebble/v2 v2.6.0 - github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d + github.com/libp2p/go-libp2p v0.37.0 github.com/mholt/acmez/v2 v2.0.3 github.com/miekg/dns v1.1.62 github.com/multiformats/go-multiaddr v0.13.0 github.com/multiformats/go-multiaddr-dns v0.4.0 github.com/multiformats/go-multibase v0.2.0 - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 + go.uber.org/zap v1.27.0 ) require ( @@ -86,7 +87,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/pprof v0.0.0-20241017200806-017d972448fc // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect @@ -105,13 +106,13 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/letsencrypt/challtestsrv v1.3.2 // indirect github.com/libdns/libdns v0.2.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect @@ -137,7 +138,7 @@ require ( github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.19.1 // indirect + github.com/onsi/ginkgo/v2 v2.20.2 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect @@ -148,37 +149,37 @@ require ( github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/philhofer/fwd v1.1.2 // indirect - github.com/pion/datachannel v1.5.8 // indirect + github.com/pion/datachannel v1.5.9 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/ice/v2 v2.3.34 // indirect - github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/ice/v2 v2.3.36 // indirect + github.com/pion/interceptor v0.1.37 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.12 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.8 // indirect - github.com/pion/sctp v1.8.20 // indirect + github.com/pion/rtp v1.8.9 // indirect + github.com/pion/sctp v1.8.33 // indirect github.com/pion/sdp/v3 v3.0.9 // indirect github.com/pion/srtp/v2 v2.0.20 // indirect github.com/pion/stun v0.6.1 // indirect github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.3.0 // indirect + github.com/pion/webrtc/v3 v3.3.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.60.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.47.0 // indirect - github.com/quic-go/webtransport-go v0.8.0 // indirect + github.com/quic-go/quic-go v0.48.1 // indirect + github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.7.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/tinylib/msgp v1.1.8 // indirect - github.com/wlynxg/anet v0.0.3 // indirect + github.com/wlynxg/anet v0.0.5 // indirect github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/etcd/api/v3 v3.5.12 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect @@ -189,28 +190,27 @@ require ( go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.22.1 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/dig v1.18.0 // indirect + go.uber.org/fx v1.23.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.24.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.23.0 // indirect + golang.org/x/tools v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index a08bb4a..918097c 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs= +github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -294,8 +294,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= @@ -319,10 +319,10 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= -github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d h1:xAUGH+UOC6gfcL7GIeMos0B8RJvCHcfhxiykmGiqSm8= -github.com/libp2p/go-libp2p v0.36.3-0.20241009065418-fa09c6c99b1d/go.mod h1:TTwkIltN7SS41Lljqp+kuI8iKp/0iyqExGinvx5PWJg= +github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= +github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +github.com/libp2p/go-libp2p v0.37.0 h1:8K3mcZgwTldydMCNOiNi/ZJrOB9BY+GlI3UxYzxBi9A= +github.com/libp2p/go-libp2p v0.37.0/go.mod h1:GOKmSN99scDuYGTwaTbQPR8Nt6dxrK3ue7OjW2NGDg4= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= @@ -403,10 +403,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= -github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= -github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= -github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= +github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= +github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -429,15 +429,15 @@ github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2D github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pion/datachannel v1.5.8 h1:ph1P1NsGkazkjrvyMfhRBUAWMxugJjq2HfQifaOoSNo= -github.com/pion/datachannel v1.5.8/go.mod h1:PgmdpoaNBLX9HNzNClmdki4DYW5JtI7Yibu8QzbL3tI= +github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= +github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.34 h1:Ic1ppYCj4tUOcPAp76U6F3fVrlSw8A9JtRXLqw6BbUM= -github.com/pion/ice/v2 v2.3.34/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= -github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= -github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/ice/v2 v2.3.36 h1:SopeXiVbbcooUg2EIR8sq4b13RQ8gzrkkldOVg+bBsc= +github.com/pion/ice/v2 v2.3.36/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= +github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= @@ -448,10 +448,10 @@ github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9 github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.8 h1:EtYFHI0rpUEjT/RMnGfb1vdJhbYmPG77szD72uUnSxs= -github.com/pion/rtp v1.8.8/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.20 h1:sOc3lkV/tQaP57ZUEXIMdM2V92IIB2ia5v/ygnBxaEg= -github.com/pion/sctp v1.8.20/go.mod h1:oTxw8i5m+WbDHZJL/xUpe6CPIn1Y0GIKKwTLF4h53H8= +github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= +github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= +github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= @@ -464,13 +464,13 @@ github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLh github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pion/transport/v3 v3.0.6 h1:k1mQU06bmmX143qSWgXFqSH1KUJceQvIUuVH/K5ELWw= -github.com/pion/transport/v3 v3.0.6/go.mod h1:HvJr2N/JwNJAfipsRleqwFoR3t/pWyHeZUs89v3+t5s= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.3.0 h1:Rf4u6n6U5t5sUxhYPQk/samzU/oDv7jk6BA5hyO2F9I= -github.com/pion/webrtc/v3 v3.3.0/go.mod h1:hVmrDJvwhEertRWObeb1xzulzHGeVUoPlWvxdGzcfU0= +github.com/pion/webrtc/v3 v3.3.4 h1:v2heQVnXTSqNRXcaFQVOhIOYkLMxOu1iJG8uy1djvkk= +github.com/pion/webrtc/v3 v3.3.4/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -478,24 +478,24 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= +github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y= -github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E= -github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= -github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= +github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA= +github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= @@ -560,8 +560,9 @@ github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkC github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg= github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -593,15 +594,15 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= -go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.22.1 h1:nvvln7mwyT5s1q201YE29V/BFrGor6vMiDNpU/78Mys= -go.uber.org/fx v1.22.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= +go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= +go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= +go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -625,11 +626,11 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -643,8 +644,8 @@ 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.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -671,14 +672,14 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -724,8 +725,8 @@ 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.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= @@ -734,8 +735,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= 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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -746,8 +747,8 @@ 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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -770,8 +771,8 @@ 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.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 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= @@ -820,8 +821,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 h1:jeZxE4ZlfAc+R0zO5TEmJBwOLet3NThsOfYJeSQg1x0= gopkg.in/DataDog/dd-trace-go.v1 v1.62.0/go.mod h1:YTvYkk3PTsfw0OWrRFxV/IQ5Gy4nZ5TRvxTAP3JcIzs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f599f4803109aeaeae1c80756580759889a92e16 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 00:18:53 +0100 Subject: [PATCH 56/61] fix(client): use dedicated cert cache aims to solve race condition when NewDefault() from certmagic is used https://github.com/ipfs/kubo/pull/10521/files/e6e0b7a1dc350430c64438417bc5ed4a38171895#diff-52740993e6a197feddd69dc9db132b0b7babd2cf3c0b337bde3476b779c07a77 --- client/acme.go | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/client/acme.go b/client/acme.go index 158e2cd..43e0bcc 100644 --- a/client/acme.go +++ b/client/acme.go @@ -42,6 +42,11 @@ type P2PForgeCertMgr struct { certCheckMx sync.RWMutex } +var ( + defaultCertCache *certmagic.Cache + defaultCertCacheMu sync.Mutex +) + func isRelayAddr(a multiaddr.Multiaddr) bool { found := false multiaddr.ForEach(a, func(c multiaddr.Component) bool { @@ -182,6 +187,35 @@ func WithLogger(log *zap.SugaredLogger) P2PForgeCertMgrOptions { } } +// newCertmagicConfig is p2p-forge/client-specific version of +// certmagic.NewDefault() that ensures we have our own cert cache. This is +// necessary to ensure cert maintenance spawned by NewCache does not share +// global certmagic.Default.Storage, and certmagic.Default.Logger and uses +// storage path specific to p2p-forge, and no other instance of certmagic in +// golang application. +func newCertmagicConfig(mgrCfg *P2PForgeCertMgrConfig) *certmagic.Config { + clog := mgrCfg.log.Desugar() + + defaultCertCacheMu.Lock() + if defaultCertCache == nil { + defaultCertCache = certmagic.NewCache(certmagic.CacheOptions{ + GetConfigForCert: func(certmagic.Certificate) (*certmagic.Config, error) { + // default getter that does not depend on certmagic defaults + // and respects Config.Storage path + return newCertmagicConfig(mgrCfg), nil + }, + Logger: clog, + }) + } + certCache := defaultCertCache + defaultCertCacheMu.Unlock() + + return certmagic.New(certCache, certmagic.Config{ + Storage: mgrCfg.storage, + Logger: clog, + }) +} + // NewP2PForgeCertMgr handles the creation and management of certificates that are automatically granted by a forge // to a libp2p host. // @@ -217,9 +251,8 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error mgrCfg.storage = &certmagic.FileStorage{Path: defaultStorageLocation} } - certCfg := certmagic.NewDefault() - certCfg.Storage = mgrCfg.storage - certCfg.Logger = mgrCfg.log.Desugar() + certCfg := newCertmagicConfig(mgrCfg) + hostChan := make(chan host.Host, 1) provideHost := func(host host.Host) { hostChan <- host } hasHostChan := make(chan struct{}) @@ -249,7 +282,9 @@ func NewP2PForgeCertMgr(opts ...P2PForgeCertMgrOptions) (*P2PForgeCertMgr, error allowPrivateForgeAddresses: mgrCfg.allowPrivateForgeAddresses, }, TrustedRoots: mgrCfg.trustedRoots, + Logger: certCfg.Logger, }) + certCfg.Issuers = []certmagic.Issuer{myACME} mgr := &P2PForgeCertMgr{ From 2595bf84fc6c9d500b3e1b6d16b8e3ef8984c1d1 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 00:35:07 +0100 Subject: [PATCH 57/61] chore: remove requirement for FORGE_ACCESS_TOKEN --- acme/writer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acme/writer.go b/acme/writer.go index 03b6f47..b45968a 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -84,8 +84,7 @@ func (c *acmeWriter) OnStartup() error { if found { c.forgeAuthKey = authKey } else { - // TODO: Remove when ready for rollout - return fmt.Errorf("environment variable %s not found", client.ForgeAuthEnv) + fmt.Println("NOTE: environment variable %s not set, registration is open to all peers", client.ForgeAuthEnv) } c.ln = ln From 1360e56fcc21922e26198c23554e3a4cd81cea01 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 00:38:08 +0100 Subject: [PATCH 58/61] chore: typo --- acme/writer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/writer.go b/acme/writer.go index b45968a..ac1dd42 100644 --- a/acme/writer.go +++ b/acme/writer.go @@ -84,7 +84,7 @@ func (c *acmeWriter) OnStartup() error { if found { c.forgeAuthKey = authKey } else { - fmt.Println("NOTE: environment variable %s not set, registration is open to all peers", client.ForgeAuthEnv) + fmt.Printf("NOTE: environment variable %s not set, registration is open to all peers\n", client.ForgeAuthEnv) } c.ln = ln From 78c3ae044719fe2318cce15ecf1d1bb207cc6abb Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 00:51:17 +0100 Subject: [PATCH 59/61] fix(test): go-libp2p v0.37 --- e2e_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e_test.go b/e2e_test.go index 476f0bc..a935b7f 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -30,6 +30,7 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" httppeeridauth "github.com/libp2p/go-libp2p/p2p/http/auth" + "github.com/libp2p/go-libp2p/p2p/net/swarm" libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" "github.com/libp2p/go-libp2p/p2p/transport/tcp" libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" @@ -600,7 +601,7 @@ func TestLibp2pACMEE2E(t *testing.T) { } h2, err := libp2p.New(libp2p.Transport(libp2pws.New, libp2pws.WithTLSClientConfig(tlsCfgWithTestCA)), - libp2p.MultiaddrResolver(customResolver)) + libp2p.MultiaddrResolver(swarm.ResolverFromMaDNS{Resolver: customResolver})) if err != nil { t.Fatal(err) } From 688ddf7d4f76ce78f3ff60b6930e2276ab979ac3 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 29 Oct 2024 15:28:50 +0100 Subject: [PATCH 60/61] chore(lint): redundant return statement (S1023) --- e2e_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e_test.go b/e2e_test.go index a935b7f..ede2884 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -218,7 +218,6 @@ func TestIPSubdomainsNonExistentRecords(t *testing.T) { if len(r.Answer) != 0 { t.Fatalf("expected no answers got %+v", r.Answer) } - return }) } } From 4468ad55a3a8bb2af1ed8d0c0791238242e2eba2 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 30 Oct 2024 03:15:05 +0100 Subject: [PATCH 61/61] docs(readme): apply suggestions from code review Co-authored-by: Alex Potsides --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cbb1fdb..3638ce4 100644 --- a/README.md +++ b/README.md @@ -130,13 +130,13 @@ To claim a domain name like `.libp2p.direct` requires: To set an ACME challenge send an HTTP request to the server (for libp2p.direct this is registration.libp2p.direct) ```shell -curl -X POST "https://registration.libp2p.direct/v1//_acme-challenge" \ +curl -X POST "https://registration.libp2p.direct/v1/_acme-challenge" \ -H "Authorization: libp2p-PeerID bearer=\"\"" -H "Content-Type: application/json" \ -d '{ "value": "your_acme_challenge_token", - "addresses": "[your_multiaddrs, comma_separated]" + "addresses": ["your", "multiaddrs"] }' ``` -Where the bearer token is derived via the [libp2p HTTP PeerID Auth Specification](https://github.com/libp2p/specs/pull/564). +Where the bearer token is derived via the [libp2p HTTP PeerID Auth Specification](https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md).