Repository: libp2p/go-libp2p
Pull request #3222 (2025-03-05 15:35:48)

optimize: using t.TempDir() replace os.MkdirTemp in testfile
logs:
```
➜  go-libp2p git:(master) ✗ go test -v ./p2p/transport/quicreuse/  -run '' 

=== RUN   TestListenOnSameProto
=== RUN   TestListenOnSameProto/with_reuseport
=== RUN   TestListenOnSameProto/without_reuseport
--- PASS: TestListenOnSameProto (0.02s)
    --- PASS: TestListenOnSameProto/with_reuseport (0.01s)
    --- PASS: TestListenOnSameProto/without_reuseport (0.01s)
=== RUN   TestConnectionPassedToQUICForListening
--- PASS: TestConnectionPassedToQUICForListening (0.00s)
=== RUN   TestAcceptErrorGetCleanedUp
    connmgr_test.go:113: num goroutines: 7
    connmgr_test.go:127: num goroutines: 7
--- PASS: TestAcceptErrorGetCleanedUp (0.00s)
=== RUN   TestConnectionPassedToQUICForDialing
--- PASS: TestConnectionPassedToQUICForDialing (0.00s)
=== RUN   TestListener
=== RUN   TestListener/with_reuseport
=== RUN   TestListener/without_reuseport
--- PASS: TestListener (0.04s)
    --- PASS: TestListener/with_reuseport (0.02s)
    --- PASS: TestListener/without_reuseport (0.02s)
=== RUN   TestExternalTransport
--- PASS: TestExternalTransport (0.02s)
=== RUN   TestConvertToQuicMultiaddr
--- PASS: TestConvertToQuicMultiaddr (0.00s)
=== RUN   TestConvertToQuicV1Multiaddr
--- PASS: TestConvertToQuicV1Multiaddr (0.00s)
=== RUN   TestConvertFromQuicV1Multiaddr
--- PASS: TestConvertFromQuicV1Multiaddr (0.00s)
=== RUN   TestReuseListenOnAllIPv4
--- PASS: TestReuseListenOnAllIPv4 (0.05s)
=== RUN   TestReuseListenOnAllIPv6
--- PASS: TestReuseListenOnAllIPv6 (0.05s)
=== RUN   TestReuseCreateNewGlobalConnOnDial
--- PASS: TestReuseCreateNewGlobalConnOnDial (0.00s)
=== RUN   TestReuseConnectionWhenDialing
--- PASS: TestReuseConnectionWhenDialing (0.00s)
=== RUN   TestReuseConnectionWhenListening
--- PASS: TestReuseConnectionWhenListening (0.00s)
=== RUN   TestReuseConnectionWhenDialBeforeListen
--- PASS: TestReuseConnectionWhenDialBeforeListen (0.00s)
=== RUN   TestReuseListenOnSpecificInterface
    reuse_test.go:167: this test only works on platforms that support routing tables
--- SKIP: TestReuseListenOnSpecificInterface (0.00s)
=== RUN   TestReuseGarbageCollect
--- PASS: TestReuseGarbageCollect (0.15s)
=== RUN   TestSaveQlog
--- PASS: TestSaveQlog (0.00s)
=== RUN   TestQlogBuffering
    tracer_test.go:51: initial log file size: 0, final log file size: 19
--- PASS: TestQlogBuffering (0.00s)
=== RUN   TestQlogCompression
--- PASS: TestQlogCompression (0.00s)
PASS
ok      github.com/libp2p/go-libp2p/p2p/transport/quicreuse     0.356s
```

argentpapa: > Thanks!
you are welcome!

Patch:
diff --git a/config/config.go b/config/config.go
index b5d42eed..607dceba 100644
--- a/config/config.go
+++ b/config/config.go
@@ -292,11 +292,11 @@ func (cfg *Config) addTransports() ([]fx.Option, error) {
 		fx.Provide(func() connmgr.ConnectionGater { return cfg.ConnectionGater }),
 		fx.Provide(func() pnet.PSK { return cfg.PSK }),
 		fx.Provide(func() network.ResourceManager { return cfg.ResourceManager }),
-		fx.Provide(func(gater connmgr.ConnectionGater, rcmgr network.ResourceManager) *tcpreuse.ConnMgr {
+		fx.Provide(func(upgrader transport.Upgrader) *tcpreuse.ConnMgr {
 			if !cfg.ShareTCPListener {
 				return nil
 			}
-			return tcpreuse.NewConnMgr(tcpreuse.EnvReuseportVal, gater, rcmgr)
+			return tcpreuse.NewConnMgr(tcpreuse.EnvReuseportVal, upgrader)
 		}),
 		fx.Provide(func(cm *quicreuse.ConnManager, sw *swarm.Swarm) libp2pwebrtc.ListenUDPFn {
 			hasQuicAddrPortFor := func(network string, laddr *net.UDPAddr) bool {
diff --git a/core/transport/transport.go b/core/transport/transport.go
index 908fc5b3..e9e59b67 100644
--- a/core/transport/transport.go
+++ b/core/transport/transport.go
@@ -129,11 +129,41 @@ type TransportNetwork interface {
 	AddTransport(t Transport) error
 }
 
+// GatedMaListener is listener that listens for raw(unsecured and non-multiplexed) incoming connections,
+// gates them with a `connmgr.ConnGater`and creates a resource management scope for them.
+// It can be upgraded to a full libp2p transport listener by the Upgrader.
+//
+// Compared to manet.Listener, this listener creates the resource management scope for the accepted connection.
+type GatedMaListener interface {
+	// Accept waits for and returns the next connection to the listener.
+	Accept() (manet.Conn, network.ConnManagementScope, error)
+
+	// Close closes the listener.
+	// Any blocked Accept operations will be unblocked and return errors.
+	Close() error
+
+	// Multiaddr returns the listener's (local) Multiaddr.
+	Multiaddr() ma.Multiaddr
+
+	// Addr returns the net.Listener's network address.
+	Addr() net.Addr
+}
+
 // Upgrader is a multistream upgrader that can upgrade an underlying connection
 // to a full transport connection (secure and multiplexed).
 type Upgrader interface {
 	// UpgradeListener upgrades the passed multiaddr-net listener into a full libp2p-transport listener.
+	//
+	// Deprecated: Use UpgradeGatedMaListener(upgrader.GateMaListener(manet.Listener)) instead.
 	UpgradeListener(Transport, manet.Listener) Listener
+
+	// GateMaListener creates a GatedMaListener from a manet.Listener. It gates the accepted connection
+	// and creates a resource scope for it.
+	GateMaListener(manet.Listener) GatedMaListener
+
+	// UpgradeGatedMaListener upgrades the passed GatedMaListener into a full libp2p-transport listener.
+	UpgradeGatedMaListener(Transport, GatedMaListener) Listener
+
 	// Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection.
 	Upgrade(ctx context.Context, t Transport, maconn manet.Conn, dir network.Direction, p peer.ID, scope network.ConnManagementScope) (CapableConn, error)
 }
diff --git a/examples/autotls/main.go b/examples/autotls/main.go
index 0caa39d8..f3a81247 100644
--- a/examples/autotls/main.go
+++ b/examples/autotls/main.go
@@ -58,6 +58,9 @@ func main() {
 		// User-Agent to use during DNS-01 ACME challenge
 		p2pforge.WithUserAgent(userAgent),
 
+		// Optional extra delay before the initial registration
+		p2pforge.WithRegistrationDelay(10*time.Second),
+
 		// Optional hook called once certificate is ready
 		p2pforge.WithOnCertLoaded(func() {
 			certLoaded <- true
@@ -130,9 +133,6 @@ func main() {
 
 	go dht.Bootstrap(ctx)
 
-	// Wait for peers to verify public address with AutoNAT
-	time.Sleep(5 * time.Second)
-
 	logger.Info("Addresses: ", h.Addrs())
 
 	certManager.ProvideHost(h)
diff --git a/examples/go.mod b/examples/go.mod
index 997eca92..9fa9d465 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -8,7 +8,7 @@ require (
 	github.com/google/uuid v1.6.0
 	github.com/ipfs/go-datastore v0.6.0
 	github.com/ipfs/go-log/v2 v2.5.1
-	github.com/ipshipyard/p2p-forge v0.3.1
+	github.com/ipshipyard/p2p-forge v0.4.0
 	github.com/libp2p/go-libp2p v0.38.2
 	github.com/libp2p/go-libp2p-kad-dht v0.28.1
 	github.com/multiformats/go-multiaddr v0.14.0
@@ -138,7 +138,7 @@ require (
 	golang.org/x/time v0.8.0 // indirect
 	golang.org/x/tools v0.29.0 // indirect
 	gonum.org/v1/gonum v0.15.1 // indirect
-	google.golang.org/protobuf v1.36.4 // indirect
+	google.golang.org/protobuf v1.36.5 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	lukechampine.com/blake3 v1.3.0 // indirect
 )
diff --git a/examples/go.sum b/examples/go.sum
index 8279eed5..c057212f 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -160,8 +160,8 @@ github.com/ipfs/go-test v0.0.4 h1:DKT66T6GBB6PsDFLoO56QZPrOmzJkqU1FZH5C9ySkew=
 github.com/ipfs/go-test v0.0.4/go.mod h1:qhIM1EluEfElKKM6fnWxGn822/z9knUGM1+I/OAQNKI=
 github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
 github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
-github.com/ipshipyard/p2p-forge v0.3.1 h1:Vr0l6wzX4zL7l8+UHJlsRBNHmlHpP3c//NrCZeGj4KU=
-github.com/ipshipyard/p2p-forge v0.3.1/go.mod h1:XQAvFJeXGo4oiyVPXkC3cph//5kF785L5Pjd3/kWFWo=
+github.com/ipshipyard/p2p-forge v0.4.0 h1:A40PW027nCZn0d/pw5ufMoxnAo9wZwrG+iuz18A8P5I=
+github.com/ipshipyard/p2p-forge v0.4.0/go.mod h1:hVGPP24xrRezP2+z6q8udEW36w89M+jWuWBz9meLggY=
 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=
@@ -651,8 +651,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 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.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
-google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 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=
diff --git a/go.mod b/go.mod
index bb0f456f..07da9bf2 100644
--- a/go.mod
+++ b/go.mod
@@ -57,7 +57,6 @@ require (
 	github.com/prometheus/client_model v0.6.1
 	github.com/quic-go/quic-go v0.50.0
 	github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66
-	github.com/raulk/go-watchdog v1.3.0
 	github.com/stretchr/testify v1.10.0
 	go.uber.org/fx v1.23.0
 	go.uber.org/goleak v1.3.0
@@ -75,18 +74,12 @@ require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash v1.1.0 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/containerd/cgroups v1.1.0 // indirect
-	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dgraph-io/badger v1.6.2 // indirect
 	github.com/dgraph-io/ristretto v0.0.2 // indirect
-	github.com/docker/go-units v0.5.0 // indirect
 	github.com/dustin/go-humanize v1.0.0 // indirect
-	github.com/elastic/gosigar v0.14.3 // indirect
 	github.com/francoispqt/gojay v1.2.13 // 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/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
 	github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
@@ -101,7 +94,6 @@ require (
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/nxadm/tail v1.4.11 // indirect
 	github.com/onsi/ginkgo/v2 v2.22.2 // indirect
-	github.com/opencontainers/runtime-spec v1.2.0 // indirect
 	github.com/pion/dtls/v2 v2.2.12 // indirect
 	github.com/pion/dtls/v3 v3.0.4 // indirect
 	github.com/pion/interceptor v0.1.37 // indirect
diff --git a/go.sum b/go.sum
index 0df1c626..fccd1bad 100644
--- a/go.sum
+++ b/go.sum
@@ -15,7 +15,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 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=
@@ -27,21 +26,12 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 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/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/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
 github.com/coreos/go-semver v0.2.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 v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -57,14 +47,8 @@ github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQ
 github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
 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/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 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-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/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=
@@ -80,14 +64,7 @@ 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-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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 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=
@@ -101,7 +78,6 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.5.2/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -158,8 +134,6 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl
 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
@@ -262,9 +236,6 @@ github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cT
 github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
 github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
-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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
@@ -334,13 +305,10 @@ github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyU
 github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
 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/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/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=
@@ -362,10 +330,8 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
 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 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -394,15 +360,12 @@ github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFd
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-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/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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-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.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
@@ -436,7 +399,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
 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.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
@@ -454,8 +416,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -472,8 +432,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
 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-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-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=
@@ -496,14 +454,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
 golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-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=
@@ -512,10 +467,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 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-20190626221950-04f50cda93cb/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-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -560,7 +512,6 @@ 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=
@@ -569,8 +520,6 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn
 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-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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
diff --git a/p2p/http/libp2phttp.go b/p2p/http/libp2phttp.go
index 26f4825d..ae73c2b5 100644
--- a/p2p/http/libp2phttp.go
+++ b/p2p/http/libp2phttp.go
@@ -45,6 +45,10 @@ const LegacyWellKnownProtocols = "/.well-known/libp2p"
 const peerMetadataLimit = 8 << 10 // 8KB
 const peerMetadataLRUSize = 256   // How many different peer's metadata to keep in our LRU cache
 
+// DefaultNewStreamTimeout is the default value for new stream establishing timeout.
+// It is the same value as basic_host.DefaultNegotiationTimeout
+var DefaultNewStreamTimeout = 10 * time.Second
+
 type clientPeerIDContextKey struct{}
 type serverPeerIDContextKey struct{}
 
@@ -496,7 +500,16 @@ func (rt *streamRoundTripper) RoundTrip(r *http.Request) (*http.Response, error)
 		})
 	}
 
-	s, err := rt.h.NewStream(r.Context(), rt.server, ProtocolIDForMultistreamSelect)
+	// If r.Context() timeout is greater than DefaultNewStreamTimeout
+	// use DefaultNewStreamTimeout for new stream negotiation.
+	newStreamCtx := r.Context()
+	if deadline, ok := newStreamCtx.Deadline(); !ok || deadline.After(time.Now().Add(DefaultNewStreamTimeout)) {
+		var cancel context.CancelFunc
+		newStreamCtx, cancel = context.WithTimeout(context.Background(), DefaultNewStreamTimeout)
+		defer cancel()
+	}
+
+	s, err := rt.h.NewStream(newStreamCtx, rt.server, ProtocolIDForMultistreamSelect)
 	if err != nil {
 		return nil, err
 	}
diff --git a/p2p/net/conngater/conngater.go b/p2p/net/conngater/conngater.go
index bcc927f1..8c9084c5 100644
--- a/p2p/net/conngater/conngater.go
+++ b/p2p/net/conngater/conngater.go
@@ -72,7 +72,7 @@ func (cg *BasicConnectionGater) loadRules(ctx context.Context) error {
 	for r := range res.Next() {
 		if r.Error != nil {
 			log.Errorf("query result error: %s", r.Error)
-			return err
+			return r.Error
 		}
 
 		p := peer.ID(r.Entry.Value)
@@ -89,7 +89,7 @@ func (cg *BasicConnectionGater) loadRules(ctx context.Context) error {
 	for r := range res.Next() {
 		if r.Error != nil {
 			log.Errorf("query result error: %s", r.Error)
-			return err
+			return r.Error
 		}
 
 		ip := net.IP(r.Entry.Value)
@@ -106,7 +106,7 @@ func (cg *BasicConnectionGater) loadRules(ctx context.Context) error {
 	for r := range res.Next() {
 		if r.Error != nil {
 			log.Errorf("query result error: %s", r.Error)
-			return err
+			return r.Error
 		}
 
 		ipnetStr := string(r.Entry.Value)
diff --git a/p2p/net/connmgr/connmgr.go b/p2p/net/connmgr/connmgr.go
index c2cd3072..57fc7da1 100644
--- a/p2p/net/connmgr/connmgr.go
+++ b/p2p/net/connmgr/connmgr.go
@@ -141,11 +141,6 @@ func NewConnManager(low, hi int, opts ...Option) (*BasicConnMgr, error) {
 
 	cm.ctx, cm.cancel = context.WithCancel(context.Background())
 
-	if cfg.emergencyTrim {
-		// When we're running low on memory, immediately trigger a trim.
-		cm.unregisterMemoryWatcher = registerWatchdog(cm.memoryEmergency)
-	}
-
 	decay, _ := NewDecayer(cfg.decayer, cm)
 	cm.decayer = decay
 
@@ -154,11 +149,11 @@ func NewConnManager(low, hi int, opts ...Option) (*BasicConnMgr, error) {
 	return cm, nil
 }
 
-// memoryEmergency is run when we run low on memory.
-// Close connections until we right the low watermark.
-// We don't pay attention to the silence period or the grace period.
-// We try to not kill protected connections, but if that turns out to be necessary, not connection is safe!
-func (cm *BasicConnMgr) memoryEmergency() {
+// ForceTrim trims connections down to the low watermark ignoring silence period, grace period,
+// or protected status. It prioritizes closing Unprotected connections. If after closing all
+// unprotected connections, we still have more than lowWaterMark connections, it'll close
+// protected connections.
+func (cm *BasicConnMgr) ForceTrim() {
 	connCount := int(cm.connCount.Load())
 	target := connCount - cm.cfg.lowWater
 	if target < 0 {
diff --git a/p2p/net/connmgr/options.go b/p2p/net/connmgr/options.go
index cde1fd79..3766e341 100644
--- a/p2p/net/connmgr/options.go
+++ b/p2p/net/connmgr/options.go
@@ -14,7 +14,6 @@ type config struct {
 	gracePeriod   time.Duration
 	silencePeriod time.Duration
 	decayer       *DecayerCfg
-	emergencyTrim bool
 	clock         clock.Clock
 }
 
diff --git a/p2p/net/connmgr/watchdog_cgo.go b/p2p/net/connmgr/watchdog_cgo.go
deleted file mode 100644
index cb7bacef..00000000
--- a/p2p/net/connmgr/watchdog_cgo.go
+++ /dev/null
@@ -1,17 +0,0 @@
-//go:build cgo && !nowatchdog
-
-package connmgr
-
-import "github.com/raulk/go-watchdog"
-
-func registerWatchdog(cb func()) (unregister func()) {
-	return watchdog.RegisterPostGCNotifee(cb)
-}
-
-// WithEmergencyTrim is an option to enable trimming connections on memory emergency.
-func WithEmergencyTrim(enable bool) Option {
-	return func(cfg *config) error {
-		cfg.emergencyTrim = enable
-		return nil
-	}
-}
diff --git a/p2p/net/connmgr/watchdog_no_cgo.go b/p2p/net/connmgr/watchdog_no_cgo.go
deleted file mode 100644
index 4f26aa2a..00000000
--- a/p2p/net/connmgr/watchdog_no_cgo.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build !cgo || nowatchdog
-
-package connmgr
-
-func registerWatchdog(func()) (unregister func()) {
-	return nil
-}
-
-// WithEmergencyTrim is an option to enable trimming connections on memory emergency.
-func WithEmergencyTrim(enable bool) Option {
-	return func(cfg *config) error {
-		log.Warn("platform doesn't support go-watchdog")
-		return nil
-	}
-}
diff --git a/p2p/net/upgrader/listener.go b/p2p/net/upgrader/listener.go
index 55783f01..07abece2 100644
--- a/p2p/net/upgrader/listener.go
+++ b/p2p/net/upgrader/listener.go
@@ -6,6 +6,7 @@ import (
 	"strings"
 	"sync"
 
+	"github.com/libp2p/go-libp2p/core/connmgr"
 	"github.com/libp2p/go-libp2p/core/network"
 	"github.com/libp2p/go-libp2p/core/transport"
 
@@ -17,7 +18,7 @@ import (
 var log = logging.Logger("upgrader")
 
 type listener struct {
-	manet.Listener
+	transport.GatedMaListener
 
 	transport transport.Transport
 	upgrader  *upgrader
@@ -35,10 +36,12 @@ type listener struct {
 	cancel func()
 }
 
+var _ transport.Listener = (*listener)(nil)
+
 // Close closes the listener.
 func (l *listener) Close() error {
 	// Do this first to try to get any relevant errors.
-	err := l.Listener.Close()
+	err := l.GatedMaListener.Close()
 
 	l.cancel()
 	// Drain and wait.
@@ -61,7 +64,7 @@ func (l *listener) handleIncoming() {
 	var wg sync.WaitGroup
 	defer func() {
 		// make sure we're closed
-		l.Listener.Close()
+		l.GatedMaListener.Close()
 		if l.err == nil {
 			l.err = fmt.Errorf("listener closed")
 		}
@@ -72,7 +75,7 @@ func (l *listener) handleIncoming() {
 
 	var catcher tec.TempErrCatcher
 	for l.ctx.Err() == nil {
-		maconn, err := l.Listener.Accept()
+		maconn, connScope, err := l.GatedMaListener.Accept()
 		if err != nil {
 			// Note: function may pause the accept loop.
 			if catcher.IsTemporary(err) {
@@ -84,33 +87,10 @@ func (l *listener) handleIncoming() {
 		}
 		catcher.Reset()
 
-		// Check if we already have a connection scope. See the comment in tcpreuse/listener.go for an explanation.
-		var connScope network.ConnManagementScope
-		if sc, ok := maconn.(interface {
-			Scope() network.ConnManagementScope
-		}); ok {
-			connScope = sc.Scope()
-		}
 		if connScope == nil {
-			// gate the connection if applicable
-			if l.upgrader.connGater != nil && !l.upgrader.connGater.InterceptAccept(maconn) {
-				log.Debugf("gater blocked incoming connection on local addr %s from %s",
-					maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())
-				if err := maconn.Close(); err != nil {
-					log.Warnf("failed to close incoming connection rejected by gater: %s", err)
-				}
-				continue
-			}
-
-			var err error
-			connScope, err = l.rcmgr.OpenConnection(network.DirInbound, true, maconn.RemoteMultiaddr())
-			if err != nil {
-				log.Debugw("resource manager blocked accept of new connection", "error", err)
-				if err := maconn.Close(); err != nil {
-					log.Warnf("failed to open incoming connection. Rejected by resource manager: %s", err)
-				}
-				continue
-			}
+			log.Errorf("BUG: got nil connScope for incoming connection from %s", maconn.RemoteMultiaddr())
+			maconn.Close()
+			continue
 		}
 
 		// The go routine below calls Release when the context is
@@ -154,14 +134,10 @@ func (l *listener) handleIncoming() {
 			select {
 			case l.incoming <- conn:
 			case <-ctx.Done():
+				// Listener not closed but the accept timeout expired.
 				if l.ctx.Err() == nil {
-					// Listener *not* closed but the accept timeout expired.
-					log.Warn("listener dropped connection due to slow accept")
+					log.Warnf("listener dropped connection due to slow accept. remote addr: %s peer: %s", maconn.RemoteMultiaddr(), conn.RemotePeer())
 				}
-				// Wait on the context with a timeout. This way,
-				// if we stop accepting connections for some reason,
-				// we'll eventually close all the open ones
-				// instead of hanging onto them.
 				conn.CloseWithError(network.ConnRateLimited)
 			}
 		}()
@@ -189,4 +165,38 @@ func (l *listener) String() string {
 	return fmt.Sprintf("<stream.Listener %s>", l.Multiaddr())
 }
 
-var _ transport.Listener = (*listener)(nil)
+type gatedMaListener struct {
+	manet.Listener
+	rcmgr     network.ResourceManager
+	connGater connmgr.ConnectionGater
+}
+
+var _ transport.GatedMaListener = &gatedMaListener{}
+
+func (l *gatedMaListener) Accept() (manet.Conn, network.ConnManagementScope, error) {
+	for {
+		conn, err := l.Listener.Accept()
+		if err != nil {
+			return nil, nil, err
+		}
+		// gate the connection if applicable
+		if l.connGater != nil && !l.connGater.InterceptAccept(conn) {
+			log.Debugf("gater blocked incoming connection on local addr %s from %s",
+				conn.LocalMultiaddr(), conn.RemoteMultiaddr())
+			if err := conn.Close(); err != nil {
+				log.Warnf("failed to close incoming connection rejected by gater: %s", err)
+			}
+			continue
+		}
+
+		connScope, err := l.rcmgr.OpenConnection(network.DirInbound, true, conn.RemoteMultiaddr())
+		if err != nil {
+			log.Debugw("resource manager blocked accept of new connection", "error", err)
+			if err := conn.Close(); err != nil {
+				log.Warnf("failed to open incoming connection. Rejected by resource manager: %s", err)
+			}
+			continue
+		}
+		return conn, connScope, nil
+	}
+}
diff --git a/p2p/net/upgrader/upgrader.go b/p2p/net/upgrader/upgrader.go
index 3a6f8b9f..99ffc691 100644
--- a/p2p/net/upgrader/upgrader.go
+++ b/p2p/net/upgrader/upgrader.go
@@ -105,19 +105,32 @@ func New(security []sec.SecureTransport, muxers []StreamMuxer, psk ipnet.PSK, rc
 
 // UpgradeListener upgrades the passed multiaddr-net listener into a full libp2p-transport listener.
 func (u *upgrader) UpgradeListener(t transport.Transport, list manet.Listener) transport.Listener {
-	ctx, cancel := context.WithCancel(context.Background())
-	l := &listener{
-		Listener:  list,
-		upgrader:  u,
-		transport: t,
+	return u.UpgradeGatedMaListener(t, u.GateMaListener(list))
+}
+
+func (u *upgrader) GateMaListener(l manet.Listener) transport.GatedMaListener {
+	return &gatedMaListener{
+		Listener:  l,
 		rcmgr:     u.rcmgr,
-		threshold: newThreshold(AcceptQueueLength),
-		incoming:  make(chan transport.CapableConn),
-		cancel:    cancel,
-		ctx:       ctx,
+		connGater: u.connGater,
+	}
+}
+
+// UpgradeGatedMaListener upgrades the passed multiaddr-net listener into a full libp2p-transport listener.
+func (u *upgrader) UpgradeGatedMaListener(t transport.Transport, l transport.GatedMaListener) transport.Listener {
+	ctx, cancel := context.WithCancel(context.Background())
+	list := &listener{
+		GatedMaListener: l,
+		upgrader:        u,
+		transport:       t,
+		rcmgr:           u.rcmgr,
+		threshold:       newThreshold(AcceptQueueLength),
+		incoming:        make(chan transport.CapableConn),
+		cancel:          cancel,
+		ctx:             ctx,
 	}
-	go l.handleIncoming()
-	return l
+	go list.handleIncoming()
+	return list
 }
 
 // Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection.
diff --git a/p2p/protocol/autonatv2/server.go b/p2p/protocol/autonatv2/server.go
index 05e0bdd9..3c6d0d53 100644
--- a/p2p/protocol/autonatv2/server.go
+++ b/p2p/protocol/autonatv2/server.go
@@ -30,7 +30,7 @@ var (
 	errDialDataRefused       = errors.New("dial data refused")
 )
 
-type dataRequestPolicyFunc = func(s network.Stream, dialAddr ma.Multiaddr) bool
+type dataRequestPolicyFunc = func(observedAddr, dialAddr ma.Multiaddr) bool
 
 type EventDialRequestCompleted struct {
 	Error            error
@@ -212,7 +212,7 @@ func (as *server) serveDialRequest(s network.Stream) EventDialRequestCompleted {
 
 	nonce := msg.GetDialRequest().Nonce
 
-	isDialDataRequired := as.dialDataRequestPolicy(s, dialAddr)
+	isDialDataRequired := as.dialDataRequestPolicy(s.Conn().RemoteMultiaddr(), dialAddr)
 	if isDialDataRequired && !as.limiter.AcceptDialDataRequest(p) {
 		msg = pb.Message{
 			Msg: &pb.Message_DialResponse{
@@ -517,11 +517,14 @@ func (r *rateLimiter) Close() {
 
 // amplificationAttackPrevention is a dialDataRequestPolicy which requests data when the peer's observed
 // IP address is different from the dial back IP address
-func amplificationAttackPrevention(s network.Stream, dialAddr ma.Multiaddr) bool {
-	connIP, err := manet.ToIP(s.Conn().RemoteMultiaddr())
+func amplificationAttackPrevention(observedAddr, dialAddr ma.Multiaddr) bool {
+	observedIP, err := manet.ToIP(observedAddr)
 	if err != nil {
 		return true
 	}
-	dialIP, _ := manet.ToIP(s.Conn().LocalMultiaddr()) // must be an IP multiaddr
-	return !connIP.Equal(dialIP)
+	dialIP, err := manet.ToIP(dialAddr) // can be dns addr
+	if err != nil {
+		return true
+	}
+	return !observedIP.Equal(dialIP)
 }
diff --git a/p2p/protocol/circuitv2/client/transport.go b/p2p/protocol/circuitv2/client/transport.go
index 553af77f..553f8fa5 100644
--- a/p2p/protocol/circuitv2/client/transport.go
+++ b/p2p/protocol/circuitv2/client/transport.go
@@ -101,7 +101,7 @@ func (c *Client) Listen(addr ma.Multiaddr) (transport.Listener, error) {
 		return nil, err
 	}
 
-	return c.upgrader.UpgradeListener(c, c.Listener()), nil
+	return c.upgrader.UpgradeGatedMaListener(c, c.upgrader.GateMaListener(c.Listener())), nil
 }
 
 func (c *Client) Protocols() []int {
diff --git a/p2p/transport/quicreuse/connmgr.go b/p2p/transport/quicreuse/connmgr.go
index bf9ba22b..c9e3088b 100644
--- a/p2p/transport/quicreuse/connmgr.go
+++ b/p2p/transport/quicreuse/connmgr.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"crypto/tls"
 	"errors"
+	"fmt"
 	"io"
 	"net"
 	"sync"
@@ -190,6 +191,18 @@ func (c *ConnManager) ListenQUICAndAssociate(association any, addr ma.Multiaddr,
 		}
 		key = tr.LocalAddr().String()
 		entry = quicListenerEntry{ln: ln}
+	} else if c.enableReuseport && association != nil {
+		reuse, err := c.getReuse(netw)
+		if err != nil {
+			return nil, fmt.Errorf("reuse error: %w", err)
+		}
+		err = reuse.AssertTransportExists(entry.ln.transport)
+		if err != nil {
+			return nil, fmt.Errorf("reuse assert transport failed: %w", err)
+		}
+		if tr, ok := entry.ln.transport.(*refcountedTransport); ok {
+			tr.associate(association)
+		}
 	}
 	l, err := entry.ln.Add(tlsConf, allowWindowIncrease, func() { c.onListenerClosed(key) })
 	if err != nil {
diff --git a/p2p/transport/quicreuse/reuse.go b/p2p/transport/quicreuse/reuse.go
index 20a6260b..6d0098e3 100644
--- a/p2p/transport/quicreuse/reuse.go
+++ b/p2p/transport/quicreuse/reuse.go
@@ -303,6 +303,10 @@ func (r *reuse) transportForDialLocked(association any, network string, source *
 					return tr, nil
 				}
 			}
+			// We don't have a transport with the association, use any one
+			for _, tr := range trs {
+				return tr, nil
+			}
 		}
 	}
 
@@ -313,6 +317,10 @@ func (r *reuse) transportForDialLocked(association any, network string, source *
 			return tr, nil
 		}
 	}
+	// We don't have a transport with the association, use any one
+	for _, tr := range r.globalListeners {
+		return tr, nil
+	}
 
 	// Use a transport we've previously dialed from
 	for _, tr := range r.globalDialers {
@@ -360,6 +368,33 @@ func (r *reuse) AddTransport(tr *refcountedTransport, laddr *net.UDPAddr) error
 	return nil
 }
 
+func (r *reuse) AssertTransportExists(tr refCountedQuicTransport) error {
+	t, ok := tr.(*refcountedTransport)
+	if !ok {
+		return fmt.Errorf("invalid transport type: expected: *refcountedTransport, got: %T", tr)
+	}
+	laddr := t.LocalAddr().(*net.UDPAddr)
+	if laddr.IP.IsUnspecified() {
+		if lt, ok := r.globalListeners[laddr.Port]; ok {
+			if lt == t {
+				return nil
+			}
+			return errors.New("two global listeners on the same port")
+		}
+		return errors.New("transport not found")
+	}
+	if m, ok := r.unicast[laddr.IP.String()]; ok {
+		if lt, ok := m[laddr.Port]; ok {
+			if lt == t {
+				return nil
+			}
+			return errors.New("two unicast listeners on same ip:port")
+		}
+		return errors.New("transport not found")
+	}
+	return errors.New("transport not found")
+}
+
 func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcountedTransport, error) {
 	r.mutex.Lock()
 	defer r.mutex.Unlock()
diff --git a/p2p/transport/tcp/metrics.go b/p2p/transport/tcp/metrics.go
index cbd2f92f..e3946cf3 100644
--- a/p2p/transport/tcp/metrics.go
+++ b/p2p/transport/tcp/metrics.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/libp2p/go-libp2p/core/network"
+	"github.com/libp2p/go-libp2p/core/transport"
 	"github.com/marten-seemann/tcp"
 	"github.com/mikioh/tcpinfo"
 	manet "github.com/multiformats/go-multiaddr/net"
@@ -253,16 +254,6 @@ func (c *tracingConn) Close() error {
 	return c.closeErr
 }
 
-func (c *tracingConn) Scope() network.ConnManagementScope {
-	if cs, ok := c.Conn.(interface {
-		Scope() network.ConnManagementScope
-	}); ok {
-		return cs.Scope()
-	}
-	// upgrader is expected to handle this
-	return nil
-}
-
 func (c *tracingConn) getTCPInfo() (*tcpinfo.Info, error) {
 	var o tcpinfo.Info
 	var b [256]byte
@@ -275,19 +266,31 @@ func (c *tracingConn) getTCPInfo() (*tcpinfo.Info, error) {
 }
 
 type tracingListener struct {
-	manet.Listener
+	transport.GatedMaListener
 	collector *aggregatingCollector
 }
 
 // newTracingListener wraps a manet.Listener with a tracingListener. A nil collector will use the default collector.
-func newTracingListener(l manet.Listener, collector *aggregatingCollector) *tracingListener {
-	return &tracingListener{Listener: l, collector: collector}
+func newTracingListener(l transport.GatedMaListener, collector *aggregatingCollector) *tracingListener {
+	return &tracingListener{GatedMaListener: l, collector: collector}
 }
 
-func (l *tracingListener) Accept() (manet.Conn, error) {
-	conn, err := l.Listener.Accept()
+func (l *tracingListener) Accept() (manet.Conn, network.ConnManagementScope, error) {
+	conn, scope, err := l.GatedMaListener.Accept()
 	if err != nil {
-		return nil, err
+		if scope != nil {
+			scope.Done()
+			log.Errorf("BUG: got non-nil scope but also an error: %s", err)
+		}
+		return nil, nil, err
+	}
+
+	tc, err := newTracingConn(conn, l.collector, false)
+	if err != nil {
+		log.Errorf("failed to create tracingConn from %T: %s", conn, err)
+		conn.Close()
+		scope.Done()
+		return nil, nil, err
 	}
-	return newTracingConn(conn, l.collector, false)
+	return tc, scope, nil
 }
diff --git a/p2p/transport/tcp/metrics_none.go b/p2p/transport/tcp/metrics_none.go
index cbee9820..2e561fb6 100644
--- a/p2p/transport/tcp/metrics_none.go
+++ b/p2p/transport/tcp/metrics_none.go
@@ -4,11 +4,16 @@
 
 package tcp
 
-import manet "github.com/multiformats/go-multiaddr/net"
+import (
+	"github.com/libp2p/go-libp2p/core/transport"
+	manet "github.com/multiformats/go-multiaddr/net"
+)
 
 type aggregatingCollector struct{}
 
 func newTracingConn(c manet.Conn, collector *aggregatingCollector, isClient bool) (manet.Conn, error) {
 	return c, nil
 }
-func newTracingListener(l manet.Listener, collector *aggregatingCollector) manet.Listener { return l }
+func newTracingListener(l transport.GatedMaListener, collector *aggregatingCollector) transport.GatedMaListener {
+	return l
+}
diff --git a/p2p/transport/tcp/tcp.go b/p2p/transport/tcp/tcp.go
index 758adde8..0b0980c9 100644
--- a/p2p/transport/tcp/tcp.go
+++ b/p2p/transport/tcp/tcp.go
@@ -41,7 +41,7 @@ var ReuseportIsAvailable = tcpreuse.ReuseportIsAvailable
 func tryKeepAlive(conn net.Conn, keepAlive bool) {
 	keepAliveConn, ok := conn.(canKeepAlive)
 	if !ok {
-		log.Errorf("Can't set TCP keepalives.")
+		log.Errorf("can't set TCP keepalives. net.Conn of type %T doesn't support SetKeepAlive", conn)
 		return
 	}
 	if err := keepAliveConn.SetKeepAlive(keepAlive); err != nil {
@@ -76,23 +76,23 @@ func tryLinger(conn net.Conn, sec int) {
 	}
 }
 
-type tcpListener struct {
-	manet.Listener
+type tcpGatedMaListener struct {
+	transport.GatedMaListener
 	sec int
 }
 
-func (ll *tcpListener) Accept() (manet.Conn, error) {
-	c, err := ll.Listener.Accept()
+func (ll *tcpGatedMaListener) Accept() (manet.Conn, network.ConnManagementScope, error) {
+	c, scope, err := ll.GatedMaListener.Accept()
 	if err != nil {
-		return nil, err
+		if scope != nil {
+			log.Errorf("BUG: got non-nil scope but also an error: %s", err)
+			scope.Done()
+		}
+		return nil, nil, err
 	}
 	tryLinger(c, ll.sec)
 	tryKeepAlive(c, true)
-	// We're not calling OpenConnection in the resource manager here,
-	// since the manet.Conn doesn't allow us to save the scope.
-	// It's the caller's (usually the p2p/net/upgrader) responsibility
-	// to call the resource manager.
-	return c, nil
+	return c, scope, nil
 }
 
 type Option func(*TcpTransport) error
@@ -316,22 +316,26 @@ func (t *TcpTransport) unsharedMAListen(laddr ma.Multiaddr) (manet.Listener, err
 
 // Listen listens on the given multiaddr.
 func (t *TcpTransport) Listen(laddr ma.Multiaddr) (transport.Listener, error) {
-	var list manet.Listener
+	var list transport.GatedMaListener
 	var err error
-
-	if t.sharedTcp == nil {
-		list, err = t.unsharedMAListen(laddr)
-	} else {
+	if t.sharedTcp != nil {
 		list, err = t.sharedTcp.DemultiplexedListen(laddr, tcpreuse.DemultiplexedConnType_MultistreamSelect)
-	}
-	if err != nil {
-		return nil, err
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		mal, err := t.unsharedMAListen(laddr)
+		if err != nil {
+			return nil, err
+		}
+		list = t.upgrader.GateMaListener(mal)
 	}
 
 	if t.enableMetrics {
-		list = newTracingListener(&tcpListener{list, 0}, t.metricsCollector)
+		// TODO: Fix this: The tcpListener wrapping should happen on both enableMetrics and disabledMetrics path
+		list = newTracingListener(&tcpGatedMaListener{list, 0}, t.metricsCollector)
 	}
-	return t.upgrader.UpgradeListener(t, list), nil
+	return t.upgrader.UpgradeGatedMaListener(t, list), nil
 }
 
 // Protocols returns the list of terminal protocols this transport can dial.
diff --git a/p2p/transport/tcpreuse/connwithscope.go b/p2p/transport/tcpreuse/connwithscope.go
index bddd3c0f..23354b81 100644
--- a/p2p/transport/tcpreuse/connwithscope.go
+++ b/p2p/transport/tcpreuse/connwithscope.go
@@ -10,19 +10,15 @@ import (
 
 type connWithScope struct {
 	sampledconn.ManetTCPConnInterface
-	scope network.ConnManagementScope
-}
-
-func (c connWithScope) Scope() network.ConnManagementScope {
-	return c.scope
+	ConnScope network.ConnManagementScope
 }
 
 func (c *connWithScope) Close() error {
-	c.scope.Done()
+	defer c.ConnScope.Done()
 	return c.ManetTCPConnInterface.Close()
 }
 
-func manetConnWithScope(c manet.Conn, scope network.ConnManagementScope) (manet.Conn, error) {
+func manetConnWithScope(c manet.Conn, scope network.ConnManagementScope) (*connWithScope, error) {
 	if tcpconn, ok := c.(sampledconn.ManetTCPConnInterface); ok {
 		return &connWithScope{tcpconn, scope}, nil
 	}
diff --git a/p2p/transport/tcpreuse/listener.go b/p2p/transport/tcpreuse/listener.go
index d0affb9f..4c787acc 100644
--- a/p2p/transport/tcpreuse/listener.go
+++ b/p2p/transport/tcpreuse/listener.go
@@ -9,7 +9,6 @@ import (
 	"time"
 
 	logging "github.com/ipfs/go-log/v2"
-	"github.com/libp2p/go-libp2p/core/connmgr"
 	"github.com/libp2p/go-libp2p/core/network"
 	"github.com/libp2p/go-libp2p/core/transport"
 	"github.com/libp2p/go-libp2p/p2p/net/reuseport"
@@ -28,32 +27,36 @@ var log = logging.Logger("tcp-demultiplex")
 type ConnMgr struct {
 	enableReuseport bool
 	reuse           reuseport.Transport
-	connGater       connmgr.ConnectionGater
-	rcmgr           network.ResourceManager
+	upgrader        transport.Upgrader
 
 	mx        sync.Mutex
 	listeners map[string]*multiplexedListener
 }
 
-func NewConnMgr(enableReuseport bool, gater connmgr.ConnectionGater, rcmgr network.ResourceManager) *ConnMgr {
-	if rcmgr == nil {
-		rcmgr = &network.NullResourceManager{}
-	}
+func NewConnMgr(enableReuseport bool, upgrader transport.Upgrader) *ConnMgr {
 	return &ConnMgr{
 		enableReuseport: enableReuseport,
 		reuse:           reuseport.Transport{},
-		connGater:       gater,
-		rcmgr:           rcmgr,
+		upgrader:        upgrader,
 		listeners:       make(map[string]*multiplexedListener),
 	}
 }
 
-func (t *ConnMgr) maListen(listenAddr ma.Multiaddr) (manet.Listener, error) {
+func (t *ConnMgr) gatedMaListen(listenAddr ma.Multiaddr) (transport.GatedMaListener, error) {
+	var mal manet.Listener
+	var err error
 	if t.useReuseport() {
-		return t.reuse.Listen(listenAddr)
+		mal, err = t.reuse.Listen(listenAddr)
+		if err != nil {
+			return nil, err
+		}
 	} else {
-		return manet.Listen(listenAddr)
+		mal, err = manet.Listen(listenAddr)
+		if err != nil {
+			return nil, err
+		}
 	}
+	return t.upgrader.GateMaListener(mal), nil
 }
 
 func (t *ConnMgr) useReuseport() bool {
@@ -80,7 +83,7 @@ func getTCPAddr(listenAddr ma.Multiaddr) (ma.Multiaddr, error) {
 // DemultiplexedListen returns a listener for laddr listening for `connType` connections. The connections
 // accepted from returned listeners need to be upgraded with a `transport.Upgrader`.
 // NOTE: All listeners for port 0 share the same underlying socket, so they have the same specific port.
-func (t *ConnMgr) DemultiplexedListen(laddr ma.Multiaddr, connType DemultiplexedConnType) (manet.Listener, error) {
+func (t *ConnMgr) DemultiplexedListen(laddr ma.Multiaddr, connType DemultiplexedConnType) (transport.GatedMaListener, error) {
 	if !connType.IsKnown() {
 		return nil, fmt.Errorf("unknown connection type: %s", connType)
 	}
@@ -100,7 +103,7 @@ func (t *ConnMgr) DemultiplexedListen(laddr ma.Multiaddr, connType Demultiplexed
 		return dl, nil
 	}
 
-	l, err := t.maListen(laddr)
+	gmal, err := t.gatedMaListen(laddr)
 	if err != nil {
 		return nil, err
 	}
@@ -111,19 +114,17 @@ func (t *ConnMgr) DemultiplexedListen(laddr ma.Multiaddr, connType Demultiplexed
 		t.mx.Lock()
 		defer t.mx.Unlock()
 		delete(t.listeners, laddr.String())
-		delete(t.listeners, l.Multiaddr().String())
-		return l.Close()
+		delete(t.listeners, gmal.Multiaddr().String())
+		return gmal.Close()
 	}
 	ml = &multiplexedListener{
-		Listener:  l,
-		listeners: make(map[DemultiplexedConnType]*demultiplexedListener),
-		ctx:       ctx,
-		closeFn:   cancelFunc,
-		connGater: t.connGater,
-		rcmgr:     t.rcmgr,
+		GatedMaListener: gmal,
+		listeners:       make(map[DemultiplexedConnType]*demultiplexedListener),
+		ctx:             ctx,
+		closeFn:         cancelFunc,
 	}
 	t.listeners[laddr.String()] = ml
-	t.listeners[l.Multiaddr().String()] = ml
+	t.listeners[gmal.Multiaddr().String()] = ml
 
 	dl, err := ml.DemultiplexedListen(connType)
 	if err != nil {
@@ -137,23 +138,21 @@ func (t *ConnMgr) DemultiplexedListen(laddr ma.Multiaddr, connType Demultiplexed
 	return dl, nil
 }
 
-var _ manet.Listener = &demultiplexedListener{}
+var _ transport.GatedMaListener = &demultiplexedListener{}
 
 type multiplexedListener struct {
-	manet.Listener
+	transport.GatedMaListener
 	listeners map[DemultiplexedConnType]*demultiplexedListener
 	mx        sync.RWMutex
 
-	connGater connmgr.ConnectionGater
-	rcmgr     network.ResourceManager
-	ctx       context.Context
-	closeFn   func() error
-	wg        sync.WaitGroup
+	ctx     context.Context
+	closeFn func() error
+	wg      sync.WaitGroup
 }
 
 var ErrListenerExists = errors.New("listener already exists for this conn type on this address")
 
-func (m *multiplexedListener) DemultiplexedListen(connType DemultiplexedConnType) (manet.Listener, error) {
+func (m *multiplexedListener) DemultiplexedListen(connType DemultiplexedConnType) (transport.GatedMaListener, error) {
 	if !connType.IsKnown() {
 		return nil, fmt.Errorf("unknown connection type: %s", connType)
 	}
@@ -166,8 +165,8 @@ func (m *multiplexedListener) DemultiplexedListen(connType DemultiplexedConnType
 
 	ctx, cancel := context.WithCancel(m.ctx)
 	l := &demultiplexedListener{
-		buffer:     make(chan manet.Conn),
-		inner:      m.Listener,
+		buffer:     make(chan *connWithScope),
+		inner:      m.GatedMaListener,
 		ctx:        ctx,
 		cancelFunc: cancel,
 		closeFn:    func() error { m.removeDemultiplexedListener(connType); return nil },
@@ -183,53 +182,35 @@ func (m *multiplexedListener) run() error {
 	defer m.wg.Done()
 	acceptQueue := make(chan struct{}, acceptQueueSize)
 	for {
-		c, err := m.Listener.Accept()
+		c, connScope, err := m.GatedMaListener.Accept()
 		if err != nil {
 			return err
 		}
-
-		// Gate and resource limit the connection here.
-		// If done after sampling the connection, we'll be vulnerable to DOS attacks by a single peer
-		// which clogs up our entire connection queue.
-		// This duplicates the responsibility of gating and resource limiting between here and the upgrader. The
-		// alternative without duplication requires moving the process of upgrading the connection here, which forces
-		// us to establish the websocket connection here. That is more duplication, or a significant breaking change.
-		//
-		// Bugs around multiple calls to OpenConnection or InterceptAccept are prevented by the transport
-		// integration tests.
-		if m.connGater != nil && !m.connGater.InterceptAccept(c) {
-			log.Debugf("gater blocked incoming connection on local addr %s from %s",
-				c.LocalMultiaddr(), c.RemoteMultiaddr())
-			if err := c.Close(); err != nil {
-				log.Warnf("failed to close incoming connection rejected by gater: %s", err)
-			}
-			continue
-		}
-		connScope, err := m.rcmgr.OpenConnection(network.DirInbound, true, c.RemoteMultiaddr())
-		if err != nil {
-			log.Debugw("resource manager blocked accept of new connection", "error", err)
-			if err := c.Close(); err != nil {
-				log.Warnf("failed to open incoming connection. Rejected by resource manager: %s", err)
-			}
-			continue
-		}
-
+		ctx, cancelCtx := context.WithTimeout(m.ctx, acceptTimeout)
 		select {
 		case acceptQueue <- struct{}{}:
-		// NOTE: We can drop the connection, but this is similar to the behaviour in the upgrader.
-		case <-m.ctx.Done():
+		case <-ctx.Done():
+			cancelCtx()
+			connScope.Done()
 			c.Close()
 			log.Debugf("accept queue full, dropping connection: %s", c.RemoteMultiaddr())
+			continue
+		case <-m.ctx.Done():
+			cancelCtx()
+			connScope.Done()
+			c.Close()
+			log.Debugf("listener closed; dropping connection from: %s", c.RemoteMultiaddr())
+			continue
 		}
 
 		m.wg.Add(1)
 		go func() {
 			defer func() { <-acceptQueue }()
 			defer m.wg.Done()
-			ctx, cancelCtx := context.WithTimeout(m.ctx, acceptTimeout)
 			defer cancelCtx()
 			t, c, err := identifyConnType(c)
 			if err != nil {
+				// conn closed by identifyConnType
 				connScope.Done()
 				log.Debugf("error demultiplexing connection: %s", err.Error())
 				return
@@ -279,7 +260,7 @@ func (m *multiplexedListener) Close() error {
 }
 
 func (m *multiplexedListener) closeListener() error {
-	lerr := m.Listener.Close()
+	lerr := m.GatedMaListener.Close()
 	cerr := m.closeFn()
 	return errors.Join(lerr, cerr)
 }
@@ -298,19 +279,19 @@ func (m *multiplexedListener) removeDemultiplexedListener(c DemultiplexedConnTyp
 }
 
 type demultiplexedListener struct {
-	buffer     chan manet.Conn
-	inner      manet.Listener
+	buffer     chan *connWithScope
+	inner      transport.GatedMaListener
 	ctx        context.Context
 	cancelFunc context.CancelFunc
 	closeFn    func() error
 }
 
-func (m *demultiplexedListener) Accept() (manet.Conn, error) {
+func (m *demultiplexedListener) Accept() (manet.Conn, network.ConnManagementScope, error) {
 	select {
 	case c := <-m.buffer:
-		return c, nil
+		return c.ManetTCPConnInterface, c.ConnScope, nil
 	case <-m.ctx.Done():
-		return nil, transport.ErrListenerClosed
+		return nil, nil, transport.ErrListenerClosed
 	}
 }
 
diff --git a/p2p/transport/webrtc/udpmux/mux.go b/p2p/transport/webrtc/udpmux/mux.go
index f01facae..76d68d8e 100644
--- a/p2p/transport/webrtc/udpmux/mux.go
+++ b/p2p/transport/webrtc/udpmux/mux.go
@@ -271,12 +271,13 @@ func (mux *UDPMux) RemoveConnByUfrag(ufrag string) {
 
 	for _, isIPv6 := range [...]bool{true, false} {
 		key := ufragConnKey{ufrag: ufrag, isIPv6: isIPv6}
-		if _, ok := mux.ufragMap[key]; ok {
+		if conn, ok := mux.ufragMap[key]; ok {
 			delete(mux.ufragMap, key)
 			for _, addr := range mux.ufragAddrMap[key] {
 				delete(mux.addrMap, addr.String())
 			}
 			delete(mux.ufragAddrMap, key)
+			conn.close()
 		}
 	}
 }
@@ -293,7 +294,7 @@ func (mux *UDPMux) getOrCreateConn(ufrag string, isIPv6 bool, _ *UDPMux, addr ne
 		return false, conn
 	}
 
-	conn := newMuxedConnection(mux, func() { mux.RemoveConnByUfrag(ufrag) })
+	conn := newMuxedConnection(mux, ufrag)
 	mux.ufragMap[key] = conn
 	mux.addrMap[addr.String()] = conn
 	mux.ufragAddrMap[key] = append(mux.ufragAddrMap[key], addr)
diff --git a/p2p/transport/webrtc/udpmux/muxed_connection.go b/p2p/transport/webrtc/udpmux/muxed_connection.go
index 2af5d332..84d30c84 100644
--- a/p2p/transport/webrtc/udpmux/muxed_connection.go
+++ b/p2p/transport/webrtc/udpmux/muxed_connection.go
@@ -23,31 +23,29 @@ const queueLen = 128
 // from which this connection (indexed by ufrag) received
 // data.
 type muxedConnection struct {
-	ctx     context.Context
-	cancel  context.CancelFunc
-	onClose func()
-	queue   chan packet
-	mux     *UDPMux
+	ctx    context.Context
+	cancel context.CancelFunc
+	queue  chan packet
+	mux    *UDPMux
+	ufrag  string
 }
 
 var _ net.PacketConn = &muxedConnection{}
 
-func newMuxedConnection(mux *UDPMux, onClose func()) *muxedConnection {
+func newMuxedConnection(mux *UDPMux, ufrag string) *muxedConnection {
 	ctx, cancel := context.WithCancel(mux.ctx)
 	return &muxedConnection{
-		ctx:     ctx,
-		cancel:  cancel,
-		queue:   make(chan packet, queueLen),
-		onClose: onClose,
-		mux:     mux,
+		ctx:    ctx,
+		cancel: cancel,
+		queue:  make(chan packet, queueLen),
+		mux:    mux,
+		ufrag:  ufrag,
 	}
 }
 
 func (c *muxedConnection) Push(buf []byte, addr net.Addr) error {
-	select {
-	case <-c.ctx.Done():
+	if c.ctx.Err() != nil {
 		return errors.New("closed")
-	default:
 	}
 	select {
 	case c.queue <- packet{buf: buf, addr: addr}:
@@ -76,12 +74,21 @@ func (c *muxedConnection) WriteTo(p []byte, addr net.Addr) (n int, err error) {
 }
 
 func (c *muxedConnection) Close() error {
-	select {
-	case <-c.ctx.Done():
+	if c.ctx.Err() != nil {
 		return nil
-	default:
 	}
-	c.onClose()
+	// mux calls close to actually close the connection
+	//
+	// Removing the connection from the mux or closing the connection
+	// must trigger the other.
+	// Doing this here ensures we don't need to call both RemoveConnByUfrag
+	// and close on all code paths.
+	c.mux.RemoveConnByUfrag(c.ufrag)
+	return nil
+}
+
+// closes the connection. Must only be called by the mux.
+func (c *muxedConnection) close() {
 	c.cancel()
 	// drain the packet queue
 	for {
@@ -89,7 +96,7 @@ func (c *muxedConnection) Close() error {
 		case p := <-c.queue:
 			pool.Put(p.buf)
 		default:
-			return nil
+			return
 		}
 	}
 }
diff --git a/p2p/transport/websocket/conn.go b/p2p/transport/websocket/conn.go
index 1c2ecd03..0d474608 100644
--- a/p2p/transport/websocket/conn.go
+++ b/p2p/transport/websocket/conn.go
@@ -1,7 +1,6 @@
 package websocket
 
 import (
-	"crypto/tls"
 	"errors"
 	"io"
 	"net"
@@ -9,7 +8,6 @@ import (
 	"time"
 
 	"github.com/libp2p/go-libp2p/core/network"
-	"github.com/libp2p/go-libp2p/core/transport"
 	ma "github.com/multiformats/go-multiaddr"
 	manet "github.com/multiformats/go-multiaddr/net"
 
@@ -23,6 +21,7 @@ var GracefulCloseTimeout = 100 * time.Millisecond
 // Conn implements net.Conn interface for gorilla/websocket.
 type Conn struct {
 	*ws.Conn
+	Scope              network.ConnManagementScope
 	secure             bool
 	DefaultMessageType int
 	reader             io.Reader
@@ -36,10 +35,8 @@ type Conn struct {
 var _ net.Conn = (*Conn)(nil)
 var _ manet.Conn = (*Conn)(nil)
 
-// NewConn creates a Conn given a regular gorilla/websocket Conn.
-//
-// Deprecated: There's no reason to use this method externally. It'll be unexported in a future release.
-func NewConn(raw *ws.Conn, secure bool) *Conn {
+// newConn creates a Conn given a regular gorilla/websocket Conn.
+func newConn(raw *ws.Conn, secure bool, scope network.ConnManagementScope) *Conn {
 	lna := NewAddrWithScheme(raw.LocalAddr().String(), secure)
 	laddr, err := manet.FromNetAddr(lna)
 	if err != nil {
@@ -56,6 +53,7 @@ func NewConn(raw *ws.Conn, secure bool) *Conn {
 
 	c := &Conn{
 		Conn:               raw,
+		Scope:              scope,
 		secure:             secure,
 		DefaultMessageType: ws.BinaryMessage,
 		laddr:              laddr,
@@ -136,23 +134,6 @@ func (c *Conn) Write(b []byte) (n int, err error) {
 	return len(b), nil
 }
 
-func (c *Conn) Scope() network.ConnManagementScope {
-	nc := c.NetConn()
-	if sc, ok := nc.(interface {
-		Scope() network.ConnManagementScope
-	}); ok {
-		return sc.Scope()
-	}
-	if nc, ok := nc.(*tls.Conn); ok {
-		if sc, ok := nc.NetConn().(interface {
-			Scope() network.ConnManagementScope
-		}); ok {
-			return sc.Scope()
-		}
-	}
-	return nil
-}
-
 // Close closes the connection.
 // subsequent and concurrent calls will return the same error value.
 // This method is thread-safe.
@@ -201,13 +182,3 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
 
 	return c.Conn.SetWriteDeadline(t)
 }
-
-type capableConn struct {
-	transport.CapableConn
-}
-
-func (c *capableConn) ConnState() network.ConnectionState {
-	cs := c.CapableConn.ConnState()
-	cs.Transport = "websocket"
-	return cs
-}
diff --git a/p2p/transport/websocket/listener.go b/p2p/transport/websocket/listener.go
index e72e7dab..b7402c0e 100644
--- a/p2p/transport/websocket/listener.go
+++ b/p2p/transport/websocket/listener.go
@@ -1,17 +1,22 @@
 package websocket
 
 import (
+	"context"
 	"crypto/tls"
 	"errors"
 	"fmt"
 	"net"
 	"net/http"
+	"net/url"
 	"sync"
+	"time"
 
 	"go.uber.org/zap"
 
+	ws "github.com/gorilla/websocket"
 	logging "github.com/ipfs/go-log/v2"
 
+	"github.com/libp2p/go-libp2p/core/network"
 	"github.com/libp2p/go-libp2p/core/transport"
 	"github.com/libp2p/go-libp2p/p2p/transport/tcpreuse"
 
@@ -23,8 +28,9 @@ var log = logging.Logger("websocket-transport")
 var stdLog = zap.NewStdLog(log.Desugar())
 
 type listener struct {
-	nl     net.Listener
-	server http.Server
+	netListener *httpNetListener
+	server      http.Server
+	wsUpgrader  ws.Upgrader
 	// The Go standard library sets the http.Server.TLSConfig no matter if this is a WS or WSS,
 	// so we can't rely on checking if server.TLSConfig is set.
 	isWss bool
@@ -36,8 +42,11 @@ type listener struct {
 	closeOnce sync.Once
 	closeErr  error
 	closed    chan struct{}
+	wsurl     *url.URL
 }
 
+var _ transport.GatedMaListener = &listener{}
+
 func (pwma *parsedWebsocketMultiaddr) toMultiaddr() ma.Multiaddr {
 	if !pwma.isWSS {
 		return pwma.restMultiaddr.AppendComponent(wsComponent)
@@ -52,7 +61,7 @@ func (pwma *parsedWebsocketMultiaddr) toMultiaddr() ma.Multiaddr {
 
 // newListener creates a new listener from a raw net.Listener.
 // tlsConf may be nil (for unencrypted websockets).
-func newListener(a ma.Multiaddr, tlsConf *tls.Config, sharedTcp *tcpreuse.ConnMgr) (*listener, error) {
+func newListener(a ma.Multiaddr, tlsConf *tls.Config, sharedTcp *tcpreuse.ConnMgr, upgrader transport.Upgrader, handshakeTimeout time.Duration) (*listener, error) {
 	parsed, err := parseWebsocketMultiaddr(a)
 	if err != nil {
 		return nil, err
@@ -62,17 +71,13 @@ func newListener(a ma.Multiaddr, tlsConf *tls.Config, sharedTcp *tcpreuse.ConnMg
 		return nil, fmt.Errorf("cannot listen on wss address %s without a tls.Config", a)
 	}
 
-	var nl net.Listener
-
+	var gmal transport.GatedMaListener
 	if sharedTcp == nil {
-		lnet, lnaddr, err := manet.DialArgs(parsed.restMultiaddr)
-		if err != nil {
-			return nil, err
-		}
-		nl, err = net.Listen(lnet, lnaddr)
+		mal, err := manet.Listen(parsed.restMultiaddr)
 		if err != nil {
 			return nil, err
 		}
+		gmal = upgrader.GateMaListener(mal)
 	} else {
 		var connType tcpreuse.DemultiplexedConnType
 		if parsed.isWSS {
@@ -80,89 +85,146 @@ func newListener(a ma.Multiaddr, tlsConf *tls.Config, sharedTcp *tcpreuse.ConnMg
 		} else {
 			connType = tcpreuse.DemultiplexedConnType_HTTP
 		}
-		mal, err := sharedTcp.DemultiplexedListen(parsed.restMultiaddr, connType)
+		gmal, err = sharedTcp.DemultiplexedListen(parsed.restMultiaddr, connType)
 		if err != nil {
 			return nil, err
 		}
-		nl = manet.NetListener(mal)
 	}
 
-	laddr, err := manet.FromNetAddr(nl.Addr())
-	if err != nil {
-		return nil, err
-	}
+	// laddr has the correct port in case we listened on port 0
+	laddr := gmal.Multiaddr()
 
-	first, _ := ma.SplitFirst(a)
 	// Don't resolve dns addresses.
 	// We want to be able to announce domain names, so the peer can validate the TLS certificate.
+	first, _ := ma.SplitFirst(a)
 	if c := first.Protocol().Code; c == ma.P_DNS || c == ma.P_DNS4 || c == ma.P_DNS6 || c == ma.P_DNSADDR {
 		_, last := ma.SplitFirst(laddr)
 		laddr = first.Encapsulate(last)
 	}
 	parsed.restMultiaddr = laddr
 
+	listenAddr := parsed.toMultiaddr()
+	wsurl, err := parseMultiaddr(listenAddr)
+	if err != nil {
+		gmal.Close()
+		return nil, fmt.Errorf("failed to parse multiaddr to URL: %v: %w", listenAddr, err)
+	}
 	ln := &listener{
-		nl:       nl,
+		netListener: &httpNetListener{
+			GatedMaListener:  gmal,
+			handshakeTimeout: handshakeTimeout,
+		},
 		laddr:    parsed.toMultiaddr(),
 		incoming: make(chan *Conn),
 		closed:   make(chan struct{}),
+		isWss:    parsed.isWSS,
+		wsurl:    wsurl,
+		wsUpgrader: ws.Upgrader{
+			// Allow requests from *all* origins.
+			CheckOrigin: func(r *http.Request) bool {
+				return true
+			},
+			HandshakeTimeout: handshakeTimeout,
+		},
 	}
-	ln.server = http.Server{Handler: ln, ErrorLog: stdLog}
-	if parsed.isWSS {
-		ln.isWss = true
-		ln.server.TLSConfig = tlsConf
-	}
+	ln.server = http.Server{Handler: ln, ErrorLog: stdLog, ConnContext: ln.ConnContext, TLSConfig: tlsConf}
 	return ln, nil
 }
 
 func (l *listener) serve() {
 	defer close(l.closed)
 	if !l.isWss {
-		l.server.Serve(l.nl)
+		l.server.Serve(l.netListener)
 	} else {
-		l.server.ServeTLS(l.nl, "", "")
+		l.server.ServeTLS(l.netListener, "", "")
 	}
 }
 
+type connKey struct{}
+
+func (l *listener) ConnContext(ctx context.Context, c net.Conn) context.Context {
+	// prefer `*tls.Conn` over `(interface{NetConn() net.Conn})` in case `manet.Conn` is extended
+	// to support a `NetConn() net.Conn` method.
+	if tc, ok := c.(*tls.Conn); ok {
+		c = tc.NetConn()
+	}
+	if nc, ok := c.(*negotiatingConn); ok {
+		return context.WithValue(ctx, connKey{}, nc)
+	}
+	log.Errorf("BUG: expected net.Conn of type *websocket.negotiatingConn: got %T", c)
+	// might as well close the connection as there's no way to proceed now.
+	c.Close()
+	return ctx
+}
+
+func (l *listener) extractConnFromContext(ctx context.Context) (*negotiatingConn, error) {
+	c := ctx.Value(connKey{})
+	if c == nil {
+		return nil, fmt.Errorf("expected *websocket.negotiatingConn in context: got nil")
+	}
+	nc, ok := c.(*negotiatingConn)
+	if !ok {
+		return nil, fmt.Errorf("expected *websocket.negotiatingConn in context: got %T", c)
+	}
+	return nc, nil
+}
+
 func (l *listener) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	c, err := upgrader.Upgrade(w, r, nil)
+	c, err := l.wsUpgrader.Upgrade(w, r, nil)
 	if err != nil {
 		// The upgrader writes a response for us.
 		return
 	}
-	nc := NewConn(c, l.isWss)
-	if nc == nil {
+	nc, err := l.extractConnFromContext(r.Context())
+	if err != nil {
 		c.Close()
 		w.WriteHeader(500)
+		log.Errorf("BUG: failed to extract conn from context: RemoteAddr: %s: err: %s", r.RemoteAddr, err)
 		return
 	}
+
+	cs, err := nc.Unwrap()
+	if err != nil {
+		c.Close()
+		w.WriteHeader(500)
+		log.Debugf("connection timed out from: %s", r.RemoteAddr)
+		return
+	}
+
+	conn := newConn(c, l.isWss, cs.Scope)
+	if conn == nil {
+		c.Close()
+		w.WriteHeader(500)
+		return
+	}
+
 	select {
-	case l.incoming <- nc:
+	case l.incoming <- conn:
 	case <-l.closed:
-		nc.Close()
+		conn.Close()
 	}
 	// The connection has been hijacked, it's safe to return.
 }
 
-func (l *listener) Accept() (manet.Conn, error) {
+func (l *listener) Accept() (manet.Conn, network.ConnManagementScope, error) {
 	select {
 	case c, ok := <-l.incoming:
 		if !ok {
-			return nil, transport.ErrListenerClosed
+			return nil, nil, transport.ErrListenerClosed
 		}
-		return c, nil
+		return c, c.Scope, nil
 	case <-l.closed:
-		return nil, transport.ErrListenerClosed
+		return nil, nil, transport.ErrListenerClosed
 	}
 }
 
 func (l *listener) Addr() net.Addr {
-	return l.nl.Addr()
+	return &Addr{URL: l.wsurl}
 }
 
 func (l *listener) Close() error {
 	l.closeOnce.Do(func() {
-		err1 := l.nl.Close()
+		err1 := l.netListener.Close()
 		err2 := l.server.Close()
 		<-l.closed
 		l.closeErr = errors.Join(err1, err2)
@@ -174,14 +236,74 @@ func (l *listener) Multiaddr() ma.Multiaddr {
 	return l.laddr
 }
 
-type transportListener struct {
-	transport.Listener
+// httpNetListener is a net.Listener that adapts a transport.GatedMaListener to a net.Listener.
+// It wraps the manet.Conn, and the Scope from the underlying gated listener in a connWithScope.
+type httpNetListener struct {
+	transport.GatedMaListener
+	handshakeTimeout time.Duration
 }
 
-func (l *transportListener) Accept() (transport.CapableConn, error) {
-	conn, err := l.Listener.Accept()
+var _ net.Listener = &httpNetListener{}
+
+func (l *httpNetListener) Accept() (net.Conn, error) {
+	conn, scope, err := l.GatedMaListener.Accept()
 	if err != nil {
+		if scope != nil {
+			log.Errorf("BUG: scope non-nil when err is non nil: %v", err)
+			scope.Done()
+		}
 		return nil, err
 	}
-	return &capableConn{CapableConn: conn}, nil
+	connWithScope := connWithScope{
+		Conn:  conn,
+		Scope: scope,
+	}
+	ctx, cancel := context.WithTimeout(context.Background(), l.handshakeTimeout)
+	return &negotiatingConn{
+		connWithScope: connWithScope,
+		ctx:           ctx,
+		cancelCtx:     cancel,
+		stopClose: context.AfterFunc(ctx, func() {
+			connWithScope.Close()
+			log.Debugf("handshake timeout for conn from: %s", conn.RemoteAddr())
+		}),
+	}, nil
+}
+
+type connWithScope struct {
+	net.Conn
+	Scope network.ConnManagementScope
+}
+
+func (c connWithScope) Close() error {
+	c.Scope.Done()
+	return c.Conn.Close()
+}
+
+type negotiatingConn struct {
+	connWithScope
+	ctx       context.Context
+	cancelCtx context.CancelFunc
+	stopClose func() bool
+}
+
+// Close closes the negotiating conn and the underlying connWithScope
+// This will be called in case the tls handshake or websocket upgrade fails.
+func (c *negotiatingConn) Close() error {
+	defer c.cancelCtx()
+	if c.stopClose != nil {
+		c.stopClose()
+	}
+	return c.connWithScope.Close()
+}
+
+func (c *negotiatingConn) Unwrap() (connWithScope, error) {
+	defer c.cancelCtx()
+	if c.stopClose != nil {
+		if !c.stopClose() {
+			return connWithScope{}, errors.New("timed out")
+		}
+		c.stopClose = nil
+	}
+	return c.connWithScope, nil
 }
diff --git a/p2p/transport/websocket/websocket.go b/p2p/transport/websocket/websocket.go
index 0ddf1905..3a6badac 100644
--- a/p2p/transport/websocket/websocket.go
+++ b/p2p/transport/websocket/websocket.go
@@ -5,7 +5,6 @@ import (
 	"context"
 	"crypto/tls"
 	"net"
-	"net/http"
 	"time"
 
 	"github.com/libp2p/go-libp2p/core/network"
@@ -51,14 +50,6 @@ func init() {
 	manet.RegisterToNetAddr(ConvertWebsocketMultiaddrToNetAddr, "wss")
 }
 
-// Default gorilla upgrader
-var upgrader = ws.Upgrader{
-	// Allow requests from *all* origins.
-	CheckOrigin: func(r *http.Request) bool {
-		return true
-	},
-}
-
 type Option func(*WebsocketTransport) error
 
 // WithTLSClientConfig sets a TLS client configuration on the WebSocket Dialer. Only
@@ -81,15 +72,24 @@ func WithTLSConfig(conf *tls.Config) Option {
 	}
 }
 
-// WebsocketTransport is the actual go-libp2p transport
-type WebsocketTransport struct {
-	upgrader transport.Upgrader
-	rcmgr    network.ResourceManager
+var defaultHandshakeTimeout = 15 * time.Second
 
-	tlsClientConf *tls.Config
-	tlsConf       *tls.Config
+// WithHandshakeTimeout sets a timeout for the websocket upgrade.
+func WithHandshakeTimeout(timeout time.Duration) Option {
+	return func(t *WebsocketTransport) error {
+		t.handshakeTimeout = timeout
+		return nil
+	}
+}
 
-	sharedTcp *tcpreuse.ConnMgr
+// WebsocketTransport is the actual go-libp2p transport
+type WebsocketTransport struct {
+	upgrader         transport.Upgrader
+	rcmgr            network.ResourceManager
+	tlsClientConf    *tls.Config
+	tlsConf          *tls.Config
+	sharedTcp        *tcpreuse.ConnMgr
+	handshakeTimeout time.Duration
 }
 
 var _ transport.Transport = (*WebsocketTransport)(nil)
@@ -99,10 +99,11 @@ func New(u transport.Upgrader, rcmgr network.ResourceManager, sharedTCP *tcpreus
 		rcmgr = &network.NullResourceManager{}
 	}
 	t := &WebsocketTransport{
-		upgrader:      u,
-		rcmgr:         rcmgr,
-		tlsClientConf: &tls.Config{},
-		sharedTcp:     sharedTCP,
+		upgrader:         u,
+		rcmgr:            rcmgr,
+		tlsClientConf:    &tls.Config{},
+		sharedTcp:        sharedTCP,
+		handshakeTimeout: defaultHandshakeTimeout,
 	}
 	for _, opt := range opts {
 		if err := opt(t); err != nil {
@@ -176,7 +177,7 @@ func (t *WebsocketTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p pee
 }
 
 func (t *WebsocketTransport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p peer.ID, connScope network.ConnManagementScope) (transport.CapableConn, error) {
-	macon, err := t.maDial(ctx, raddr)
+	macon, err := t.maDial(ctx, raddr, connScope)
 	if err != nil {
 		return nil, err
 	}
@@ -187,14 +188,14 @@ func (t *WebsocketTransport) dialWithScope(ctx context.Context, raddr ma.Multiad
 	return &capableConn{CapableConn: conn}, nil
 }
 
-func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (manet.Conn, error) {
+func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr, scope network.ConnManagementScope) (manet.Conn, error) {
 	wsurl, err := parseMultiaddr(raddr)
 	if err != nil {
 		return nil, err
 	}
 	isWss := wsurl.Scheme == "wss"
 	dialer := ws.Dialer{
-		HandshakeTimeout: 30 * time.Second,
+		HandshakeTimeout: t.handshakeTimeout,
 		// Inherit the default proxy behavior
 		Proxy: ws.DefaultDialer.Proxy,
 	}
@@ -236,7 +237,7 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma
 		return nil, err
 	}
 
-	mnc, err := manet.WrapNetConn(NewConn(wscon, isWss))
+	mnc, err := manet.WrapNetConn(newConn(wscon, isWss, scope))
 	if err != nil {
 		wscon.Close()
 		return nil, err
@@ -244,12 +245,12 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma
 	return mnc, nil
 }
 
-func (t *WebsocketTransport) maListen(a ma.Multiaddr) (manet.Listener, error) {
+func (t *WebsocketTransport) gatedMaListen(a ma.Multiaddr) (transport.GatedMaListener, error) {
 	var tlsConf *tls.Config
 	if t.tlsConf != nil {
 		tlsConf = t.tlsConf.Clone()
 	}
-	l, err := newListener(a, tlsConf, t.sharedTcp)
+	l, err := newListener(a, tlsConf, t.sharedTcp, t.upgrader, t.handshakeTimeout)
 	if err != nil {
 		return nil, err
 	}
@@ -258,9 +259,32 @@ func (t *WebsocketTransport) maListen(a ma.Multiaddr) (manet.Listener, error) {
 }
 
 func (t *WebsocketTransport) Listen(a ma.Multiaddr) (transport.Listener, error) {
-	malist, err := t.maListen(a)
+	gmal, err := t.gatedMaListen(a)
+	if err != nil {
+		return nil, err
+	}
+	return &transportListener{Listener: t.upgrader.UpgradeGatedMaListener(t, gmal)}, nil
+}
+
+// transportListener wraps a transport.Listener to provide connections with a `ConnState() network.ConnectionState` method.
+type transportListener struct {
+	transport.Listener
+}
+
+type capableConn struct {
+	transport.CapableConn
+}
+
+func (c *capableConn) ConnState() network.ConnectionState {
+	cs := c.CapableConn.ConnState()
+	cs.Transport = "websocket"
+	return cs
+}
+
+func (l *transportListener) Accept() (transport.CapableConn, error) {
+	conn, err := l.Listener.Accept()
 	if err != nil {
 		return nil, err
 	}
-	return &transportListener{Listener: t.upgrader.UpgradeListener(t, malist)}, nil
+	return &capableConn{CapableConn: conn}, nil
 }
diff --git a/p2p/transport/webtransport/stream.go b/p2p/transport/webtransport/stream.go
index 83ee52a5..115d3a83 100644
--- a/p2p/transport/webtransport/stream.go
+++ b/p2p/transport/webtransport/stream.go
@@ -36,16 +36,30 @@ var _ network.MuxedStream = &stream{}
 
 func (s *stream) Read(b []byte) (n int, err error) {
 	n, err = s.Stream.Read(b)
-	if err != nil && errors.Is(err, &webtransport.StreamError{}) {
-		err = network.ErrReset
+	if err != nil {
+		var streamErr *webtransport.StreamError
+		if errors.As(err, &streamErr) {
+			err = &network.StreamError{
+				ErrorCode:      0,
+				Remote:         streamErr.Remote,
+				TransportError: err,
+			}
+		}
 	}
 	return n, err
 }
 
 func (s *stream) Write(b []byte) (n int, err error) {
 	n, err = s.Stream.Write(b)
-	if err != nil && errors.Is(err, &webtransport.StreamError{}) {
-		err = network.ErrReset
+	if err != nil {
+		var streamErr *webtransport.StreamError
+		if errors.As(err, &streamErr) {
+			err = &network.StreamError{
+				ErrorCode:      0,
+				Remote:         streamErr.Remote,
+				TransportError: err,
+			}
+		}
 	}
 	return n, err
 }


Test patch:
diff --git a/p2p/net/upgrader/listener_test.go b/p2p/net/upgrader/listener_test.go
index 14800e59..e2def7cc 100644
--- a/p2p/net/upgrader/listener_test.go
+++ b/p2p/net/upgrader/listener_test.go
@@ -30,7 +30,7 @@ func createListener(t *testing.T, u transport.Upgrader) transport.Listener {
 	require.NoError(t, err)
 	ln, err := manet.Listen(addr)
 	require.NoError(t, err)
-	return u.UpgradeListener(nil, ln)
+	return u.UpgradeGatedMaListener(nil, u.GateMaListener(ln))
 }
 
 func TestAcceptSingleConn(t *testing.T) {
diff --git a/p2p/protocol/autonatv2/server_test.go b/p2p/protocol/autonatv2/server_test.go
index 6664f1c3..65b1b131 100644
--- a/p2p/protocol/autonatv2/server_test.go
+++ b/p2p/protocol/autonatv2/server_test.go
@@ -143,7 +143,7 @@ func TestServerDataRequest(t *testing.T) {
 	dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP))
 	// ask for dial data for quic address
 	an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy(
-		func(s network.Stream, dialAddr ma.Multiaddr) bool {
+		func(_, dialAddr ma.Multiaddr) bool {
 			if _, err := dialAddr.ValueForProtocol(ma.P_QUIC_V1); err == nil {
 				return true
 			}
@@ -197,7 +197,7 @@ func TestServerMaxConcurrentRequestsPerPeer(t *testing.T) {
 	doneChan := make(chan struct{})
 	an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy(
 		// stall all allowed requests
-		func(s network.Stream, dialAddr ma.Multiaddr) bool {
+		func(_, dialAddr ma.Multiaddr) bool {
 			<-doneChan
 			return true
 		}),
@@ -255,7 +255,7 @@ func TestServerDataRequestJitter(t *testing.T) {
 	dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP))
 	// ask for dial data for quic address
 	an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy(
-		func(s network.Stream, dialAddr ma.Multiaddr) bool {
+		func(_, dialAddr ma.Multiaddr) bool {
 			if _, err := dialAddr.ValueForProtocol(ma.P_QUIC_V1); err == nil {
 				return true
 			}
@@ -520,6 +520,83 @@ func TestReadDialData(t *testing.T) {
 	}
 }
 
+func TestServerDataRequestWithAmplificationAttackPrevention(t *testing.T) {
+	// server will skip all tcp addresses
+	dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP))
+	// ask for dial data for quic address
+	an := newAutoNAT(t, dialer, allowPrivateAddrs,
+		WithServerRateLimit(10, 10, 10, 2),
+		withAmplificationAttackPreventionDialWait(0),
+	)
+	defer an.Close()
+	defer an.host.Close()
+
+	c := newAutoNAT(t, nil, allowPrivateAddrs)
+	defer c.Close()
+	defer c.host.Close()
+
+	idAndWait(t, c, an)
+
+	err := c.host.Network().Listen(ma.StringCast("/ip6/::1/udp/0/quic-v1"))
+	if err != nil {
+		// machine doesn't have ipv6
+		t.Skip("skipping test because machine doesn't have ipv6")
+	}
+
+	var quicv4Addr ma.Multiaddr
+	var quicv6Addr ma.Multiaddr
+	for _, a := range c.host.Addrs() {
+		if _, err := a.ValueForProtocol(ma.P_QUIC_V1); err == nil {
+			if _, err := a.ValueForProtocol(ma.P_IP4); err == nil {
+				quicv4Addr = a
+			} else {
+				quicv6Addr = a
+			}
+		}
+	}
+	res, err := c.GetReachability(context.Background(), []Request{{Addr: quicv4Addr, SendDialData: false}})
+	require.NoError(t, err)
+	require.Equal(t, Result{
+		Addr:         quicv4Addr,
+		Reachability: network.ReachabilityPublic,
+		Status:       pb.DialStatus_OK,
+	}, res)
+
+	// ipv6 address should require dial data
+	_, err = c.GetReachability(context.Background(), []Request{{Addr: quicv6Addr, SendDialData: false}})
+	require.Error(t, err)
+	require.ErrorContains(t, err, "invalid dial data request: low priority addr")
+
+	// ipv6 address should work fine with dial data
+	res, err = c.GetReachability(context.Background(), []Request{{Addr: quicv6Addr, SendDialData: true}})
+	require.NoError(t, err)
+	require.Equal(t, Result{
+		Addr:         quicv6Addr,
+		Reachability: network.ReachabilityPublic,
+		Status:       pb.DialStatus_OK,
+	}, res)
+}
+
+func TestDefaultAmplificationAttackPrevention(t *testing.T) {
+	q1 := ma.StringCast("/ip4/1.2.3.4/udp/1234/quic-v1")
+	q2 := ma.StringCast("/ip4/1.2.3.4/udp/1235/quic-v1")
+	t1 := ma.StringCast("/ip4/1.2.3.4/tcp/1234")
+
+	require.False(t, amplificationAttackPrevention(q1, q1))
+	require.False(t, amplificationAttackPrevention(q1, q2))
+	require.False(t, amplificationAttackPrevention(q1, t1))
+
+	t2 := ma.StringCast("/ip4/1.1.1.1/tcp/1235") // different IP
+	require.True(t, amplificationAttackPrevention(q2, t2))
+
+	// always ask dial data for dns addrs
+	d1 := ma.StringCast("/dns/localhost/udp/1/quic-v1")
+	d2 := ma.StringCast("/dnsaddr/libp2p.io/tcp/1")
+	require.True(t, amplificationAttackPrevention(d1, t1))
+	require.True(t, amplificationAttackPrevention(d2, t1))
+
+}
+
 func FuzzServerDialRequest(f *testing.F) {
 	a := newAutoNAT(f, nil, allowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2))
 	c := newAutoNAT(f, nil)
diff --git a/p2p/protocol/holepunch/holepunch_test.go b/p2p/protocol/holepunch/holepunch_test.go
index 28e61229..a7638807 100644
--- a/p2p/protocol/holepunch/holepunch_test.go
+++ b/p2p/protocol/holepunch/holepunch_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"net"
+	"slices"
 	"sync"
 	"sync/atomic"
 	"testing"
@@ -682,3 +683,98 @@ func SetLegacyBehavior(legacyBehavior bool) holepunch.Option {
 		return nil
 	}
 }
+
+// TestEndToEndSimConnectQUICReuse tests that hole punching works if we are
+// reusing the same port for QUIC and WebTransport, and when we have multiple
+// QUIC listeners on different ports.
+//
+// If this tests fails or is flaky it may be because:
+// - The quicreuse logic (and association logic) is not returning the appropriate transport for holepunching.
+// - The ordering of listeners is unexpected (remember the swarm will sort the listeners with `.ListenOrder()`).
+func TestEndToEndSimConnectQUICReuse(t *testing.T) {
+	h1tr := &mockEventTracer{}
+	h2tr := &mockEventTracer{}
+
+	router := &simconn.SimpleFirewallRouter{}
+	relay := MustNewHost(t,
+		quicSimConn(true, router),
+		libp2p.ListenAddrs(ma.StringCast("/ip4/1.2.0.1/udp/8000/quic-v1")),
+		libp2p.DisableRelay(),
+		libp2p.ResourceManager(&network.NullResourceManager{}),
+		libp2p.WithFxOption(fx.Invoke(func(h host.Host) {
+			// Setup relay service
+			_, err := relayv2.New(h)
+			require.NoError(t, err)
+		})),
+	)
+
+	// We return addrs of quic on port 8001 and circuit.
+	// This lets us listen on other ports for QUIC in order to confuse the quicreuse logic during hole punching.
+	onlyQuicOnPort8001AndCircuit := func(addrs []ma.Multiaddr) []ma.Multiaddr {
+		return slices.DeleteFunc(addrs, func(a ma.Multiaddr) bool {
+			_, err := a.ValueForProtocol(ma.P_CIRCUIT)
+			isCircuit := err == nil
+			if isCircuit {
+				return false
+			}
+			_, err = a.ValueForProtocol(ma.P_QUIC_V1)
+			isQuic := err == nil
+			if !isQuic {
+				return true
+			}
+			port, err := a.ValueForProtocol(ma.P_UDP)
+			if err != nil {
+				return true
+			}
+			isPort8001 := port == "8001"
+			return !isPort8001
+		})
+	}
+
+	h1 := MustNewHost(t,
+		quicSimConn(false, router),
+		libp2p.EnableHolePunching(holepunch.WithTracer(h1tr), holepunch.DirectDialTimeout(100*time.Millisecond)),
+		libp2p.ListenAddrs(ma.StringCast("/ip4/2.2.0.1/udp/8001/quic-v1/webtransport")),
+		libp2p.ResourceManager(&network.NullResourceManager{}),
+		libp2p.AddrsFactory(onlyQuicOnPort8001AndCircuit),
+		libp2p.ForceReachabilityPrivate(),
+	)
+	// Listen on quic *after* listening on webtransport.
+	// This is to test that the quicreuse logic is not returning the wrong transport.
+	// See: https://github.com/libp2p/go-libp2p/issues/3165#issuecomment-2700126706 for details.
+	h1.Network().Listen(
+		ma.StringCast("/ip4/2.2.0.1/udp/8001/quic-v1"),
+		ma.StringCast("/ip4/2.2.0.1/udp/9001/quic-v1"),
+	)
+
+	h2 := MustNewHost(t,
+		quicSimConn(false, router),
+		libp2p.ListenAddrs(
+			ma.StringCast("/ip4/2.2.0.2/udp/8001/quic-v1/webtransport"),
+		),
+		libp2p.ResourceManager(&network.NullResourceManager{}),
+		connectToRelay(&relay),
+		libp2p.EnableHolePunching(holepunch.WithTracer(h2tr), holepunch.DirectDialTimeout(100*time.Millisecond)),
+		libp2p.AddrsFactory(onlyQuicOnPort8001AndCircuit),
+		libp2p.ForceReachabilityPrivate(),
+	)
+	// Listen on quic after listening on webtransport.
+	h2.Network().Listen(
+		ma.StringCast("/ip4/2.2.0.2/udp/8001/quic-v1"),
+		ma.StringCast("/ip4/2.2.0.2/udp/9001/quic-v1"),
+	)
+
+	defer h1.Close()
+	defer h2.Close()
+	defer relay.Close()
+
+	// Wait for holepunch service to start
+	waitForHolePunchingSvcActive(t, h1)
+	waitForHolePunchingSvcActive(t, h2)
+
+	learnAddrs(h1, h2)
+	pingAtoB(t, h1, h2)
+
+	// wait till a direct connection is complete
+	ensureDirectConn(t, h1, h2)
+}
diff --git a/p2p/test/transport/gating_test.go b/p2p/test/transport/gating_test.go
index 52f6477c..c9ae4fd8 100644
--- a/p2p/test/transport/gating_test.go
+++ b/p2p/test/transport/gating_test.go
@@ -203,7 +203,7 @@ func TestInterceptAccept(t *testing.T) {
 				connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) {
 					require.Equal(t, normalize(h2.Addrs()[0]), normalize(addrs.LocalMultiaddr()))
 				}).AnyTimes()
-			} else if strings.Contains(tc.Name, "WebSocket-Shared") || strings.Contains(tc.Name, "WebSocket-Secured-Shared") {
+			} else if strings.Contains(tc.Name, "WebSocket") {
 				connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) {
 					require.Equal(t, addrPort(h2.Addrs()[0]), addrPort(addrs.LocalMultiaddr()))
 				})
diff --git a/p2p/transport/quicreuse/connmgr_test.go b/p2p/transport/quicreuse/connmgr_test.go
index 51646bac..d128119d 100644
--- a/p2p/transport/quicreuse/connmgr_test.go
+++ b/p2p/transport/quicreuse/connmgr_test.go
@@ -315,3 +315,59 @@ func TestExternalTransport(t *testing.T) {
 		t.Fatal("doneWithTr not closed")
 	}
 }
+
+func TestAssociate(t *testing.T) {
+	testAssociate := func(lnAddr1, lnAddr2 ma.Multiaddr, dialAddr *net.UDPAddr) {
+		cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{})
+		require.NoError(t, err)
+		defer cm.Close()
+
+		lp2pTLS := &tls.Config{NextProtos: []string{"libp2p"}}
+		assoc1 := "test-1"
+		ln1, err := cm.ListenQUICAndAssociate(assoc1, lnAddr1, lp2pTLS, nil)
+		require.NoError(t, err)
+		defer ln1.Close()
+		addrs := ln1.Multiaddrs()
+		require.Len(t, addrs, 1)
+
+		addr := addrs[0]
+		assoc2 := "test-2"
+		h3TLS := &tls.Config{NextProtos: []string{"h3"}}
+		ln2, err := cm.ListenQUICAndAssociate(assoc2, addr, h3TLS, nil)
+		require.NoError(t, err)
+		defer ln2.Close()
+
+		tr1, err := cm.TransportWithAssociationForDial(assoc1, "udp4", dialAddr)
+		require.NoError(t, err)
+		defer tr1.Close()
+		require.Equal(t, tr1.LocalAddr().String(), ln1.Addr().String())
+
+		tr2, err := cm.TransportWithAssociationForDial(assoc2, "udp4", dialAddr)
+		require.NoError(t, err)
+		defer tr2.Close()
+		require.Equal(t, tr2.LocalAddr().String(), ln2.Addr().String())
+
+		ln3, err := cm.ListenQUICAndAssociate(assoc1, lnAddr2, lp2pTLS, nil)
+		require.NoError(t, err)
+		defer ln3.Close()
+
+		// an unused association should also return the same transport
+		// association is only a preference for a specific transport, not an exclusion criteria
+		tr3, err := cm.TransportWithAssociationForDial("unused", "udp4", dialAddr)
+		require.NoError(t, err)
+		defer tr3.Close()
+		require.Contains(t, []string{ln2.Addr().String(), ln3.Addr().String()}, tr3.LocalAddr().String())
+	}
+
+	t.Run("MultipleUnspecifiedListeners", func(t *testing.T) {
+		testAssociate(ma.StringCast("/ip4/0.0.0.0/udp/0/quic-v1"),
+			ma.StringCast("/ip4/0.0.0.0/udp/0/quic-v1"),
+			&net.UDPAddr{IP: net.IPv4(1, 1, 1, 1), Port: 1})
+	})
+	t.Run("MultipleSpecificListeners", func(t *testing.T) {
+		testAssociate(ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"),
+			ma.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"),
+			&net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1},
+		)
+	})
+}
diff --git a/p2p/transport/quicreuse/tracer_test.go b/p2p/transport/quicreuse/tracer_test.go
index 3347c5f7..bea6b91d 100644
--- a/p2p/transport/quicreuse/tracer_test.go
+++ b/p2p/transport/quicreuse/tracer_test.go
@@ -13,13 +13,6 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func createLogDir(t *testing.T) string {
-	dir, err := os.MkdirTemp("", "libp2p-quic-transport-test")
-	require.NoError(t, err)
-	t.Cleanup(func() { os.RemoveAll(dir) })
-	return dir
-}
-
 func getFile(t *testing.T, dir string) os.FileInfo {
 	files, err := os.ReadDir(dir)
 	require.NoError(t, err)
@@ -30,7 +23,7 @@ func getFile(t *testing.T, dir string) os.FileInfo {
 }
 
 func TestSaveQlog(t *testing.T) {
-	qlogDir := createLogDir(t)
+	qlogDir := t.TempDir()
 	logger := newQlogger(qlogDir, logging.PerspectiveServer, quic.ConnectionIDFromBytes([]byte{0xde, 0xad, 0xbe, 0xef}))
 	file := getFile(t, qlogDir)
 	require.Equal(t, ".", string(file.Name()[0]))
@@ -45,7 +38,7 @@ func TestSaveQlog(t *testing.T) {
 }
 
 func TestQlogBuffering(t *testing.T) {
-	qlogDir := createLogDir(t)
+	qlogDir := t.TempDir()
 	logger := newQlogger(qlogDir, logging.PerspectiveServer, quic.ConnectionIDFromBytes([]byte("connid")))
 	initialSize := getFile(t, qlogDir).Size()
 	// Do a small write.
@@ -60,7 +53,7 @@ func TestQlogBuffering(t *testing.T) {
 }
 
 func TestQlogCompression(t *testing.T) {
-	qlogDir := createLogDir(t)
+	qlogDir := t.TempDir()
 	logger := newQlogger(qlogDir, logging.PerspectiveServer, quic.ConnectionIDFromBytes([]byte("connid")))
 	logger.Write([]byte("foobar"))
 	require.NoError(t, logger.Close())
diff --git a/p2p/transport/tcp/metrics_test.go b/p2p/transport/tcp/metrics_test.go
index 9a994696..7645abc8 100644
--- a/p2p/transport/tcp/metrics_test.go
+++ b/p2p/transport/tcp/metrics_test.go
@@ -15,8 +15,10 @@ func TestTcpTransportCollectsMetricsWithSharedTcpSocket(t *testing.T) {
 	peerA, ia := makeInsecureMuxer(t)
 	_, ib := makeInsecureMuxer(t)
 
-	sharedTCPSocketA := tcpreuse.NewConnMgr(false, nil, nil)
-	sharedTCPSocketB := tcpreuse.NewConnMgr(false, nil, nil)
+	upg, err := tptu.New(ia, muxers, nil, nil, nil)
+	require.NoError(t, err)
+	sharedTCPSocketA := tcpreuse.NewConnMgr(false, upg)
+	sharedTCPSocketB := tcpreuse.NewConnMgr(false, upg)
 
 	ua, err := tptu.New(ia, muxers, nil, nil, nil)
 	require.NoError(t, err)
diff --git a/p2p/transport/tcpreuse/listener_test.go b/p2p/transport/tcpreuse/listener_test.go
index b5dc49f2..0f91d499 100644
--- a/p2p/transport/tcpreuse/listener_test.go
+++ b/p2p/transport/tcpreuse/listener_test.go
@@ -17,6 +17,9 @@ import (
 	"time"
 
 	"github.com/gorilla/websocket"
+	"github.com/libp2p/go-libp2p/core/network"
+	"github.com/libp2p/go-libp2p/core/transport"
+	tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
 	ma "github.com/multiformats/go-multiaddr"
 	manet "github.com/multiformats/go-multiaddr/net"
 	"github.com/multiformats/go-multistream"
@@ -53,6 +56,17 @@ func selfSignedTLSConfig(t *testing.T) *tls.Config {
 	return tlsConfig
 }
 
+type maListener struct {
+	transport.GatedMaListener
+}
+
+var _ manet.Listener = &maListener{}
+
+func (ml *maListener) Accept() (manet.Conn, error) {
+	c, _, err := ml.GatedMaListener.Accept()
+	return c, err
+}
+
 type wsHandler struct{ conns chan *websocket.Conn }
 
 func (wh wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -61,12 +75,19 @@ func (wh wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	wh.conns <- c
 }
 
+func upgrader(t *testing.T) transport.Upgrader {
+	t.Helper()
+	upd, err := tptu.New(nil, nil, nil, &network.NullResourceManager{}, nil)
+	require.NoError(t, err)
+	return upd
+}
+
 func TestListenerSingle(t *testing.T) {
 	listenAddr := ma.StringCast("/ip4/0.0.0.0/tcp/0")
 	const N = 64
 	for _, enableReuseport := range []bool{true, false} {
 		t.Run(fmt.Sprintf("multistream-reuseport:%v", enableReuseport), func(t *testing.T) {
-			cm := NewConnMgr(enableReuseport, nil, nil)
+			cm := NewConnMgr(enableReuseport, upgrader(t))
 			l, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_MultistreamSelect)
 			require.NoError(t, err)
 			go func() {
@@ -96,7 +117,7 @@ func TestListenerSingle(t *testing.T) {
 
 			var wg sync.WaitGroup
 			for i := 0; i < N; i++ {
-				c, err := l.Accept()
+				c, _, err := l.Accept()
 				require.NoError(t, err)
 				wg.Add(1)
 				go func() {
@@ -117,12 +138,12 @@ func TestListenerSingle(t *testing.T) {
 		})
 
 		t.Run(fmt.Sprintf("WebSocket-reuseport:%v", enableReuseport), func(t *testing.T) {
-			cm := NewConnMgr(enableReuseport, nil, nil)
+			cm := NewConnMgr(enableReuseport, upgrader(t))
 			l, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_HTTP)
 			require.NoError(t, err)
 			wh := wsHandler{conns: make(chan *websocket.Conn, acceptQueueSize)}
 			go func() {
-				http.Serve(manet.NetListener(l), wh)
+				http.Serve(manet.NetListener(&maListener{GatedMaListener: l}), wh)
 			}()
 			go func() {
 				d := websocket.Dialer{}
@@ -169,14 +190,14 @@ func TestListenerSingle(t *testing.T) {
 		})
 
 		t.Run(fmt.Sprintf("WebSocketTLS-reuseport:%v", enableReuseport), func(t *testing.T) {
-			cm := NewConnMgr(enableReuseport, nil, nil)
+			cm := NewConnMgr(enableReuseport, upgrader(t))
 			l, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_TLS)
 			require.NoError(t, err)
 			defer l.Close()
 			wh := wsHandler{conns: make(chan *websocket.Conn, acceptQueueSize)}
 			go func() {
 				s := http.Server{Handler: wh, TLSConfig: selfSignedTLSConfig(t)}
-				s.ServeTLS(manet.NetListener(l), "", "")
+				s.ServeTLS(manet.NetListener(&maListener{GatedMaListener: l}), "", "")
 			}()
 			go func() {
 				d := websocket.Dialer{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
@@ -228,7 +249,7 @@ func TestListenerMultiplexed(t *testing.T) {
 	listenAddr := ma.StringCast("/ip4/0.0.0.0/tcp/0")
 	const N = 20
 	for _, enableReuseport := range []bool{true, false} {
-		cm := NewConnMgr(enableReuseport, nil, nil)
+		cm := NewConnMgr(enableReuseport, upgrader(t))
 		msl, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_MultistreamSelect)
 		require.NoError(t, err)
 		defer msl.Close()
@@ -239,7 +260,7 @@ func TestListenerMultiplexed(t *testing.T) {
 		require.Equal(t, wsl.Multiaddr(), msl.Multiaddr())
 		wh := wsHandler{conns: make(chan *websocket.Conn, acceptQueueSize)}
 		go func() {
-			http.Serve(manet.NetListener(wsl), wh)
+			http.Serve(manet.NetListener(&maListener{GatedMaListener: wsl}), wh)
 		}()
 
 		wssl, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_TLS)
@@ -249,7 +270,7 @@ func TestListenerMultiplexed(t *testing.T) {
 		whs := wsHandler{conns: make(chan *websocket.Conn, acceptQueueSize)}
 		go func() {
 			s := http.Server{Handler: whs, TLSConfig: selfSignedTLSConfig(t)}
-			s.ServeTLS(manet.NetListener(wssl), "", "")
+			s.ServeTLS(manet.NetListener(&maListener{GatedMaListener: wssl}), "", "")
 		}()
 
 		// multistream connections
@@ -331,7 +352,7 @@ func TestListenerMultiplexed(t *testing.T) {
 		go func() {
 			defer wg.Done()
 			for i := 0; i < N; i++ {
-				c, err := msl.Accept()
+				c, _, err := msl.Accept()
 				if !assert.NoError(t, err) {
 					return
 				}
@@ -404,7 +425,7 @@ func TestListenerMultiplexed(t *testing.T) {
 func TestListenerClose(t *testing.T) {
 	testClose := func(listenAddr ma.Multiaddr) {
 		// listen on port 0
-		cm := NewConnMgr(false, nil, nil)
+		cm := NewConnMgr(false, upgrader(t))
 		ml, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_MultistreamSelect)
 		require.NoError(t, err)
 		wl, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_HTTP)
@@ -459,7 +480,7 @@ func setDeferReset[T any](t testing.TB, ptr *T, val T) {
 func TestHitTimeout(t *testing.T) {
 	setDeferReset(t, &identifyConnTimeout, 100*time.Millisecond)
 	// listen on port 0
-	cm := NewConnMgr(false, nil, nil)
+	cm := NewConnMgr(false, upgrader(t))
 
 	listenAddr := ma.StringCast("/ip4/127.0.0.1/tcp/0")
 	ml, err := cm.DemultiplexedListen(listenAddr, DemultiplexedConnType_MultistreamSelect)
diff --git a/p2p/transport/webrtc/udpmux/mux_test.go b/p2p/transport/webrtc/udpmux/mux_test.go
index 298e5c92..b75f3e83 100644
--- a/p2p/transport/webrtc/udpmux/mux_test.go
+++ b/p2p/transport/webrtc/udpmux/mux_test.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/pion/stun"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
@@ -246,3 +247,28 @@ func TestMuxedConnection(t *testing.T) {
 	}
 	require.Empty(t, addrUfragMap)
 }
+
+func TestRemovingUfragClosesConn(t *testing.T) {
+	c := newPacketConn(t)
+	m := NewUDPMux(c)
+	m.Start()
+	defer m.Close()
+	remoteAddr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 1234}
+	conn, err := m.GetConn("a", remoteAddr)
+	require.NoError(t, err)
+	defer conn.Close()
+
+	connClosed := make(chan bool)
+	go func() {
+		_, _, err := conn.ReadFrom(make([]byte, 100))
+		assert.ErrorIs(t, err, context.Canceled)
+		close(connClosed)
+	}()
+	require.NoError(t, err)
+	m.RemoveConnByUfrag("a")
+	select {
+	case <-connClosed:
+	case <-time.After(1 * time.Second):
+		t.Fatalf("expected the connection to be closed")
+	}
+}
diff --git a/p2p/transport/websocket/addrs_test.go b/p2p/transport/websocket/addrs_test.go
index 50a8b9e8..1a73c287 100644
--- a/p2p/transport/websocket/addrs_test.go
+++ b/p2p/transport/websocket/addrs_test.go
@@ -4,8 +4,6 @@ import (
 	"net/url"
 	"testing"
 
-	"github.com/stretchr/testify/require"
-
 	ma "github.com/multiformats/go-multiaddr"
 )
 
@@ -67,15 +65,3 @@ func TestConvertWebsocketMultiaddrToNetAddr(t *testing.T) {
 		t.Fatalf("expected network: \"websocket\", got \"%s\"", wsaddr.Network())
 	}
 }
-
-func TestListeningOnDNSAddr(t *testing.T) {
-	ln, err := newListener(ma.StringCast("/dns/localhost/tcp/0/ws"), nil, nil)
-	require.NoError(t, err)
-	addr := ln.Multiaddr()
-	first, rest := ma.SplitFirst(addr)
-	require.Equal(t, ma.P_DNS, first.Protocol().Code)
-	require.Equal(t, "localhost", first.Value())
-	next, _ := ma.SplitFirst(rest)
-	require.Equal(t, ma.P_TCP, next.Protocol().Code)
-	require.NotEqual(t, 0, next.Value())
-}
diff --git a/p2p/transport/websocket/websocket_test.go b/p2p/transport/websocket/websocket_test.go
index f83576ba..2c47adf3 100644
--- a/p2p/transport/websocket/websocket_test.go
+++ b/p2p/transport/websocket/websocket_test.go
@@ -35,6 +35,7 @@ import (
 	ttransport "github.com/libp2p/go-libp2p/p2p/transport/testsuite"
 
 	ma "github.com/multiformats/go-multiaddr"
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
@@ -296,18 +297,39 @@ func TestDialWssNoClientCert(t *testing.T) {
 }
 
 func TestWebsocketTransport(t *testing.T) {
-	peerA, ua := newUpgrader(t)
-	ta, err := New(ua, nil, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, ub := newUpgrader(t)
-	tb, err := New(ub, nil, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
+	t.Run("/ws", func(t *testing.T) {
+		peerA, ua := newUpgrader(t)
+		ta, err := New(ua, nil, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		peerB, ub := newUpgrader(t)
+		tb, err := New(ub, nil, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
 
-	ttransport.SubtestTransport(t, ta, tb, "/ip4/127.0.0.1/tcp/0/ws", peerA)
+		ttransport.SubtestTransport(t, ta, tb, "/ip4/127.0.0.1/tcp/0/ws", peerA)
+		ttransport.SubtestTransport(t, tb, ta, "/ip4/127.0.0.1/tcp/0/ws", peerB)
+
+	})
+	t.Run("/wss", func(t *testing.T) {
+		peerA, ua := newUpgrader(t)
+		tca := generateTLSConfig(t)
+		ta, err := New(ua, nil, nil, WithTLSConfig(tca), WithTLSClientConfig(&tls.Config{InsecureSkipVerify: true}))
+		if err != nil {
+			t.Fatal(err)
+		}
+		peerB, ub := newUpgrader(t)
+		tcb := generateTLSConfig(t)
+		tb, err := New(ub, nil, nil, WithTLSConfig(tcb), WithTLSClientConfig(&tls.Config{InsecureSkipVerify: true}))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		ttransport.SubtestTransport(t, ta, tb, "/ip4/127.0.0.1/tcp/0/wss", peerA)
+		ttransport.SubtestTransport(t, tb, ta, "/ip4/127.0.0.1/tcp/0/ws", peerB)
+	})
 }
 
 func isWSS(addr ma.Multiaddr) bool {
@@ -441,7 +463,7 @@ func TestConcurrentClose(t *testing.T) {
 	_, u := newUpgrader(t)
 	tpt, err := New(u, &network.NullResourceManager{}, nil)
 	require.NoError(t, err)
-	l, err := tpt.maListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
+	l, err := tpt.gatedMaListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -451,7 +473,7 @@ func TestConcurrentClose(t *testing.T) {
 
 	go func() {
 		for i := 0; i < 100; i++ {
-			c, err := tpt.maDial(context.Background(), l.Multiaddr())
+			c, err := tpt.maDial(context.Background(), l.Multiaddr(), &network.NullScope{})
 			if err != nil {
 				t.Error(err)
 				return
@@ -467,7 +489,7 @@ func TestConcurrentClose(t *testing.T) {
 	}()
 
 	for i := 0; i < 100; i++ {
-		c, err := l.Accept()
+		c, _, err := l.Accept()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -481,7 +503,7 @@ func TestWriteZero(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	l, err := tpt.maListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
+	l, err := tpt.gatedMaListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -490,7 +512,7 @@ func TestWriteZero(t *testing.T) {
 	msg := []byte(nil)
 
 	go func() {
-		c, err := tpt.maDial(context.Background(), l.Multiaddr())
+		c, err := tpt.maDial(context.Background(), l.Multiaddr(), &network.NullScope{})
 		if err != nil {
 			t.Error(err)
 			return
@@ -509,7 +531,7 @@ func TestWriteZero(t *testing.T) {
 		}
 	}()
 
-	c, err := l.Accept()
+	c, _, err := l.Accept()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -623,3 +645,98 @@ func TestSocksProxy(t *testing.T) {
 		})
 	}
 }
+
+func TestListenerAddr(t *testing.T) {
+	_, upgrader := newUpgrader(t)
+	transport, err := New(upgrader, &network.NullResourceManager{}, nil, WithTLSConfig(generateTLSConfig(t)))
+	require.NoError(t, err)
+	l1, err := transport.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
+	require.NoError(t, err)
+	defer l1.Close()
+	require.Regexp(t, `^ws://127\.0\.0\.1:[\d]+$`, l1.Addr().String())
+	l2, err := transport.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0/wss"))
+	require.NoError(t, err)
+	defer l2.Close()
+	require.Regexp(t, `^wss://127\.0\.0\.1:[\d]+$`, l2.Addr().String())
+}
+func TestHandshakeTimeout(t *testing.T) {
+	handshakeTimeout := 200 * time.Millisecond
+	_, upgrader := newUpgrader(t)
+	tlsconf := generateTLSConfig(t)
+	transport, err := New(upgrader, &network.NullResourceManager{}, nil, WithHandshakeTimeout(handshakeTimeout), WithTLSConfig(tlsconf))
+	require.NoError(t, err)
+
+	fastWSDialer := gws.Dialer{
+		HandshakeTimeout: 10 * handshakeTimeout,
+		TLSClientConfig:  &tls.Config{InsecureSkipVerify: true},
+		NetDial: func(network, addr string) (net.Conn, error) {
+			tcpConn, err := net.Dial("tcp", addr)
+			if !assert.NoError(t, err) {
+				return nil, err
+			}
+			return tcpConn, nil
+		},
+	}
+
+	slowWSDialer := gws.Dialer{
+		HandshakeTimeout: 10 * handshakeTimeout,
+		NetDial: func(network, addr string) (net.Conn, error) {
+			tcpConn, err := net.Dial("tcp", addr)
+			if !assert.NoError(t, err) {
+				return nil, err
+			}
+			// wait to simulate a slow handshake
+			time.Sleep(2 * handshakeTimeout)
+			return tcpConn, nil
+		},
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+	}
+	t.Run("ws", func(t *testing.T) {
+		// test the gatedMaListener as we're interested in the websocket handshake timeout and not the upgrader steps.
+		wsListener, err := transport.gatedMaListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/ws"))
+		require.NoError(t, err)
+		defer wsListener.Close()
+
+		ctx, cancel := context.WithTimeout(context.Background(), 10*handshakeTimeout)
+		defer cancel()
+		conn, resp, err := fastWSDialer.DialContext(ctx, wsListener.Addr().String(), nil)
+		if !assert.NoError(t, err) {
+			return
+		}
+		conn.Close()
+		resp.Body.Close()
+
+		ctx, cancel = context.WithTimeout(context.Background(), 10*handshakeTimeout)
+		defer cancel()
+		conn, resp, err = slowWSDialer.DialContext(ctx, wsListener.Addr().String(), nil)
+		if err == nil {
+			conn.Close()
+			resp.Body.Close()
+			t.Fatal("should error as the handshake will time out")
+		}
+	})
+
+	t.Run("wss", func(t *testing.T) {
+		// test the gatedMaListener as we're interested in the websocket handshake timeout and not the upgrader steps.
+		wsListener, err := transport.gatedMaListen(ma.StringCast("/ip4/127.0.0.1/tcp/0/wss"))
+		require.NoError(t, err)
+		defer wsListener.Close()
+
+		// Test that the normal dial works fine
+		ctx, cancel := context.WithTimeout(context.Background(), 10*handshakeTimeout)
+		defer cancel()
+		wsConn, resp, err := fastWSDialer.DialContext(ctx, wsListener.Addr().String(), nil)
+		require.NoError(t, err)
+		wsConn.Close()
+		resp.Body.Close()
+
+		ctx, cancel = context.WithTimeout(context.Background(), 10*handshakeTimeout)
+		defer cancel()
+		wsConn, resp, err = slowWSDialer.DialContext(ctx, wsListener.Addr().String(), nil)
+		if err == nil {
+			wsConn.Close()
+			resp.Body.Close()
+			t.Fatal("websocket handshake should have timed out")
+		}
+	})
+}
diff --git a/test-plans/go.mod b/test-plans/go.mod
index 75153bfe..d363d183 100644
--- a/test-plans/go.mod
+++ b/test-plans/go.mod
@@ -12,18 +12,12 @@ require (
 	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-systemd/v22 v22.5.0 // indirect
 	github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
 	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/docker/go-units v0.5.0 // indirect
-	github.com/elastic/gosigar v0.14.3 // indirect
 	github.com/flynn/noise v1.1.0 // indirect
 	github.com/francoispqt/gojay v1.2.13 // 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/google/gopacket v1.1.19 // indirect
 	github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
 	github.com/google/uuid v1.6.0 // indirect
@@ -61,7 +55,6 @@ require (
 	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.22.2 // indirect
-	github.com/opencontainers/runtime-spec v1.2.0 // indirect
 	github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
 	github.com/pion/datachannel v1.5.10 // indirect
 	github.com/pion/dtls/v2 v2.2.12 // indirect
@@ -82,7 +75,6 @@ require (
 	github.com/pion/transport/v3 v3.0.7 // indirect
 	github.com/pion/turn/v4 v4.0.0 // indirect
 	github.com/pion/webrtc/v4 v4.0.10 // indirect
-	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.21.0 // indirect
 	github.com/prometheus/client_model v0.6.1 // indirect
 	github.com/prometheus/common v0.62.0 // indirect
@@ -90,7 +82,6 @@ require (
 	github.com/quic-go/qpack v0.5.1 // indirect
 	github.com/quic-go/quic-go v0.50.0 // 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/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/wlynxg/anet v0.0.5 // indirect
 	go.uber.org/dig v1.18.0 // indirect
diff --git a/test-plans/go.sum b/test-plans/go.sum
index 43ce4641..c5599a79 100644
--- a/test-plans/go.sum
+++ b/test-plans/go.sum
@@ -10,7 +10,6 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 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=
@@ -20,17 +19,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT
 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
 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/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/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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -42,13 +32,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-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/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/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=
@@ -66,14 +50,7 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
 github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
 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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 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=
@@ -82,7 +59,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 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=
@@ -115,8 +91,6 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw
 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
@@ -209,9 +183,6 @@ github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU
 github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
 github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
 github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
-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/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
@@ -258,8 +229,6 @@ github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGux
 github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q=
 github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck=
 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -280,12 +249,9 @@ github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyU
 github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
 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/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/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=
@@ -307,10 +273,8 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b
 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=
@@ -320,7 +284,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 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.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=
@@ -329,14 +292,11 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-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/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=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
@@ -364,7 +324,6 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
 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.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
@@ -381,8 +340,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
 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.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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -399,8 +356,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
 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-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-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=
@@ -422,24 +377,18 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 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.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
 golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-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-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -479,14 +428,11 @@ 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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
@@ -494,7 +440,6 @@ golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
 golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 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=