diff --git a/cmd/ipfs/kubo/start.go b/cmd/ipfs/kubo/start.go index 4a8709cc63c..b5aff3bc3ec 100644 --- a/cmd/ipfs/kubo/start.go +++ b/cmd/ipfs/kubo/start.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "net/http" "os" @@ -33,6 +34,7 @@ import ( "github.com/ipfs/kubo/repo" "github.com/ipfs/kubo/repo/fsrepo" "github.com/ipfs/kubo/tracing" + "github.com/libp2p/go-libp2p/gologshim" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" manet "github.com/multiformats/go-multiaddr/net" @@ -50,6 +52,17 @@ var ( tracer trace.Tracer ) +func init() { + // Set go-log's slog handler as the application-wide default. + // This ensures all slog-based logging uses go-log's formatting. + slog.SetDefault(slog.New(logging.SlogHandler())) + + // Wire go-log's slog bridge to go-libp2p's gologshim. + // This provides go-libp2p loggers with the "logger" attribute + // for per-subsystem level control (e.g., `ipfs log level libp2p-swarm debug`). + gologshim.SetDefaultHandler(logging.SlogHandler()) +} + // declared as a var for testing purposes. var dnsResolver = madns.DefaultResolver diff --git a/docs/changelogs/v0.39.md b/docs/changelogs/v0.39.md index 177aca4fdef..29e9e28b837 100644 --- a/docs/changelogs/v0.39.md +++ b/docs/changelogs/v0.39.md @@ -154,8 +154,9 @@ For Docker users, the legacy `ipfs/go-ipfs` image name now shows a deprecation n ### 📦️ Important dependency updates -- update `go-libp2p` to [v0.44.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.44.0) with self-healing UPnP port mappings +- update `go-libp2p` to [v0.45.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.45.0) (incl. [v0.44.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.44.0)) with self-healing UPnP port mappings and go-log/slog interop fixes - update `quic-go` to [v0.55.0](https://github.com/quic-go/quic-go/releases/tag/v0.55.0) +- update `go-log` to [v2.9.0](https://github.com/ipfs/go-log/releases/tag/v2.9.0) with slog integration for go-libp2p - update `go-ds-pebble` to [v0.5.6](https://github.com/ipfs/go-ds-pebble/releases/tag/v0.5.6) (includes pebble [v2.1.1](https://github.com/cockroachdb/pebble/releases/tag/v2.1.1)) - update `boxo` to [v0.35.1](https://github.com/ipfs/boxo/releases/tag/v0.35.1) diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index d77196d61aa..59b61053bcd 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -9,7 +9,7 @@ replace github.com/ipfs/kubo => ./../../.. require ( github.com/ipfs/boxo v0.35.1 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 - github.com/libp2p/go-libp2p v0.44.0 + github.com/libp2p/go-libp2p v0.45.0 github.com/multiformats/go-multiaddr v0.16.1 ) @@ -93,7 +93,7 @@ require ( github.com/ipfs/go-ipld-format v0.6.3 // indirect github.com/ipfs/go-ipld-git v0.1.1 // indirect github.com/ipfs/go-ipld-legacy v0.2.2 // indirect - github.com/ipfs/go-log/v2 v2.8.2 // indirect + github.com/ipfs/go-log/v2 v2.9.0 // indirect github.com/ipfs/go-metrics-interface v0.3.0 // indirect github.com/ipfs/go-peertaskqueue v0.8.2 // indirect github.com/ipfs/go-test v0.2.3 // indirect diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 0fe61d434e6..9b778401436 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -349,8 +349,8 @@ github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYD github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ= github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I= -github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= +github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= +github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU= @@ -424,8 +424,8 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784= github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo= -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs= -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= +github.com/libp2p/go-libp2p v0.45.0 h1:Pdhr2HsFXaYjtfiNcBP4CcRUONvbMFdH3puM9vV4Tiw= +github.com/libp2p/go-libp2p v0.45.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= 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-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= diff --git a/go.mod b/go.mod index a24c63ca28f..7ce14c0508a 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/ipfs/go-ipld-format v0.6.3 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.2.2 - github.com/ipfs/go-log/v2 v2.8.2 + github.com/ipfs/go-log/v2 v2.9.0 github.com/ipfs/go-metrics-interface v0.3.0 github.com/ipfs/go-metrics-prometheus v0.1.0 github.com/ipfs/go-test v0.2.3 @@ -51,7 +51,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/julienschmidt/httprouter v1.3.0 github.com/libp2p/go-doh-resolver v0.5.0 - github.com/libp2p/go-libp2p v0.44.0 + github.com/libp2p/go-libp2p v0.45.0 github.com/libp2p/go-libp2p-http v0.5.0 github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 github.com/libp2p/go-libp2p-kbucket v0.8.0 diff --git a/go.sum b/go.sum index 5791d79c949..55a1d6f5c99 100644 --- a/go.sum +++ b/go.sum @@ -416,8 +416,8 @@ github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYD github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ= github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I= -github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= +github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= +github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= github.com/ipfs/go-metrics-prometheus v0.1.0 h1:bApWOHkrH3VTBHzTHrZSfq4n4weOZDzZFxUXv+HyKcA= @@ -504,8 +504,8 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784= github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo= -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs= -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= +github.com/libp2p/go-libp2p v0.45.0 h1:Pdhr2HsFXaYjtfiNcBP4CcRUONvbMFdH3puM9vV4Tiw= +github.com/libp2p/go-libp2p v0.45.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= 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-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= diff --git a/test/cli/log_level_test.go b/test/cli/log_level_test.go index e5c9eb8f801..4858f26574f 100644 --- a/test/cli/log_level_test.go +++ b/test/cli/log_level_test.go @@ -1,11 +1,16 @@ package cli import ( + "bufio" + "context" "encoding/json" "fmt" "net/http" + "os" + "os/exec" "strings" "testing" + "time" "github.com/ipfs/kubo/test/cli/harness" . "github.com/ipfs/kubo/test/cli/testutils" @@ -599,6 +604,164 @@ func TestLogLevel(t *testing.T) { }) }) + // Constants for slog interop tests + const ( + slogTestLogTailTimeout = 10 * time.Second + slogTestLogWaitTimeout = 5 * time.Second + slogTestLogStartupDelay = 1 * time.Second // Wait for log tail to start + slogTestSubsystemCmdsHTTP = "cmds/http" // Native go-log subsystem + slogTestSubsystemNetIdentify = "net/identify" // go-libp2p slog subsystem + ) + + // logMatch represents a matched log entry for slog interop tests + type logMatch struct { + subsystem string + line string + } + + // startLogMonitoring starts ipfs log tail and returns command and channel for matched logs. + startLogMonitoring := func(t *testing.T, node *harness.Node) (*exec.Cmd, chan logMatch) { + t.Helper() + + ctx, cancel := context.WithTimeout(context.Background(), slogTestLogTailTimeout) + t.Cleanup(cancel) + + cmd := exec.CommandContext(ctx, node.IPFSBin, "log", "tail") + cmd.Env = append([]string(nil), os.Environ()...) + for k, v := range node.Runner.Env { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) + } + cmd.Dir = node.Runner.Dir + + stdout, err := cmd.StdoutPipe() + require.NoError(t, err) + require.NoError(t, cmd.Start()) + + matches := make(chan logMatch, 10) + + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + line := scanner.Text() + // Check for actual logger field in JSON, not just substring match + if strings.Contains(line, `"logger":"cmds/http"`) { + matches <- logMatch{slogTestSubsystemCmdsHTTP, line} + } + if strings.Contains(line, `"logger":"net/identify"`) { + matches <- logMatch{slogTestSubsystemNetIdentify, line} + } + } + }() + + return cmd, matches + } + + // waitForBothSubsystems waits for both native go-log and slog subsystems to appear in logs. + waitForBothSubsystems := func(t *testing.T, matches chan logMatch, timeout time.Duration) { + t.Helper() + + seen := make(map[string]struct{}) + deadline := time.After(timeout) + + for len(seen) < 2 { + select { + case match := <-matches: + if _, exists := seen[match.subsystem]; !exists { + t.Logf("Found %s log", match.subsystem) + seen[match.subsystem] = struct{}{} + } + case <-deadline: + t.Fatalf("Timeout waiting for logs. Seen: %v", seen) + } + } + + assert.Contains(t, seen, slogTestSubsystemCmdsHTTP, "should see cmds/http (native go-log)") + assert.Contains(t, seen, slogTestSubsystemNetIdentify, "should see net/identify (slog from go-libp2p)") + } + + // triggerIdentifyProtocol connects node1 to node2, triggering net/identify logs. + triggerIdentifyProtocol := func(t *testing.T, node1, node2 *harness.Node) { + t.Helper() + + // Get node2's peer ID and address + node2ID := node2.PeerID().String() + addrsRes := node2.IPFS("id", "-f", "") + require.NoError(t, addrsRes.Err) + + addrs := strings.Split(strings.TrimSpace(addrsRes.Stdout.String()), "\n") + require.NotEmpty(t, addrs, "node2 should have at least one address") + + // Connect node1 to node2 + multiaddr := fmt.Sprintf("%s/p2p/%s", addrs[0], node2ID) + res := node1.IPFS("swarm", "connect", multiaddr) + require.NoError(t, res.Err) + } + + // verifySlogInterop verifies that both native go-log and slog from go-libp2p + // appear in ipfs log tail with correct formatting and level control. + verifySlogInterop := func(t *testing.T, node1, node2 *harness.Node) { + t.Helper() + + cmd, matches := startLogMonitoring(t, node1) + defer func() { + _ = cmd.Process.Kill() + }() + + time.Sleep(slogTestLogStartupDelay) + + // Trigger cmds/http (native go-log) + node1.IPFS("version") + + // Trigger net/identify (slog from go-libp2p) + triggerIdentifyProtocol(t, node1, node2) + + waitForBothSubsystems(t, matches, slogTestLogWaitTimeout) + } + + // This test verifies that go-log's slog bridge works with go-libp2p's gologshim + // when log levels are set via GOLOG_LOG_LEVEL environment variable. + // It tests both native go-log loggers (cmds/http) and slog-based loggers from + // go-libp2p (net/identify), ensuring both types appear in `ipfs log tail`. + t.Run("slog interop via env var", func(t *testing.T) { + t.Parallel() + h := harness.NewT(t) + + node1 := h.NewNode().Init() + node1.Runner.Env["GOLOG_LOG_LEVEL"] = "error,cmds/http=debug,net/identify=debug" + node1.StartDaemon() + defer node1.StopDaemon() + + node2 := h.NewNode().Init().StartDaemon() + defer node2.StopDaemon() + + verifySlogInterop(t, node1, node2) + }) + + // This test verifies that go-log's slog bridge works with go-libp2p's gologshim + // when log levels are set dynamically via `ipfs log level` CLI commands. + // It tests the key feature that SetLogLevel auto-creates level entries for subsystems + // that don't exist yet, enabling `ipfs log level net/identify debug` to work even + // before the net/identify logger is created. This is critical for slog interop. + t.Run("slog interop via CLI", func(t *testing.T) { + t.Parallel() + h := harness.NewT(t) + + node1 := h.NewNode().Init().StartDaemon() + defer node1.StopDaemon() + + node2 := h.NewNode().Init().StartDaemon() + defer node2.StopDaemon() + + // Set levels via CLI for both subsystems BEFORE triggering events + res := node1.IPFS("log", "level", slogTestSubsystemCmdsHTTP, "debug") + require.NoError(t, res.Err) + + res = node1.IPFS("log", "level", slogTestSubsystemNetIdentify, "debug") + require.NoError(t, res.Err) // Auto-creates level entry for slog subsystem + + verifySlogInterop(t, node1, node2) + }) + } func getExpectedSubsystems(t *testing.T, node *harness.Node) []string { diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 29ab89f02d7..c2854686dff 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -8,7 +8,7 @@ require ( github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd github.com/golangci/golangci-lint v1.64.8 github.com/ipfs/go-cidutil v0.1.0 - github.com/ipfs/go-log/v2 v2.8.2 + github.com/ipfs/go-log/v2 v2.9.0 github.com/ipfs/go-test v0.2.3 github.com/ipfs/hang-fds v0.1.0 github.com/ipfs/iptb v1.4.1 @@ -182,7 +182,7 @@ require ( github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-doh-resolver v0.5.0 // indirect github.com/libp2p/go-flow-metrics v0.3.0 // indirect - github.com/libp2p/go-libp2p v0.44.0 // indirect + github.com/libp2p/go-libp2p v0.45.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 // indirect github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 99b07b13908..6723c2b8843 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -364,8 +364,8 @@ github.com/ipfs/go-ipld-format v0.6.3 h1:9/lurLDTotJpZSuL++gh3sTdmcFhVkCwsgx2+rA github.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvGqdmrcYZvCBk= github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ= github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU= -github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I= -github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= +github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= +github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU= @@ -458,8 +458,8 @@ github.com/libp2p/go-doh-resolver v0.5.0 h1:4h7plVVW+XTS+oUBw2+8KfoM1jF6w8XmO7+s github.com/libp2p/go-doh-resolver v0.5.0/go.mod h1:aPDxfiD2hNURgd13+hfo29z9IC22fv30ee5iM31RzxU= github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784= github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo= -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs= -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= +github.com/libp2p/go-libp2p v0.45.0 h1:Pdhr2HsFXaYjtfiNcBP4CcRUONvbMFdH3puM9vV4Tiw= +github.com/libp2p/go-libp2p v0.45.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc= 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-kad-dht v0.35.2-0.20251025120456-f33906fd2f32 h1:xZj18PsLD157snR/BFo547jwOkGDH7jZjMEkBDOoD4Q=