diff --git a/.github/workflows/go-check.yml b/.github/workflows/go-check.yml index 617f59e480..c82b34a980 100644 --- a/.github/workflows/go-check.yml +++ b/.github/workflows/go-check.yml @@ -17,5 +17,5 @@ jobs: go-check: uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 with: - go-version: "1.22.x" + go-version: "1.24.x" go-generate-ignore-protoc-version-comments: true diff --git a/.github/workflows/go-test-template.yml b/.github/workflows/go-test-template.yml index fa7c974ea2..f79719ec4b 100644 --- a/.github/workflows/go-test-template.yml +++ b/.github/workflows/go-test-template.yml @@ -109,7 +109,7 @@ jobs: run: test_analysis ${{ env.GOTESTFLAGS }} - name: Upload test results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.os }}_${{ matrix.go }}_test_results.db path: ./test_results.db @@ -131,7 +131,7 @@ jobs: run: test_analysis -race ${{ env.GORACEFLAGS }} ./... - name: Upload test results (Race) if: (steps.race.conclusion == 'success' || steps.race.conclusion == 'failure') - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.os }}_${{ matrix.go }}_test_results_race.db path: ./test_results.db diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 66cacd9928..c77bc74493 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -17,6 +17,6 @@ jobs: go-test: uses: ./.github/workflows/go-test-template.yml with: - go-versions: '["1.22.x", "1.23.x"]' + go-versions: '["1.23.x", "1.24.x"]' secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/interop-test.yml b/.github/workflows/interop-test.yml index e51c51cddd..1c5be0a5c4 100644 --- a/.github/workflows/interop-test.yml +++ b/.github/workflows/interop-test.yml @@ -1,4 +1,5 @@ name: Interoperability Testing + on: workflow_dispatch: pull_request: @@ -8,6 +9,7 @@ on: - 'internal/**' - 'p2p/**' - 'test-plans/**' + - '.github/workflows/interop-test.yml' push: branches: - "master" @@ -23,6 +25,11 @@ jobs: name: Run transport interoperability tests runs-on: ${{ fromJSON(vars['INTEROP_TEST_RUNNER_UBUNTU'] || '"ubuntu-22.04"') }} steps: + - name: Free Disk Space (Ubuntu) + if: vars['INTEROP_TEST_RUNNER_UBUNTU'] == '' + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: true - uses: actions/checkout@v4 - name: Build image run: docker build -t go-libp2p-head -f test-plans/PingDockerfile . diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml index 4d37f9b4a3..0b5ff6070f 100644 --- a/.github/workflows/release-check.yml +++ b/.github/workflows/release-check.yml @@ -16,4 +16,4 @@ concurrency: jobs: release-check: - uses: marcopolo/unified-github-workflows/.github/workflows/release-check.yml@e66cb9667a2e1148efda4591e29c56258eaf385b + uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 diff --git a/README.md b/README.md index f785935fc2..8b9cde5634 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,25 @@ Guidelines: - ask questions or talk about things in our [discussion forums](https://discuss.libp2p.io), or open an [issue](https://github.com/libp2p/go-libp2p/issues) for bug reports, or #libp2p-implementers on [Filecoin slack](https://filecoin.io/slack). - ensure you are able to contribute (no legal issues please -- we use the DCO) - get in touch with @libp2p/go-libp2p-maintainers about how best to contribute +- No drive-by contributions seeking to collect airdrops. + - Many projects aim to reward contributors to common goods. Great. However, + this creates an unfortunate incentive for low-effort PRs, submitted solely to + claim rewards. These PRs consume maintainers’ time and energy to triage, with + little to no impact on end users. If we suspect this is the intent of a PR, + we may close it without comment. If you believe this was done in error, + contact us via email. Reference this README section and explain why your PR + is not a “drive-by contribution.” - have fun! There's a few things you can do right now to help out: - - Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically. - **Perform code reviews**. - **Add tests**. There can never be enough tests. + - Go through the modules below and **check out existing issues**. This would + be especially useful for modules in active development. Some knowledge of + IPFS/libp2p may be required, as well as the infrastructure behind it - for + instance, you may need to read up on p2p and more complex operations like + muxing to be able to help technically. + ## Supported Go Versions diff --git a/config/config.go b/config/config.go index baf5c3f273..4347eb72af 100644 --- a/config/config.go +++ b/config/config.go @@ -448,12 +448,9 @@ func (cfg *Config) newBasicHost(swrm *swarm.Swarm, eventBus event.Bus) (*bhost.B return h, nil } -// NewNode constructs a new libp2p Host from the Config. -// -// This function consumes the config. Do not reuse it (really!). -func (cfg *Config) NewNode() (host.Host, error) { +func (cfg *Config) validate() error { if cfg.EnableAutoRelay && !cfg.Relay { - return nil, fmt.Errorf("cannot enable autorelay; relay is not enabled") + return fmt.Errorf("cannot enable autorelay; relay is not enabled") } // If possible check that the resource manager conn limit is higher than the // limit set in the conn manager. @@ -464,6 +461,33 @@ func (cfg *Config) NewNode() (host.Host, error) { } } + if len(cfg.PSK) > 0 && cfg.ShareTCPListener { + return errors.New("cannot use shared TCP listener with PSK") + } + + return nil +} + +// NewNode constructs a new libp2p Host from the Config. +// +// This function consumes the config. Do not reuse it (really!). +func (cfg *Config) NewNode() (host.Host, error) { + + validateErr := cfg.validate() + if validateErr != nil { + if cfg.ResourceManager != nil { + cfg.ResourceManager.Close() + } + if cfg.ConnManager != nil { + cfg.ConnManager.Close() + } + if cfg.Peerstore != nil { + cfg.Peerstore.Close() + } + + return nil, validateErr + } + if !cfg.DisableMetrics { rcmgr.MustRegisterWith(cfg.PrometheusRegisterer) } @@ -510,7 +534,7 @@ func (cfg *Config) NewNode() (host.Host, error) { } fxopts = append(fxopts, transportOpts...) - // Configure routing and autorelay + // Configure routing if cfg.Routing != nil { fxopts = append(fxopts, fx.Provide(cfg.Routing), diff --git a/core/connmgr/manager.go b/core/connmgr/manager.go index d756e4399f..c4d796b39a 100644 --- a/core/connmgr/manager.go +++ b/core/connmgr/manager.go @@ -34,7 +34,7 @@ type ConnManager interface { // TagPeer tags a peer with a string, associating a weight with the tag. TagPeer(peer.ID, string, int) - // Untag removes the tagged value from the peer. + // UntagPeer removes the tagged value from the peer. UntagPeer(p peer.ID, tag string) // UpsertTag updates an existing tag or inserts a new one. diff --git a/core/crypto/pb/crypto.pb.go b/core/crypto/pb/crypto.pb.go index d960889763..ef4d18dc76 100644 --- a/core/crypto/pb/crypto.pb.go +++ b/core/crypto/pb/crypto.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: core/crypto/pb/crypto.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -83,12 +84,11 @@ func (KeyType) EnumDescriptor() ([]byte, []int) { } type PublicKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"` + Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"` unknownFields protoimpl.UnknownFields - - Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"` - Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PublicKey) Reset() { @@ -136,12 +136,11 @@ func (x *PublicKey) GetData() []byte { } type PrivateKey struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"` + Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"` unknownFields protoimpl.UnknownFields - - Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"` - Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PrivateKey) Reset() { @@ -190,7 +189,7 @@ func (x *PrivateKey) GetData() []byte { var File_core_crypto_pb_crypto_proto protoreflect.FileDescriptor -var file_core_crypto_pb_crypto_proto_rawDesc = []byte{ +var file_core_crypto_pb_crypto_proto_rawDesc = string([]byte{ 0x0a, 0x1b, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x62, 0x22, 0x47, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, @@ -210,16 +209,16 @@ var file_core_crypto_pb_crypto_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x70, 0x62, -} +}) var ( file_core_crypto_pb_crypto_proto_rawDescOnce sync.Once - file_core_crypto_pb_crypto_proto_rawDescData = file_core_crypto_pb_crypto_proto_rawDesc + file_core_crypto_pb_crypto_proto_rawDescData []byte ) func file_core_crypto_pb_crypto_proto_rawDescGZIP() []byte { file_core_crypto_pb_crypto_proto_rawDescOnce.Do(func() { - file_core_crypto_pb_crypto_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_crypto_pb_crypto_proto_rawDescData) + file_core_crypto_pb_crypto_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_core_crypto_pb_crypto_proto_rawDesc), len(file_core_crypto_pb_crypto_proto_rawDesc))) }) return file_core_crypto_pb_crypto_proto_rawDescData } @@ -250,7 +249,7 @@ func file_core_crypto_pb_crypto_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_core_crypto_pb_crypto_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_crypto_pb_crypto_proto_rawDesc), len(file_core_crypto_pb_crypto_proto_rawDesc)), NumEnums: 1, NumMessages: 2, NumExtensions: 0, @@ -262,7 +261,6 @@ func file_core_crypto_pb_crypto_proto_init() { MessageInfos: file_core_crypto_pb_crypto_proto_msgTypes, }.Build() File_core_crypto_pb_crypto_proto = out.File - file_core_crypto_pb_crypto_proto_rawDesc = nil file_core_crypto_pb_crypto_proto_goTypes = nil file_core_crypto_pb_crypto_proto_depIdxs = nil } diff --git a/core/event/addrs.go b/core/event/addrs.go index d0b578352e..67849aedb3 100644 --- a/core/event/addrs.go +++ b/core/event/addrs.go @@ -83,6 +83,6 @@ type EvtLocalAddressesUpdated struct { } // EvtAutoRelayAddrsUpdated is sent by the autorelay when the node's relay addresses are updated -type EvtAutoRelayAddrs struct { +type EvtAutoRelayAddrsUpdated struct { RelayAddrs []ma.Multiaddr } diff --git a/core/host/host.go b/core/host/host.go index 0a8dbe4b0c..ca0a7e00d9 100644 --- a/core/host/host.go +++ b/core/host/host.go @@ -28,10 +28,10 @@ type Host interface { // Peerstore returns the Host's repository of Peer Addresses and Keys. Peerstore() peerstore.Peerstore - // Returns the listen addresses of the Host + // Addrs returns the listen addresses of the Host Addrs() []ma.Multiaddr - // Networks returns the Network interface of the Host + // Network returns the Network interface of the Host Network() network.Network // Mux returns the Mux multiplexing incoming streams to protocol handlers diff --git a/core/network/conn.go b/core/network/conn.go index 3be8cb0d69..aa6b96f718 100644 --- a/core/network/conn.go +++ b/core/network/conn.go @@ -2,15 +2,60 @@ package network import ( "context" + "fmt" "io" ic "github.com/libp2p/go-libp2p/core/crypto" + "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" ma "github.com/multiformats/go-multiaddr" ) +type ConnErrorCode uint32 + +type ConnError struct { + Remote bool + ErrorCode ConnErrorCode + TransportError error +} + +func (c *ConnError) Error() string { + side := "local" + if c.Remote { + side = "remote" + } + if c.TransportError != nil { + return fmt.Sprintf("connection closed (%s): code: 0x%x: transport error: %s", side, c.ErrorCode, c.TransportError) + } + return fmt.Sprintf("connection closed (%s): code: 0x%x", side, c.ErrorCode) +} + +func (c *ConnError) Is(target error) bool { + if tce, ok := target.(*ConnError); ok { + return tce.ErrorCode == c.ErrorCode && tce.Remote == c.Remote + } + return false +} + +func (c *ConnError) Unwrap() []error { + return []error{ErrReset, c.TransportError} +} + +const ( + ConnNoError ConnErrorCode = 0 + ConnProtocolNegotiationFailed ConnErrorCode = 0x1000 + ConnResourceLimitExceeded ConnErrorCode = 0x1001 + ConnRateLimited ConnErrorCode = 0x1002 + ConnProtocolViolation ConnErrorCode = 0x1003 + ConnSupplanted ConnErrorCode = 0x1004 + ConnGarbageCollected ConnErrorCode = 0x1005 + ConnShutdown ConnErrorCode = 0x1006 + ConnGated ConnErrorCode = 0x1007 + ConnCodeOutOfRange ConnErrorCode = 0x1008 +) + // Conn is a connection to a remote peer. It multiplexes streams. // Usually there is no need to use a Conn directly, but it may // be useful to get information about the peer on the other side: @@ -24,6 +69,11 @@ type Conn interface { ConnStat ConnScoper + // CloseWithError closes the connection with errCode. The errCode is sent to the + // peer on a best effort basis. For transports that do not support sending error + // codes on connection close, the behavior is identical to calling Close. + CloseWithError(errCode ConnErrorCode) error + // ID returns an identifier that uniquely identifies this Conn within this // host, during this run. Connection IDs may repeat across restarts. ID() string diff --git a/core/network/mux.go b/core/network/mux.go index d12e2ea34b..be61ccf62a 100644 --- a/core/network/mux.go +++ b/core/network/mux.go @@ -3,6 +3,7 @@ package network import ( "context" "errors" + "fmt" "io" "net" "time" @@ -11,6 +12,49 @@ import ( // ErrReset is returned when reading or writing on a reset stream. var ErrReset = errors.New("stream reset") +type StreamErrorCode uint32 + +type StreamError struct { + ErrorCode StreamErrorCode + Remote bool + TransportError error +} + +func (s *StreamError) Error() string { + side := "local" + if s.Remote { + side = "remote" + } + if s.TransportError != nil { + return fmt.Sprintf("stream reset (%s): code: 0x%x: transport error: %s", side, s.ErrorCode, s.TransportError) + } + return fmt.Sprintf("stream reset (%s): code: 0x%x", side, s.ErrorCode) +} + +func (s *StreamError) Is(target error) bool { + if tse, ok := target.(*StreamError); ok { + return tse.ErrorCode == s.ErrorCode && tse.Remote == s.Remote + } + return false +} + +func (s *StreamError) Unwrap() []error { + return []error{ErrReset, s.TransportError} +} + +const ( + StreamNoError StreamErrorCode = 0 + StreamProtocolNegotiationFailed StreamErrorCode = 0x1001 + StreamResourceLimitExceeded StreamErrorCode = 0x1002 + StreamRateLimited StreamErrorCode = 0x1003 + StreamProtocolViolation StreamErrorCode = 0x1004 + StreamSupplanted StreamErrorCode = 0x1005 + StreamGarbageCollected StreamErrorCode = 0x1006 + StreamShutdown StreamErrorCode = 0x1007 + StreamGated StreamErrorCode = 0x1008 + StreamCodeOutOfRange StreamErrorCode = 0x1009 +) + // MuxedStream is a bidirectional io pipe within a connection. type MuxedStream interface { io.Reader @@ -56,6 +100,11 @@ type MuxedStream interface { // side to hang up and go away. Reset() error + // ResetWithError aborts both ends of the stream with `errCode`. `errCode` is sent + // to the peer on a best effort basis. For transports that do not support sending + // error codes to remote peer, the behavior is identical to calling Reset + ResetWithError(errCode StreamErrorCode) error + SetDeadline(time.Time) error SetReadDeadline(time.Time) error SetWriteDeadline(time.Time) error @@ -75,6 +124,10 @@ type MuxedConn interface { // Close closes the stream muxer and the the underlying net.Conn. io.Closer + // CloseWithError closes the connection with errCode. The errCode is sent + // to the peer. + CloseWithError(errCode ConnErrorCode) error + // IsClosed returns whether a connection is fully closed, so it can // be garbage collected. IsClosed() bool diff --git a/core/network/stream.go b/core/network/stream.go index 62e230034c..f2b6cbcb88 100644 --- a/core/network/stream.go +++ b/core/network/stream.go @@ -27,4 +27,8 @@ type Stream interface { // Scope returns the user's view of this stream's resource scope Scope() StreamScope + + // ResetWithError closes both ends of the stream with errCode. The errCode is sent + // to the peer. + ResetWithError(errCode StreamErrorCode) error } diff --git a/core/peer/pb/peer_record.pb.go b/core/peer/pb/peer_record.pb.go index 56146e32b6..841bf97d2e 100644 --- a/core/peer/pb/peer_record.pb.go +++ b/core/peer/pb/peer_record.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: core/peer/pb/peer_record.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -26,19 +27,18 @@ const ( // // PeerRecords are designed to be serialized to bytes and placed inside of // SignedEnvelopes before sharing with other peers. -// See https://github.com/libp2p/go-libp2p/core/record/pb/envelope.proto for +// See https://github.com/libp2p/go-libp2p/blob/master/core/record/pb/envelope.proto for // the SignedEnvelope definition. type PeerRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // peer_id contains a libp2p peer id in its binary representation. PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"` // addresses is a list of public listen addresses for the peer. - Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` + Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *PeerRecord) Reset() { @@ -95,11 +95,10 @@ func (x *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo { // AddressInfo is a wrapper around a binary multiaddr. It is defined as a // separate message to allow us to add per-address metadata in the future. type PeerRecord_AddressInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` unknownFields protoimpl.UnknownFields - - Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PeerRecord_AddressInfo) Reset() { @@ -141,7 +140,7 @@ func (x *PeerRecord_AddressInfo) GetMultiaddr() []byte { var File_core_peer_pb_peer_record_proto protoreflect.FileDescriptor -var file_core_peer_pb_peer_record_proto_rawDesc = []byte{ +var file_core_peer_pb_peer_record_proto_rawDesc = string([]byte{ 0x0a, 0x1e, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x2f, 0x70, 0x62, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x70, 0x65, 0x65, 0x72, 0x2e, 0x70, 0x62, 0x22, 0xa3, 0x01, 0x0a, 0x0a, 0x50, 0x65, @@ -159,16 +158,16 @@ var file_core_peer_pb_peer_record_proto_rawDesc = []byte{ 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_core_peer_pb_peer_record_proto_rawDescOnce sync.Once - file_core_peer_pb_peer_record_proto_rawDescData = file_core_peer_pb_peer_record_proto_rawDesc + file_core_peer_pb_peer_record_proto_rawDescData []byte ) func file_core_peer_pb_peer_record_proto_rawDescGZIP() []byte { file_core_peer_pb_peer_record_proto_rawDescOnce.Do(func() { - file_core_peer_pb_peer_record_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_peer_pb_peer_record_proto_rawDescData) + file_core_peer_pb_peer_record_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_core_peer_pb_peer_record_proto_rawDesc), len(file_core_peer_pb_peer_record_proto_rawDesc))) }) return file_core_peer_pb_peer_record_proto_rawDescData } @@ -196,7 +195,7 @@ func file_core_peer_pb_peer_record_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_core_peer_pb_peer_record_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_peer_pb_peer_record_proto_rawDesc), len(file_core_peer_pb_peer_record_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -207,7 +206,6 @@ func file_core_peer_pb_peer_record_proto_init() { MessageInfos: file_core_peer_pb_peer_record_proto_msgTypes, }.Build() File_core_peer_pb_peer_record_proto = out.File - file_core_peer_pb_peer_record_proto_rawDesc = nil file_core_peer_pb_peer_record_proto_goTypes = nil file_core_peer_pb_peer_record_proto_depIdxs = nil } diff --git a/core/peer/pb/peer_record.proto b/core/peer/pb/peer_record.proto index 3a97e1a410..c5022f49ed 100644 --- a/core/peer/pb/peer_record.proto +++ b/core/peer/pb/peer_record.proto @@ -10,7 +10,7 @@ option go_package = "github.com/libp2p/go-libp2p/core/peer/pb"; // // PeerRecords are designed to be serialized to bytes and placed inside of // SignedEnvelopes before sharing with other peers. -// See https://github.com/libp2p/go-libp2p/core/record/pb/envelope.proto for +// See https://github.com/libp2p/go-libp2p/blob/master/core/record/pb/envelope.proto for // the SignedEnvelope definition. message PeerRecord { diff --git a/core/record/pb/envelope.pb.go b/core/record/pb/envelope.pb.go index 8da0e0eea5..33bd67f330 100644 --- a/core/record/pb/envelope.pb.go +++ b/core/record/pb/envelope.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: core/record/pb/envelope.proto package pb @@ -12,6 +12,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -29,10 +30,7 @@ const ( // can be deserialized deterministically. Often, this byte string is a // multicodec. type Envelope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // public_key is the public key of the keypair the enclosed payload was // signed with. PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` @@ -44,7 +42,9 @@ type Envelope struct { // signature is the signature produced by the private key corresponding to // the enclosed public key, over the payload, prefixing a domain string for // additional security. - Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` + Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Envelope) Reset() { @@ -107,7 +107,7 @@ func (x *Envelope) GetSignature() []byte { var File_core_record_pb_envelope_proto protoreflect.FileDescriptor -var file_core_record_pb_envelope_proto_rawDesc = []byte{ +var file_core_record_pb_envelope_proto_rawDesc = string([]byte{ 0x0a, 0x1d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x70, 0x62, 0x2f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x62, 0x1a, 0x1b, 0x63, 0x6f, 0x72, 0x65, @@ -126,16 +126,16 @@ var file_core_record_pb_envelope_proto_rawDesc = []byte{ 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_core_record_pb_envelope_proto_rawDescOnce sync.Once - file_core_record_pb_envelope_proto_rawDescData = file_core_record_pb_envelope_proto_rawDesc + file_core_record_pb_envelope_proto_rawDescData []byte ) func file_core_record_pb_envelope_proto_rawDescGZIP() []byte { file_core_record_pb_envelope_proto_rawDescOnce.Do(func() { - file_core_record_pb_envelope_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_record_pb_envelope_proto_rawDescData) + file_core_record_pb_envelope_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_core_record_pb_envelope_proto_rawDesc), len(file_core_record_pb_envelope_proto_rawDesc))) }) return file_core_record_pb_envelope_proto_rawDescData } @@ -163,7 +163,7 @@ func file_core_record_pb_envelope_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_core_record_pb_envelope_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_record_pb_envelope_proto_rawDesc), len(file_core_record_pb_envelope_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -174,7 +174,6 @@ func file_core_record_pb_envelope_proto_init() { MessageInfos: file_core_record_pb_envelope_proto_msgTypes, }.Build() File_core_record_pb_envelope_proto = out.File - file_core_record_pb_envelope_proto_rawDesc = nil file_core_record_pb_envelope_proto_goTypes = nil file_core_record_pb_envelope_proto_depIdxs = nil } diff --git a/core/sec/insecure/pb/plaintext.pb.go b/core/sec/insecure/pb/plaintext.pb.go index 64ab191b99..97e1864758 100644 --- a/core/sec/insecure/pb/plaintext.pb.go +++ b/core/sec/insecure/pb/plaintext.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: core/sec/insecure/pb/plaintext.proto package pb @@ -12,6 +12,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,12 +23,11 @@ const ( ) type Exchange struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Pubkey *pb.PublicKey `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"` unknownFields protoimpl.UnknownFields - - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Pubkey *pb.PublicKey `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Exchange) Reset() { @@ -76,7 +76,7 @@ func (x *Exchange) GetPubkey() *pb.PublicKey { var File_core_sec_insecure_pb_plaintext_proto protoreflect.FileDescriptor -var file_core_sec_insecure_pb_plaintext_proto_rawDesc = []byte{ +var file_core_sec_insecure_pb_plaintext_proto_rawDesc = string([]byte{ 0x0a, 0x24, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x63, 0x2f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2f, 0x70, 0x62, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, @@ -90,16 +90,16 @@ var file_core_sec_insecure_pb_plaintext_proto_rawDesc = []byte{ 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x63, 0x2f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2f, 0x70, 0x62, -} +}) var ( file_core_sec_insecure_pb_plaintext_proto_rawDescOnce sync.Once - file_core_sec_insecure_pb_plaintext_proto_rawDescData = file_core_sec_insecure_pb_plaintext_proto_rawDesc + file_core_sec_insecure_pb_plaintext_proto_rawDescData []byte ) func file_core_sec_insecure_pb_plaintext_proto_rawDescGZIP() []byte { file_core_sec_insecure_pb_plaintext_proto_rawDescOnce.Do(func() { - file_core_sec_insecure_pb_plaintext_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_sec_insecure_pb_plaintext_proto_rawDescData) + file_core_sec_insecure_pb_plaintext_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_core_sec_insecure_pb_plaintext_proto_rawDesc), len(file_core_sec_insecure_pb_plaintext_proto_rawDesc))) }) return file_core_sec_insecure_pb_plaintext_proto_rawDescData } @@ -127,7 +127,7 @@ func file_core_sec_insecure_pb_plaintext_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_core_sec_insecure_pb_plaintext_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_sec_insecure_pb_plaintext_proto_rawDesc), len(file_core_sec_insecure_pb_plaintext_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -138,7 +138,6 @@ func file_core_sec_insecure_pb_plaintext_proto_init() { MessageInfos: file_core_sec_insecure_pb_plaintext_proto_msgTypes, }.Build() File_core_sec_insecure_pb_plaintext_proto = out.File - file_core_sec_insecure_pb_plaintext_proto_rawDesc = nil file_core_sec_insecure_pb_plaintext_proto_goTypes = nil file_core_sec_insecure_pb_plaintext_proto_depIdxs = nil } diff --git a/examples/README.md b/examples/README.md index f9074de2af..8e86d5e953 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,7 @@ Let us know if you find any issue or if you want to contribute and add a new tut ## Examples and Tutorials - [The libp2p 'host'](./libp2p-host) +- [The libp2p 'host' with Secure WebSockets and AutoTLS](./autotls) - [Building an http proxy with libp2p](./http-proxy) - [An echo host](./echo) - [Routed echo host](./routed-echo/) diff --git a/examples/autotls/.gitignore b/examples/autotls/.gitignore new file mode 100644 index 0000000000..7f968b0b0d --- /dev/null +++ b/examples/autotls/.gitignore @@ -0,0 +1,3 @@ +autotls +p2p-forge-certs/ +identity.key diff --git a/examples/autotls/README.md b/examples/autotls/README.md new file mode 100644 index 0000000000..bb0cb5f0ea --- /dev/null +++ b/examples/autotls/README.md @@ -0,0 +1,14 @@ +# libp2p host with Secure WebSockets and AutoTLS + +This example builds on the [libp2p host example](../libp2p-host) example and demonstrates how to use [AutoTLS](https://blog.ipfs.tech/2024-shipyard-improving-ipfs-on-the-web/#autotls-with-libp2p-direct) to automatically generate a wildcard Let's Encrypt TLS certificate unique to the libp2p host (`*..libp2p.direct`), and use it with [libp2p WebSockets transport over TCP](https://github.com/libp2p/specs/blob/master/websockets/README.md) enabling browsers to directly connect to the libp2p host. + +For this example to work, you need to have a public IP address and be publicly reachable. AutoTLS is guarded by connectivity check, and will not ask for a certificate unless your libp2p node emits `event.EvtLocalReachabilityChanged` with `network.ReachabilityPublic`. + +## Running the example + +From the `go-libp2p/examples` directory run the following: + +```sh +cd autotls/ +go run . +``` diff --git a/examples/autotls/identity.go b/examples/autotls/identity.go new file mode 100644 index 0000000000..c76187e240 --- /dev/null +++ b/examples/autotls/identity.go @@ -0,0 +1,47 @@ +package main + +import ( + "os" + + "github.com/libp2p/go-libp2p/core/crypto" +) + +// LoadIdentity reads a private key from the given path and, if it does not +// exist, generates a new one. +func LoadIdentity(keyPath string) (crypto.PrivKey, error) { + if _, err := os.Stat(keyPath); err == nil { + return ReadIdentity(keyPath) + } else if os.IsNotExist(err) { + logger.Infof("Generating peer identity in %s\n", keyPath) + return GenerateIdentity(keyPath) + } else { + return nil, err + } +} + +// ReadIdentity reads a private key from the given path. +func ReadIdentity(path string) (crypto.PrivKey, error) { + bytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + return crypto.UnmarshalPrivateKey(bytes) +} + +// GenerateIdentity writes a new random private key to the given path. +func GenerateIdentity(path string) (crypto.PrivKey, error) { + privk, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 0) + if err != nil { + return nil, err + } + + bytes, err := crypto.MarshalPrivateKey(privk) + if err != nil { + return nil, err + } + + err = os.WriteFile(path, bytes, 0400) + + return privk, err +} diff --git a/examples/autotls/main.go b/examples/autotls/main.go new file mode 100644 index 0000000000..0caa39d832 --- /dev/null +++ b/examples/autotls/main.go @@ -0,0 +1,151 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "time" + + "github.com/caddyserver/certmagic" + "github.com/ipfs/go-log/v2" + + p2pforge "github.com/ipshipyard/p2p-forge/client" + "github.com/libp2p/go-libp2p" + dht "github.com/libp2p/go-libp2p-kad-dht" + "github.com/libp2p/go-libp2p/p2p/transport/tcp" + ws "github.com/libp2p/go-libp2p/p2p/transport/websocket" +) + +var logger = log.Logger("autotls-example") + +const userAgent = "go-libp2p/example/autotls" +const identityKeyFile = "identity.key" + +func main() { + // Create a background context + ctx := context.Background() + + log.SetLogLevel("*", "error") + log.SetLogLevel("autotls-example", "debug") // Set the log level for the example to debug + log.SetLogLevel("basichost", "info") // Set the log level for the basichost package to info + log.SetLogLevel("autotls", "debug") // Set the log level for the autotls-example package to debug + log.SetLogLevel("p2p-forge", "debug") // Set the log level for the p2pforge package to debug + log.SetLogLevel("nat", "debug") // Set the log level for the libp2p nat package to debug + + certLoaded := make(chan bool, 1) // Create a channel to signal when the cert is loaded + + // use dedicated logger for autotls feature + rawLogger := logger.Desugar() + + // p2pforge is the AutoTLS client library. + // The cert manager handles the creation and management of certificate + certManager, err := p2pforge.NewP2PForgeCertMgr( + // Configure CA ACME endpoint + // NOTE: + // This example uses Let's Encrypt staging CA (p2pforge.DefaultCATestEndpoint) + // which will not work correctly in browser, but is useful for initial testing. + // Production should use Let's Encrypt production CA (p2pforge.DefaultCAEndpoint). + p2pforge.WithCAEndpoint(p2pforge.DefaultCATestEndpoint), // test CA endpoint + // TODO: p2pforge.WithCAEndpoint(p2pforge.DefaultCAEndpoint), // production CA endpoint + + // Configure where to store certificate + p2pforge.WithCertificateStorage(&certmagic.FileStorage{Path: "p2p-forge-certs"}), + + // Configure logger to use + p2pforge.WithLogger(rawLogger.Sugar().Named("autotls")), + + // User-Agent to use during DNS-01 ACME challenge + p2pforge.WithUserAgent(userAgent), + + // Optional hook called once certificate is ready + p2pforge.WithOnCertLoaded(func() { + certLoaded <- true + }), + ) + + if err != nil { + panic(err) + } + + // Start the cert manager + certManager.Start() + defer certManager.Stop() + + // Load or generate a persistent peer identity key + privKey, err := LoadIdentity(identityKeyFile) + if err != nil { + panic(err) + } + + opts := []libp2p.Option{ + libp2p.Identity(privKey), // Use the loaded identity key + libp2p.DisableRelay(), // Disable relay, since we need a public IP address + libp2p.NATPortMap(), // Attempt to open ports using UPnP for NATed hosts. + + libp2p.ListenAddrStrings( + "/ip4/0.0.0.0/tcp/5500", // regular TCP IPv4 connections + "/ip6/::/tcp/5500", // regular TCP IPv6 connections + + // Configure Secure WebSockets listeners on the same TCP port + // AutoTLS will automatically generate a certificate for this host + // and use the forge domain (`libp2p.direct`) as the SNI hostname. + fmt.Sprintf("/ip4/0.0.0.0/tcp/5500/tls/sni/*.%s/ws", p2pforge.DefaultForgeDomain), + fmt.Sprintf("/ip6/::/tcp/5500/tls/sni/*.%s/ws", p2pforge.DefaultForgeDomain), + ), + + // Configure the TCP transport + libp2p.Transport(tcp.NewTCPTransport), + + // Share the same TCP listener between the TCP and WS transports + libp2p.ShareTCPListener(), + + // Configure the WS transport with the AutoTLS cert manager + libp2p.Transport(ws.New, ws.WithTLSConfig(certManager.TLSConfig())), + + // Configure user agent for libp2p identify protocol (https://github.com/libp2p/specs/blob/master/identify/README.md) + libp2p.UserAgent(userAgent), + + // AddrsFactory takes the multiaddrs we're listening on and sets the multiaddrs to advertise to the network. + // We use the AutoTLS address factory so that the `*` in the AutoTLS address string is replaced with the + // actual IP address of the host once detected + libp2p.AddrsFactory(certManager.AddressFactory()), + } + h, err := libp2p.New(opts...) + if err != nil { + panic(err) + } + + logger.Info("Host created with PeerID: ", h.ID()) + + // Bootstrap the DHT to verify our public IPs address with AutoNAT + dhtOpts := []dht.Option{ + dht.Mode(dht.ModeClient), + dht.BootstrapPeers(dht.GetDefaultBootstrapPeerAddrInfos()...), + } + dht, err := dht.New(ctx, h, dhtOpts...) + if err != nil { + panic(err) + } + + 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) + + select { + case <-certLoaded: + logger.Info("TLS certificate loaded ") + logger.Info("Addresses: ", h.Addrs()) + case <-ctx.Done(): + logger.Info("Context done") + } + // Wait for interrupt signal + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c +} diff --git a/examples/go.mod b/examples/go.mod index e4ba498316..997eca9220 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,113 +1,144 @@ module github.com/libp2p/go-libp2p/examples -go 1.22 +go 1.23 require ( + github.com/caddyserver/certmagic v0.21.6 github.com/gogo/protobuf v1.3.2 - github.com/google/uuid v1.4.0 + 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/libp2p/go-libp2p v0.33.0 - github.com/libp2p/go-libp2p-kad-dht v0.25.1 - github.com/multiformats/go-multiaddr v0.12.2 - github.com/prometheus/client_golang v1.18.0 + github.com/ipshipyard/p2p-forge v0.3.1 + 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 + github.com/prometheus/client_golang v1.20.5 ) require ( github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/caddyserver/zerossl v0.1.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/elastic/gosigar v0.14.2 // 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-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect - github.com/gorilla/websocket v1.5.1 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/ipfs/boxo v0.10.0 // indirect + github.com/ipfs/boxo v0.25.0 // indirect github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipld/go-ipld-prime v0.20.0 // indirect + github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.17.6 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/koron/go-ssdp v0.0.5 // indirect + github.com/libdns/libdns v0.2.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect + github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect + github.com/libp2p/go-libp2p-kbucket v0.6.4 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect - github.com/libp2p/go-libp2p-routing-helpers v0.7.2 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.7.4 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.58 // indirect + github.com/mholt/acmez/v3 v3.0.0 // indirect + github.com/miekg/dns v1.1.62 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.5.0 // indirect + github.com/multiformats/go-multistream v0.6.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // 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/opentracing/opentracing-go 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 + github.com/pion/ice/v2 v2.3.37 // indirect + github.com/pion/interceptor v0.1.37 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.10 // indirect + github.com/pion/sctp v1.8.35 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.20 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.3.5 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.41.0 // indirect - github.com/quic-go/webtransport-go v0.6.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.61.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.48.2 // 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/stretchr/testify v1.10.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.20.1 // indirect - go.uber.org/mock v0.4.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect + go.uber.org/dig v1.18.0 // indirect + go.uber.org/fx v1.23.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect - golang.org/x/mod v0.15.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.18.0 // indirect - gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + go.uber.org/zap/exp v0.3.0 // indirect + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + 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 + 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 bae05796c7..8279eed5b7 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -18,9 +18,13 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/caddyserver/certmagic v0.21.6 h1:1th6GfprVfsAtFNOu4StNMF5IxK5XiaI0yZhAHlZFPE= +github.com/caddyserver/certmagic v0.21.6/go.mod h1:n1sCo7zV1Ez2j+89wrzDxo4N/T1Ws/Vx8u5NvuBFabw= +github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= +github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -34,21 +38,22 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV 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= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/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.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= -github.com/elastic/gosigar v0.14.2/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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -58,19 +63,19 @@ github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +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/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -82,8 +87,8 @@ 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/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -97,8 +102,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -115,19 +118,19 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -135,27 +138,30 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/boxo v0.10.0 h1:tdDAxq8jrsbRkYoF+5Rcqyeb91hgWe2hp7iLu7ORZLY= -github.com/ipfs/boxo v0.10.0/go.mod h1:Fg+BnfxZ0RPzR0nOodzdIq3A7KgoWAOWsEIImrIQdBM= +github.com/ipfs/boxo v0.25.0 h1:FNZaKVirUDafGz3Y9sccztynAUazs9GfSapLk/5c7is= +github.com/ipfs/boxo v0.25.0/go.mod h1:MQVkL3V8RfuIsn+aajCR0MXLl8nRlz+5uGlHMWFVyuE= +github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= +github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= -github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= -github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= +github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= +github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g= -github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M= +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/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= @@ -171,12 +177,12 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= +github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -186,32 +192,36 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s= +github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= -github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.33.0 h1:yTPSr8sJRbfeEYXyeN8VPVSlTlFjtMUwGDRniwaf/xQ= -github.com/libp2p/go-libp2p v0.33.0/go.mod h1:RIJFRQVUBKy82dnW7J5f1homqqv6NcsDJAl3e7CRGfE= +github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw= +github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc= +github.com/libp2p/go-libp2p v0.38.2 h1:9SZQDOCi82A25An4kx30lEtr6kGTxrtoaDkbs5xrK5k= +github.com/libp2p/go-libp2p v0.38.2/go.mod h1:QWV4zGL3O9nXKdHirIC59DoRcZ446dfkjbOJ55NEWFo= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= -github.com/libp2p/go-libp2p-kad-dht v0.25.1 h1:ofFNrf6MMEy4vi3R1VbJ7LOcTn3Csh0cDcaWHTxtWNA= -github.com/libp2p/go-libp2p-kad-dht v0.25.1/go.mod h1:6za56ncRHYXX4Nc2vn8z7CZK0P4QiMcrn77acKLM2Oo= -github.com/libp2p/go-libp2p-kbucket v0.6.3 h1:p507271wWzpy2f1XxPzCQG9NiN6R6lHL9GiSErbQQo0= -github.com/libp2p/go-libp2p-kbucket v0.6.3/go.mod h1:RCseT7AH6eJWxxk2ol03xtP9pEHetYSPXOaJnOiD8i0= +github.com/libp2p/go-libp2p-kad-dht v0.28.1 h1:DVTfzG8Ybn88g9RycIq47evWCRss5f0Wm8iWtpwyHso= +github.com/libp2p/go-libp2p-kad-dht v0.28.1/go.mod h1:0wHURlSFdAC42+wF7GEmpLoARw8JuS8do2guCtc/Y/w= +github.com/libp2p/go-libp2p-kbucket v0.6.4 h1:OjfiYxU42TKQSB8t8WYd8MKhYhMJeO2If+NiuKfb6iQ= +github.com/libp2p/go-libp2p-kbucket v0.6.4/go.mod h1:jp6w82sczYaBsAypt5ayACcRJi0lgsba7o4TzJKEfWA= github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= -github.com/libp2p/go-libp2p-routing-helpers v0.7.2 h1:xJMFyhQ3Iuqnk9Q2dYE1eUTzsah7NLw3Qs2zjUV78T0= -github.com/libp2p/go-libp2p-routing-helpers v0.7.2/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= +github.com/libp2p/go-libp2p-routing-helpers v0.7.4 h1:6LqS1Bzn5CfDJ4tzvP9uwh42IB7TJLNFJA6dEeGBv84= +github.com/libp2p/go-libp2p-routing-helpers v0.7.4/go.mod h1:we5WDj9tbolBXOuF1hGOkR+r7Uh1408tQbAKaT5n1LE= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= @@ -226,11 +236,12 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mholt/acmez/v3 v3.0.0 h1:r1NcjuWR0VaKP2BTjDK9LRFBw/WvURx3jlaEUl9Ht8E= +github.com/mholt/acmez/v3 v3.0.0/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -251,11 +262,10 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.12.2 h1:9G9sTY/wCYajKa9lyfWPmpZAwe6oV+Wb1zcmMS1HG24= -github.com/multiformats/go-multiaddr v0.12.2/go.mod h1:GKyaTYjZRdcUhyOetrxTk9z0cW+jA/YrnqTOvKgi44M= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= +github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= +github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= +github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= @@ -265,56 +275,97 @@ github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI1 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= -github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-multistream v0.6.0 h1:ZaHKbsL404720283o4c/IHQXiS6gb8qAN5EIJ4PN5EA= +github.com/multiformats/go-multistream v0.6.0/go.mod h1:MOyoG5otO24cHIg8kf9QW2/NozURlkP/rvi2FQJyCPg= github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +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/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/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= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0= +github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= +github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.10 h1:puphjdbjPB+L+NFaVuZ5h6bt1g5q4kFIoI+r5q/g0CU= +github.com/pion/rtp v1.8.10/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= +github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= +github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.3.5 h1:ZsSzaMz/i9nblPdiAkZoP+E6Kmjw+jnyq3bEmU3EtRg= +github.com/pion/webrtc/v3 v3.3.5/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ= +github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k= -github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA= -github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= -github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= +github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/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/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 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= @@ -353,16 +404,19 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -372,69 +426,81 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +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= +github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= +github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= +github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= +github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= -go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= -go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= +go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= +go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= +go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= +go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +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= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -453,8 +519,14 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -468,8 +540,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ 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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.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= @@ -487,20 +561,41 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.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= @@ -510,22 +605,21 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-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.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= +golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= golang.org/x/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= -gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= -gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= +gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= +gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -557,13 +651,13 @@ 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.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -579,8 +673,7 @@ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/ipfs-camp-2019/go.mod b/examples/ipfs-camp-2019/go.mod index 268135abab..7a52a1de0a 100644 --- a/examples/ipfs-camp-2019/go.mod +++ b/examples/ipfs-camp-2019/go.mod @@ -1,6 +1,6 @@ module github.com/libp2p/go-libp2p/examples/ipfs-camp-2019 -go 1.22 +go 1.23 require ( github.com/gogo/protobuf v1.3.2 diff --git a/examples/pubsub/basic-chat-with-rendezvous/go.mod b/examples/pubsub/basic-chat-with-rendezvous/go.mod index c45d19866d..c03b5421d9 100644 --- a/examples/pubsub/basic-chat-with-rendezvous/go.mod +++ b/examples/pubsub/basic-chat-with-rendezvous/go.mod @@ -1,6 +1,6 @@ module github.com/libp2p/go-libp2p/examples/pubsub/chat -go 1.22 +go 1.23 require ( github.com/libp2p/go-libp2p v0.33.0 diff --git a/examples/pubsub/chat/go.mod b/examples/pubsub/chat/go.mod index 3f1e6c2f07..7157db7902 100644 --- a/examples/pubsub/chat/go.mod +++ b/examples/pubsub/chat/go.mod @@ -1,6 +1,6 @@ module github.com/libp2p/go-libp2p/examples/pubsub/chat -go 1.22 +go 1.23 require ( github.com/gdamore/tcell/v2 v2.5.2 diff --git a/examples/relay/main.go b/examples/relay/main.go index 7e16b1b19d..a92ab96812 100644 --- a/examples/relay/main.go +++ b/examples/relay/main.go @@ -150,7 +150,7 @@ func run() { // relayed connection. In general, we should only do this if we have low bandwidth requirements, // and we're happy for the connection to be killed when the relayed connection is replaced with a // direct (holepunched) connection. - s, err := unreachable1.NewStream(network.WithUseTransient(context.Background(), "customprotocol"), unreachable2.ID(), "/customprotocol") + s, err := unreachable1.NewStream(network.WithAllowLimitedConn(context.Background(), "customprotocol"), unreachable2.ID(), "/customprotocol") if err != nil { log.Println("Whoops, this should have worked...: ", err) return diff --git a/go.mod b/go.mod index 62ef58c06c..8e027dae27 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/libp2p/go-libp2p -go 1.22.0 - -toolchain go1.22.1 +go 1.23 retract v0.26.1 // Tag was applied incorrectly due to a bug in the release workflow. @@ -17,7 +15,7 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/hashicorp/golang-lru/arc/v2 v2.0.7 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/ipfs/go-cid v0.4.1 + github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-badger v0.3.0 github.com/ipfs/go-ds-leveldb v0.5.0 @@ -30,15 +28,15 @@ require ( github.com/libp2p/go-libp2p-testing v0.12.0 github.com/libp2p/go-msgio v0.3.0 github.com/libp2p/go-nat v0.2.0 - github.com/libp2p/go-netroute v0.2.1 + github.com/libp2p/go-netroute v0.2.2 github.com/libp2p/go-reuseport v0.4.0 - github.com/libp2p/go-yamux/v4 v4.0.1 + github.com/libp2p/go-yamux/v5 v5.0.0 github.com/libp2p/zeroconf/v2 v2.2.0 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.13.0 + github.com/multiformats/go-multiaddr v0.14.0 github.com/multiformats/go-multiaddr-dns v0.4.1 github.com/multiformats/go-multiaddr-fmt v0.1.0 github.com/multiformats/go-multibase v0.2.0 @@ -47,28 +45,27 @@ require ( github.com/multiformats/go-multistream v0.6.0 github.com/multiformats/go-varint v0.0.7 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 - github.com/pion/datachannel v1.5.9 - github.com/pion/ice/v2 v2.3.36 - github.com/pion/logging v0.2.2 - github.com/pion/sctp v1.8.33 + github.com/pion/datachannel v1.5.10 + github.com/pion/ice/v4 v4.0.6 + github.com/pion/logging v0.2.3 + github.com/pion/sctp v1.8.35 github.com/pion/stun v0.6.1 - github.com/pion/webrtc/v3 v3.3.4 + github.com/pion/webrtc/v4 v4.0.9 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 - github.com/quic-go/quic-go v0.48.2 + github.com/quic-go/quic-go v0.49.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.9.0 + github.com/stretchr/testify v1.10.0 go.uber.org/fx v1.23.0 go.uber.org/goleak v1.3.0 go.uber.org/mock v0.5.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.28.0 - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.26.0 - golang.org/x/tools v0.26.0 - google.golang.org/protobuf v1.35.1 + golang.org/x/crypto v0.33.0 + golang.org/x/sync v0.11.0 + golang.org/x/sys v0.30.0 + golang.org/x/tools v0.30.0 + google.golang.org/protobuf v1.36.5 ) require ( @@ -90,35 +87,38 @@ require ( 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-20241017200806-017d972448fc // indirect + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect github.com/google/uuid v1.6.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/koron/go-ssdp v0.0.5 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.63 // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.11 // indirect - github.com/onsi/ginkgo/v2 v2.20.2 // 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 - github.com/pion/mdns v0.0.12 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.9 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.20 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect + github.com/pion/srtp/v3 v3.0.4 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v2 v2.2.10 // indirect - github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect + github.com/pion/turn/v4 v4.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/common v0.60.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect @@ -126,9 +126,10 @@ require ( github.com/wlynxg/anet v0.0.5 // indirect go.uber.org/dig v1.18.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/text v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 047083b063..393653bf2d 100644 --- a/go.sum +++ b/go.sum @@ -111,11 +111,10 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= @@ -134,8 +133,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= @@ -164,10 +163,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= +github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -190,12 +189,12 @@ github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0 github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po= +github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q= github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= @@ -209,8 +208,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -233,8 +232,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= -github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= +github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -260,11 +259,11 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/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.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +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= @@ -272,48 +271,48 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.36 h1:SopeXiVbbcooUg2EIR8sq4b13RQ8gzrkkldOVg+bBsc= -github.com/pion/ice/v2 v2.3.36/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= +github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= +github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM= +github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= -github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= -github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= -github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= +github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= +github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= -github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.3.4 h1:v2heQVnXTSqNRXcaFQVOhIOYkLMxOu1iJG8uy1djvkk= -github.com/pion/webrtc/v3 v3.3.4/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= +github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= +github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= +github.com/pion/webrtc/v4 v4.0.9 h1:PyOYMRKJgfy0dzPcYtFD/4oW9zaw3Ze3oZzzbj2LV9E= +github.com/pion/webrtc/v4 v4.0.9/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= @@ -326,15 +325,15 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= -github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= +github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= 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= @@ -383,7 +382,6 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -392,8 +390,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -446,11 +444,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -463,8 +461,8 @@ 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= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -488,8 +486,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -505,8 +503,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-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= @@ -535,11 +533,10 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -556,8 +553,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -579,8 +576,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +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= @@ -603,8 +600,8 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/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/libp2p_test.go b/libp2p_test.go index eb04cd1e6d..f10bbb9b75 100644 --- a/libp2p_test.go +++ b/libp2p_test.go @@ -26,6 +26,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/core/pnet" "github.com/libp2p/go-libp2p/core/routing" "github.com/libp2p/go-libp2p/core/transport" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" @@ -465,7 +466,6 @@ func TestDialCircuitAddrWithWrappedResourceManager(t *testing.T) { ), peerstore.TempAddrTTL, ) - require.NoError(t, err) require.Eventually(t, func() bool { ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) @@ -761,6 +761,7 @@ func TestSharedTCPAddr(t *testing.T) { ListenAddrStrings("/ip4/0.0.0.0/tcp/8888/ws"), ) require.NoError(t, err) + defer h.Close() sawTCP := false sawWS := false for _, addr := range h.Addrs() { @@ -773,7 +774,42 @@ func TestSharedTCPAddr(t *testing.T) { } require.True(t, sawTCP) require.True(t, sawWS) - h.Close() + + _, err = New( + ShareTCPListener(), + Transport(tcp.NewTCPTransport), + Transport(websocket.New), + PrivateNetwork(pnet.PSK([]byte{1, 2, 3})), + ) + require.ErrorContains(t, err, "cannot use shared TCP listener with PSK") +} + +func TestCustomTCPDialer(t *testing.T) { + expectedErr := errors.New("custom dialer called, but not implemented") + customDialer := func(raddr ma.Multiaddr) (tcp.ContextDialer, error) { + // Normally a user would implement this by returning a custom dialer + // Here, we just test that this is called. + return nil, expectedErr + } + + h, err := New( + Transport(tcp.NewTCPTransport, tcp.WithDialerForAddr(customDialer)), + ) + require.NoError(t, err) + defer h.Close() + + var randID peer.ID + priv, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 256) + require.NoError(t, err) + randID, err = peer.IDFromPrivateKey(priv) + require.NoError(t, err) + + err = h.Connect(context.Background(), peer.AddrInfo{ + ID: randID, + // This won't actually be dialed since we return an error above + Addrs: []ma.Multiaddr{ma.StringCast("/ip4/1.2.3.4/tcp/4")}, + }) + require.ErrorContains(t, err, expectedErr.Error()) } func BenchmarkAllAddrs(b *testing.B) { diff --git a/p2p/host/autonat/pb/autonat.pb.go b/p2p/host/autonat/pb/autonat.pb.go index 46eed5986b..0345d85e1a 100644 --- a/p2p/host/autonat/pb/autonat.pb.go +++ b/p2p/host/autonat/pb/autonat.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/host/autonat/pb/autonat.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -142,13 +143,12 @@ func (Message_ResponseStatus) EnumDescriptor() ([]byte, []int) { } type Message struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=autonat.pb.Message_MessageType" json:"type,omitempty"` + Dial *Message_Dial `protobuf:"bytes,2,opt,name=dial" json:"dial,omitempty"` + DialResponse *Message_DialResponse `protobuf:"bytes,3,opt,name=dialResponse" json:"dialResponse,omitempty"` unknownFields protoimpl.UnknownFields - - Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=autonat.pb.Message_MessageType" json:"type,omitempty"` - Dial *Message_Dial `protobuf:"bytes,2,opt,name=dial" json:"dial,omitempty"` - DialResponse *Message_DialResponse `protobuf:"bytes,3,opt,name=dialResponse" json:"dialResponse,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Message) Reset() { @@ -203,12 +203,11 @@ func (x *Message) GetDialResponse() *Message_DialResponse { } type Message_PeerInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` unknownFields protoimpl.UnknownFields - - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Message_PeerInfo) Reset() { @@ -256,11 +255,10 @@ func (x *Message_PeerInfo) GetAddrs() [][]byte { } type Message_Dial struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Peer *Message_PeerInfo `protobuf:"bytes,1,opt,name=peer" json:"peer,omitempty"` unknownFields protoimpl.UnknownFields - - Peer *Message_PeerInfo `protobuf:"bytes,1,opt,name=peer" json:"peer,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Message_Dial) Reset() { @@ -301,13 +299,12 @@ func (x *Message_Dial) GetPeer() *Message_PeerInfo { } type Message_DialResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Status *Message_ResponseStatus `protobuf:"varint,1,opt,name=status,enum=autonat.pb.Message_ResponseStatus" json:"status,omitempty"` + StatusText *string `protobuf:"bytes,2,opt,name=statusText" json:"statusText,omitempty"` + Addr []byte `protobuf:"bytes,3,opt,name=addr" json:"addr,omitempty"` unknownFields protoimpl.UnknownFields - - Status *Message_ResponseStatus `protobuf:"varint,1,opt,name=status,enum=autonat.pb.Message_ResponseStatus" json:"status,omitempty"` - StatusText *string `protobuf:"bytes,2,opt,name=statusText" json:"statusText,omitempty"` - Addr []byte `protobuf:"bytes,3,opt,name=addr" json:"addr,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Message_DialResponse) Reset() { @@ -363,7 +360,7 @@ func (x *Message_DialResponse) GetAddr() []byte { var File_p2p_host_autonat_pb_autonat_proto protoreflect.FileDescriptor -var file_p2p_host_autonat_pb_autonat_proto_rawDesc = []byte{ +var file_p2p_host_autonat_pb_autonat_proto_rawDesc = string([]byte{ 0x0a, 0x21, 0x70, 0x32, 0x70, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x2f, 0x70, 0x62, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x2e, 0x70, 0x62, 0x22, @@ -406,16 +403,16 @@ var file_p2p_host_autonat_pb_autonat_proto_rawDesc = []byte{ 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x2f, 0x70, 0x62, -} +}) var ( file_p2p_host_autonat_pb_autonat_proto_rawDescOnce sync.Once - file_p2p_host_autonat_pb_autonat_proto_rawDescData = file_p2p_host_autonat_pb_autonat_proto_rawDesc + file_p2p_host_autonat_pb_autonat_proto_rawDescData []byte ) func file_p2p_host_autonat_pb_autonat_proto_rawDescGZIP() []byte { file_p2p_host_autonat_pb_autonat_proto_rawDescOnce.Do(func() { - file_p2p_host_autonat_pb_autonat_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_host_autonat_pb_autonat_proto_rawDescData) + file_p2p_host_autonat_pb_autonat_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_host_autonat_pb_autonat_proto_rawDesc), len(file_p2p_host_autonat_pb_autonat_proto_rawDesc))) }) return file_p2p_host_autonat_pb_autonat_proto_rawDescData } @@ -452,7 +449,7 @@ func file_p2p_host_autonat_pb_autonat_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_host_autonat_pb_autonat_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_host_autonat_pb_autonat_proto_rawDesc), len(file_p2p_host_autonat_pb_autonat_proto_rawDesc)), NumEnums: 2, NumMessages: 4, NumExtensions: 0, @@ -464,7 +461,6 @@ func file_p2p_host_autonat_pb_autonat_proto_init() { MessageInfos: file_p2p_host_autonat_pb_autonat_proto_msgTypes, }.Build() File_p2p_host_autonat_pb_autonat_proto = out.File - file_p2p_host_autonat_pb_autonat_proto_rawDesc = nil file_p2p_host_autonat_pb_autonat_proto_goTypes = nil file_p2p_host_autonat_pb_autonat_proto_depIdxs = nil } diff --git a/p2p/host/autorelay/autorelay.go b/p2p/host/autorelay/autorelay.go index 3ba685f658..a8ac286d6d 100644 --- a/p2p/host/autorelay/autorelay.go +++ b/p2p/host/autorelay/autorelay.go @@ -10,7 +10,6 @@ import ( "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/p2p/host/eventbus" - ma "github.com/multiformats/go-multiaddr" logging "github.com/ipfs/go-log/v2" ) @@ -54,10 +53,6 @@ func NewAutoRelay(host host.Host, opts ...Option) (*AutoRelay, error) { return r, nil } -func (r *AutoRelay) RelayAddrs() []ma.Multiaddr { - return r.relayFinder.RelayAddrs() -} - func (r *AutoRelay) Start() { r.refCount.Add(1) go func() { @@ -82,7 +77,6 @@ func (r *AutoRelay) background() { if !ok { return } - // TODO: push changed addresses evt := ev.(event.EvtLocalReachabilityChanged) switch evt.Reachability { case network.ReachabilityPrivate, network.ReachabilityUnknown: diff --git a/p2p/host/autorelay/autorelay_test.go b/p2p/host/autorelay/autorelay_test.go index a7fdcd39d5..a2186b5183 100644 --- a/p2p/host/autorelay/autorelay_test.go +++ b/p2p/host/autorelay/autorelay_test.go @@ -19,6 +19,7 @@ import ( circuitv2_proto "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto" ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -524,13 +525,14 @@ func TestNoBusyLoop0MinInterval(t *testing.T) { } func TestAutoRelayAddrsEvent(t *testing.T) { cl := newMockClock() - r1, r2 := newRelay(t), newRelay(t) + relays := []host.Host{newRelay(t), newRelay(t), newRelay(t), newRelay(t), newRelay(t)} t.Cleanup(func() { - r1.Close() - r2.Close() + for _, r := range relays { + r.Close() + } }) - relayFromP2PAddr := func(a ma.Multiaddr) peer.ID { + relayIDFromP2PAddr := func(a ma.Multiaddr) peer.ID { r, c := ma.SplitLast(a) if c.Protocol().Code != ma.P_CIRCUIT { return "" @@ -541,15 +543,15 @@ func TestAutoRelayAddrsEvent(t *testing.T) { return "" } - checkPeersExist := func(addrs []ma.Multiaddr, peers ...peer.ID) bool { + checkAddrsContainsPeersAsRelay := func(addrs []ma.Multiaddr, peers ...peer.ID) bool { for _, p := range peers { - if !slices.ContainsFunc(addrs, func(a ma.Multiaddr) bool { return relayFromP2PAddr(a) == p }) { + if !slices.ContainsFunc(addrs, func(a ma.Multiaddr) bool { return relayIDFromP2PAddr(a) == p }) { return false } } return true } - peerChan := make(chan peer.AddrInfo, 3) + peerChan := make(chan peer.AddrInfo, 5) h := newPrivateNode(t, func(context.Context, int) <-chan peer.AddrInfo { return peerChan @@ -557,31 +559,45 @@ func TestAutoRelayAddrsEvent(t *testing.T) { autorelay.WithClock(cl), autorelay.WithMinCandidates(1), autorelay.WithMaxCandidates(10), - autorelay.WithNumRelays(3), + autorelay.WithNumRelays(5), autorelay.WithBootDelay(1*time.Second), autorelay.WithMinInterval(time.Hour), ) defer h.Close() - sub, err := h.EventBus().Subscribe(new(event.EvtAutoRelayAddrs)) + sub, err := h.EventBus().Subscribe(new(event.EvtAutoRelayAddrsUpdated)) require.NoError(t, err) - peerChan <- peer.AddrInfo{ID: r1.ID(), Addrs: r1.Addrs()} + peerChan <- peer.AddrInfo{ID: relays[0].ID(), Addrs: relays[0].Addrs()} cl.AdvanceBy(time.Second) - require.Eventually(t, func() bool { + require.EventuallyWithT(t, func(collect *assert.CollectT) { e := <-sub.Out() - if !checkPeersExist(e.(event.EvtAutoRelayAddrs).RelayAddrs, r1.ID()) { - return false + evt := e.(event.EvtAutoRelayAddrsUpdated) + if !checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relays[0].ID()) { + collect.Errorf("expected %s to be in %v", relays[0].ID(), evt.RelayAddrs) } - if checkPeersExist(e.(event.EvtAutoRelayAddrs).RelayAddrs, r2.ID()) { - return false + if checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relays[1].ID()) { + collect.Errorf("expected %s to not be in %v", relays[1].ID(), evt.RelayAddrs) } - return true }, 5*time.Second, 50*time.Millisecond) - peerChan <- peer.AddrInfo{ID: r2.ID(), Addrs: r2.Addrs()} - require.Eventually(t, func() bool { + for _, r := range relays[1:] { + peerChan <- peer.AddrInfo{ID: r.ID(), Addrs: r.Addrs()} + } + require.EventuallyWithT(t, func(c *assert.CollectT) { e := <-sub.Out() - return checkPeersExist(e.(event.EvtAutoRelayAddrs).RelayAddrs, r1.ID(), r2.ID()) + evt := e.(event.EvtAutoRelayAddrsUpdated) + relayIds := []peer.ID{} + for _, r := range relays[1:] { + relayIds = append(relayIds, r.ID()) + } + if !checkAddrsContainsPeersAsRelay(evt.RelayAddrs, relayIds...) { + c.Errorf("expected %s to be in %v", relayIds, evt.RelayAddrs) + } }, 5*time.Second, 50*time.Millisecond) + select { + case e := <-sub.Out(): + t.Fatal("expected no more events after all reservations obtained; got: ", e.(event.EvtAutoRelayAddrsUpdated)) + case <-time.After(1 * time.Second): + } } diff --git a/p2p/host/autorelay/relay_finder.go b/p2p/host/autorelay/relay_finder.go index d4fabddaa0..009629a5cc 100644 --- a/p2p/host/autorelay/relay_finder.go +++ b/p2p/host/autorelay/relay_finder.go @@ -29,7 +29,8 @@ const protoIDv2 = circuitv2_proto.ProtoIDv2Hop // Terminology: // Candidate: Once we connect to a node and it supports relay protocol, // we call it a candidate, and consider using it as a relay. -// Relay: Out of the list of candidates, we select a relay to connect to. +// +// Relay: Out of the list candidates, the ones we have a reservation with. // Currently, we just randomly select a candidate, but we can employ more sophisticated // selection strategies here (e.g. by facotring in the RTT). @@ -37,7 +38,8 @@ const ( rsvpRefreshInterval = time.Minute rsvpExpirationSlack = 2 * time.Minute - autorelayTag = "autorelay" + autorelayTag = "autorelay" + maxRelayAddrs = 100 ) type candidate struct { @@ -72,11 +74,12 @@ type relayFinder struct { // * a candidate is deleted due to its age maybeRequestNewCandidates chan struct{} // cap: 1. - relayUpdated chan struct{} + relayReservationUpdated chan struct{} + + relayMx sync.Mutex + relays map[peer.ID]*circuitv2.Reservation - relayMx sync.Mutex - relays map[peer.ID]*circuitv2.Reservation - cachedAddrs []ma.Multiaddr + circuitAddrs []ma.Multiaddr // A channel that triggers a run of `runScheduledWork`. triggerRunScheduledWork chan struct{} @@ -92,7 +95,7 @@ func newRelayFinder(host host.Host, conf *config) (*relayFinder, error) { panic("Can not create a new relayFinder. Need a Peer Source fn or a list of static relays. Refer to the documentation around `libp2p.EnableAutoRelay`") } - emitter, err := host.EventBus().Emitter(new(event.EvtAutoRelayAddrs)) + emitter, err := host.EventBus().Emitter(new(event.EvtAutoRelayAddrsUpdated), eventbus.Stateful) if err != nil { return nil, err } @@ -109,7 +112,7 @@ func newRelayFinder(host host.Host, conf *config) (*relayFinder, error) { maybeRequestNewCandidates: make(chan struct{}, 1), triggerRunScheduledWork: make(chan struct{}, 1), relays: make(map[peer.ID]*circuitv2.Reservation), - relayUpdated: make(chan struct{}, 1), + relayReservationUpdated: make(chan struct{}, 1), metricsTracer: &wrappedMetricsTracer{conf.metricsTracer}, emitter: emitter, }, nil @@ -123,6 +126,45 @@ type scheduledWorkTimes struct { nextAllowedCallToPeerSource time.Time } +func (rf *relayFinder) cleanupDisconnectedPeers(ctx context.Context) { + subConnectedness, err := rf.host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged), eventbus.Name("autorelay (relay finder)"), eventbus.BufSize(32)) + if err != nil { + log.Error("failed to subscribe to the EvtPeerConnectednessChanged") + return + } + defer subConnectedness.Close() + for { + select { + case <-ctx.Done(): + return + case ev, ok := <-subConnectedness.Out(): + if !ok { + return + } + evt := ev.(event.EvtPeerConnectednessChanged) + if evt.Connectedness != network.NotConnected { + continue + } + push := false + + rf.relayMx.Lock() + if rf.usingRelay(evt.Peer) { // we were disconnected from a relay + log.Debugw("disconnected from relay", "id", evt.Peer) + delete(rf.relays, evt.Peer) + rf.notifyMaybeConnectToRelay() + rf.notifyMaybeNeedNewCandidates() + push = true + } + rf.relayMx.Unlock() + + if push { + rf.notifyRelayReservationUpdated() + rf.metricsTracer.ReservationEnded(1) + } + } + } +} + func (rf *relayFinder) background(ctx context.Context) { peerSourceRateLimiter := make(chan struct{}, 1) rf.refCount.Add(1) @@ -137,13 +179,6 @@ func (rf *relayFinder) background(ctx context.Context) { rf.handleNewCandidates(ctx) }() - subConnectedness, err := rf.host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged), eventbus.Name("autorelay (relay finder)")) - if err != nil { - log.Error("failed to subscribe to the EvtPeerConnectednessChanged") - return - } - defer subConnectedness.Close() - now := rf.conf.clock.Now() bootDelayTimer := rf.conf.clock.InstantTimer(now.Add(rf.conf.bootDelay)) defer bootDelayTimer.Stop() @@ -172,38 +207,18 @@ func (rf *relayFinder) background(ctx context.Context) { workTimer := rf.conf.clock.InstantTimer(rf.runScheduledWork(ctx, now, scheduledWork, peerSourceRateLimiter)) defer workTimer.Stop() + go rf.cleanupDisconnectedPeers(ctx) + + // update addrs on starting the relay finder. + rf.updateAddrs() for { select { - case ev, ok := <-subConnectedness.Out(): - if !ok { - return - } - evt := ev.(event.EvtPeerConnectednessChanged) - if evt.Connectedness != network.NotConnected { - continue - } - push := false - - rf.relayMx.Lock() - if rf.usingRelay(evt.Peer) { // we were disconnected from a relay - log.Debugw("disconnected from relay", "id", evt.Peer) - delete(rf.relays, evt.Peer) - rf.notifyMaybeConnectToRelay() - rf.notifyMaybeNeedNewCandidates() - push = true - } - rf.relayMx.Unlock() - - if push { - rf.clearCachedAddrsAndSignalAddressChange() - rf.metricsTracer.ReservationEnded(1) - } case <-rf.candidateFound: rf.notifyMaybeConnectToRelay() case <-bootDelayTimer.Ch(): rf.notifyMaybeConnectToRelay() - case <-rf.relayUpdated: - rf.clearCachedAddrsAndSignalAddressChange() + case <-rf.relayReservationUpdated: + rf.updateAddrs() case now := <-workTimer.Ch(): // Note: `now` is not guaranteed to be the current time. It's the time // that the timer was fired. This is okay because we'll schedule @@ -219,26 +234,39 @@ func (rf *relayFinder) background(ctx context.Context) { } } -func (rf *relayFinder) clearCachedAddrsAndSignalAddressChange() { - rf.relayMx.Lock() - oldAddrs := rf.cachedAddrs - rf.cachedAddrs = rf.relayAddrsUnlocked() - newAddrs := rf.cachedAddrs - rf.relayMx.Unlock() +func (rf *relayFinder) updateAddrs() { + oldAddrs := rf.circuitAddrs + rf.circuitAddrs = rf.getCircuitAddrs() - rf.metricsTracer.RelayAddressCount(len(rf.cachedAddrs)) - if haveAddrsDiff(newAddrs, oldAddrs) { - log.Debug("relay addresses updated") + if areSortedAddrsDifferent(rf.circuitAddrs, oldAddrs) { + log.Debug("relay addresses updated", rf.circuitAddrs) rf.metricsTracer.RelayAddressUpdated() - rf.emitter.Emit(event.EvtAutoRelayAddrs{RelayAddrs: newAddrs}) + rf.metricsTracer.RelayAddressCount(len(rf.circuitAddrs)) + if err := rf.emitter.Emit(event.EvtAutoRelayAddrsUpdated{RelayAddrs: slices.Clone(rf.circuitAddrs)}); err != nil { + log.Error("failed to emit event.EvtAutoRelayAddrs with RelayAddrs", rf.circuitAddrs, err) + } } } -// RelayAddrs returns the node's relay addresses -func (rf *relayFinder) RelayAddrs() []ma.Multiaddr { - rf.relayMx.Lock() - defer rf.relayMx.Unlock() - return rf.cachedAddrs +// This function returns the p2p-circuit addrs for the host. +// The returned addresses are of the form /p2p//p2p-circuit. +func (rf *relayFinder) getCircuitAddrs() []ma.Multiaddr { + raddrs := make([]ma.Multiaddr, 0, 4*len(rf.relays)+4) + for p := range rf.relays { + addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p)) + circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p)) + for _, addr := range addrs { + pub := addr.Encapsulate(circuit) + raddrs = append(raddrs, pub) + } + } + + // Sort the addresses. We depend on this order for checking diffs to send address update events. + slices.SortStableFunc(raddrs, func(a, b ma.Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) }) + if len(raddrs) > maxRelayAddrs { + raddrs = raddrs[:maxRelayAddrs] + } + return raddrs } func (rf *relayFinder) runScheduledWork(ctx context.Context, now time.Time, scheduledWork *scheduledWorkTimes, peerSourceRateLimiter chan<- struct{}) time.Time { @@ -247,7 +275,7 @@ func (rf *relayFinder) runScheduledWork(ctx context.Context, now time.Time, sche if now.After(scheduledWork.nextRefresh) { scheduledWork.nextRefresh = now.Add(rsvpRefreshInterval) if rf.refreshReservations(ctx, now) { - rf.clearCachedAddrsAndSignalAddressChange() + rf.notifyRelayReservationUpdated() } } @@ -285,7 +313,7 @@ func (rf *relayFinder) runScheduledWork(ctx context.Context, now time.Time, sche if scheduledWork.nextOldCandidateCheck.Before(nextTime) { nextTime = scheduledWork.nextOldCandidateCheck } - if nextTime == now { + if nextTime.Equal(now) { // Only happens in CI with a mock clock nextTime = nextTime.Add(1) // avoids an infinite loop } @@ -438,6 +466,13 @@ func (rf *relayFinder) notifyNewCandidate() { } } +func (rf *relayFinder) notifyRelayReservationUpdated() { + select { + case rf.relayReservationUpdated <- struct{}{}: + default: + } +} + // handleNewNode tests if a peer supports circuit v2. // This method is only run on private nodes. // If a peer does, it is added to the candidates map. @@ -597,10 +632,7 @@ func (rf *relayFinder) maybeConnectToRelay(ctx context.Context) { rf.host.ConnManager().Protect(id, autorelayTag) // protect the connection - select { - case rf.relayUpdated <- struct{}{}: - default: - } + rf.notifyRelayReservationUpdated() rf.metricsTracer.ReservationRequestFinished(false, nil) @@ -658,7 +690,6 @@ func (rf *relayFinder) refreshReservations(ctx context.Context, now time.Time) b g.Go(func() error { err := rf.refreshRelayReservation(ctx, p) rf.metricsTracer.ReservationRequestFinished(true, err) - return err }) } @@ -733,30 +764,6 @@ func (rf *relayFinder) selectCandidates() []*candidate { return candidates } -// This function computes the relay addrs when our status is private. -// The returned addresses are of the for /p2p/relay-id/p2p-circuit. -// -// caller must hold the relay lock -func (rf *relayFinder) relayAddrsUnlocked() []ma.Multiaddr { - raddrs := make([]ma.Multiaddr, 0, 4*len(rf.relays)+4) - - relayAddrCnt := 0 - for p := range rf.relays { - addrs := cleanupAddressSet(rf.host.Peerstore().Addrs(p)) - relayAddrCnt += len(addrs) - circuit := ma.StringCast(fmt.Sprintf("/p2p/%s/p2p-circuit", p)) - for _, addr := range addrs { - pub := addr.Encapsulate(circuit) - raddrs = append(raddrs, pub) - } - } - if relayAddrCnt > 100 { - slices.SortStableFunc(raddrs, func(a, b ma.Multiaddr) int { return bytes.Compare(a.Bytes(), b.Bytes()) }) - raddrs = raddrs[:100] - } - return raddrs -} - func (rf *relayFinder) Start() error { rf.ctxCancelMx.Lock() defer rf.ctxCancelMx.Unlock() @@ -816,31 +823,12 @@ func (rf *relayFinder) resetMetrics() { rf.metricsTracer.ScheduledWorkUpdated(&scheduledWorkTimes{}) } -func haveAddrsDiff(a, b []ma.Multiaddr) bool { +func areSortedAddrsDifferent(a, b []ma.Multiaddr) bool { if len(a) != len(b) { return true } - for _, aa := range a { - found := false - for _, bb := range b { - if aa.Equal(bb) { - found = true - break - } - } - if !found { - return true - } - } - for _, bb := range b { - found := false - for _, aa := range a { - if aa.Equal(bb) { - found = true - break - } - } - if !found { + for i, aa := range a { + if !aa.Equal(b[i]) { return true } } diff --git a/p2p/host/basic/address_service.go b/p2p/host/basic/address_service.go index f5e639681f..036bafb340 100644 --- a/p2p/host/basic/address_service.go +++ b/p2p/host/basic/address_service.go @@ -48,7 +48,7 @@ type addressManager struct { nodeReachability atomic.Pointer[network.Reachability] } -func NewAddressManager( +func newAddressManager( eventbus event.Bus, natmgr NATManager, addrFactory AddrsFactory, @@ -116,7 +116,7 @@ func (a *addressManager) signalAddressChange() { } func (a *addressManager) background() error { - autoRelayAddrsSub, err := a.eventbus.Subscribe(new(event.EvtAutoRelayAddrs)) + autoRelayAddrsSub, err := a.eventbus.Subscribe(new(event.EvtAutoRelayAddrsUpdated)) if err != nil { return fmt.Errorf("error subscribing to auto relay addrs: %s", err) } @@ -125,15 +125,26 @@ func (a *addressManager) background() error { if err != nil { return fmt.Errorf("error subscribing to autonat reachability: %s", err) } + // ensure that we have the correct address after returning from Start() + // update local addrs a.updateLocalAddrs() + // update relay addrs in case we're private select { case e := <-autoRelayAddrsSub.Out(): - if evt, ok := e.(*event.EvtAutoRelayAddrs); ok { + if evt, ok := e.(event.EvtAutoRelayAddrsUpdated); ok { a.updateRelayAddrs(evt.RelayAddrs) } default: } + select { + case e := <-autonatReachabilitySub.Out(): + if evt, ok := e.(event.EvtLocalReachabilityChanged); ok { + a.nodeReachability.Store(&evt.Reachability) + } + default: + } + a.wg.Add(1) go func() { defer a.wg.Done() @@ -167,7 +178,7 @@ func (a *addressManager) background() error { case <-ticker.C: case <-a.addrsChangeChan: case e := <-autoRelayAddrsSub.Out(): - if evt, ok := e.(event.EvtAutoRelayAddrs); ok { + if evt, ok := e.(event.EvtAutoRelayAddrsUpdated); ok { a.updateRelayAddrs(evt.RelayAddrs) } case e := <-autonatReachabilitySub.Out(): diff --git a/p2p/host/basic/address_service_test.go b/p2p/host/basic/address_service_test.go index bee6da1939..eaec4ec40f 100644 --- a/p2p/host/basic/address_service_test.go +++ b/p2p/host/basic/address_service_test.go @@ -154,12 +154,13 @@ func TestAddressService(t *testing.T) { h.Start() t.Cleanup(func() { h.Close() }) - rAddrEM, err := h.eventbus.Emitter(new(event.EvtAutoRelayAddrs), eventbus.Stateful) + rAddrEM, err := h.eventbus.Emitter(new(event.EvtAutoRelayAddrsUpdated), eventbus.Stateful) require.NoError(t, err) + rchEM, err := h.eventbus.Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful) require.NoError(t, err) return h.addressService, func(relayAddrs []ma.Multiaddr) { - err := rAddrEM.Emit(event.EvtAutoRelayAddrs{RelayAddrs: relayAddrs}) + err := rAddrEM.Emit(event.EvtAutoRelayAddrsUpdated{RelayAddrs: relayAddrs}) require.NoError(t, err) }, func(rch network.Reachability) { err := rchEM.Emit(event.EvtLocalReachabilityChanged{Reachability: rch}) diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go index dda03ae111..2348d64b00 100644 --- a/p2p/host/basic/basic_host.go +++ b/p2p/host/basic/basic_host.go @@ -258,7 +258,7 @@ func NewHost(n network.Network, opts *HostOpts) (*BasicHost, error) { }); ok { tfl = s.TransportForListening } - h.addressService, err = NewAddressManager(h.eventbus, natmgr, addrFactory, h.Network().ListenAddresses, tfl, h.ids) + h.addressService, err = newAddressManager(h.eventbus, natmgr, addrFactory, h.Network().ListenAddresses, tfl, h.ids) if err != nil { return nil, fmt.Errorf("failed to create address service: %w", err) } @@ -387,7 +387,7 @@ func (h *BasicHost) newStreamHandler(s network.Stream) { } else { log.Debugf("protocol mux failed: %s (took %s, id:%s, remote peer:%s, remote addr:%v)", err, took, s.ID(), s.Conn().RemotePeer(), s.Conn().RemoteMultiaddr()) } - s.Reset() + s.ResetWithError(network.StreamProtocolNegotiationFailed) return } @@ -401,7 +401,7 @@ func (h *BasicHost) newStreamHandler(s network.Stream) { if err := s.SetProtocol(protoID); err != nil { log.Debugf("error setting stream protocol: %s", err) - s.Reset() + s.ResetWithError(network.StreamResourceLimitExceeded) return } @@ -621,7 +621,7 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I } defer func() { if strErr != nil && s != nil { - s.Reset() + s.ResetWithError(network.StreamProtocolNegotiationFailed) } }() @@ -665,13 +665,14 @@ func (h *BasicHost) NewStream(ctx context.Context, p peer.ID, pids ...protocol.I return nil, fmt.Errorf("failed to negotiate protocol: %w", err) } case <-ctx.Done(): - s.Reset() + s.ResetWithError(network.StreamProtocolNegotiationFailed) // wait for `SelectOneOf` to error out because of resetting the stream. <-errCh return nil, fmt.Errorf("failed to negotiate protocol: %w", ctx.Err()) } if err := s.SetProtocol(selected); err != nil { + s.ResetWithError(network.StreamResourceLimitExceeded) return nil, err } _ = h.Peerstore().AddProtocols(p, selected) // adding the protocol to the peerstore isn't critical diff --git a/p2p/host/basic/basic_host_test.go b/p2p/host/basic/basic_host_test.go index 49dbbb87b2..5d8d009662 100644 --- a/p2p/host/basic/basic_host_test.go +++ b/p2p/host/basic/basic_host_test.go @@ -931,6 +931,9 @@ func TestHostTimeoutNewStream(t *testing.T) { require.NoError(t, err) h1.Start() defer h1.Close() + defer func() { + fmt.Println("starting close") + }() const proto = "/testing" h2 := swarmt.GenSwarm(t) diff --git a/p2p/host/peerstore/pstoreds/pb/pstore.pb.go b/p2p/host/peerstore/pstoreds/pb/pstore.pb.go index 5130bb3865..45a22c2a85 100644 --- a/p2p/host/peerstore/pstoreds/pb/pstore.pb.go +++ b/p2p/host/peerstore/pstoreds/pb/pstore.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/host/peerstore/pstoreds/pb/pstore.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -22,16 +23,15 @@ const ( // AddrBookRecord represents a record for a peer in the address book. type AddrBookRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The peer ID. Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // The multiaddresses. This is a sorted list where element 0 expires the soonest. Addrs []*AddrBookRecord_AddrEntry `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"` // The most recently received signed PeerRecord. CertifiedRecord *AddrBookRecord_CertifiedRecord `protobuf:"bytes,3,opt,name=certified_record,json=certifiedRecord,proto3" json:"certified_record,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AddrBookRecord) Reset() { @@ -87,15 +87,14 @@ func (x *AddrBookRecord) GetCertifiedRecord() *AddrBookRecord_CertifiedRecord { // AddrEntry represents a single multiaddress. type AddrBookRecord_AddrEntry struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Addr []byte `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Addr []byte `protobuf:"bytes,1,opt,name=addr,proto3" json:"addr,omitempty"` // The point in time when this address expires. Expiry int64 `protobuf:"varint,2,opt,name=expiry,proto3" json:"expiry,omitempty"` // The original TTL of this address. - Ttl int64 `protobuf:"varint,3,opt,name=ttl,proto3" json:"ttl,omitempty"` + Ttl int64 `protobuf:"varint,3,opt,name=ttl,proto3" json:"ttl,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AddrBookRecord_AddrEntry) Reset() { @@ -152,14 +151,13 @@ func (x *AddrBookRecord_AddrEntry) GetTtl() int64 { // CertifiedRecord contains a serialized signed PeerRecord used to // populate the signedAddrs list. type AddrBookRecord_CertifiedRecord struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The Seq counter from the signed PeerRecord envelope Seq uint64 `protobuf:"varint,1,opt,name=seq,proto3" json:"seq,omitempty"` // The serialized bytes of the SignedEnvelope containing the PeerRecord. - Raw []byte `protobuf:"bytes,2,opt,name=raw,proto3" json:"raw,omitempty"` + Raw []byte `protobuf:"bytes,2,opt,name=raw,proto3" json:"raw,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *AddrBookRecord_CertifiedRecord) Reset() { @@ -208,7 +206,7 @@ func (x *AddrBookRecord_CertifiedRecord) GetRaw() []byte { var File_p2p_host_peerstore_pstoreds_pb_pstore_proto protoreflect.FileDescriptor -var file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc = []byte{ +var file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc = string([]byte{ 0x0a, 0x2b, 0x70, 0x32, 0x70, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x70, 0x62, 0x2f, 0x70, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x70, @@ -237,16 +235,16 @@ var file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc = []byte{ 0x70, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x73, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescOnce sync.Once - file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData = file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc + file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData []byte ) func file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescGZIP() []byte { file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescOnce.Do(func() { - file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData) + file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc), len(file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc))) }) return file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDescData } @@ -276,7 +274,7 @@ func file_p2p_host_peerstore_pstoreds_pb_pstore_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc), len(file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc)), NumEnums: 0, NumMessages: 3, NumExtensions: 0, @@ -287,7 +285,6 @@ func file_p2p_host_peerstore_pstoreds_pb_pstore_proto_init() { MessageInfos: file_p2p_host_peerstore_pstoreds_pb_pstore_proto_msgTypes, }.Build() File_p2p_host_peerstore_pstoreds_pb_pstore_proto = out.File - file_p2p_host_peerstore_pstoreds_pb_pstore_proto_rawDesc = nil file_p2p_host_peerstore_pstoreds_pb_pstore_proto_goTypes = nil file_p2p_host_peerstore_pstoreds_pb_pstore_proto_depIdxs = nil } diff --git a/p2p/host/peerstore/pstoremem/addr_book.go b/p2p/host/peerstore/pstoremem/addr_book.go index 2520f6ef22..32758f2ab9 100644 --- a/p2p/host/peerstore/pstoremem/addr_book.go +++ b/p2p/host/peerstore/pstoremem/addr_book.go @@ -42,22 +42,6 @@ func ttlIsConnected(ttl time.Duration) bool { return ttl >= peerstore.ConnectedAddrTTL } -var expiringAddrPool = sync.Pool{New: func() any { return &expiringAddr{} }} - -func getExpiringAddrs() *expiringAddr { - a := expiringAddrPool.Get().(*expiringAddr) - a.heapIndex = -1 - return a -} - -func putExpiringAddrs(ea *expiringAddr) { - if ea == nil { - return - } - *ea = expiringAddr{} - expiringAddrPool.Put(ea) -} - type peerRecordState struct { Envelope *record.Envelope Seq uint64 @@ -280,7 +264,6 @@ func (mab *memoryAddrBook) gc() { if !ok { return } - putExpiringAddrs(ea) mab.maybeDeleteSignedPeerRecordUnlocked(ea.Peer) } } @@ -382,8 +365,7 @@ func (mab *memoryAddrBook) addAddrsUnlocked(p peer.ID, addrs []ma.Multiaddr, ttl a, found := mab.addrs.FindAddr(p, addr) if !found { // not found, announce it. - entry := getExpiringAddrs() - *entry = expiringAddr{Addr: addr, Expiry: exp, TTL: ttl, Peer: p} + entry := &expiringAddr{Addr: addr, Expiry: exp, TTL: ttl, Peer: p} mab.addrs.Insert(entry) mab.subManager.BroadcastAddr(p, addr) } else { @@ -433,7 +415,6 @@ func (mab *memoryAddrBook) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Du if ttl > 0 { if a.IsConnected() && !ttlIsConnected(ttl) && mab.addrs.NumUnconnectedAddrs() >= mab.maxUnconnectedAddrs { mab.addrs.Delete(a) - putExpiringAddrs(a) } else { a.Addr = addr a.Expiry = exp @@ -443,15 +424,13 @@ func (mab *memoryAddrBook) SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Du } } else { mab.addrs.Delete(a) - putExpiringAddrs(a) } } else { if ttl > 0 { if !ttlIsConnected(ttl) && mab.addrs.NumUnconnectedAddrs() >= mab.maxUnconnectedAddrs { continue } - entry := getExpiringAddrs() - *entry = expiringAddr{Addr: addr, Expiry: exp, TTL: ttl, Peer: p} + entry := &expiringAddr{Addr: addr, Expiry: exp, TTL: ttl, Peer: p} mab.addrs.Insert(entry) mab.subManager.BroadcastAddr(p, addr) } @@ -472,12 +451,10 @@ func (mab *memoryAddrBook) UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL t if oldTTL == a.TTL { if newTTL == 0 { mab.addrs.Delete(a) - putExpiringAddrs(a) } else { // We are over limit, drop these addresses. if ttlIsConnected(oldTTL) && !ttlIsConnected(newTTL) && mab.addrs.NumUnconnectedAddrs() >= mab.maxUnconnectedAddrs { mab.addrs.Delete(a) - putExpiringAddrs(a) } else { a.TTL = newTTL a.Expiry = exp @@ -541,7 +518,6 @@ func (mab *memoryAddrBook) ClearAddrs(p peer.ID) { delete(mab.signedPeerRecords, p) for _, a := range mab.addrs.Addrs[p] { mab.addrs.Delete(a) - putExpiringAddrs(a) } } diff --git a/p2p/host/peerstore/pstoremem/peerstore.go b/p2p/host/peerstore/pstoremem/peerstore.go index d5a41cc56a..15383f068e 100644 --- a/p2p/host/peerstore/pstoremem/peerstore.go +++ b/p2p/host/peerstore/pstoremem/peerstore.go @@ -26,28 +26,26 @@ type Option interface{} // It's the caller's responsibility to call RemovePeer to ensure // that memory consumption of the peerstore doesn't grow unboundedly. func NewPeerstore(opts ...Option) (ps *pstoremem, err error) { - ab := NewAddrBook() - defer func() { - if err != nil { - ab.Close() - } - }() - var protoBookOpts []ProtoBookOption + var addrBookOpts []AddrBookOption for _, opt := range opts { switch o := opt.(type) { case ProtoBookOption: protoBookOpts = append(protoBookOpts, o) case AddrBookOption: - o(ab) + addrBookOpts = append(addrBookOpts, o) default: return nil, fmt.Errorf("unexpected peer store option: %v", o) } } + ab := NewAddrBook(addrBookOpts...) + pb, err := NewProtoBook(protoBookOpts...) if err != nil { + ab.Close() return nil, err } + return &pstoremem{ Metrics: pstore.NewMetrics(), memoryKeyBook: NewKeyBook(), diff --git a/p2p/host/peerstore/pstoremem/peerstore_test.go b/p2p/host/peerstore/pstoremem/peerstore_test.go new file mode 100644 index 0000000000..5a07e266da --- /dev/null +++ b/p2p/host/peerstore/pstoremem/peerstore_test.go @@ -0,0 +1,23 @@ +package pstoremem + +import ( + "testing" + + "github.com/libp2p/go-libp2p/core/peerstore" + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestPeerStoreAddrBookOpts(t *testing.T) { + ps, err := NewPeerstore(WithMaxAddresses(1)) + require.NoError(t, err) + defer ps.Close() + + ps.AddAddr("p1", ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"), peerstore.TempAddrTTL) + res := ps.Addrs("p1") + require.NotEmpty(t, res) + + ps.AddAddr("p2", ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1"), peerstore.TempAddrTTL) + res = ps.Addrs("p2") + require.Empty(t, res) +} diff --git a/p2p/host/peerstore/test/benchmarks_suite.go b/p2p/host/peerstore/test/benchmarks_suite.go index d45cac897e..01669a1b2d 100644 --- a/p2p/host/peerstore/test/benchmarks_suite.go +++ b/p2p/host/peerstore/test/benchmarks_suite.go @@ -1,124 +1,79 @@ package test import ( - "context" "fmt" - "sort" "testing" pstore "github.com/libp2p/go-libp2p/core/peerstore" ) -var peerstoreBenchmarks = map[string]func(pstore.Peerstore, chan *peerpair) func(*testing.B){ - "AddAddrs": benchmarkAddAddrs, - "SetAddrs": benchmarkSetAddrs, - "GetAddrs": benchmarkGetAddrs, - // The in-between get allows us to benchmark the read-through cache. - "AddGetAndClearAddrs": benchmarkAddGetAndClearAddrs, - // Calls PeersWithAddr on a peerstore with 1000 peers. - "Get1000PeersWithAddrs": benchmarkGet1000PeersWithAddrs, -} - func BenchmarkPeerstore(b *testing.B, factory PeerstoreFactory, variant string) { - // Parameterises benchmarks to tackle peers with 1, 10, 100 multiaddrs. - params := []struct { - n int - ch chan *peerpair - }{ - {1, make(chan *peerpair, 100)}, - {10, make(chan *peerpair, 100)}, - {100, make(chan *peerpair, 100)}, - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // Start all test peer producing goroutines, where each produces peers with as many - // multiaddrs as the n field in the param struct. - for _, p := range params { - go AddressProducer(ctx, b, p.ch, p.n) - } - - // So tests are always run in the same order. - ordernames := make([]string, 0, len(peerstoreBenchmarks)) - for name := range peerstoreBenchmarks { - ordernames = append(ordernames, name) - } - sort.Strings(ordernames) - - for _, name := range ordernames { - bench := peerstoreBenchmarks[name] - for _, p := range params { - // Create a new peerstore. - ps, closeFunc := factory() - - // Run the test. - b.Run(fmt.Sprintf("%s-%dAddrs-%s", name, p.n, variant), bench(ps, p.ch)) - - // Cleanup. - if closeFunc != nil { - closeFunc() + for _, sz := range []int{1, 10, 100} { + const N = 10000 + peers := getPeerPairs(b, N, sz) + + b.Run(fmt.Sprintf("AddAddrs-%d", sz), func(b *testing.B) { + ps, cleanup := factory() + defer cleanup() + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp := peers[i%N] + ps.AddAddrs(pp.ID, pp.Addr, pstore.RecentlyConnectedAddrTTL) } - } - } -} - -func benchmarkAddAddrs(ps pstore.Peerstore, addrs chan *peerpair) func(*testing.B) { - return func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - pp := <-addrs - ps.AddAddrs(pp.ID, pp.Addr, pstore.PermanentAddrTTL) - } - } -} - -func benchmarkSetAddrs(ps pstore.Peerstore, addrs chan *peerpair) func(*testing.B) { - return func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - pp := <-addrs - ps.SetAddrs(pp.ID, pp.Addr, pstore.PermanentAddrTTL) - } - } -} - -func benchmarkGetAddrs(ps pstore.Peerstore, addrs chan *peerpair) func(*testing.B) { - return func(b *testing.B) { - pp := <-addrs - ps.SetAddrs(pp.ID, pp.Addr, pstore.PermanentAddrTTL) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ps.Addrs(pp.ID) - } - } -} - -func benchmarkAddGetAndClearAddrs(ps pstore.Peerstore, addrs chan *peerpair) func(*testing.B) { - return func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - pp := <-addrs - ps.AddAddrs(pp.ID, pp.Addr, pstore.PermanentAddrTTL) - ps.Addrs(pp.ID) - ps.ClearAddrs(pp.ID) - } - } -} + }) + + b.Run(fmt.Sprintf("GetAddrs-%d", sz), func(b *testing.B) { + ps, cleanup := factory() + defer cleanup() + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp := peers[i%N] + ps.SetAddrs(pp.ID, pp.Addr, pstore.RecentlyConnectedAddrTTL) + } + }) + + b.Run(fmt.Sprintf("GetAndClearAddrs-%d", sz), func(b *testing.B) { + ps, cleanup := factory() + defer cleanup() + b.ResetTimer() + itersPerBM := 10 + for i := 0; i < b.N; i++ { + for j := 0; j < itersPerBM; j++ { + pp := peers[(i+j)%N] + ps.AddAddrs(pp.ID, pp.Addr, pstore.RecentlyConnectedAddrTTL) + } + for j := 0; j < itersPerBM; j++ { + pp := peers[(i+j)%N] + ps.Addrs(pp.ID) + } + for j := 0; j < itersPerBM; j++ { + pp := peers[(i+j)%N] + ps.ClearAddrs(pp.ID) + } + } + }) -func benchmarkGet1000PeersWithAddrs(ps pstore.Peerstore, addrs chan *peerpair) func(*testing.B) { - return func(b *testing.B) { - var peers = make([]*peerpair, 1000) - for i := range peers { - pp := <-addrs - ps.AddAddrs(pp.ID, pp.Addr, pstore.PermanentAddrTTL) - peers[i] = pp - } + b.Run(fmt.Sprintf("PeersWithAddrs-%d", sz), func(b *testing.B) { + ps, cleanup := factory() + defer cleanup() + for _, pp := range peers { + ps.AddAddrs(pp.ID, pp.Addr, pstore.RecentlyConnectedAddrTTL) + } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = ps.PeersWithAddrs() - } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = ps.PeersWithAddrs() + } + }) + + b.Run(fmt.Sprintf("SetAddrs-%d", sz), func(b *testing.B) { + ps, cleanup := factory() + defer cleanup() + b.ResetTimer() + for i := 0; i < b.N; i++ { + pp := peers[i%N] + ps.SetAddrs(pp.ID, pp.Addr, pstore.RecentlyConnectedAddrTTL) + } + }) } } diff --git a/p2p/host/peerstore/test/utils.go b/p2p/host/peerstore/test/utils.go index 254b713957..cb7309290c 100644 --- a/p2p/host/peerstore/test/utils.go +++ b/p2p/host/peerstore/test/utils.go @@ -1,7 +1,6 @@ package test import ( - "context" "fmt" "testing" @@ -45,17 +44,12 @@ func RandomPeer(b *testing.B, addrCount int) *peerpair { return &peerpair{pid, addrs} } -func AddressProducer(ctx context.Context, b *testing.B, addrs chan *peerpair, addrsPerPeer int) { - b.Helper() - defer close(addrs) - for { - p := RandomPeer(b, addrsPerPeer) - select { - case addrs <- p: - case <-ctx.Done(): - return - } +func getPeerPairs(b *testing.B, n int, addrsPerPeer int) []*peerpair { + pps := make([]*peerpair, n) + for i := 0; i < n; i++ { + pps[i] = RandomPeer(b, addrsPerPeer) } + return pps } func GenerateAddrs(count int) []ma.Multiaddr { diff --git a/p2p/http/auth/auth_test.go b/p2p/http/auth/auth_test.go index d080b19511..9d1b4688d4 100644 --- a/p2p/http/auth/auth_test.go +++ b/p2p/http/auth/auth_test.go @@ -2,11 +2,9 @@ package httppeeridauth import ( "bytes" - "crypto/hmac" "crypto/rand" - "crypto/sha256" "crypto/tls" - "hash" + "fmt" "io" "net/http" "net/http/httptest" @@ -171,14 +169,12 @@ func TestMutualAuth(t *testing.T) { t.Run("Tokens Invalidated", func(t *testing.T) { // Clear the auth token on the server side - server.Hmac = func() hash.Hash { - key := make([]byte, 32) - _, err := rand.Read(key) - if err != nil { - panic(err) - } - return hmac.New(sha256.New, key) - }() + key := make([]byte, 32) + _, err := rand.Read(key) + if err != nil { + panic(err) + } + server.hmacPool = newHmacPool(key) req, err := http.NewRequest("POST", ts.URL, nil) req.GetBody = func() (io.ReadCloser, error) { @@ -241,3 +237,51 @@ func (irt *instrumentedRoundTripper) RoundTrip(req *http.Request) (*http.Respons func (irt *instrumentedRoundTripper) TLSClientConfig() *tls.Config { return irt.RoundTripper.(*http.Transport).TLSClientConfig } + +func TestConcurrentAuth(t *testing.T) { + serverKey, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + auth := ServerPeerIDAuth{ + PrivKey: serverKey, + ValidHostnameFn: func(s string) bool { + return s == "example.com" + }, + TokenTTL: time.Hour, + NoTLS: true, + Next: func(peer peer.ID, w http.ResponseWriter, r *http.Request) { + reqBody, err := io.ReadAll(r.Body) + require.NoError(t, err) + _, err = w.Write(reqBody) + require.NoError(t, err) + }, + } + + ts := httptest.NewServer(&auth) + t.Cleanup(ts.Close) + + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + clientKey, _, err := crypto.GenerateEd25519Key(rand.Reader) + require.NoError(t, err) + + clientAuth := ClientPeerIDAuth{PrivKey: clientKey} + reqBody := []byte(fmt.Sprintf("echo %d", i)) + req, err := http.NewRequest("POST", ts.URL, bytes.NewReader(reqBody)) + require.NoError(t, err) + req.Host = "example.com" + + client := ts.Client() + _, resp, err := clientAuth.AuthenticatedDo(client, req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + respBody, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, reqBody, respBody) + }() + } + wg.Wait() +} diff --git a/p2p/http/auth/server.go b/p2p/http/auth/server.go index 3ee4f96dc8..b17c3fccf1 100644 --- a/p2p/http/auth/server.go +++ b/p2p/http/auth/server.go @@ -15,6 +15,30 @@ import ( "github.com/libp2p/go-libp2p/p2p/http/auth/internal/handshake" ) +type hmacPool struct { + p sync.Pool +} + +func newHmacPool(key []byte) *hmacPool { + return &hmacPool{ + p: sync.Pool{ + New: func() any { + return hmac.New(sha256.New, key) + }, + }, + } +} + +func (p *hmacPool) Get() hash.Hash { + h := p.p.Get().(hash.Hash) + h.Reset() + return h +} + +func (p *hmacPool) Put(h hash.Hash) { + p.p.Put(h) +} + type ServerPeerIDAuth struct { PrivKey crypto.PrivKey TokenTTL time.Duration @@ -26,8 +50,9 @@ type ServerPeerIDAuth struct { // which the Host header returns true. ValidHostnameFn func(hostname string) bool - Hmac hash.Hash + HmacKey []byte initHmac sync.Once + hmacPool *hmacPool } // ServeHTTP implements the http.Handler interface for PeerIDAuth. It will @@ -36,14 +61,15 @@ type ServerPeerIDAuth struct { // requests. func (a *ServerPeerIDAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) { a.initHmac.Do(func() { - if a.Hmac == nil { + if a.HmacKey == nil { key := make([]byte, 32) _, err := rand.Read(key) if err != nil { panic(err) } - a.Hmac = hmac.New(sha256.New, key) + a.HmacKey = key } + a.hmacPool = newHmacPool(a.HmacKey) }) hostname := r.Host @@ -76,11 +102,13 @@ func (a *ServerPeerIDAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } + hmac := a.hmacPool.Get() + defer a.hmacPool.Put(hmac) hs := handshake.PeerIDAuthHandshakeServer{ Hostname: hostname, PrivKey: a.PrivKey, TokenTTL: a.TokenTTL, - Hmac: a.Hmac, + Hmac: hmac, } err := hs.ParseHeaderVal([]byte(r.Header.Get("Authorization"))) if err != nil { @@ -95,11 +123,12 @@ func (a *ServerPeerIDAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) { errors.Is(err, handshake.ErrExpiredChallenge), errors.Is(err, handshake.ErrExpiredToken): + hmac.Reset() hs := handshake.PeerIDAuthHandshakeServer{ Hostname: hostname, PrivKey: a.PrivKey, TokenTTL: a.TokenTTL, - Hmac: a.Hmac, + Hmac: hmac, } hs.Run() hs.SetHeader(w.Header()) diff --git a/p2p/muxer/testsuite/mux.go b/p2p/muxer/testsuite/mux.go index 5b47117fd6..93d24785ea 100644 --- a/p2p/muxer/testsuite/mux.go +++ b/p2p/muxer/testsuite/mux.go @@ -4,6 +4,7 @@ import ( "bytes" "context" crand "crypto/rand" + "errors" "fmt" "io" mrand "math/rand" @@ -462,7 +463,7 @@ func SubtestStreamReset(t *testing.T, tr network.Multiplexer) { time.Sleep(time.Millisecond * 50) _, err = s.Write([]byte("foo")) - if err != network.ErrReset { + if !errors.Is(err, network.ErrReset) { t.Error("should have been stream reset") } s.Close() diff --git a/p2p/muxer/yamux/conn.go b/p2p/muxer/yamux/conn.go index 40c4af4052..54a856e58c 100644 --- a/p2p/muxer/yamux/conn.go +++ b/p2p/muxer/yamux/conn.go @@ -5,7 +5,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-yamux/v4" + "github.com/libp2p/go-yamux/v5" ) // conn implements mux.MuxedConn over yamux.Session. @@ -23,6 +23,10 @@ func (c *conn) Close() error { return c.yamux().Close() } +func (c *conn) CloseWithError(errCode network.ConnErrorCode) error { + return c.yamux().CloseWithError(uint32(errCode)) +} + // IsClosed checks if yamux.Session is in closed state. func (c *conn) IsClosed() bool { return c.yamux().IsClosed() @@ -32,7 +36,7 @@ func (c *conn) IsClosed() bool { func (c *conn) OpenStream(ctx context.Context) (network.MuxedStream, error) { s, err := c.yamux().OpenStream(ctx) if err != nil { - return nil, err + return nil, parseError(err) } return (*stream)(s), nil @@ -41,7 +45,7 @@ func (c *conn) OpenStream(ctx context.Context) (network.MuxedStream, error) { // AcceptStream accepts a stream opened by the other side. func (c *conn) AcceptStream() (network.MuxedStream, error) { s, err := c.yamux().AcceptStream() - return (*stream)(s), err + return (*stream)(s), parseError(err) } func (c *conn) yamux() *yamux.Session { diff --git a/p2p/muxer/yamux/stream.go b/p2p/muxer/yamux/stream.go index b50bc0bb87..450bdec479 100644 --- a/p2p/muxer/yamux/stream.go +++ b/p2p/muxer/yamux/stream.go @@ -1,11 +1,13 @@ package yamux import ( + "errors" + "fmt" "time" "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-yamux/v4" + "github.com/libp2p/go-yamux/v5" ) // stream implements mux.MuxedStream over yamux.Stream. @@ -13,22 +15,32 @@ type stream yamux.Stream var _ network.MuxedStream = &stream{} -func (s *stream) Read(b []byte) (n int, err error) { - n, err = s.yamux().Read(b) - if err == yamux.ErrStreamReset { - err = network.ErrReset +func parseError(err error) error { + if err == nil { + return err + } + se := &yamux.StreamError{} + if errors.As(err, &se) { + return &network.StreamError{Remote: se.Remote, ErrorCode: network.StreamErrorCode(se.ErrorCode), TransportError: err} } + ce := &yamux.GoAwayError{} + if errors.As(err, &ce) { + return &network.ConnError{Remote: ce.Remote, ErrorCode: network.ConnErrorCode(ce.ErrorCode), TransportError: err} + } + if errors.Is(err, yamux.ErrStreamReset) { + return fmt.Errorf("%w: %w", network.ErrReset, err) + } + return err +} - return n, err +func (s *stream) Read(b []byte) (n int, err error) { + n, err = s.yamux().Read(b) + return n, parseError(err) } func (s *stream) Write(b []byte) (n int, err error) { n, err = s.yamux().Write(b) - if err == yamux.ErrStreamReset { - err = network.ErrReset - } - - return n, err + return n, parseError(err) } func (s *stream) Close() error { @@ -39,6 +51,10 @@ func (s *stream) Reset() error { return s.yamux().Reset() } +func (s *stream) ResetWithError(errCode network.StreamErrorCode) error { + return s.yamux().ResetWithError(uint32(errCode)) +} + func (s *stream) CloseRead() error { return s.yamux().CloseRead() } diff --git a/p2p/muxer/yamux/transport.go b/p2p/muxer/yamux/transport.go index 3273836331..8350abdd86 100644 --- a/p2p/muxer/yamux/transport.go +++ b/p2p/muxer/yamux/transport.go @@ -7,7 +7,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-yamux/v4" + "github.com/libp2p/go-yamux/v5" ) var DefaultTransport *Transport diff --git a/p2p/net/connmgr/connmgr.go b/p2p/net/connmgr/connmgr.go index 5033538e3b..c2cd307259 100644 --- a/p2p/net/connmgr/connmgr.go +++ b/p2p/net/connmgr/connmgr.go @@ -175,7 +175,8 @@ func (cm *BasicConnMgr) memoryEmergency() { // Trim connections without paying attention to the silence period. for _, c := range cm.getConnsToCloseEmergency(target) { log.Infow("low on memory. closing conn", "peer", c.RemotePeer()) - c.Close() + + c.CloseWithError(network.ConnGarbageCollected) } // finally, update the last trim time. @@ -388,7 +389,7 @@ func (cm *BasicConnMgr) trim() { // do the actual trim. for _, c := range cm.getConnsToClose() { log.Debugw("closing conn", "peer", c.RemotePeer()) - c.Close() + c.CloseWithError(network.ConnGarbageCollected) } } diff --git a/p2p/net/connmgr/connmgr_test.go b/p2p/net/connmgr/connmgr_test.go index 2c657255f0..f47557b02c 100644 --- a/p2p/net/connmgr/connmgr_test.go +++ b/p2p/net/connmgr/connmgr_test.go @@ -11,8 +11,11 @@ import ( "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" + "github.com/libp2p/go-libp2p/core/peerstore" tu "github.com/libp2p/go-libp2p/core/test" + swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" + ma "github.com/multiformats/go-multiaddr" "github.com/stretchr/testify/require" ) @@ -33,6 +36,14 @@ func (c *tconn) Close() error { return nil } +func (c *tconn) CloseWithError(code network.ConnErrorCode) error { + atomic.StoreUint32(&c.closed, 1) + if c.disconnectNotify != nil { + c.disconnectNotify(nil, c) + } + return nil +} + func (c *tconn) isClosed() bool { return atomic.LoadUint32(&c.closed) == 1 } @@ -794,6 +805,7 @@ type mockConn struct { } func (m mockConn) Close() error { panic("implement me") } +func (m mockConn) CloseWithError(errCode network.ConnErrorCode) error { panic("implement me") } func (m mockConn) LocalPeer() peer.ID { panic("implement me") } func (m mockConn) RemotePeer() peer.ID { panic("implement me") } func (m mockConn) RemotePublicKey() crypto.PubKey { panic("implement me") } @@ -986,3 +998,79 @@ type testLimitGetter struct { func (g testLimitGetter) GetConnLimit() int { return g.limit } + +func TestErrorCode(t *testing.T) { + sw1, sw2, sw3 := swarmt.GenSwarm(t), swarmt.GenSwarm(t), swarmt.GenSwarm(t) + defer sw1.Close() + defer sw2.Close() + defer sw3.Close() + + cm, err := NewConnManager(1, 1, WithGracePeriod(0), WithSilencePeriod(10)) + require.NoError(t, err) + defer cm.Close() + + sw1.Peerstore().AddAddrs(sw2.LocalPeer(), sw2.ListenAddresses(), peerstore.PermanentAddrTTL) + sw1.Peerstore().AddAddrs(sw3.LocalPeer(), sw3.ListenAddresses(), peerstore.PermanentAddrTTL) + + c12, err := sw1.DialPeer(context.Background(), sw2.LocalPeer()) + require.NoError(t, err) + + var c21 network.Conn + require.Eventually(t, func() bool { + conns := sw2.ConnsToPeer(sw1.LocalPeer()) + if len(conns) == 0 { + return false + } + c21 = conns[0] + return true + }, 10*time.Second, 100*time.Millisecond) + + c13, err := sw1.DialPeer(context.Background(), sw3.LocalPeer()) + require.NoError(t, err) + + var c31 network.Conn + require.Eventually(t, func() bool { + conns := sw3.ConnsToPeer(sw1.LocalPeer()) + if len(conns) == 0 { + return false + } + c31 = conns[0] + return true + }, 10*time.Second, 100*time.Millisecond) + + not := cm.Notifee() + not.Connected(sw1, c12) + not.Connected(sw1, c13) + + cm.TrimOpenConns(context.Background()) + + require.True(t, c12.IsClosed() || c13.IsClosed()) + var c, cr network.Conn + if c12.IsClosed() { + c = c12 + require.Eventually(t, func() bool { + conns := sw2.ConnsToPeer(sw1.LocalPeer()) + if len(conns) == 0 { + cr = c21 + return true + } + return false + }, 5*time.Second, 100*time.Millisecond) + } else { + c = c13 + require.Eventually(t, func() bool { + conns := sw3.ConnsToPeer(sw1.LocalPeer()) + if len(conns) == 0 { + cr = c31 + return true + } + return false + }, 5*time.Second, 100*time.Millisecond) + } + + _, err = c.NewStream(context.Background()) + require.ErrorIs(t, err, &network.ConnError{ErrorCode: network.ConnGarbageCollected, Remote: false}) + + _, err = cr.NewStream(context.Background()) + require.ErrorIs(t, err, &network.ConnError{ErrorCode: network.ConnGarbageCollected, Remote: true}) +} diff --git a/p2p/net/mock/mock_conn.go b/p2p/net/mock/mock_conn.go index 8c3dc87299..fc4e0ad670 100644 --- a/p2p/net/mock/mock_conn.go +++ b/p2p/net/mock/mock_conn.go @@ -185,3 +185,7 @@ func (c *conn) Stat() network.ConnStats { func (c *conn) Scope() network.ConnScope { return &network.NullScope{} } + +func (c *conn) CloseWithError(_ network.ConnErrorCode) error { + return c.Close() +} diff --git a/p2p/net/mock/mock_stream.go b/p2p/net/mock/mock_stream.go index c85cca544d..27e32d9e9e 100644 --- a/p2p/net/mock/mock_stream.go +++ b/p2p/net/mock/mock_stream.go @@ -144,6 +144,24 @@ func (s *stream) Reset() error { return nil } +// ResetWithError resets the stream. It ignores the provided error code. +// TODO: Implement error code support. +func (s *stream) ResetWithError(_ network.StreamErrorCode) error { + // Cancel any pending reads/writes with an error. + + s.write.CloseWithError(network.ErrReset) + s.read.CloseWithError(network.ErrReset) + + select { + case s.reset <- struct{}{}: + default: + } + <-s.closed + + // No meaningful error case here. + return nil +} + func (s *stream) teardown() { // at this point, no streams are writing. s.conn.removeStream(s) diff --git a/p2p/net/nat/nat.go b/p2p/net/nat/nat.go index 1701ca8e00..7713c6c5fe 100644 --- a/p2p/net/nat/nat.go +++ b/p2p/net/nat/nat.go @@ -6,6 +6,7 @@ import ( "fmt" "net/netip" "sync" + "sync/atomic" "time" logging "github.com/ipfs/go-log/v2" @@ -55,11 +56,11 @@ func DiscoverNAT(ctx context.Context) (*NAT, error) { ctx, cancel := context.WithCancel(context.Background()) nat := &NAT{ nat: natInstance, - extAddr: extAddr, mappings: make(map[entry]int), ctx: ctx, ctxCancel: cancel, } + nat.extAddr.Store(&extAddr) nat.refCount.Add(1) go func() { defer nat.refCount.Done() @@ -76,7 +77,7 @@ type NAT struct { natmu sync.Mutex nat nat.NAT // External IP of the NAT. Will be renewed periodically (every CacheTime). - extAddr netip.Addr + extAddr atomic.Pointer[netip.Addr] refCount sync.WaitGroup ctx context.Context @@ -102,14 +103,15 @@ func (nat *NAT) GetMapping(protocol string, port int) (addr netip.AddrPort, foun nat.mappingmu.Lock() defer nat.mappingmu.Unlock() - if !nat.extAddr.IsValid() { + if !nat.extAddr.Load().IsValid() { return netip.AddrPort{}, false } extPort, found := nat.mappings[entry{protocol: protocol, port: port}] - if !found { + // The mapping may have an invalid port. + if !found || extPort == 0 { return netip.AddrPort{}, false } - return netip.AddrPortFrom(nat.extAddr, uint16(extPort)), true + return netip.AddrPortFrom(*nat.extAddr.Load(), uint16(extPort)), true } // AddMapping attempts to construct a mapping on protocol and internal port. @@ -134,6 +136,9 @@ func (nat *NAT) AddMapping(ctx context.Context, protocol string, port int) error // do it once synchronously, so first mapping is done right away, and before exiting, // allowing users -- in the optimistic case -- to use results right after. extPort := nat.establishMapping(ctx, protocol, port) + // Don't validate the mapping here, we refresh the mappings based on this map. + // We can try getting a port again in case it succeeds. In the worst case, + // this is one extra LAN request every few minutes. nat.mappings[entry{protocol: protocol, port: port}] = extPort return nil } @@ -201,7 +206,7 @@ func (nat *NAT) background() { if err == nil { extAddr, _ = netip.AddrFromSlice(extIP) } - nat.extAddr = extAddr + nat.extAddr.Store(&extAddr) nextAddrUpdate = time.Now().Add(CacheTime) } t.Reset(time.Until(minTime(nextAddrUpdate, nextMappingUpdate))) diff --git a/p2p/net/nat/nat_test.go b/p2p/net/nat/nat_test.go index 772c876c72..e370fc8907 100644 --- a/p2p/net/nat/nat_test.go +++ b/p2p/net/nat/nat_test.go @@ -68,3 +68,18 @@ func TestRemoveMapping(t *testing.T) { _, found = nat.GetMapping("tcp", 10000) require.False(t, found, "didn't expect port mapping for deleted mapping") } + +func TestAddMappingInvalidPort(t *testing.T) { + mockNAT, reset := setupMockNAT(t) + defer reset() + + mockNAT.EXPECT().GetExternalAddress().Return(net.IPv4(1, 2, 3, 4), nil) + nat, err := DiscoverNAT(context.Background()) + require.NoError(t, err) + + mockNAT.EXPECT().AddPortMapping(gomock.Any(), "tcp", 10000, gomock.Any(), MappingDuration).Return(0, nil) + require.NoError(t, nat.AddMapping(context.Background(), "tcp", 10000)) + + _, found := nat.GetMapping("tcp", 10000) + require.False(t, found, "didn't expect a port mapping for invalid nat-ed port") +} diff --git a/p2p/net/swarm/dial_ranker.go b/p2p/net/swarm/dial_ranker.go index 7e58876b91..154a0344a1 100644 --- a/p2p/net/swarm/dial_ranker.go +++ b/p2p/net/swarm/dial_ranker.go @@ -22,11 +22,15 @@ const ( // RelayDelay is the duration by which relay dials are delayed relative to direct addresses RelayDelay = 500 * time.Millisecond + + // delay for other transport addresses. This will apply to /webrtc-direct. + PublicOtherDelay = 1 * time.Second + PrivateOtherDelay = 100 * time.Millisecond ) // NoDelayDialRanker ranks addresses with no delay. This is useful for simultaneous connect requests. func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { - return getAddrDelay(addrs, 0, 0, 0) + return getAddrDelay(addrs, 0, 0, 0, 0) } // DefaultDialRanker determines the ranking of outgoing connection attempts. @@ -67,8 +71,11 @@ func NoDelayDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { // 5. If only one of TCP IPv6 or TCP IPv4 addresses are present, dial the TCP address with the lowest port // first. After this we dial the rest of the TCP addresses delayed by 250ms (PublicTCPDelay) for public // addresses, and 30ms (PrivateTCPDelay) for local addresses. -// 6. When a TCP socket is connected and awaiting security and muxer upgrade, we stop new dials for 2*PrivateTCPDelay +// 6. When a TCP socket is connected and awaiting security and muxer upgrade, we stop new dials for 2*PublicTCPDelay // to allow for the upgrade to complete. +// 7. WebRTC Direct, and other IP transport addresses are dialed 1 second after the last QUIC or TCP dial. +// We only ever need to dial these if the peer doesn't have any other transport available, in which +// case these are dialed immediately. // // We dial lowest ports first as they are more likely to be the listen port. func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { @@ -83,13 +90,18 @@ func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { } res := make([]network.AddrDelay, 0, len(addrs)) + res = append(res, getAddrDelay(pvt, PrivateTCPDelay, PrivateQUICDelay, PrivateOtherDelay, 0)...) + res = append(res, getAddrDelay(public, PublicTCPDelay, PublicQUICDelay, PublicOtherDelay, 0)...) + res = append(res, getAddrDelay(relay, PublicTCPDelay, PublicQUICDelay, PublicOtherDelay, relayOffset)...) + var maxDelay time.Duration + if len(res) > 0 { + maxDelay = res[len(res)-1].Delay + } + for i := 0; i < len(addrs); i++ { - res = append(res, network.AddrDelay{Addr: addrs[i], Delay: 0}) + res = append(res, network.AddrDelay{Addr: addrs[i], Delay: maxDelay + PublicOtherDelay}) } - res = append(res, getAddrDelay(pvt, PrivateTCPDelay, PrivateQUICDelay, 0)...) - res = append(res, getAddrDelay(public, PublicTCPDelay, PublicQUICDelay, 0)...) - res = append(res, getAddrDelay(relay, PublicTCPDelay, PublicQUICDelay, relayOffset)...) return res } @@ -98,7 +110,7 @@ func DefaultDialRanker(addrs []ma.Multiaddr) []network.AddrDelay { // offset is used to delay all addresses by a fixed duration. This is useful for delaying all relay // addresses relative to direct addresses. func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.Duration, - offset time.Duration) []network.AddrDelay { + otherDelay time.Duration, offset time.Duration) []network.AddrDelay { if len(addrs) == 0 { return nil } @@ -158,6 +170,7 @@ func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.D res := make([]network.AddrDelay, 0, len(addrs)) var tcpFirstDialDelay time.Duration + var lastQUICOrTCPDelay time.Duration for i, addr := range addrs { var delay time.Duration switch { @@ -176,6 +189,7 @@ func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.D delay = quicDelay } } + lastQUICOrTCPDelay = delay tcpFirstDialDelay = delay + tcpDelay case isProtocolAddr(addr, ma.P_TCP): // We dial an IPv6 address, then after tcpDelay an IPv4 @@ -193,6 +207,10 @@ func getAddrDelay(addrs []ma.Multiaddr, tcpDelay time.Duration, quicDelay time.D } } delay += tcpFirstDialDelay + lastQUICOrTCPDelay = delay + // if it's neither quic, webtransport, tcp, or websocket address + default: + delay = lastQUICOrTCPDelay + otherDelay } res = append(res, network.AddrDelay{Addr: addr, Delay: offset + delay}) } @@ -230,6 +248,9 @@ func score(a ma.Multiaddr) int { pi, _ := strconv.Atoi(p) return ip4Weight + pi + (1 << 20) } + if _, err := a.ValueForProtocol(ma.P_WEBRTC_DIRECT); err == nil { + return 1 << 21 + } return (1 << 30) } diff --git a/p2p/net/swarm/dial_ranker_test.go b/p2p/net/swarm/dial_ranker_test.go index 5ef3cc27f1..f7a6172122 100644 --- a/p2p/net/swarm/dial_ranker_test.go +++ b/p2p/net/swarm/dial_ranker_test.go @@ -29,6 +29,7 @@ func TestNoDelayDialRanker(t *testing.T) { q3v1 := ma.StringCast("/ip4/1.2.3.4/udp/3/quic-v1") q4 := ma.StringCast("/ip4/1.2.3.4/udp/4/quic-v1") t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") + wrtc1 := ma.StringCast("/ip4/1.1.1.1/udp/1/webrtc-direct") testCase := []struct { name string @@ -37,7 +38,7 @@ func TestNoDelayDialRanker(t *testing.T) { }{ { name: "quic+webtransport filtered when quicv1", - addrs: []ma.Multiaddr{q1, q2, q3, q4, q1v1, q2v1, q3v1, wt1, t1}, + addrs: []ma.Multiaddr{q1, q2, q3, q4, q1v1, q2v1, q3v1, wt1, t1, wrtc1}, output: []network.AddrDelay{ {Addr: q1, Delay: 0}, {Addr: q2, Delay: 0}, @@ -48,6 +49,7 @@ func TestNoDelayDialRanker(t *testing.T) { {Addr: q3v1, Delay: 0}, {Addr: wt1, Delay: 0}, {Addr: t1, Delay: 0}, + {Addr: wrtc1, Delay: 0}, }, }, } @@ -287,3 +289,69 @@ func TestDelayRankerRelay(t *testing.T) { }) } } + +func TestDelayRankerOtherTransportDelay(t *testing.T) { + q1v1 := ma.StringCast("/ip4/1.2.3.4/udp/1/quic-v1") + q1v16 := ma.StringCast("/ip6/1::2/udp/1/quic-v1") + t1 := ma.StringCast("/ip4/1.2.3.5/tcp/1/") + t1v6 := ma.StringCast("/ip6/1::2/tcp/1") + wrtc1 := ma.StringCast("/ip4/1.2.3.4/udp/1/webrtc-direct") + wrtc1v6 := ma.StringCast("/ip6/1::2/udp/1/webrtc-direct") + onion1 := ma.StringCast("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234") + onlyIP := ma.StringCast("/ip4/1.2.3.4/") + testCase := []struct { + name string + addrs []ma.Multiaddr + output []network.AddrDelay + }{ + { + name: "quic-with-other", + addrs: []ma.Multiaddr{q1v1, q1v16, wrtc1, wrtc1v6, onion1, onlyIP}, + output: []network.AddrDelay{ + {Addr: q1v16, Delay: 0}, + {Addr: q1v1, Delay: PublicQUICDelay}, + {Addr: wrtc1, Delay: PublicQUICDelay + PublicOtherDelay}, + {Addr: wrtc1v6, Delay: PublicQUICDelay + PublicOtherDelay}, + {Addr: onlyIP, Delay: PublicQUICDelay + PublicOtherDelay}, + {Addr: onion1, Delay: PublicQUICDelay + 2*PublicOtherDelay}, + }, + }, + { + name: "quic-and-tcp-with-other", + addrs: []ma.Multiaddr{q1v1, t1, t1v6, wrtc1, wrtc1v6, onion1, onlyIP}, + output: []network.AddrDelay{ + {Addr: q1v1, Delay: 0}, + {Addr: t1v6, Delay: PublicQUICDelay}, + {Addr: t1, Delay: 2 * PublicQUICDelay}, + {Addr: wrtc1, Delay: 2*PublicQUICDelay + PublicOtherDelay}, + {Addr: wrtc1v6, Delay: 2*PublicQUICDelay + PublicOtherDelay}, + {Addr: onlyIP, Delay: 2*PublicQUICDelay + PublicOtherDelay}, + {Addr: onion1, Delay: 2*PublicQUICDelay + 2*PublicOtherDelay}, + }, + }, + { + name: "only-non-ip-addr", + addrs: []ma.Multiaddr{onion1}, + output: []network.AddrDelay{ + {Addr: onion1, Delay: PublicOtherDelay}, + }, + }, + } + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res := DefaultDialRanker(tc.addrs) + if len(res) != len(tc.output) { + log.Errorf("expected %s got %s", tc.output, res) + t.Errorf("expected elems: %d got: %d", len(tc.output), len(res)) + return + } + sortAddrDelays(res) + sortAddrDelays(tc.output) + for i := 0; i < len(tc.output); i++ { + if !tc.output[i].Addr.Equal(res[i].Addr) || tc.output[i].Delay != res[i].Delay { + t.Fatalf("expected %+v got %+v", tc.output, res) + } + } + }) + } +} diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go index ef1fc2a2b3..9fff13f8e2 100644 --- a/p2p/net/swarm/swarm.go +++ b/p2p/net/swarm/swarm.go @@ -385,8 +385,7 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn, // If we do this in the Upgrader, we will not be able to do this. if s.gater != nil { if allow, _ := s.gater.InterceptUpgraded(c); !allow { - // TODO Send disconnect with reason here - err := tc.Close() + err := tc.CloseWithError(network.ConnGated) if err != nil { log.Warnf("failed to close connection with peer %s and addr %s; err: %s", p, addr, err) } @@ -511,6 +510,7 @@ func (s *Swarm) NewStream(ctx context.Context, p peer.ID) (network.Stream, error var err error c, err = s.waitForDirectConn(ctx, p) if err != nil { + log.Debugf("failed to get direct connection to a limited peer %s: %s", p, err) return nil, err } } @@ -823,31 +823,44 @@ type connWithMetrics struct { opened time.Time dir network.Direction metricsTracer MetricsTracer + once sync.Once + closeErr error } -func wrapWithMetrics(capableConn transport.CapableConn, metricsTracer MetricsTracer, opened time.Time, dir network.Direction) connWithMetrics { - c := connWithMetrics{CapableConn: capableConn, opened: opened, dir: dir, metricsTracer: metricsTracer} +func wrapWithMetrics(capableConn transport.CapableConn, metricsTracer MetricsTracer, opened time.Time, dir network.Direction) *connWithMetrics { + c := &connWithMetrics{CapableConn: capableConn, opened: opened, dir: dir, metricsTracer: metricsTracer} c.metricsTracer.OpenedConnection(c.dir, capableConn.RemotePublicKey(), capableConn.ConnState(), capableConn.LocalMultiaddr()) return c } -func (c connWithMetrics) completedHandshake() { +func (c *connWithMetrics) completedHandshake() { c.metricsTracer.CompletedHandshake(time.Since(c.opened), c.ConnState(), c.LocalMultiaddr()) } -func (c connWithMetrics) Close() error { - c.metricsTracer.ClosedConnection(c.dir, time.Since(c.opened), c.ConnState(), c.LocalMultiaddr()) - return c.CapableConn.Close() +func (c *connWithMetrics) Close() error { + c.once.Do(func() { + c.metricsTracer.ClosedConnection(c.dir, time.Since(c.opened), c.ConnState(), c.LocalMultiaddr()) + c.closeErr = c.CapableConn.Close() + }) + return c.closeErr +} + +func (c *connWithMetrics) CloseWithError(errCode network.ConnErrorCode) error { + c.once.Do(func() { + c.metricsTracer.ClosedConnection(c.dir, time.Since(c.opened), c.ConnState(), c.LocalMultiaddr()) + c.closeErr = c.CapableConn.CloseWithError(errCode) + }) + return c.closeErr } -func (c connWithMetrics) Stat() network.ConnStats { +func (c *connWithMetrics) Stat() network.ConnStats { if cs, ok := c.CapableConn.(network.ConnStat); ok { return cs.Stat() } return network.ConnStats{} } -var _ network.ConnStat = connWithMetrics{} +var _ network.ConnStat = &connWithMetrics{} type ResolverFromMaDNS struct { *madns.Resolver diff --git a/p2p/net/swarm/swarm_conn.go b/p2p/net/swarm/swarm_conn.go index 5fd41c8d9f..1d6cf96b4e 100644 --- a/p2p/net/swarm/swarm_conn.go +++ b/p2p/net/swarm/swarm_conn.go @@ -58,11 +58,20 @@ func (c *Conn) ID() string { // open notifications must finish before we can fire off the close // notifications). func (c *Conn) Close() error { - c.closeOnce.Do(c.doClose) + c.closeOnce.Do(func() { + c.doClose(0) + }) return c.err } -func (c *Conn) doClose() { +func (c *Conn) CloseWithError(errCode network.ConnErrorCode) error { + c.closeOnce.Do(func() { + c.doClose(errCode) + }) + return c.err +} + +func (c *Conn) doClose(errCode network.ConnErrorCode) { c.swarm.removeConn(c) // Prevent new streams from opening. @@ -71,7 +80,11 @@ func (c *Conn) doClose() { c.streams.m = nil c.streams.Unlock() - c.err = c.conn.Close() + if errCode != 0 { + c.err = c.conn.CloseWithError(errCode) + } else { + c.err = c.conn.Close() + } // Send the connectedness event after closing the connection. // This ensures that both remote connection close and local connection @@ -121,7 +134,7 @@ func (c *Conn) start() { } scope, err := c.swarm.ResourceManager().OpenStream(c.RemotePeer(), network.DirInbound) if err != nil { - ts.Reset() + ts.ResetWithError(network.StreamResourceLimitExceeded) continue } c.swarm.refs.Add(1) diff --git a/p2p/net/swarm/swarm_dial_test.go b/p2p/net/swarm/swarm_dial_test.go index add6f5cbba..d3586ca5d9 100644 --- a/p2p/net/swarm/swarm_dial_test.go +++ b/p2p/net/swarm/swarm_dial_test.go @@ -399,8 +399,23 @@ func TestBlackHoledAddrBlocked(t *testing.T) { require.ErrorIs(t, err, ErrDialRefusedBlackHole) } +type mockDNSResolver struct { + ipsToReturn []net.IPAddr + txtsToReturn []string +} + +var _ madns.BasicResolver = (*mockDNSResolver)(nil) + +func (m *mockDNSResolver) LookupIPAddr(_ context.Context, _ string) ([]net.IPAddr, error) { + return m.ipsToReturn, nil +} + +func (m *mockDNSResolver) LookupTXT(_ context.Context, _ string) ([]string, error) { + return m.txtsToReturn, nil +} + func TestSkipDialingManyDNS(t *testing.T) { - resolver, err := madns.NewResolver() + resolver, err := madns.NewResolver(madns.WithDefaultResolver(&mockDNSResolver{ipsToReturn: []net.IPAddr{{IP: net.ParseIP("1.2.3.4")}, {IP: net.ParseIP("1.2.3.5")}}})) if err != nil { t.Fatal(err) } diff --git a/p2p/net/swarm/swarm_stream.go b/p2p/net/swarm/swarm_stream.go index b7846adec2..4fee368250 100644 --- a/p2p/net/swarm/swarm_stream.go +++ b/p2p/net/swarm/swarm_stream.go @@ -91,6 +91,12 @@ func (s *Stream) Reset() error { return err } +func (s *Stream) ResetWithError(errCode network.StreamErrorCode) error { + err := s.stream.ResetWithError(errCode) + s.closeAndRemoveStream() + return err +} + func (s *Stream) closeAndRemoveStream() { s.closeMx.Lock() defer s.closeMx.Unlock() diff --git a/p2p/net/swarm/swarm_test.go b/p2p/net/swarm/swarm_test.go index 3d92690b98..496236f826 100644 --- a/p2p/net/swarm/swarm_test.go +++ b/p2p/net/swarm/swarm_test.go @@ -538,7 +538,7 @@ func TestResourceManagerAcceptStream(t *testing.T) { if err == nil { _, err = str.Read([]byte{0}) } - require.EqualError(t, err, "stream reset") + require.ErrorContains(t, err, "stream reset") } func TestListenCloseCount(t *testing.T) { diff --git a/p2p/net/swarm/swarm_transport.go b/p2p/net/swarm/swarm_transport.go index 3aaa335cbc..ff944813bd 100644 --- a/p2p/net/swarm/swarm_transport.go +++ b/p2p/net/swarm/swarm_transport.go @@ -60,10 +60,6 @@ func (s *Swarm) TransportForListening(a ma.Multiaddr) transport.Transport { s.transports.RLock() defer s.transports.RUnlock() if len(s.transports.m) == 0 { - // make sure we're not just shutting down. - if s.transports.m != nil { - log.Error("you have no transports configured") - } return nil } diff --git a/p2p/net/upgrader/conn.go b/p2p/net/upgrader/conn.go index 1c23a01aed..2cc4dcfbb6 100644 --- a/p2p/net/upgrader/conn.go +++ b/p2p/net/upgrader/conn.go @@ -63,3 +63,8 @@ func (t *transportConn) ConnState() network.ConnectionState { UsedEarlyMuxerNegotiation: t.usedEarlyMuxerNegotiation, } } + +func (t *transportConn) CloseWithError(errCode network.ConnErrorCode) error { + defer t.scope.Done() + return t.MuxedConn.CloseWithError(errCode) +} diff --git a/p2p/net/upgrader/listener.go b/p2p/net/upgrader/listener.go index c2e81d2e93..55783f0154 100644 --- a/p2p/net/upgrader/listener.go +++ b/p2p/net/upgrader/listener.go @@ -162,7 +162,7 @@ func (l *listener) handleIncoming() { // if we stop accepting connections for some reason, // we'll eventually close all the open ones // instead of hanging onto them. - conn.Close() + conn.CloseWithError(network.ConnRateLimited) } }() } diff --git a/p2p/protocol/autonatv2/autonat.go b/p2p/protocol/autonatv2/autonat.go index de933d73c8..ee4318dd87 100644 --- a/p2p/protocol/autonatv2/autonat.go +++ b/p2p/protocol/autonatv2/autonat.go @@ -8,6 +8,8 @@ import ( "sync" "time" + "math/rand/v2" + logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p/core/event" "github.com/libp2p/go-libp2p/core/host" @@ -16,7 +18,6 @@ import ( "github.com/libp2p/go-libp2p/p2p/protocol/autonatv2/pb" ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" - "golang.org/x/exp/rand" ) const ( @@ -211,7 +212,7 @@ func (p *peersMap) GetRand() peer.ID { if len(p.peers) == 0 { return "" } - return p.peers[rand.Intn(len(p.peers))] + return p.peers[rand.IntN(len(p.peers))] } func (p *peersMap) Put(pid peer.ID) { diff --git a/p2p/protocol/autonatv2/client.go b/p2p/protocol/autonatv2/client.go index 6ed7a6bb92..bbb6145b8c 100644 --- a/p2p/protocol/autonatv2/client.go +++ b/p2p/protocol/autonatv2/client.go @@ -8,13 +8,14 @@ import ( "sync" "time" + "math/rand/v2" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/p2p/protocol/autonatv2/pb" "github.com/libp2p/go-msgio/pbio" ma "github.com/multiformats/go-multiaddr" - "golang.org/x/exp/rand" ) // client implements the client for making dial requests for AutoNAT v2. It verifies successful diff --git a/p2p/protocol/autonatv2/options.go b/p2p/protocol/autonatv2/options.go index 15268f6290..76cd3735f4 100644 --- a/p2p/protocol/autonatv2/options.go +++ b/p2p/protocol/autonatv2/options.go @@ -8,6 +8,7 @@ type autoNATSettings struct { serverRPM int serverPerPeerRPM int serverDialDataRPM int + maxConcurrentRequestsPerPeer int dataRequestPolicy dataRequestPolicyFunc now func() time.Time amplificatonAttackPreventionDialWait time.Duration @@ -20,6 +21,7 @@ func defaultSettings() *autoNATSettings { serverRPM: 60, // 1 every second serverPerPeerRPM: 12, // 1 every 5 seconds serverDialDataRPM: 12, // 1 every 5 seconds + maxConcurrentRequestsPerPeer: 2, dataRequestPolicy: amplificationAttackPrevention, amplificatonAttackPreventionDialWait: 3 * time.Second, now: time.Now, @@ -28,11 +30,12 @@ func defaultSettings() *autoNATSettings { type AutoNATOption func(s *autoNATSettings) error -func WithServerRateLimit(rpm, perPeerRPM, dialDataRPM int) AutoNATOption { +func WithServerRateLimit(rpm, perPeerRPM, dialDataRPM int, maxConcurrentRequestsPerPeer int) AutoNATOption { return func(s *autoNATSettings) error { s.serverRPM = rpm s.serverPerPeerRPM = perPeerRPM s.serverDialDataRPM = dialDataRPM + s.maxConcurrentRequestsPerPeer = maxConcurrentRequestsPerPeer return nil } } diff --git a/p2p/protocol/autonatv2/pb/autonatv2.pb.go b/p2p/protocol/autonatv2/pb/autonatv2.pb.go index 3c1016fefd..8e1207b3a8 100644 --- a/p2p/protocol/autonatv2/pb/autonatv2.pb.go +++ b/p2p/protocol/autonatv2/pb/autonatv2.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/protocol/autonatv2/pb/autonatv2.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -168,17 +169,16 @@ func (DialBackResponse_DialBackStatus) EnumDescriptor() ([]byte, []int) { } type Message struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Msg: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Msg: // // *Message_DialRequest // *Message_DialResponse // *Message_DialDataRequest // *Message_DialDataResponse - Msg isMessage_Msg `protobuf_oneof:"msg"` + Msg isMessage_Msg `protobuf_oneof:"msg"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Message) Reset() { @@ -211,37 +211,45 @@ func (*Message) Descriptor() ([]byte, []int) { return file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescGZIP(), []int{0} } -func (m *Message) GetMsg() isMessage_Msg { - if m != nil { - return m.Msg +func (x *Message) GetMsg() isMessage_Msg { + if x != nil { + return x.Msg } return nil } func (x *Message) GetDialRequest() *DialRequest { - if x, ok := x.GetMsg().(*Message_DialRequest); ok { - return x.DialRequest + if x != nil { + if x, ok := x.Msg.(*Message_DialRequest); ok { + return x.DialRequest + } } return nil } func (x *Message) GetDialResponse() *DialResponse { - if x, ok := x.GetMsg().(*Message_DialResponse); ok { - return x.DialResponse + if x != nil { + if x, ok := x.Msg.(*Message_DialResponse); ok { + return x.DialResponse + } } return nil } func (x *Message) GetDialDataRequest() *DialDataRequest { - if x, ok := x.GetMsg().(*Message_DialDataRequest); ok { - return x.DialDataRequest + if x != nil { + if x, ok := x.Msg.(*Message_DialDataRequest); ok { + return x.DialDataRequest + } } return nil } func (x *Message) GetDialDataResponse() *DialDataResponse { - if x, ok := x.GetMsg().(*Message_DialDataResponse); ok { - return x.DialDataResponse + if x != nil { + if x, ok := x.Msg.(*Message_DialDataResponse); ok { + return x.DialDataResponse + } } return nil } @@ -275,12 +283,11 @@ func (*Message_DialDataRequest) isMessage_Msg() {} func (*Message_DialDataResponse) isMessage_Msg() {} type DialRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Addrs [][]byte `protobuf:"bytes,1,rep,name=addrs,proto3" json:"addrs,omitempty"` + Nonce uint64 `protobuf:"fixed64,2,opt,name=nonce,proto3" json:"nonce,omitempty"` unknownFields protoimpl.UnknownFields - - Addrs [][]byte `protobuf:"bytes,1,rep,name=addrs,proto3" json:"addrs,omitempty"` - Nonce uint64 `protobuf:"fixed64,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialRequest) Reset() { @@ -328,12 +335,11 @@ func (x *DialRequest) GetNonce() uint64 { } type DialDataRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + AddrIdx uint32 `protobuf:"varint,1,opt,name=addrIdx,proto3" json:"addrIdx,omitempty"` + NumBytes uint64 `protobuf:"varint,2,opt,name=numBytes,proto3" json:"numBytes,omitempty"` unknownFields protoimpl.UnknownFields - - AddrIdx uint32 `protobuf:"varint,1,opt,name=addrIdx,proto3" json:"addrIdx,omitempty"` - NumBytes uint64 `protobuf:"varint,2,opt,name=numBytes,proto3" json:"numBytes,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialDataRequest) Reset() { @@ -381,13 +387,12 @@ func (x *DialDataRequest) GetNumBytes() uint64 { } type DialResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Status DialResponse_ResponseStatus `protobuf:"varint,1,opt,name=status,proto3,enum=autonatv2.pb.DialResponse_ResponseStatus" json:"status,omitempty"` + AddrIdx uint32 `protobuf:"varint,2,opt,name=addrIdx,proto3" json:"addrIdx,omitempty"` + DialStatus DialStatus `protobuf:"varint,3,opt,name=dialStatus,proto3,enum=autonatv2.pb.DialStatus" json:"dialStatus,omitempty"` unknownFields protoimpl.UnknownFields - - Status DialResponse_ResponseStatus `protobuf:"varint,1,opt,name=status,proto3,enum=autonatv2.pb.DialResponse_ResponseStatus" json:"status,omitempty"` - AddrIdx uint32 `protobuf:"varint,2,opt,name=addrIdx,proto3" json:"addrIdx,omitempty"` - DialStatus DialStatus `protobuf:"varint,3,opt,name=dialStatus,proto3,enum=autonatv2.pb.DialStatus" json:"dialStatus,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialResponse) Reset() { @@ -442,11 +447,10 @@ func (x *DialResponse) GetDialStatus() DialStatus { } type DialDataResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialDataResponse) Reset() { @@ -487,11 +491,10 @@ func (x *DialDataResponse) GetData() []byte { } type DialBack struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Nonce uint64 `protobuf:"fixed64,1,opt,name=nonce,proto3" json:"nonce,omitempty"` unknownFields protoimpl.UnknownFields - - Nonce uint64 `protobuf:"fixed64,1,opt,name=nonce,proto3" json:"nonce,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialBack) Reset() { @@ -532,11 +535,10 @@ func (x *DialBack) GetNonce() uint64 { } type DialBackResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Status DialBackResponse_DialBackStatus `protobuf:"varint,1,opt,name=status,proto3,enum=autonatv2.pb.DialBackResponse_DialBackStatus" json:"status,omitempty"` unknownFields protoimpl.UnknownFields - - Status DialBackResponse_DialBackStatus `protobuf:"varint,1,opt,name=status,proto3,enum=autonatv2.pb.DialBackResponse_DialBackStatus" json:"status,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DialBackResponse) Reset() { @@ -578,7 +580,7 @@ func (x *DialBackResponse) GetStatus() DialBackResponse_DialBackStatus { var File_p2p_protocol_autonatv2_pb_autonatv2_proto protoreflect.FileDescriptor -var file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc = []byte{ +var file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc = string([]byte{ 0x0a, 0x29, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x61, 0x75, 0x74, @@ -647,16 +649,16 @@ var file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc = []byte{ 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x6e, 0x61, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescOnce sync.Once - file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData = file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc + file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData []byte ) func file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescGZIP() []byte { file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescOnce.Do(func() { - file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData) + file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc), len(file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc))) }) return file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDescData } @@ -705,7 +707,7 @@ func file_p2p_protocol_autonatv2_pb_autonatv2_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc), len(file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc)), NumEnums: 3, NumMessages: 7, NumExtensions: 0, @@ -717,7 +719,6 @@ func file_p2p_protocol_autonatv2_pb_autonatv2_proto_init() { MessageInfos: file_p2p_protocol_autonatv2_pb_autonatv2_proto_msgTypes, }.Build() File_p2p_protocol_autonatv2_pb_autonatv2_proto = out.File - file_p2p_protocol_autonatv2_pb_autonatv2_proto_rawDesc = nil file_p2p_protocol_autonatv2_pb_autonatv2_proto_goTypes = nil file_p2p_protocol_autonatv2_pb_autonatv2_proto_depIdxs = nil } diff --git a/p2p/protocol/autonatv2/server.go b/p2p/protocol/autonatv2/server.go index d28cfc9371..05e0bdd9fd 100644 --- a/p2p/protocol/autonatv2/server.go +++ b/p2p/protocol/autonatv2/server.go @@ -67,10 +67,11 @@ func newServer(host, dialer host.Host, s *autoNATSettings) *server { amplificatonAttackPreventionDialWait: s.amplificatonAttackPreventionDialWait, allowPrivateAddrs: s.allowPrivateAddrs, limiter: &rateLimiter{ - RPM: s.serverRPM, - PerPeerRPM: s.serverPerPeerRPM, - DialDataRPM: s.serverDialDataRPM, - now: s.now, + RPM: s.serverRPM, + PerPeerRPM: s.serverPerPeerRPM, + DialDataRPM: s.serverDialDataRPM, + MaxConcurrentRequestsPerPeer: s.maxConcurrentRequestsPerPeer, + now: s.now, }, now: s.now, metricsTracer: s.metricsTracer, @@ -391,16 +392,17 @@ type rateLimiter struct { RPM int // DialDataRPM is the rate limit for requests that require dial data DialDataRPM int + // MaxConcurrentRequestsPerPeer is the maximum number of concurrent requests per peer + MaxConcurrentRequestsPerPeer int mu sync.Mutex closed bool reqs []entry peerReqs map[peer.ID][]time.Time dialDataReqs []time.Time - // ongoingReqs tracks in progress requests. This is used to disallow multiple concurrent requests by the - // same peer - // TODO: Should we allow a few concurrent requests per peer? - ongoingReqs map[peer.ID]struct{} + // inProgressReqs tracks in progress requests. This is used to limit multiple + // concurrent requests by the same peer. + inProgressReqs map[peer.ID]int now func() time.Time // for tests } @@ -410,28 +412,31 @@ type entry struct { Time time.Time } +func (r *rateLimiter) init() { + if r.peerReqs == nil { + r.peerReqs = make(map[peer.ID][]time.Time) + r.inProgressReqs = make(map[peer.ID]int) + } +} + func (r *rateLimiter) Accept(p peer.ID) bool { r.mu.Lock() defer r.mu.Unlock() if r.closed { return false } - if r.peerReqs == nil { - r.peerReqs = make(map[peer.ID][]time.Time) - r.ongoingReqs = make(map[peer.ID]struct{}) - } - + r.init() nw := r.now() r.cleanup(nw) - if _, ok := r.ongoingReqs[p]; ok { + if r.inProgressReqs[p] >= r.MaxConcurrentRequestsPerPeer { return false } if len(r.reqs) >= r.RPM || len(r.peerReqs[p]) >= r.PerPeerRPM { return false } - r.ongoingReqs[p] = struct{}{} + r.inProgressReqs[p]++ r.reqs = append(r.reqs, entry{PeerID: p, Time: nw}) r.peerReqs[p] = append(r.peerReqs[p], nw) return true @@ -443,10 +448,7 @@ func (r *rateLimiter) AcceptDialDataRequest(p peer.ID) bool { if r.closed { return false } - if r.peerReqs == nil { - r.peerReqs = make(map[peer.ID][]time.Time) - r.ongoingReqs = make(map[peer.ID]struct{}) - } + r.init() nw := r.now() r.cleanup(nw) if len(r.dialDataReqs) >= r.DialDataRPM { @@ -495,7 +497,13 @@ func (r *rateLimiter) cleanup(now time.Time) { func (r *rateLimiter) CompleteRequest(p peer.ID) { r.mu.Lock() defer r.mu.Unlock() - delete(r.ongoingReqs, p) + r.inProgressReqs[p]-- + if r.inProgressReqs[p] <= 0 { + delete(r.inProgressReqs, p) + if r.inProgressReqs[p] < 0 { + log.Errorf("BUG: negative in progress requests for peer %s", p) + } + } } func (r *rateLimiter) Close() { @@ -503,7 +511,7 @@ func (r *rateLimiter) Close() { defer r.mu.Unlock() r.closed = true r.peerReqs = nil - r.ongoingReqs = nil + r.inProgressReqs = nil r.dialDataReqs = nil } diff --git a/p2p/protocol/autonatv2/server_test.go b/p2p/protocol/autonatv2/server_test.go index 0b40f27535..6664f1c397 100644 --- a/p2p/protocol/autonatv2/server_test.go +++ b/p2p/protocol/autonatv2/server_test.go @@ -149,7 +149,7 @@ func TestServerDataRequest(t *testing.T) { } return false }), - WithServerRateLimit(10, 10, 10), + WithServerRateLimit(10, 10, 10, 2), withAmplificationAttackPreventionDialWait(0), ) defer an.Close() @@ -187,6 +187,69 @@ func TestServerDataRequest(t *testing.T) { _, err = c.GetReachability(context.Background(), []Request{{Addr: quicAddr, SendDialData: true}, {Addr: tcpAddr}}) require.Error(t, err) } + +func TestServerMaxConcurrentRequestsPerPeer(t *testing.T) { + const concurrentRequests = 5 + + // server will skip all tcp addresses + dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) + + doneChan := make(chan struct{}) + an := newAutoNAT(t, dialer, allowPrivateAddrs, withDataRequestPolicy( + // stall all allowed requests + func(s network.Stream, dialAddr ma.Multiaddr) bool { + <-doneChan + return true + }), + WithServerRateLimit(10, 10, 10, concurrentRequests), + 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) + + errChan := make(chan error) + const N = 10 + // num concurrentRequests will stall and N will fail + for i := 0; i < concurrentRequests+N; i++ { + go func() { + _, err := c.GetReachability(context.Background(), []Request{{Addr: c.host.Addrs()[0], SendDialData: false}}) + errChan <- err + }() + } + + // check N failures + for i := 0; i < N; i++ { + select { + case err := <-errChan: + require.Error(t, err) + case <-time.After(10 * time.Second): + t.Fatalf("expected %d errors: got: %d", N, i) + } + } + + // check concurrentRequests failures, as we won't send dial data + close(doneChan) + for i := 0; i < concurrentRequests; i++ { + select { + case err := <-errChan: + require.Error(t, err) + case <-time.After(5 * time.Second): + t.Fatalf("expected %d errors: got: %d", concurrentRequests, i) + } + } + select { + case err := <-errChan: + t.Fatalf("expected no more errors: got: %v", err) + default: + } +} + func TestServerDataRequestJitter(t *testing.T) { // server will skip all tcp addresses dialer := bhost.NewBlankHost(swarmt.GenSwarm(t, swarmt.OptDisableTCP)) @@ -198,7 +261,7 @@ func TestServerDataRequestJitter(t *testing.T) { } return false }), - WithServerRateLimit(10, 10, 10), + WithServerRateLimit(10, 10, 10, 2), withAmplificationAttackPreventionDialWait(5*time.Second), ) defer an.Close() @@ -238,7 +301,7 @@ func TestServerDataRequestJitter(t *testing.T) { } func TestServerDial(t *testing.T) { - an := newAutoNAT(t, nil, WithServerRateLimit(10, 10, 10), allowPrivateAddrs) + an := newAutoNAT(t, nil, WithServerRateLimit(10, 10, 10, 2), allowPrivateAddrs) defer an.Close() defer an.host.Close() @@ -295,7 +358,7 @@ func TestServerDial(t *testing.T) { func TestRateLimiter(t *testing.T) { cl := test.NewMockClock() - r := rateLimiter{RPM: 3, PerPeerRPM: 2, DialDataRPM: 1, now: cl.Now} + r := rateLimiter{RPM: 3, PerPeerRPM: 2, DialDataRPM: 1, now: cl.Now, MaxConcurrentRequestsPerPeer: 1} require.True(t, r.Accept("peer1")) @@ -333,12 +396,37 @@ func TestRateLimiter(t *testing.T) { cl.AdvanceBy(10 * time.Second) require.True(t, r.Accept("peer3")) + +} + +func TestRateLimiterConcurrentRequests(t *testing.T) { + const N = 5 + const Peers = 5 + for concurrentRequests := 1; concurrentRequests <= N; concurrentRequests++ { + cl := test.NewMockClock() + r := rateLimiter{RPM: 10 * Peers * N, PerPeerRPM: 10 * Peers * N, DialDataRPM: 10 * Peers * N, now: cl.Now, MaxConcurrentRequestsPerPeer: concurrentRequests} + for p := 0; p < Peers; p++ { + for i := 0; i < concurrentRequests; i++ { + require.True(t, r.Accept(peer.ID(fmt.Sprintf("peer-%d", p)))) + } + require.False(t, r.Accept(peer.ID(fmt.Sprintf("peer-%d", p)))) + // Now complete the requests + for i := 0; i < concurrentRequests; i++ { + r.CompleteRequest(peer.ID(fmt.Sprintf("peer-%d", p))) + } + // Now we should be able to accept new requests + for i := 0; i < concurrentRequests; i++ { + require.True(t, r.Accept(peer.ID(fmt.Sprintf("peer-%d", p)))) + } + require.False(t, r.Accept(peer.ID(fmt.Sprintf("peer-%d", p)))) + } + } } func TestRateLimiterStress(t *testing.T) { cl := test.NewMockClock() for i := 0; i < 10; i++ { - r := rateLimiter{RPM: 20 + i, PerPeerRPM: 10 + i, DialDataRPM: i, now: cl.Now} + r := rateLimiter{RPM: 20 + i, PerPeerRPM: 10 + i, DialDataRPM: i, MaxConcurrentRequestsPerPeer: 1, now: cl.Now} peers := make([]peer.ID, 10+i) for i := 0; i < len(peers); i++ { @@ -386,7 +474,7 @@ func TestRateLimiterStress(t *testing.T) { require.Equal(t, len(r.peerReqs), 1) require.Equal(t, len(r.peerReqs[peers[0]]), 1) require.Equal(t, len(r.dialDataReqs), 0) - require.Equal(t, len(r.ongoingReqs), 1) + require.Equal(t, len(r.inProgressReqs), 1) } } @@ -433,7 +521,7 @@ func TestReadDialData(t *testing.T) { } func FuzzServerDialRequest(f *testing.F) { - a := newAutoNAT(f, nil, allowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32)) + a := newAutoNAT(f, nil, allowPrivateAddrs, WithServerRateLimit(math.MaxInt32, math.MaxInt32, math.MaxInt32, 2)) c := newAutoNAT(f, nil) idAndWait(f, c, a) // reduce the streamTimeout before running this. TODO: fix this diff --git a/p2p/protocol/circuitv2/pb/circuit.pb.go b/p2p/protocol/circuitv2/pb/circuit.pb.go index fda13bcbbc..2ce4c66c48 100644 --- a/p2p/protocol/circuitv2/pb/circuit.pb.go +++ b/p2p/protocol/circuitv2/pb/circuit.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/protocol/circuitv2/pb/circuit.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -184,17 +185,16 @@ func (StopMessage_Type) EnumDescriptor() ([]byte, []int) { } type HopMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // This field is marked optional for backwards compatibility with proto2. // Users should make sure to always set this. - Type *HopMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=circuit.pb.HopMessage_Type,oneof" json:"type,omitempty"` - Peer *Peer `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` - Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation,proto3,oneof" json:"reservation,omitempty"` - Limit *Limit `protobuf:"bytes,4,opt,name=limit,proto3,oneof" json:"limit,omitempty"` - Status *Status `protobuf:"varint,5,opt,name=status,proto3,enum=circuit.pb.Status,oneof" json:"status,omitempty"` + Type *HopMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=circuit.pb.HopMessage_Type,oneof" json:"type,omitempty"` + Peer *Peer `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` + Reservation *Reservation `protobuf:"bytes,3,opt,name=reservation,proto3,oneof" json:"reservation,omitempty"` + Limit *Limit `protobuf:"bytes,4,opt,name=limit,proto3,oneof" json:"limit,omitempty"` + Status *Status `protobuf:"varint,5,opt,name=status,proto3,enum=circuit.pb.Status,oneof" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *HopMessage) Reset() { @@ -263,16 +263,15 @@ func (x *HopMessage) GetStatus() Status { } type StopMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // This field is marked optional for backwards compatibility with proto2. // Users should make sure to always set this. - Type *StopMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=circuit.pb.StopMessage_Type,oneof" json:"type,omitempty"` - Peer *Peer `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` - Limit *Limit `protobuf:"bytes,3,opt,name=limit,proto3,oneof" json:"limit,omitempty"` - Status *Status `protobuf:"varint,4,opt,name=status,proto3,enum=circuit.pb.Status,oneof" json:"status,omitempty"` + Type *StopMessage_Type `protobuf:"varint,1,opt,name=type,proto3,enum=circuit.pb.StopMessage_Type,oneof" json:"type,omitempty"` + Peer *Peer `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` + Limit *Limit `protobuf:"bytes,3,opt,name=limit,proto3,oneof" json:"limit,omitempty"` + Status *Status `protobuf:"varint,4,opt,name=status,proto3,enum=circuit.pb.Status,oneof" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StopMessage) Reset() { @@ -334,14 +333,13 @@ func (x *StopMessage) GetStatus() Status { } type Peer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // This field is marked optional for backwards compatibility with proto2. // Users should make sure to always set this. - Id []byte `protobuf:"bytes,1,opt,name=id,proto3,oneof" json:"id,omitempty"` - Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"` + Id []byte `protobuf:"bytes,1,opt,name=id,proto3,oneof" json:"id,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Peer) Reset() { @@ -389,15 +387,14 @@ func (x *Peer) GetAddrs() [][]byte { } type Reservation struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // This field is marked optional for backwards compatibility with proto2. // Users should make sure to always set this. - Expire *uint64 `protobuf:"varint,1,opt,name=expire,proto3,oneof" json:"expire,omitempty"` // Unix expiration time (UTC) - Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"` // relay addrs for reserving peer - Voucher []byte `protobuf:"bytes,3,opt,name=voucher,proto3,oneof" json:"voucher,omitempty"` // reservation voucher + Expire *uint64 `protobuf:"varint,1,opt,name=expire,proto3,oneof" json:"expire,omitempty"` // Unix expiration time (UTC) + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"` // relay addrs for reserving peer + Voucher []byte `protobuf:"bytes,3,opt,name=voucher,proto3,oneof" json:"voucher,omitempty"` // reservation voucher + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Reservation) Reset() { @@ -452,12 +449,11 @@ func (x *Reservation) GetVoucher() []byte { } type Limit struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Duration *uint32 `protobuf:"varint,1,opt,name=duration,proto3,oneof" json:"duration,omitempty"` // seconds + Data *uint64 `protobuf:"varint,2,opt,name=data,proto3,oneof" json:"data,omitempty"` // bytes unknownFields protoimpl.UnknownFields - - Duration *uint32 `protobuf:"varint,1,opt,name=duration,proto3,oneof" json:"duration,omitempty"` // seconds - Data *uint64 `protobuf:"varint,2,opt,name=data,proto3,oneof" json:"data,omitempty"` // bytes + sizeCache protoimpl.SizeCache } func (x *Limit) Reset() { @@ -506,7 +502,7 @@ func (x *Limit) GetData() uint64 { var File_p2p_protocol_circuitv2_pb_circuit_proto protoreflect.FileDescriptor -var file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc = []byte{ +var file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc = string([]byte{ 0x0a, 0x27, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x63, 0x69, 0x72, 0x63, 0x75, @@ -585,16 +581,16 @@ var file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc = []byte{ 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescOnce sync.Once - file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData = file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc + file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData []byte ) func file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescGZIP() []byte { file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescOnce.Do(func() { - file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData) + file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc), len(file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc))) }) return file_p2p_protocol_circuitv2_pb_circuit_proto_rawDescData } @@ -642,7 +638,7 @@ func file_p2p_protocol_circuitv2_pb_circuit_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc), len(file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc)), NumEnums: 3, NumMessages: 5, NumExtensions: 0, @@ -654,7 +650,6 @@ func file_p2p_protocol_circuitv2_pb_circuit_proto_init() { MessageInfos: file_p2p_protocol_circuitv2_pb_circuit_proto_msgTypes, }.Build() File_p2p_protocol_circuitv2_pb_circuit_proto = out.File - file_p2p_protocol_circuitv2_pb_circuit_proto_rawDesc = nil file_p2p_protocol_circuitv2_pb_circuit_proto_goTypes = nil file_p2p_protocol_circuitv2_pb_circuit_proto_depIdxs = nil } diff --git a/p2p/protocol/circuitv2/pb/voucher.pb.go b/p2p/protocol/circuitv2/pb/voucher.pb.go index 5837d4de23..19e6872aa5 100644 --- a/p2p/protocol/circuitv2/pb/voucher.pb.go +++ b/p2p/protocol/circuitv2/pb/voucher.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/protocol/circuitv2/pb/voucher.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,15 +22,14 @@ const ( ) type ReservationVoucher struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // These fields are marked optional for backwards compatibility with proto2. // Users should make sure to always set these. - Relay []byte `protobuf:"bytes,1,opt,name=relay,proto3,oneof" json:"relay,omitempty"` - Peer []byte `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` - Expiration *uint64 `protobuf:"varint,3,opt,name=expiration,proto3,oneof" json:"expiration,omitempty"` + Relay []byte `protobuf:"bytes,1,opt,name=relay,proto3,oneof" json:"relay,omitempty"` + Peer []byte `protobuf:"bytes,2,opt,name=peer,proto3,oneof" json:"peer,omitempty"` + Expiration *uint64 `protobuf:"varint,3,opt,name=expiration,proto3,oneof" json:"expiration,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReservationVoucher) Reset() { @@ -85,7 +85,7 @@ func (x *ReservationVoucher) GetExpiration() uint64 { var File_p2p_protocol_circuitv2_pb_voucher_proto protoreflect.FileDescriptor -var file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc = []byte{ +var file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc = string([]byte{ 0x0a, 0x27, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x2f, 0x76, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x63, 0x69, 0x72, 0x63, 0x75, @@ -103,16 +103,16 @@ var file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc = []byte{ 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x69, 0x72, 0x63, 0x75, 0x69, 0x74, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +}) var ( file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescOnce sync.Once - file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData = file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc + file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData []byte ) func file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescGZIP() []byte { file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescOnce.Do(func() { - file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData) + file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc), len(file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc))) }) return file_p2p_protocol_circuitv2_pb_voucher_proto_rawDescData } @@ -139,7 +139,7 @@ func file_p2p_protocol_circuitv2_pb_voucher_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc), len(file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -150,7 +150,6 @@ func file_p2p_protocol_circuitv2_pb_voucher_proto_init() { MessageInfos: file_p2p_protocol_circuitv2_pb_voucher_proto_msgTypes, }.Build() File_p2p_protocol_circuitv2_pb_voucher_proto = out.File - file_p2p_protocol_circuitv2_pb_voucher_proto_rawDesc = nil file_p2p_protocol_circuitv2_pb_voucher_proto_goTypes = nil file_p2p_protocol_circuitv2_pb_voucher_proto_depIdxs = nil } diff --git a/p2p/protocol/circuitv2/relay/relay_test.go b/p2p/protocol/circuitv2/relay/relay_test.go index f6b63e32de..7c5ec927df 100644 --- a/p2p/protocol/circuitv2/relay/relay_test.go +++ b/p2p/protocol/circuitv2/relay/relay_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/rand" + "errors" "fmt" "io" "testing" @@ -267,12 +268,12 @@ func TestRelayLimitTime(t *testing.T) { if n > 0 { t.Fatalf("expected to write 0 bytes, wrote %d", n) } - if err != network.ErrReset { + if !errors.Is(err, network.ErrReset) { t.Fatalf("expected reset, but got %s", err) } err = <-rch - if err != network.ErrReset { + if !errors.Is(err, network.ErrReset) { t.Fatalf("expected reset, but got %s", err) } } @@ -300,7 +301,7 @@ func TestRelayLimitData(t *testing.T) { } n, err := s.Read(buf) - if err != network.ErrReset { + if !errors.Is(err, network.ErrReset) { t.Fatalf("expected reset but got %s", err) } rch <- n diff --git a/p2p/protocol/holepunch/holepuncher.go b/p2p/protocol/holepunch/holepuncher.go index 20d0558fc5..ff5e8a7364 100644 --- a/p2p/protocol/holepunch/holepuncher.go +++ b/p2p/protocol/holepunch/holepuncher.go @@ -133,7 +133,6 @@ func (hp *holePuncher) directConnect(rp peer.ID) error { for i := 1; i <= maxRetries; i++ { addrs, obsAddrs, rtt, err := hp.initiateHolePunch(rp) if err != nil { - log.Debugw("hole punching failed", "peer", rp, "error", err) hp.tracer.ProtocolError(rp, err) return err } @@ -184,9 +183,8 @@ func (hp *holePuncher) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, []ma.Multi addr, obsAddr, rtt, err := hp.initiateHolePunchImpl(str) if err != nil { - log.Debugf("%s", err) str.Reset() - return addr, obsAddr, rtt, err + return addr, obsAddr, rtt, fmt.Errorf("failed to initiateHolePunch: %w", err) } return addr, obsAddr, rtt, err } @@ -278,7 +276,10 @@ func (nn *netNotifiee) Connected(_ network.Network, conn network.Conn) { return } - _ = hs.DirectConnect(conn.RemotePeer()) + err := hs.DirectConnect(conn.RemotePeer()) + if err != nil { + log.Debugf("attempt to perform DirectConnect to %s failed: %s", conn.RemotePeer(), err) + } }() } } diff --git a/p2p/protocol/holepunch/pb/holepunch.pb.go b/p2p/protocol/holepunch/pb/holepunch.pb.go index c8ab6f16c4..07e78c07c5 100644 --- a/p2p/protocol/holepunch/pb/holepunch.pb.go +++ b/p2p/protocol/holepunch/pb/holepunch.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/protocol/holepunch/pb/holepunch.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -78,12 +79,11 @@ func (HolePunch_Type) EnumDescriptor() ([]byte, []int) { // spec: https://github.com/libp2p/specs/blob/master/relay/DCUtR.md type HolePunch struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Type *HolePunch_Type `protobuf:"varint,1,req,name=type,enum=holepunch.pb.HolePunch_Type" json:"type,omitempty"` + ObsAddrs [][]byte `protobuf:"bytes,2,rep,name=ObsAddrs" json:"ObsAddrs,omitempty"` unknownFields protoimpl.UnknownFields - - Type *HolePunch_Type `protobuf:"varint,1,req,name=type,enum=holepunch.pb.HolePunch_Type" json:"type,omitempty"` - ObsAddrs [][]byte `protobuf:"bytes,2,rep,name=ObsAddrs" json:"ObsAddrs,omitempty"` + sizeCache protoimpl.SizeCache } func (x *HolePunch) Reset() { @@ -132,7 +132,7 @@ func (x *HolePunch) GetObsAddrs() [][]byte { var File_p2p_protocol_holepunch_pb_holepunch_proto protoreflect.FileDescriptor -var file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc = []byte{ +var file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc = string([]byte{ 0x0a, 0x29, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, 0x6f, 0x6c, 0x65, 0x70, 0x75, 0x6e, 0x63, 0x68, 0x2f, 0x70, 0x62, 0x2f, 0x68, 0x6f, 0x6c, 0x65, 0x70, 0x75, 0x6e, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x68, 0x6f, 0x6c, @@ -148,16 +148,16 @@ var file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc = []byte{ 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, 0x6f, 0x6c, 0x65, 0x70, 0x75, 0x6e, 0x63, 0x68, 0x2f, 0x70, 0x62, -} +}) var ( file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescOnce sync.Once - file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData = file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc + file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData []byte ) func file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescGZIP() []byte { file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescOnce.Do(func() { - file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData) + file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc), len(file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc))) }) return file_p2p_protocol_holepunch_pb_holepunch_proto_rawDescData } @@ -186,7 +186,7 @@ func file_p2p_protocol_holepunch_pb_holepunch_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc), len(file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc)), NumEnums: 1, NumMessages: 1, NumExtensions: 0, @@ -198,7 +198,6 @@ func file_p2p_protocol_holepunch_pb_holepunch_proto_init() { MessageInfos: file_p2p_protocol_holepunch_pb_holepunch_proto_msgTypes, }.Build() File_p2p_protocol_holepunch_pb_holepunch_proto = out.File - file_p2p_protocol_holepunch_pb_holepunch_proto_rawDesc = nil file_p2p_protocol_holepunch_pb_holepunch_proto_goTypes = nil file_p2p_protocol_holepunch_pb_holepunch_proto_depIdxs = nil } diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go index b6d5240ba6..de25436dc2 100644 --- a/p2p/protocol/identify/id.go +++ b/p2p/protocol/identify/id.go @@ -19,6 +19,7 @@ import ( "github.com/libp2p/go-libp2p/core/protocol" "github.com/libp2p/go-libp2p/core/record" "github.com/libp2p/go-libp2p/p2p/host/eventbus" + useragent "github.com/libp2p/go-libp2p/p2p/protocol/identify/internal/user-agent" "github.com/libp2p/go-libp2p/p2p/protocol/identify/pb" logging "github.com/ipfs/go-log/v2" @@ -54,8 +55,6 @@ const ( connectedPeerMaxAddrs = 500 ) -var defaultUserAgent = "github.com/libp2p/go-libp2p" - type identifySnapshot struct { seq uint64 protocols []protocol.ID @@ -188,7 +187,7 @@ func NewIDService(h host.Host, opts ...Option) (*idService, error) { opt(&cfg) } - userAgent := defaultUserAgent + userAgent := useragent.DefaultUserAgent() if cfg.userAgent != "" { userAgent = cfg.userAgent } @@ -445,10 +444,9 @@ func newStreamAndNegotiate(ctx context.Context, c network.Conn, proto protocol.I log.Debugw("error opening identify stream", "peer", c.RemotePeer(), "error", err) return nil, err } - err = s.SetDeadline(time.Now().Add(Timeout)) - if err != nil { - return nil, err - } + + // Ignore the error. Consistent with our previous behavior. (See https://github.com/libp2p/go-libp2p/issues/3109) + _ = s.SetDeadline(time.Now().Add(Timeout)) if err := s.SetProtocol(proto); err != nil { log.Warnf("error setting identify protocol for stream: %s", err) diff --git a/p2p/protocol/identify/id_test.go b/p2p/protocol/identify/id_test.go index 06ea0119df..994f042b3e 100644 --- a/p2p/protocol/identify/id_test.go +++ b/p2p/protocol/identify/id_test.go @@ -27,6 +27,7 @@ import ( "github.com/libp2p/go-libp2p/p2p/net/swarm" swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing" "github.com/libp2p/go-libp2p/p2p/protocol/identify" + useragent "github.com/libp2p/go-libp2p/p2p/protocol/identify/internal/user-agent" "github.com/libp2p/go-libp2p/p2p/protocol/identify/pb" mockClock "github.com/benbjohnson/clock" @@ -44,9 +45,8 @@ func testKnowsAddrs(t *testing.T, h host.Host, p peer.ID, expected []ma.Multiadd func testHasAgentVersion(t *testing.T, h host.Host, p peer.ID) { v, err := h.Peerstore().Get(p, "AgentVersion") - if v.(string) != "github.com/libp2p/go-libp2p" { // this is the default user agent - t.Error("agent version mismatch", err) - } + require.NoError(t, err, "fetching agent version") + require.Equal(t, useragent.DefaultUserAgent(), v, "agent version") } func testHasPublicKey(t *testing.T, h host.Host, p peer.ID, shouldBe ic.PubKey) { @@ -104,7 +104,7 @@ func emitAddrChangeEvt(t *testing.T, h host.Host) { } } -// TestIDServiceWait gives the ID service 1s to finish after dialing +// TestIDService gives the ID service 1s to finish after dialing // this is because it used to be concurrent. Now, Dial wait till the // id service is done. func TestIDService(t *testing.T) { diff --git a/p2p/protocol/identify/user_agent.go b/p2p/protocol/identify/internal/user-agent/user_agent.go similarity index 84% rename from p2p/protocol/identify/user_agent.go rename to p2p/protocol/identify/internal/user-agent/user_agent.go index 016f941f39..a639d4c5f5 100644 --- a/p2p/protocol/identify/user_agent.go +++ b/p2p/protocol/identify/internal/user-agent/user_agent.go @@ -1,10 +1,16 @@ -package identify +package useragent import ( "fmt" "runtime/debug" ) +func DefaultUserAgent() string { + return defaultUserAgent +} + +var defaultUserAgent = "github.com/libp2p/go-libp2p" + func init() { bi, ok := debug.ReadBuildInfo() if !ok { diff --git a/p2p/protocol/identify/pb/identify.pb.go b/p2p/protocol/identify/pb/identify.pb.go index 66f4cb703a..1224d4feb3 100644 --- a/p2p/protocol/identify/pb/identify.pb.go +++ b/p2p/protocol/identify/pb/identify.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/protocol/identify/pb/identify.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,10 +22,7 @@ const ( ) type Identify struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // protocolVersion determines compatibility between peers ProtocolVersion *string `protobuf:"bytes,5,opt,name=protocolVersion" json:"protocolVersion,omitempty"` // e.g. ipfs/1.0.0 // agentVersion is like a UserAgent string in browsers, or client version in bittorrent @@ -48,6 +46,8 @@ type Identify struct { // see github.com/libp2p/go-libp2p/core/record/pb/envelope.proto and // github.com/libp2p/go-libp2p/core/peer/pb/peer_record.proto for message definitions. SignedPeerRecord []byte `protobuf:"bytes,8,opt,name=signedPeerRecord" json:"signedPeerRecord,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Identify) Reset() { @@ -131,7 +131,7 @@ func (x *Identify) GetSignedPeerRecord() []byte { var File_p2p_protocol_identify_pb_identify_proto protoreflect.FileDescriptor -var file_p2p_protocol_identify_pb_identify_proto_rawDesc = []byte{ +var file_p2p_protocol_identify_pb_identify_proto_rawDesc = string([]byte{ 0x0a, 0x27, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x62, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, @@ -156,16 +156,16 @@ var file_p2p_protocol_identify_pb_identify_proto_rawDesc = []byte{ 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x79, 0x2f, 0x70, 0x62, -} +}) var ( file_p2p_protocol_identify_pb_identify_proto_rawDescOnce sync.Once - file_p2p_protocol_identify_pb_identify_proto_rawDescData = file_p2p_protocol_identify_pb_identify_proto_rawDesc + file_p2p_protocol_identify_pb_identify_proto_rawDescData []byte ) func file_p2p_protocol_identify_pb_identify_proto_rawDescGZIP() []byte { file_p2p_protocol_identify_pb_identify_proto_rawDescOnce.Do(func() { - file_p2p_protocol_identify_pb_identify_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_protocol_identify_pb_identify_proto_rawDescData) + file_p2p_protocol_identify_pb_identify_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_protocol_identify_pb_identify_proto_rawDesc), len(file_p2p_protocol_identify_pb_identify_proto_rawDesc))) }) return file_p2p_protocol_identify_pb_identify_proto_rawDescData } @@ -191,7 +191,7 @@ func file_p2p_protocol_identify_pb_identify_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_protocol_identify_pb_identify_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_protocol_identify_pb_identify_proto_rawDesc), len(file_p2p_protocol_identify_pb_identify_proto_rawDesc)), NumEnums: 0, NumMessages: 1, NumExtensions: 0, @@ -202,7 +202,6 @@ func file_p2p_protocol_identify_pb_identify_proto_init() { MessageInfos: file_p2p_protocol_identify_pb_identify_proto_msgTypes, }.Build() File_p2p_protocol_identify_pb_identify_proto = out.File - file_p2p_protocol_identify_pb_identify_proto_rawDesc = nil file_p2p_protocol_identify_pb_identify_proto_goTypes = nil file_p2p_protocol_identify_pb_identify_proto_depIdxs = nil } diff --git a/p2p/security/noise/pb/payload.pb.go b/p2p/security/noise/pb/payload.pb.go index 45a104e222..e218cf52be 100644 --- a/p2p/security/noise/pb/payload.pb.go +++ b/p2p/security/noise/pb/payload.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/security/noise/pb/payload.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -21,12 +22,11 @@ const ( ) type NoiseExtensions struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - WebtransportCerthashes [][]byte `protobuf:"bytes,1,rep,name=webtransport_certhashes,json=webtransportCerthashes" json:"webtransport_certhashes,omitempty"` - StreamMuxers []string `protobuf:"bytes,2,rep,name=stream_muxers,json=streamMuxers" json:"stream_muxers,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + WebtransportCerthashes [][]byte `protobuf:"bytes,1,rep,name=webtransport_certhashes,json=webtransportCerthashes" json:"webtransport_certhashes,omitempty"` + StreamMuxers []string `protobuf:"bytes,2,rep,name=stream_muxers,json=streamMuxers" json:"stream_muxers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *NoiseExtensions) Reset() { @@ -74,13 +74,12 @@ func (x *NoiseExtensions) GetStreamMuxers() []string { } type NoiseHandshakePayload struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + IdentityKey []byte `protobuf:"bytes,1,opt,name=identity_key,json=identityKey" json:"identity_key,omitempty"` + IdentitySig []byte `protobuf:"bytes,2,opt,name=identity_sig,json=identitySig" json:"identity_sig,omitempty"` + Extensions *NoiseExtensions `protobuf:"bytes,4,opt,name=extensions" json:"extensions,omitempty"` unknownFields protoimpl.UnknownFields - - IdentityKey []byte `protobuf:"bytes,1,opt,name=identity_key,json=identityKey" json:"identity_key,omitempty"` - IdentitySig []byte `protobuf:"bytes,2,opt,name=identity_sig,json=identitySig" json:"identity_sig,omitempty"` - Extensions *NoiseExtensions `protobuf:"bytes,4,opt,name=extensions" json:"extensions,omitempty"` + sizeCache protoimpl.SizeCache } func (x *NoiseHandshakePayload) Reset() { @@ -136,7 +135,7 @@ func (x *NoiseHandshakePayload) GetExtensions() *NoiseExtensions { var File_p2p_security_noise_pb_payload_proto protoreflect.FileDescriptor -var file_p2p_security_noise_pb_payload_proto_rawDesc = []byte{ +var file_p2p_security_noise_pb_payload_proto_rawDesc = string([]byte{ 0x0a, 0x23, 0x70, 0x32, 0x70, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x2f, 0x70, 0x62, 0x2f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, 0x62, 0x22, 0x6f, 0x0a, 0x0f, 0x4e, 0x6f, 0x69, @@ -160,16 +159,16 @@ var file_p2p_security_noise_pb_payload_proto_rawDesc = []byte{ 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x2f, 0x70, 0x62, -} +}) var ( file_p2p_security_noise_pb_payload_proto_rawDescOnce sync.Once - file_p2p_security_noise_pb_payload_proto_rawDescData = file_p2p_security_noise_pb_payload_proto_rawDesc + file_p2p_security_noise_pb_payload_proto_rawDescData []byte ) func file_p2p_security_noise_pb_payload_proto_rawDescGZIP() []byte { file_p2p_security_noise_pb_payload_proto_rawDescOnce.Do(func() { - file_p2p_security_noise_pb_payload_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_security_noise_pb_payload_proto_rawDescData) + file_p2p_security_noise_pb_payload_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_security_noise_pb_payload_proto_rawDesc), len(file_p2p_security_noise_pb_payload_proto_rawDesc))) }) return file_p2p_security_noise_pb_payload_proto_rawDescData } @@ -197,7 +196,7 @@ func file_p2p_security_noise_pb_payload_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_security_noise_pb_payload_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_security_noise_pb_payload_proto_rawDesc), len(file_p2p_security_noise_pb_payload_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -208,7 +207,6 @@ func file_p2p_security_noise_pb_payload_proto_init() { MessageInfos: file_p2p_security_noise_pb_payload_proto_msgTypes, }.Build() File_p2p_security_noise_pb_payload_proto = out.File - file_p2p_security_noise_pb_payload_proto_rawDesc = nil file_p2p_security_noise_pb_payload_proto_goTypes = nil file_p2p_security_noise_pb_payload_proto_depIdxs = nil } diff --git a/p2p/test/basichost/basic_host_test.go b/p2p/test/basichost/basic_host_test.go index 9cd442dbf0..0197387b1b 100644 --- a/p2p/test/basichost/basic_host_test.go +++ b/p2p/test/basichost/basic_host_test.go @@ -8,11 +8,14 @@ import ( "time" "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" + "github.com/libp2p/go-libp2p/p2p/net/swarm" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" + libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic" libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport" ma "github.com/multiformats/go-multiaddr" @@ -199,3 +202,69 @@ func TestAddrFactorCertHashAppend(t *testing.T) { return hasWebRTC && hasWebTransport }, 5*time.Second, 100*time.Millisecond) } + +func TestOnlyWebRTCDirectDialNoDelay(t *testing.T) { + // This tests that only webrtc-direct dials are dialled immediately + // and not delayed by dial ranker. + h1, err := libp2p.New( + libp2p.Transport(libp2pwebrtc.New), + libp2p.ListenAddrStrings( + "/ip4/0.0.0.0/udp/0/webrtc-direct", + ), + ) + require.NoError(t, err) + h2, err := libp2p.New( + libp2p.Transport(libp2pwebrtc.New), + libp2p.NoListenAddrs, + ) + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), swarm.PrivateOtherDelay-10*time.Millisecond) + defer cancel() + err = h2.Connect(ctx, peer.AddrInfo{ID: h1.ID(), Addrs: h1.Addrs()}) + require.NoError(t, err) +} + +func TestWebRTCWithQUICManyConnections(t *testing.T) { + // Correctly fixes: https://github.com/libp2p/js-libp2p/issues/2805 + + // The server has both /quic-v1 and /webrtc-direct listen addresses + h, err := libp2p.New( + libp2p.Transport(libp2pquic.NewTransport), + libp2p.Transport(libp2pwebrtc.New), + libp2p.ListenAddrStrings("/ip4/0.0.0.0/udp/0/quic-v1"), + libp2p.ListenAddrStrings("/ip4/0.0.0.0/udp/0/webrtc-direct"), + libp2p.ResourceManager(&network.NullResourceManager{}), + ) + require.NoError(t, err) + defer h.Close() + + const N = 200 + // These N dialers have both /quic-v1 and /webrtc-direct transports + var dialers [N]host.Host + for i := 0; i < N; i++ { + dialers[i], err = libp2p.New(libp2p.NoListenAddrs) + require.NoError(t, err) + defer dialers[i].Close() + } + // This dialer has only /webrtc-direct transport + d, err := libp2p.New(libp2p.Transport(libp2pwebrtc.New), libp2p.NoListenAddrs) + require.NoError(t, err) + defer d.Close() + + for i := 0; i < N; i++ { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + // With happy eyeballs these dialers will connect over only /quic-v1 + // and not stall the /webrtc-direct handshake goroutines. + // it is fine if the dial fails, we just want to ensure that there's space + // in the /webrtc-direct listen queue + _ = dialers[i].Connect(ctx, peer.AddrInfo{ID: h.ID(), Addrs: h.Addrs()}) + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + // The webrtc only dialer should be able to connect to the peer + err = d.Connect(ctx, peer.AddrInfo{ID: h.ID(), Addrs: h.Addrs()}) + require.NoError(t, err) +} diff --git a/p2p/test/transport/gating_test.go b/p2p/test/transport/gating_test.go index 99ce67b521..a26378357a 100644 --- a/p2p/test/transport/gating_test.go +++ b/p2p/test/transport/gating_test.go @@ -22,14 +22,26 @@ import ( //go:generate go run go.uber.org/mock/mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater -func stripCertHash(addr ma.Multiaddr) ma.Multiaddr { +// normalize removes the certhash and replaces /wss with /tls/ws +func normalize(addr ma.Multiaddr) ma.Multiaddr { for { if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err != nil { break } addr, _ = ma.SplitLast(addr) } - return addr + + // replace /wss with /tls/ws + components := []ma.Multiaddr{} + ma.ForEach(addr, func(c ma.Component) bool { + if c.Protocol().Code == ma.P_WSS { + components = append(components, ma.StringCast("/tls/ws")) + } else { + components = append(components, &c) + } + return true + }) + return ma.Join(components...) } func addrPort(addr ma.Multiaddr) netip.AddrPort { @@ -119,8 +131,7 @@ func TestInterceptSecuredOutgoing(t *testing.T) { connGater.EXPECT().InterceptPeerDial(h2.ID()).Return(true), connGater.EXPECT().InterceptAddrDial(h2.ID(), gomock.Any()).Return(true), connGater.EXPECT().InterceptSecured(network.DirOutbound, h2.ID(), gomock.Any()).Do(func(_ network.Direction, _ peer.ID, addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport and WebRTC addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]).String(), addrs.RemoteMultiaddr().String()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(addrs.RemoteMultiaddr())) }), ) err := h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) @@ -154,8 +165,7 @@ func TestInterceptUpgradedOutgoing(t *testing.T) { connGater.EXPECT().InterceptAddrDial(h2.ID(), gomock.Any()).Return(true), connGater.EXPECT().InterceptSecured(network.DirOutbound, h2.ID(), gomock.Any()).Return(true), connGater.EXPECT().InterceptUpgraded(gomock.Any()).Do(func(c network.Conn) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), c.RemoteMultiaddr()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(c.RemoteMultiaddr())) require.Equal(t, h1.ID(), c.LocalPeer()) require.Equal(t, h2.ID(), c.RemotePeer()) })) @@ -189,17 +199,15 @@ func TestInterceptAccept(t *testing.T) { // In WebRTC, retransmissions of the STUN packet might cause us to create multiple connections, // if the first connection attempt is rejected. connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(addrs.LocalMultiaddr())) }).AnyTimes() - } else if strings.Contains(tc.Name, "WebSocket-Shared") { + } else if strings.Contains(tc.Name, "WebSocket-Shared") || strings.Contains(tc.Name, "WebSocket-Secured-Shared") { connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { require.Equal(t, addrPort(h2.Addrs()[0]), addrPort(addrs.LocalMultiaddr())) }) } else { connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr(), "%s\n%s", h2.Addrs()[0], addrs.LocalMultiaddr()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(addrs.LocalMultiaddr())) }) } @@ -236,8 +244,7 @@ func TestInterceptSecuredIncoming(t *testing.T) { gomock.InOrder( connGater.EXPECT().InterceptAccept(gomock.Any()).Return(true), connGater.EXPECT().InterceptSecured(network.DirInbound, h1.ID(), gomock.Any()).Do(func(_ network.Direction, _ peer.ID, addrs network.ConnMultiaddrs) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(addrs.LocalMultiaddr())) }), ) h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), time.Hour) @@ -270,8 +277,7 @@ func TestInterceptUpgradedIncoming(t *testing.T) { connGater.EXPECT().InterceptAccept(gomock.Any()).Return(true), connGater.EXPECT().InterceptSecured(network.DirInbound, h1.ID(), gomock.Any()).Return(true), connGater.EXPECT().InterceptUpgraded(gomock.Any()).Do(func(c network.Conn) { - // remove the certhash component from WebTransport addresses - require.Equal(t, stripCertHash(h2.Addrs()[0]), c.LocalMultiaddr()) + require.Equal(t, normalize(h2.Addrs()[0]), normalize(c.LocalMultiaddr())) require.Equal(t, h1.ID(), c.RemotePeer()) require.Equal(t, h2.ID(), c.LocalPeer()) }), diff --git a/p2p/test/transport/transport_test.go b/p2p/test/transport/transport_test.go index 60f8ca0c06..c8445a3997 100644 --- a/p2p/test/transport/transport_test.go +++ b/p2p/test/transport/transport_test.go @@ -3,10 +3,16 @@ package transport_integration import ( "bytes" "context" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" "errors" "fmt" "io" + "math/big" "net" "runtime" "strings" @@ -15,6 +21,8 @@ import ( "testing" "time" + libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" + "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/config" "github.com/libp2p/go-libp2p/core/connmgr" @@ -30,11 +38,13 @@ import ( "github.com/libp2p/go-libp2p/p2p/net/swarm" "github.com/libp2p/go-libp2p/p2p/protocol/ping" "github.com/libp2p/go-libp2p/p2p/security/noise" - tls "github.com/libp2p/go-libp2p/p2p/security/tls" + "github.com/libp2p/go-libp2p/p2p/transport/tcp" libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc" + "github.com/libp2p/go-libp2p/p2p/transport/websocket" "go.uber.org/mock/gomock" ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -66,6 +76,44 @@ func transformOpts(opts TransportTestCaseOpts) []config.Option { return libp2pOpts } +func selfSignedTLSConfig(t *testing.T) *tls.Config { + t.Helper() + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + notBefore := time.Now() + notAfter := notBefore.Add(365 * 24 * time.Hour) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + require.NoError(t, err) + + certTemplate := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Test"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &certTemplate, &certTemplate, &priv.PublicKey, priv) + require.NoError(t, err) + + cert := tls.Certificate{ + Certificate: [][]byte{derBytes}, + PrivateKey: priv, + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + } + return tlsConfig +} + var transportsToTest = []TransportTestCase{ { Name: "TCP / Noise / Yamux", @@ -87,7 +135,7 @@ var transportsToTest = []TransportTestCase{ Name: "TCP / TLS / Yamux", HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { libp2pOpts := transformOpts(opts) - libp2pOpts = append(libp2pOpts, libp2p.Security(tls.ID, tls.New)) + libp2pOpts = append(libp2pOpts, libp2p.Security(libp2ptls.ID, libp2ptls.New)) libp2pOpts = append(libp2pOpts, libp2p.Muxer(yamux.ID, yamux.DefaultTransport)) if opts.NoListen { libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) @@ -104,8 +152,43 @@ var transportsToTest = []TransportTestCase{ HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { libp2pOpts := transformOpts(opts) libp2pOpts = append(libp2pOpts, libp2p.ShareTCPListener()) - libp2pOpts = append(libp2pOpts, libp2p.Security(tls.ID, tls.New)) + libp2pOpts = append(libp2pOpts, libp2p.Security(libp2ptls.ID, libp2ptls.New)) + libp2pOpts = append(libp2pOpts, libp2p.Muxer(yamux.ID, yamux.DefaultTransport)) + if opts.NoListen { + libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) + } else { + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0")) + } + h, err := libp2p.New(libp2pOpts...) + require.NoError(t, err) + return h + }, + }, + { + Name: "TCP-Shared-WithMetrics / TLS / Yamux", + HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { + libp2pOpts := transformOpts(opts) + libp2pOpts = append(libp2pOpts, libp2p.ShareTCPListener()) + libp2pOpts = append(libp2pOpts, libp2p.Security(libp2ptls.ID, libp2ptls.New)) + libp2pOpts = append(libp2pOpts, libp2p.Muxer(yamux.ID, yamux.DefaultTransport)) + libp2pOpts = append(libp2pOpts, libp2p.Transport(tcp.NewTCPTransport, tcp.WithMetrics())) + if opts.NoListen { + libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) + } else { + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0")) + } + h, err := libp2p.New(libp2pOpts...) + require.NoError(t, err) + return h + }, + }, + { + Name: "TCP-WithMetrics / TLS / Yamux", + HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { + libp2pOpts := transformOpts(opts) + libp2pOpts = append(libp2pOpts, libp2p.Security(libp2ptls.ID, libp2ptls.New)) libp2pOpts = append(libp2pOpts, libp2p.Muxer(yamux.ID, yamux.DefaultTransport)) + libp2pOpts = append(libp2pOpts, libp2p.Transport(tcp.NewTCPTransport, tcp.WithMetrics())) if opts.NoListen { libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs) } else { @@ -131,6 +214,23 @@ var transportsToTest = []TransportTestCase{ return h }, }, + { + Name: "WebSocket-Secured-Shared", + HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { + libp2pOpts := transformOpts(opts) + libp2pOpts = append(libp2pOpts, libp2p.ShareTCPListener()) + if opts.NoListen { + config := tls.Config{InsecureSkipVerify: true} + libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs, libp2p.Transport(websocket.New, websocket.WithTLSClientConfig(&config))) + } else { + config := selfSignedTLSConfig(t) + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0/sni/localhost/tls/ws"), libp2p.Transport(websocket.New, websocket.WithTLSConfig(config))) + } + h, err := libp2p.New(libp2pOpts...) + require.NoError(t, err) + return h + }, + }, { Name: "WebSocket", HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { @@ -145,6 +245,22 @@ var transportsToTest = []TransportTestCase{ return h }, }, + { + Name: "WebSocket-Secured", + HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { + libp2pOpts := transformOpts(opts) + if opts.NoListen { + config := tls.Config{InsecureSkipVerify: true} + libp2pOpts = append(libp2pOpts, libp2p.NoListenAddrs, libp2p.Transport(websocket.New, websocket.WithTLSClientConfig(&config))) + } else { + config := selfSignedTLSConfig(t) + libp2pOpts = append(libp2pOpts, libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0/sni/localhost/tls/ws"), libp2p.Transport(websocket.New, websocket.WithTLSConfig(config))) + } + h, err := libp2p.New(libp2pOpts...) + require.NoError(t, err) + return h + }, + }, { Name: "QUIC", HostGenerator: func(t *testing.T, opts TransportTestCaseOpts) host.Host { @@ -830,3 +946,170 @@ func TestConnClosedWhenRemoteCloses(t *testing.T) { }) } } + +func TestErrorCodes(t *testing.T) { + assertStreamErrors := func(s network.Stream, expectedError error) { + buf := make([]byte, 10) + _, err := s.Read(buf) + require.ErrorIs(t, err, expectedError) + + _, err = s.Write(buf) + require.ErrorIs(t, err, expectedError) + } + + for _, tc := range transportsToTest { + t.Run(tc.Name, func(t *testing.T) { + server := tc.HostGenerator(t, TransportTestCaseOpts{}) + client := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) + defer server.Close() + defer client.Close() + + client.Peerstore().AddAddrs(server.ID(), server.Addrs(), peerstore.PermanentAddrTTL) + + // setup stream handler + remoteStreamQ := make(chan network.Stream) + server.SetStreamHandler("/test", func(s network.Stream) { + b := make([]byte, 10) + n, err := s.Read(b) + if !assert.NoError(t, err) { + return + } + _, err = s.Write(b[:n]) + if !assert.NoError(t, err) { + return + } + remoteStreamQ <- s + }) + + // pingPong writes and reads "hello" on the stream + pingPong := func(s network.Stream) { + buf := []byte("hello") + _, err := s.Write(buf) + require.NoError(t, err) + + _, err = s.Read(buf) + require.NoError(t, err) + require.Equal(t, buf, []byte("hello")) + } + + t.Run("StreamResetWithError", func(t *testing.T) { + if tc.Name == "WebTransport" { + t.Skipf("skipping: %s, not implemented", tc.Name) + return + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + s, err := client.NewStream(ctx, server.ID(), "/test") + require.NoError(t, err) + pingPong(s) + + remoteStream := <-remoteStreamQ + defer remoteStream.Reset() + + err = s.ResetWithError(42) + require.NoError(t, err) + assertStreamErrors(s, &network.StreamError{ + ErrorCode: 42, + Remote: false, + }) + + assertStreamErrors(remoteStream, &network.StreamError{ + ErrorCode: 42, + Remote: true, + }) + }) + t.Run("StreamResetWithErrorByRemote", func(t *testing.T) { + if tc.Name == "WebTransport" { + t.Skipf("skipping: %s, not implemented", tc.Name) + return + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + s, err := client.NewStream(ctx, server.ID(), "/test") + require.NoError(t, err) + pingPong(s) + + remoteStream := <-remoteStreamQ + + err = remoteStream.ResetWithError(42) + require.NoError(t, err) + + assertStreamErrors(s, &network.StreamError{ + ErrorCode: 42, + Remote: true, + }) + + assertStreamErrors(remoteStream, &network.StreamError{ + ErrorCode: 42, + Remote: false, + }) + }) + + t.Run("StreamResetByConnCloseWithError", func(t *testing.T) { + if tc.Name == "WebTransport" || tc.Name == "WebRTC" { + t.Skipf("skipping: %s, not implemented", tc.Name) + return + } + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + s, err := client.NewStream(ctx, server.ID(), "/test") + require.NoError(t, err) + pingPong(s) + + remoteStream := <-remoteStreamQ + defer remoteStream.Reset() + + err = s.Conn().CloseWithError(42) + require.NoError(t, err) + + assertStreamErrors(s, &network.ConnError{ + ErrorCode: 42, + Remote: false, + }) + + assertStreamErrors(remoteStream, &network.ConnError{ + ErrorCode: 42, + Remote: true, + }) + }) + + t.Run("NewStreamErrorByConnCloseWithError", func(t *testing.T) { + if tc.Name == "WebTransport" || tc.Name == "WebRTC" { + t.Skipf("skipping: %s, not implemented", tc.Name) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + s, err := client.NewStream(ctx, server.ID(), "/test") + require.NoError(t, err) + pingPong(s) + + err = s.Conn().CloseWithError(42) + require.NoError(t, err) + + remoteStream := <-remoteStreamQ + defer remoteStream.Reset() + + localErr := &network.ConnError{ + ErrorCode: 42, + Remote: false, + } + + remoteErr := &network.ConnError{ + ErrorCode: 42, + Remote: true, + } + + // assert these first to ensure that remote has closed the connection + assertStreamErrors(remoteStream, remoteErr) + + _, err = s.Conn().NewStream(ctx) + require.ErrorIs(t, err, localErr) + + _, err = remoteStream.Conn().NewStream(ctx) + require.ErrorIs(t, err, remoteErr) + }) + }) + } +} diff --git a/p2p/transport/quic/conn.go b/p2p/transport/quic/conn.go index a2da81eb34..8b381d8eda 100644 --- a/p2p/transport/quic/conn.go +++ b/p2p/transport/quic/conn.go @@ -34,6 +34,13 @@ func (c *conn) Close() error { return c.closeWithError(0, "") } +// CloseWithError closes the connection +// It must be called even if the peer closed the connection in order for +// garbage collection to properly work in this package. +func (c *conn) CloseWithError(errCode network.ConnErrorCode) error { + return c.closeWithError(quic.ApplicationErrorCode(errCode), "") +} + func (c *conn) closeWithError(errCode quic.ApplicationErrorCode, errString string) error { c.transport.removeConn(c.quicConn) err := c.quicConn.CloseWithError(errCode, errString) @@ -53,13 +60,19 @@ func (c *conn) allowWindowIncrease(size uint64) bool { // OpenStream creates a new stream. func (c *conn) OpenStream(ctx context.Context) (network.MuxedStream, error) { qstr, err := c.quicConn.OpenStreamSync(ctx) - return &stream{Stream: qstr}, err + if err != nil { + return nil, parseStreamError(err) + } + return &stream{Stream: qstr}, nil } // AcceptStream accepts a stream opened by the other side. func (c *conn) AcceptStream() (network.MuxedStream, error) { qstr, err := c.quicConn.AcceptStream(context.Background()) - return &stream{Stream: qstr}, err + if err != nil { + return nil, parseStreamError(err) + } + return &stream{Stream: qstr}, nil } // LocalPeer returns our peer ID diff --git a/p2p/transport/quic/conn_test.go b/p2p/transport/quic/conn_test.go index d3e27a7e16..bf3f7b0751 100644 --- a/p2p/transport/quic/conn_test.go +++ b/p2p/transport/quic/conn_test.go @@ -270,6 +270,9 @@ func TestStreams(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { testStreams(t, tc) }) + t.Run(tc.Name, func(t *testing.T) { + testStreamsErrorCode(t, tc) + }) } } @@ -305,6 +308,45 @@ func testStreams(t *testing.T, tc *connTestCase) { require.Equal(t, data, []byte("foobar")) } +func testStreamsErrorCode(t *testing.T, tc *connTestCase) { + serverID, serverKey := createPeer(t) + _, clientKey := createPeer(t) + + serverTransport, err := NewTransport(serverKey, newConnManager(t, tc.Options...), nil, nil, nil) + require.NoError(t, err) + defer serverTransport.(io.Closer).Close() + ln := runServer(t, serverTransport, "/ip4/127.0.0.1/udp/0/quic-v1") + defer ln.Close() + + clientTransport, err := NewTransport(clientKey, newConnManager(t, tc.Options...), nil, nil, nil) + require.NoError(t, err) + defer clientTransport.(io.Closer).Close() + conn, err := clientTransport.Dial(context.Background(), ln.Multiaddr(), serverID) + require.NoError(t, err) + defer conn.Close() + serverConn, err := ln.Accept() + require.NoError(t, err) + defer serverConn.Close() + + str, err := conn.OpenStream(context.Background()) + require.NoError(t, err) + err = str.ResetWithError(42) + require.NoError(t, err) + + sstr, err := serverConn.AcceptStream() + require.NoError(t, err) + _, err = io.ReadAll(sstr) + require.Error(t, err) + se := &network.StreamError{} + if errors.As(err, &se) { + require.Equal(t, se.ErrorCode, network.StreamErrorCode(42)) + require.True(t, se.Remote) + } else { + t.Fatalf("expected error to be of network.StreamError type, got %T, %v", err, err) + } + +} + func TestHandshakeFailPeerIDMismatch(t *testing.T) { for _, tc := range connTestCases { t.Run(tc.Name, func(t *testing.T) { diff --git a/p2p/transport/quic/listener.go b/p2p/transport/quic/listener.go index f90bdf53f0..30868e49eb 100644 --- a/p2p/transport/quic/listener.go +++ b/p2p/transport/quic/listener.go @@ -11,7 +11,6 @@ import ( tpt "github.com/libp2p/go-libp2p/core/transport" p2ptls "github.com/libp2p/go-libp2p/p2p/security/tls" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" - ma "github.com/multiformats/go-multiaddr" "github.com/quic-go/quic-go" ) @@ -54,12 +53,12 @@ func (l *listener) Accept() (tpt.CapableConn, error) { c, err := l.wrapConn(qconn) if err != nil { log.Debugf("failed to setup connection: %s", err) - qconn.CloseWithError(1, "") + qconn.CloseWithError(quic.ApplicationErrorCode(network.ConnResourceLimitExceeded), "") continue } l.transport.addConn(qconn, c) if l.transport.gater != nil && !(l.transport.gater.InterceptAccept(c) && l.transport.gater.InterceptSecured(network.DirInbound, c.remotePeerID, c)) { - c.closeWithError(errorCodeConnectionGating, "connection gated") + c.closeWithError(quic.ApplicationErrorCode(network.ConnGated), "connection gated") continue } diff --git a/p2p/transport/quic/listener_test.go b/p2p/transport/quic/listener_test.go index dbd6d810e4..53d6001d35 100644 --- a/p2p/transport/quic/listener_test.go +++ b/p2p/transport/quic/listener_test.go @@ -159,10 +159,11 @@ func TestCleanupConnWhenBlocked(t *testing.T) { s.SetReadDeadline(time.Now().Add(10 * time.Second)) b := [1]byte{} _, err = s.Read(b[:]) - if err != nil && errors.As(err, &quicErr) { + connError := &network.ConnError{} + if err != nil && errors.As(err, &connError) { // We hit our expected application error return } - t.Fatalf("expected application error, got %v", err) + t.Fatalf("expected network.ConnError, got %v", err) } diff --git a/p2p/transport/quic/stream.go b/p2p/transport/quic/stream.go index 56f12dade2..1de4770dce 100644 --- a/p2p/transport/quic/stream.go +++ b/p2p/transport/quic/stream.go @@ -2,6 +2,7 @@ package libp2pquic import ( "errors" + "math" "github.com/libp2p/go-libp2p/core/network" @@ -18,20 +19,49 @@ type stream struct { var _ network.MuxedStream = &stream{} +func parseStreamError(err error) error { + if err == nil { + return err + } + se := &quic.StreamError{} + if errors.As(err, &se) { + var code network.StreamErrorCode + if se.ErrorCode > math.MaxUint32 { + code = network.StreamCodeOutOfRange + } else { + code = network.StreamErrorCode(se.ErrorCode) + } + err = &network.StreamError{ + ErrorCode: code, + Remote: se.Remote, + TransportError: se, + } + } + ae := &quic.ApplicationError{} + if errors.As(err, &ae) { + var code network.ConnErrorCode + if ae.ErrorCode > math.MaxUint32 { + code = network.ConnCodeOutOfRange + } else { + code = network.ConnErrorCode(ae.ErrorCode) + } + err = &network.ConnError{ + ErrorCode: code, + Remote: ae.Remote, + TransportError: ae, + } + } + return err +} + func (s *stream) Read(b []byte) (n int, err error) { n, err = s.Stream.Read(b) - if err != nil && errors.Is(err, &quic.StreamError{}) { - err = network.ErrReset - } - return n, err + return n, parseStreamError(err) } func (s *stream) Write(b []byte) (n int, err error) { n, err = s.Stream.Write(b) - if err != nil && errors.Is(err, &quic.StreamError{}) { - err = network.ErrReset - } - return n, err + return n, parseStreamError(err) } func (s *stream) Reset() error { @@ -40,6 +70,12 @@ func (s *stream) Reset() error { return nil } +func (s *stream) ResetWithError(errCode network.StreamErrorCode) error { + s.Stream.CancelRead(quic.StreamErrorCode(errCode)) + s.Stream.CancelWrite(quic.StreamErrorCode(errCode)) + return nil +} + func (s *stream) Close() error { s.Stream.CancelRead(reset) return s.Stream.Close() diff --git a/p2p/transport/quic/transport.go b/p2p/transport/quic/transport.go index 4d3d9e551d..62d31a8d2a 100644 --- a/p2p/transport/quic/transport.go +++ b/p2p/transport/quic/transport.go @@ -34,8 +34,6 @@ var ErrHolePunching = errors.New("hole punching attempted; no active dial") var HolePunchTimeout = 5 * time.Second -const errorCodeConnectionGating = 0x47415445 // GATE in ASCII - // The Transport implements the tpt.Transport interface for QUIC connections. type transport struct { privKey ic.PrivKey @@ -169,7 +167,7 @@ func (t *transport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p pee remoteMultiaddr: raddr, } if t.gater != nil && !t.gater.InterceptSecured(network.DirOutbound, p, c) { - pconn.CloseWithError(errorCodeConnectionGating, "connection gated") + pconn.CloseWithError(quic.ApplicationErrorCode(network.ConnGated), "connection gated") return nil, fmt.Errorf("secured connection gated") } t.addConn(pconn, c) diff --git a/p2p/transport/quic/virtuallistener.go b/p2p/transport/quic/virtuallistener.go index 7927225567..5b23e4c507 100644 --- a/p2p/transport/quic/virtuallistener.go +++ b/p2p/transport/quic/virtuallistener.go @@ -3,6 +3,7 @@ package libp2pquic import ( "sync" + "github.com/libp2p/go-libp2p/core/network" tpt "github.com/libp2p/go-libp2p/core/transport" "github.com/libp2p/go-libp2p/p2p/transport/quicreuse" @@ -142,8 +143,8 @@ func (r *acceptLoopRunner) innerAccept(l *listener, expectedVersion quic.Version select { case ch <- acceptVal{conn: conn}: default: + conn.CloseWithError(network.ConnRateLimited) // accept queue filled up, drop the connection - conn.Close() log.Warn("Accept queue filled. Dropping connection.") } diff --git a/p2p/transport/quicreuse/connmgr.go b/p2p/transport/quicreuse/connmgr.go index c3aa0fa046..def7c5da56 100644 --- a/p2p/transport/quicreuse/connmgr.go +++ b/p2p/transport/quicreuse/connmgr.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "errors" + "io" "net" "sync" @@ -15,6 +16,22 @@ import ( quicmetrics "github.com/quic-go/quic-go/metrics" ) +type QUICListener interface { + Accept(ctx context.Context) (quic.Connection, error) + Close() error + Addr() net.Addr +} + +var _ QUICListener = &quic.Listener{} + +type QUICTransport interface { + Listen(tlsConf *tls.Config, conf *quic.Config) (QUICListener, error) + Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *quic.Config) (quic.Connection, error) + WriteTo(b []byte, addr net.Addr) (int, error) + ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error) + io.Closer +} + type ConnManager struct { reuseUDP4 *reuse reuseUDP6 *reuse @@ -101,6 +118,32 @@ func (c *ConnManager) getReuse(network string) (*reuse, error) { } } +// LendTransport is an advanced method used to lend an existing QUICTransport +// to the ConnManager. The ConnManager will close the returned channel when it +// is done with the transport, so that the owner may safely close the transport. +func (c *ConnManager) LendTransport(network string, tr QUICTransport, conn net.PacketConn) (<-chan struct{}, error) { + c.quicListenersMu.Lock() + defer c.quicListenersMu.Unlock() + + localAddr, ok := conn.LocalAddr().(*net.UDPAddr) + if !ok { + return nil, errors.New("expected a conn.LocalAddr() to return a *net.UDPAddr") + } + + refCountedTr := &refcountedTransport{ + QUICTransport: tr, + packetConn: conn, + borrowDoneSignal: make(chan struct{}), + } + + var reuse *reuse + reuse, err := c.getReuse(network) + if err != nil { + return nil, err + } + return refCountedTr.borrowDoneSignal, reuse.AddTransport(refCountedTr, localAddr) +} + func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (Listener, error) { return c.ListenQUICAndAssociate(nil, addr, tlsConf, allowWindowIncrease) } @@ -175,7 +218,7 @@ func (c *ConnManager) SharedNonQUICPacketConn(network string, laddr *net.UDPAddr ctx: ctx, ctxCancel: cancel, owningTransport: t, - tr: &t.Transport, + tr: t.QUICTransport, }, nil } return nil, errors.New("expected to be able to share with a QUIC listener, but the QUIC listener is not using a refcountedTransport. `DisableReuseport` should not be set") @@ -201,10 +244,12 @@ func (c *ConnManager) transportForListen(association any, network string, laddr } return &singleOwnerTransport{ packetConn: conn, - Transport: quic.Transport{ - Conn: conn, - StatelessResetKey: &c.srk, - TokenGeneratorKey: &c.tokenKey, + Transport: &wrappedQUICTransport{ + &quic.Transport{ + Conn: conn, + StatelessResetKey: &c.srk, + TokenGeneratorKey: &c.tokenKey, + }, }, }, nil } @@ -279,7 +324,7 @@ func (c *ConnManager) TransportWithAssociationForDial(association any, network s if err != nil { return nil, err } - return &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn}, nil + return &singleOwnerTransport{Transport: &wrappedQUICTransport{&quic.Transport{Conn: conn, StatelessResetKey: &c.srk}}, packetConn: conn}, nil } func (c *ConnManager) Protocols() []int { @@ -299,3 +344,11 @@ func (c *ConnManager) Close() error { func (c *ConnManager) ClientConfig() *quic.Config { return c.clientConfig } + +type wrappedQUICTransport struct { + *quic.Transport +} + +func (t *wrappedQUICTransport) Listen(tlsConf *tls.Config, conf *quic.Config) (QUICListener, error) { + return t.Transport.Listen(tlsConf, conf) +} diff --git a/p2p/transport/quicreuse/connmgr_test.go b/p2p/transport/quicreuse/connmgr_test.go index 8e7da2cd7f..51646bac98 100644 --- a/p2p/transport/quicreuse/connmgr_test.go +++ b/p2p/transport/quicreuse/connmgr_test.go @@ -97,7 +97,7 @@ func TestConnectionPassedToQUICForListening(t *testing.T) { quicTr, err := cm.transportForListen(nil, netw, naddr) require.NoError(t, err) defer quicTr.Close() - if _, ok := quicTr.(*singleOwnerTransport).Transport.Conn.(quic.OOBCapablePacketConn); !ok { + if _, ok := quicTr.(*singleOwnerTransport).packetConn.(quic.OOBCapablePacketConn); !ok { t.Fatal("connection passed to quic-go cannot be type asserted to a *net.UDPConn") } } @@ -156,7 +156,7 @@ func TestConnectionPassedToQUICForDialing(t *testing.T) { require.NoError(t, err, "dial error") defer quicTr.Close() - if _, ok := quicTr.(*singleOwnerTransport).Transport.Conn.(quic.OOBCapablePacketConn); !ok { + if _, ok := quicTr.(*singleOwnerTransport).packetConn.(quic.OOBCapablePacketConn); !ok { t.Fatal("connection passed to quic-go cannot be type asserted to a *net.UDPConn") } } @@ -257,3 +257,61 @@ func testListener(t *testing.T, enableReuseport bool) { checkClosed(t, cm) } + +func TestExternalTransport(t *testing.T) { + conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero}) + require.NoError(t, err) + defer conn.Close() + port := conn.LocalAddr().(*net.UDPAddr).Port + tr := &quic.Transport{Conn: conn} + defer tr.Close() + + cm, err := NewConnManager(quic.StatelessResetKey{}, quic.TokenGeneratorKey{}) + require.NoError(t, err) + doneWithTr, err := cm.LendTransport("udp4", &wrappedQUICTransport{tr}, conn) + require.NoError(t, err) + + // make sure this transport is used when listening on the same port + ln, err := cm.ListenQUICAndAssociate( + "quic", + ma.StringCast(fmt.Sprintf("/ip4/0.0.0.0/udp/%d", port)), + &tls.Config{NextProtos: []string{"libp2p"}}, + func(quic.Connection, uint64) bool { return false }, + ) + require.NoError(t, err) + defer ln.Close() + require.Equal(t, port, ln.Addr().(*net.UDPAddr).Port) + + // make sure this transport is used when dialing out + udpLn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}) + require.NoError(t, err) + defer udpLn.Close() + addrChan := make(chan net.Addr, 1) + go func() { + _, addr, _ := udpLn.ReadFrom(make([]byte, 2000)) + addrChan <- addr + }() + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) + defer cancel() + _, err = cm.DialQUIC( + ctx, + ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/udp/%d/quic-v1", udpLn.LocalAddr().(*net.UDPAddr).Port)), + &tls.Config{NextProtos: []string{"libp2p"}}, + func(quic.Connection, uint64) bool { return false }, + ) + require.ErrorIs(t, err, context.DeadlineExceeded) + + select { + case addr := <-addrChan: + require.Equal(t, port, addr.(*net.UDPAddr).Port) + case <-time.After(time.Second): + t.Fatal("timeout") + } + + cm.Close() + select { + case <-doneWithTr: + default: + t.Fatal("doneWithTr not closed") + } +} diff --git a/p2p/transport/quicreuse/listener.go b/p2p/transport/quicreuse/listener.go index 4ee20042d3..44028197d8 100644 --- a/p2p/transport/quicreuse/listener.go +++ b/p2p/transport/quicreuse/listener.go @@ -10,6 +10,7 @@ import ( "strings" "sync" + "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/transport" ma "github.com/multiformats/go-multiaddr" "github.com/quic-go/quic-go" @@ -29,7 +30,7 @@ type protoConf struct { } type quicListener struct { - l *quic.Listener + l QUICListener transport refCountedQuicTransport running chan struct{} addrs []ma.Multiaddr @@ -212,7 +213,7 @@ func (l *listener) Close() error { close(l.queue) // drain the queue for conn := range l.queue { - conn.CloseWithError(1, "closing") + conn.CloseWithError(quic.ApplicationErrorCode(network.ConnShutdown), "closing") } }) return nil diff --git a/p2p/transport/quicreuse/nonquic_packetconn.go b/p2p/transport/quicreuse/nonquic_packetconn.go index 2f950e76a1..833bd5804a 100644 --- a/p2p/transport/quicreuse/nonquic_packetconn.go +++ b/p2p/transport/quicreuse/nonquic_packetconn.go @@ -4,8 +4,6 @@ import ( "context" "net" "time" - - "github.com/quic-go/quic-go" ) // nonQUICPacketConn is a net.PacketConn that can be used to read and write @@ -13,7 +11,7 @@ import ( // other transports like WebRTC. type nonQUICPacketConn struct { owningTransport refCountedQuicTransport - tr *quic.Transport + tr QUICTransport ctx context.Context ctxCancel context.CancelFunc readCtx context.Context @@ -32,7 +30,7 @@ func (n *nonQUICPacketConn) Close() error { // LocalAddr implements net.PacketConn. func (n *nonQUICPacketConn) LocalAddr() net.Addr { - return n.tr.Conn.LocalAddr() + return n.owningTransport.LocalAddr() } // ReadFrom implements net.PacketConn. diff --git a/p2p/transport/quicreuse/reuse.go b/p2p/transport/quicreuse/reuse.go index c6fc611331..e329ea49dd 100644 --- a/p2p/transport/quicreuse/reuse.go +++ b/p2p/transport/quicreuse/reuse.go @@ -3,6 +3,8 @@ package quicreuse import ( "context" "crypto/tls" + "errors" + "fmt" "net" "sync" "time" @@ -25,23 +27,30 @@ type refCountedQuicTransport interface { IncreaseCount() Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *quic.Config) (quic.Connection, error) - Listen(tlsConf *tls.Config, conf *quic.Config) (*quic.Listener, error) + Listen(tlsConf *tls.Config, conf *quic.Config) (QUICListener, error) } type singleOwnerTransport struct { - quic.Transport + Transport QUICTransport // Used to write packets directly around QUIC. packetConn net.PacketConn } +var _ QUICTransport = &singleOwnerTransport{} + func (c *singleOwnerTransport) IncreaseCount() {} -func (c *singleOwnerTransport) DecreaseCount() { - c.Transport.Close() +func (c *singleOwnerTransport) DecreaseCount() { c.Transport.Close() } +func (c *singleOwnerTransport) LocalAddr() net.Addr { + return c.packetConn.LocalAddr() } -func (c *singleOwnerTransport) LocalAddr() net.Addr { - return c.Transport.Conn.LocalAddr() +func (c *singleOwnerTransport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *quic.Config) (quic.Connection, error) { + return c.Transport.Dial(ctx, addr, tlsConf, conf) +} + +func (c *singleOwnerTransport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error) { + return c.Transport.ReadNonQUICPacket(ctx, b) } func (c *singleOwnerTransport) Close() error { @@ -54,6 +63,10 @@ func (c *singleOwnerTransport) WriteTo(b []byte, addr net.Addr) (int, error) { return c.Transport.WriteTo(b, addr) } +func (c *singleOwnerTransport) Listen(tlsConf *tls.Config, conf *quic.Config) (QUICListener, error) { + return c.Transport.Listen(tlsConf, conf) +} + // Constant. Defined as variables to simplify testing. var ( garbageCollectInterval = 30 * time.Second @@ -61,7 +74,7 @@ var ( ) type refcountedTransport struct { - quic.Transport + QUICTransport // Used to write packets directly around QUIC. packetConn net.PacketConn @@ -70,6 +83,11 @@ type refcountedTransport struct { refCount int unusedSince time.Time + // Only set for transports we are borrowing. + // If set, we will _never_ close the underlying transport. We only close this + // channel to signal to the owner that we are done with it. + borrowDoneSignal chan struct{} + assocations map[any]struct{} } @@ -109,17 +127,24 @@ func (c *refcountedTransport) IncreaseCount() { } func (c *refcountedTransport) Close() error { - // TODO(when we drop support for go 1.19) use errors.Join - c.Transport.Close() - return c.packetConn.Close() + if c.borrowDoneSignal != nil { + close(c.borrowDoneSignal) + return nil + } + + return errors.Join(c.QUICTransport.Close(), c.packetConn.Close()) } func (c *refcountedTransport) WriteTo(b []byte, addr net.Addr) (int, error) { - return c.Transport.WriteTo(b, addr) + return c.QUICTransport.WriteTo(b, addr) } func (c *refcountedTransport) LocalAddr() net.Addr { - return c.Transport.Conn.LocalAddr() + return c.packetConn.LocalAddr() +} + +func (c *refcountedTransport) Listen(tlsConf *tls.Config, conf *quic.Config) (QUICListener, error) { + return c.QUICTransport.Listen(tlsConf, conf) } func (c *refcountedTransport) DecreaseCount() { @@ -302,15 +327,34 @@ func (r *reuse) transportForDialLocked(association any, network string, source * if err != nil { return nil, err } - tr := &refcountedTransport{Transport: quic.Transport{ - Conn: conn, - StatelessResetKey: r.statelessResetKey, - TokenGeneratorKey: r.tokenGeneratorKey, - }, packetConn: conn} + tr := &refcountedTransport{ + QUICTransport: &wrappedQUICTransport{ + Transport: &quic.Transport{ + Conn: conn, + StatelessResetKey: r.statelessResetKey, + TokenGeneratorKey: r.tokenGeneratorKey, + }, + }, + packetConn: conn, + } r.globalDialers[conn.LocalAddr().(*net.UDPAddr).Port] = tr return tr, nil } +func (r *reuse) AddTransport(tr *refcountedTransport, laddr *net.UDPAddr) error { + r.mutex.Lock() + defer r.mutex.Unlock() + + if !laddr.IP.IsUnspecified() { + return errors.New("adding transport for specific IP not supported") + } + if _, ok := r.globalDialers[laddr.Port]; ok { + return fmt.Errorf("already have global dialer for port %d", laddr.Port) + } + r.globalDialers[laddr.Port] = tr + return nil +} + func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcountedTransport, error) { r.mutex.Lock() defer r.mutex.Unlock() @@ -351,9 +395,11 @@ func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcoun } localAddr := conn.LocalAddr().(*net.UDPAddr) tr := &refcountedTransport{ - Transport: quic.Transport{ - Conn: conn, - StatelessResetKey: r.statelessResetKey, + QUICTransport: &wrappedQUICTransport{ + Transport: &quic.Transport{ + Conn: conn, + StatelessResetKey: r.statelessResetKey, + }, }, packetConn: conn, } diff --git a/p2p/transport/tcp/metrics.go b/p2p/transport/tcp/metrics.go index 50820d870c..cbd2f92f73 100644 --- a/p2p/transport/tcp/metrics.go +++ b/p2p/transport/tcp/metrics.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/libp2p/go-libp2p/core/network" "github.com/marten-seemann/tcp" "github.com/mikioh/tcpinfo" manet "github.com/multiformats/go-multiaddr/net" @@ -252,6 +253,16 @@ 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 diff --git a/p2p/transport/tcp/metrics_unix_test.go b/p2p/transport/tcp/metrics_test.go similarity index 98% rename from p2p/transport/tcp/metrics_unix_test.go rename to p2p/transport/tcp/metrics_test.go index 0a09526206..9a9946968b 100644 --- a/p2p/transport/tcp/metrics_unix_test.go +++ b/p2p/transport/tcp/metrics_test.go @@ -1,5 +1,3 @@ -// go:build: unix - package tcp import ( diff --git a/p2p/transport/tcp/tcp.go b/p2p/transport/tcp/tcp.go index 61e68941e2..758adde877 100644 --- a/p2p/transport/tcp/tcp.go +++ b/p2p/transport/tcp/tcp.go @@ -3,6 +3,7 @@ package tcp import ( "context" "errors" + "fmt" "net" "os" "runtime" @@ -117,12 +118,35 @@ func WithMetrics() Option { } } +// WithDialerForAddr sets a custom dialer for the given address. +// If set, it will be the *ONLY* dialer used. +func WithDialerForAddr(d DialerForAddr) Option { + return func(tr *TcpTransport) error { + tr.overrideDialerForAddr = d + return nil + } +} + +type ContextDialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// DialerForAddr is a function that returns a dialer for a given address. +// Implementations must return either a ContextDialer or an error. It is +// invalid to return nil, nil. +type DialerForAddr func(raddr ma.Multiaddr) (ContextDialer, error) + // TcpTransport is the TCP transport. type TcpTransport struct { // Connection upgrader for upgrading insecure stream connections to // secure multiplex connections. upgrader transport.Upgrader + // optional custom dialer to use for dialing. If set, it will be the *ONLY* dialer + // used. The transport will not attempt to reuse the listen port to + // dial or the shared TCP transport for dialing. + overrideDialerForAddr DialerForAddr + disableReuseport bool // Explicitly disable reuseport. enableMetrics bool @@ -170,6 +194,35 @@ func (t *TcpTransport) CanDial(addr ma.Multiaddr) bool { return dialMatcher.Matches(addr) } +func (t *TcpTransport) customDial(ctx context.Context, raddr ma.Multiaddr) (manet.Conn, error) { + // get the net.Dial friendly arguments from the remote addr + rnet, rnaddr, err := manet.DialArgs(raddr) + if err != nil { + return nil, err + } + dialer, err := t.overrideDialerForAddr(raddr) + if err != nil { + return nil, err + } + if dialer == nil { + return nil, fmt.Errorf("dialer for address %s is nil", raddr) + } + + // ok, Dial! + var nconn net.Conn + switch rnet { + case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix": + nconn, err = dialer.DialContext(ctx, rnet, rnaddr) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unrecognized network: %s", rnet) + } + + return manet.WrapNetConn(nconn) +} + func (t *TcpTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (manet.Conn, error) { // Apply the deadline iff applicable if t.connectTimeout > 0 { @@ -178,6 +231,10 @@ func (t *TcpTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (manet.Co defer cancel() } + if t.overrideDialerForAddr != nil { + return t.customDial(ctx, raddr) + } + if t.sharedTcp != nil { return t.sharedTcp.DialContext(ctx, raddr) } diff --git a/p2p/transport/tcp/tcp_test.go b/p2p/transport/tcp/tcp_test.go index 1f939d92be..1a712acf35 100644 --- a/p2p/transport/tcp/tcp_test.go +++ b/p2p/transport/tcp/tcp_test.go @@ -3,6 +3,7 @@ package tcp import ( "context" "errors" + "net" "testing" "github.com/libp2p/go-libp2p/core/crypto" @@ -205,3 +206,75 @@ func makeInsecureMuxer(t *testing.T) (peer.ID, []sec.SecureTransport) { require.NoError(t, err) return id, []sec.SecureTransport{insecure.NewWithIdentity(insecure.ID, id, priv)} } + +type errDialer struct { + err error +} + +func (d errDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return nil, d.err +} + +func TestCustomOverrideTCPDialer(t *testing.T) { + t.Run("success", func(t *testing.T) { + peerA, ia := makeInsecureMuxer(t) + ua, err := tptu.New(ia, muxers, nil, nil, nil) + require.NoError(t, err) + ta, err := NewTCPTransport(ua, nil, nil) + require.NoError(t, err) + ln, err := ta.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + require.NoError(t, err) + defer ln.Close() + + _, ib := makeInsecureMuxer(t) + ub, err := tptu.New(ib, muxers, nil, nil, nil) + require.NoError(t, err) + called := false + customDialer := func(raddr ma.Multiaddr) (ContextDialer, error) { + called = true + return &net.Dialer{}, nil + } + tb, err := NewTCPTransport(ub, nil, nil, WithDialerForAddr(customDialer)) + require.NoError(t, err) + + conn, err := tb.Dial(context.Background(), ln.Multiaddr(), peerA) + require.NoError(t, err) + require.NotNil(t, conn) + require.True(t, called, "custom dialer should have been called") + conn.Close() + }) + + t.Run("errors", func(t *testing.T) { + peerA, ia := makeInsecureMuxer(t) + ua, err := tptu.New(ia, muxers, nil, nil, nil) + require.NoError(t, err) + ta, err := NewTCPTransport(ua, nil, nil) + require.NoError(t, err) + ln, err := ta.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + require.NoError(t, err) + defer ln.Close() + + for _, test := range []string{"error in factory", "error in custom dialer"} { + t.Run(test, func(t *testing.T) { + _, ib := makeInsecureMuxer(t) + ub, err := tptu.New(ib, muxers, nil, nil, nil) + require.NoError(t, err) + customErr := errors.New("custom dialer error") + customDialer := func(raddr ma.Multiaddr) (ContextDialer, error) { + if test == "error in factory" { + return nil, customErr + } else { + return errDialer{err: customErr}, nil + } + } + tb, err := NewTCPTransport(ub, nil, nil, WithDialerForAddr(customDialer)) + require.NoError(t, err) + + conn, err := tb.Dial(context.Background(), ln.Multiaddr(), peerA) + require.Error(t, err) + require.ErrorContains(t, err, customErr.Error()) + require.Nil(t, conn) + }) + } + }) +} diff --git a/p2p/transport/tcpreuse/connwithscope.go b/p2p/transport/tcpreuse/connwithscope.go index ca66f20325..bddd3c0f3b 100644 --- a/p2p/transport/tcpreuse/connwithscope.go +++ b/p2p/transport/tcpreuse/connwithscope.go @@ -17,6 +17,11 @@ func (c connWithScope) Scope() network.ConnManagementScope { return c.scope } +func (c *connWithScope) Close() error { + c.scope.Done() + return c.ManetTCPConnInterface.Close() +} + func manetConnWithScope(c manet.Conn, scope network.ConnManagementScope) (manet.Conn, error) { if tcpconn, ok := c.(sampledconn.ManetTCPConnInterface); ok { return &connWithScope{tcpconn, scope}, nil diff --git a/p2p/transport/tcpreuse/dialer.go b/p2p/transport/tcpreuse/dialer.go index ad634583ed..d6ea1fc6a0 100644 --- a/p2p/transport/tcpreuse/dialer.go +++ b/p2p/transport/tcpreuse/dialer.go @@ -2,6 +2,7 @@ package tcpreuse import ( "context" + ma "github.com/multiformats/go-multiaddr" manet "github.com/multiformats/go-multiaddr/net" ) diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_common.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn.go similarity index 69% rename from p2p/transport/tcpreuse/internal/sampledconn/sampledconn_common.go rename to p2p/transport/tcpreuse/internal/sampledconn/sampledconn.go index 7324b45849..ff1f8caf44 100644 --- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_common.go +++ b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn.go @@ -14,30 +14,17 @@ const peekSize = 3 type PeekedBytes = [peekSize]byte -var errNotSupported = errors.New("not supported on this platform") - var ErrNotTCPConn = errors.New("passed conn is not a TCPConn") func PeekBytes(conn manet.Conn) (PeekedBytes, manet.Conn, error) { - if c, ok := conn.(syscall.Conn); ok { - b, err := OSPeekConn(c) - if err == nil { - return b, conn, nil - } - if err != errNotSupported { - return PeekedBytes{}, nil, err - } - // Fallback to wrapping the coonn - } - if c, ok := conn.(ManetTCPConnInterface); ok { - return newFallbackSampledConn(c) + return newWrappedSampledConn(c) } return PeekedBytes{}, nil, ErrNotTCPConn } -type fallbackPeekingConn struct { +type wrappedSampledConn struct { ManetTCPConnInterface peekedBytes PeekedBytes bytesPeeked uint8 @@ -69,16 +56,19 @@ type ManetTCPConnInterface interface { tcpConnInterface } -func newFallbackSampledConn(conn ManetTCPConnInterface) (PeekedBytes, *fallbackPeekingConn, error) { - s := &fallbackPeekingConn{ManetTCPConnInterface: conn} - _, err := io.ReadFull(conn, s.peekedBytes[:]) +func newWrappedSampledConn(conn ManetTCPConnInterface) (PeekedBytes, *wrappedSampledConn, error) { + s := &wrappedSampledConn{ManetTCPConnInterface: conn} + n, err := io.ReadFull(conn, s.peekedBytes[:]) if err != nil { + if n == 0 && err == io.EOF { + err = io.ErrUnexpectedEOF + } return s.peekedBytes, nil, err } return s.peekedBytes, s, nil } -func (sc *fallbackPeekingConn) Read(b []byte) (int, error) { +func (sc *wrappedSampledConn) Read(b []byte) (int, error) { if int(sc.bytesPeeked) != len(sc.peekedBytes) { red := copy(b, sc.peekedBytes[sc.bytesPeeked:]) sc.bytesPeeked += uint8(red) diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go deleted file mode 100644 index 5197052fab..0000000000 --- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_other.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !unix - -package sampledconn - -import ( - "syscall" -) - -func OSPeekConn(conn syscall.Conn) (PeekedBytes, error) { - return PeekedBytes{}, errNotSupported -} diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go index d5b31009e2..6c4e989b16 100644 --- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go +++ b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_test.go @@ -10,6 +10,7 @@ import ( manet "github.com/multiformats/go-multiaddr/net" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSampledConn(t *testing.T) { @@ -63,7 +64,7 @@ func TestSampledConn(t *testing.T) { assert.Equal(t, "hello", string(buf)) } else { // Wrap the client connection in SampledConn - sample, sampledConn, err := newFallbackSampledConn(clientConn.(ManetTCPConnInterface)) + sample, sampledConn, err := newWrappedSampledConn(clientConn.(ManetTCPConnInterface)) assert.NoError(t, err) assert.Equal(t, "hel", string(sample[:])) @@ -76,3 +77,102 @@ func TestSampledConn(t *testing.T) { }) } } + +func spawnServerAndClientConn(t *testing.T) (serverConn manet.Conn, clientConn manet.Conn) { + serverConnChan := make(chan manet.Conn, 1) + + listener, err := manet.Listen(ma.StringCast("/ip4/127.0.0.1/tcp/0")) + assert.NoError(t, err) + defer listener.Close() + + serverAddr := listener.Multiaddr() + + // Server goroutine + go func() { + conn, err := listener.Accept() + assert.NoError(t, err) + serverConnChan <- conn + }() + + // Give the server a moment to start + time.Sleep(100 * time.Millisecond) + + // Create a TCP client + clientConn, err = manet.Dial(serverAddr) + assert.NoError(t, err) + + return <-serverConnChan, clientConn +} + +func TestHandleNoBytes(t *testing.T) { + serverConn, clientConn := spawnServerAndClientConn(t) + defer clientConn.Close() + + // Server goroutine + go func() { + serverConn.Close() + }() + _, _, err := PeekBytes(clientConn.(interface { + manet.Conn + syscall.Conn + })) + assert.ErrorIs(t, err, io.ErrUnexpectedEOF) +} + +func TestHandle1ByteAndClose(t *testing.T) { + serverConn, clientConn := spawnServerAndClientConn(t) + defer clientConn.Close() + + // Server goroutine + go func() { + defer serverConn.Close() + _, err := serverConn.Write([]byte("h")) + assert.NoError(t, err) + }() + _, _, err := PeekBytes(clientConn.(interface { + manet.Conn + syscall.Conn + })) + assert.ErrorIs(t, err, io.ErrUnexpectedEOF) +} + +func TestSlowBytes(t *testing.T) { + serverConn, clientConn := spawnServerAndClientConn(t) + + interval := 100 * time.Millisecond + + // Server goroutine + go func() { + defer serverConn.Close() + + time.Sleep(interval) + _, err := serverConn.Write([]byte("h")) + assert.NoError(t, err) + time.Sleep(interval) + _, err = serverConn.Write([]byte("e")) + assert.NoError(t, err) + time.Sleep(interval) + _, err = serverConn.Write([]byte("l")) + assert.NoError(t, err) + time.Sleep(interval) + _, err = serverConn.Write([]byte("lo")) + assert.NoError(t, err) + }() + + defer clientConn.Close() + + err := clientConn.SetReadDeadline(time.Now().Add(interval * 10)) + require.NoError(t, err) + + peeked, clientConn, err := PeekBytes(clientConn.(interface { + manet.Conn + syscall.Conn + })) + assert.NoError(t, err) + assert.Equal(t, "hel", string(peeked[:])) + + buf := make([]byte, 5) + _, err = io.ReadFull(clientConn, buf) + assert.NoError(t, err) + assert.Equal(t, "hello", string(buf)) +} diff --git a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_unix.go b/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_unix.go deleted file mode 100644 index 9847e8d4be..0000000000 --- a/p2p/transport/tcpreuse/internal/sampledconn/sampledconn_unix.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build unix - -package sampledconn - -import ( - "errors" - "syscall" -) - -func OSPeekConn(conn syscall.Conn) (PeekedBytes, error) { - s := PeekedBytes{} - - rawConn, err := conn.SyscallConn() - if err != nil { - return s, err - } - - readBytes := 0 - var readErr error - err = rawConn.Read(func(fd uintptr) bool { - for readBytes < peekSize { - var n int - n, _, readErr = syscall.Recvfrom(int(fd), s[readBytes:], syscall.MSG_PEEK) - if errors.Is(readErr, syscall.EAGAIN) { - return false - } - if readErr != nil { - return true - } - readBytes += n - } - return true - }) - if readErr != nil { - return s, readErr - } - if err != nil { - return s, err - } - - return s, nil -} diff --git a/p2p/transport/tcpreuse/listener.go b/p2p/transport/tcpreuse/listener.go index d94186e7ec..d0affb9fdf 100644 --- a/p2p/transport/tcpreuse/listener.go +++ b/p2p/transport/tcpreuse/listener.go @@ -260,6 +260,7 @@ func (m *multiplexedListener) run() error { select { case demux.buffer <- connWithScope: case <-ctx.Done(): + log.Debug("accept timeout; dropping connection from: %v", connWithScope.RemoteMultiaddr()) connWithScope.Close() } }() diff --git a/p2p/transport/webrtc/connection.go b/p2p/transport/webrtc/connection.go index 2fba37a970..77b293fadb 100644 --- a/p2p/transport/webrtc/connection.go +++ b/p2p/transport/webrtc/connection.go @@ -17,7 +17,7 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/pion/datachannel" "github.com/pion/sctp" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" ) var _ tpt.CapableConn = &connection{} @@ -132,6 +132,12 @@ func (c *connection) Close() error { return nil } +// CloseWithError closes the connection ignoring the error code. As there's no way to signal +// the remote peer on closing the underlying peerconnection, we ignore the error code. +func (c *connection) CloseWithError(_ network.ConnErrorCode) error { + return c.Close() +} + // closeWithError is used to Close the connection when the underlying DTLS connection fails func (c *connection) closeWithError(err error) { c.closeOnce.Do(func() { diff --git a/p2p/transport/webrtc/fingerprint.go b/p2p/transport/webrtc/fingerprint.go index fd715865a8..0b1fe488b4 100644 --- a/p2p/transport/webrtc/fingerprint.go +++ b/p2p/transport/webrtc/fingerprint.go @@ -8,7 +8,7 @@ import ( ma "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multibase" mh "github.com/multiformats/go-multihash" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" ) // parseFingerprint is forked from pion to avoid bytes to string alloc, diff --git a/p2p/transport/webrtc/listener.go b/p2p/transport/webrtc/listener.go index c3e2f29799..3534fd2c76 100644 --- a/p2p/transport/webrtc/listener.go +++ b/p2p/transport/webrtc/listener.go @@ -20,7 +20,7 @@ import ( manet "github.com/multiformats/go-multiaddr/net" "github.com/multiformats/go-multibase" "github.com/multiformats/go-multihash" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" ) type connMultiaddrs struct { diff --git a/p2p/transport/webrtc/pb/message.pb.go b/p2p/transport/webrtc/pb/message.pb.go index d7d4d583af..f598009702 100644 --- a/p2p/transport/webrtc/pb/message.pb.go +++ b/p2p/transport/webrtc/pb/message.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.35.1 -// protoc v5.28.2 +// protoc-gen-go v1.36.5 +// protoc v5.29.2 // source: p2p/transport/webrtc/pb/message.proto package pb @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -91,12 +92,12 @@ func (Message_Flag) EnumDescriptor() ([]byte, []int) { } type Message struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Flag *Message_Flag `protobuf:"varint,1,opt,name=flag,enum=Message_Flag" json:"flag,omitempty"` + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + ErrorCode *uint32 `protobuf:"varint,3,opt,name=errorCode" json:"errorCode,omitempty"` unknownFields protoimpl.UnknownFields - - Flag *Message_Flag `protobuf:"varint,1,opt,name=flag,enum=Message_Flag" json:"flag,omitempty"` - Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Message) Reset() { @@ -143,34 +144,42 @@ func (x *Message) GetMessage() []byte { return nil } +func (x *Message) GetErrorCode() uint32 { + if x != nil && x.ErrorCode != nil { + return *x.ErrorCode + } + return 0 +} + var File_p2p_transport_webrtc_pb_message_proto protoreflect.FileDescriptor -var file_p2p_transport_webrtc_pb_message_proto_rawDesc = []byte{ +var file_p2p_transport_webrtc_pb_message_proto_rawDesc = string([]byte{ 0x0a, 0x25, 0x70, 0x32, 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2f, 0x70, 0x62, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x81, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9f, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x39, 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x49, 0x4e, 0x10, - 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x49, 0x4e, - 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x02, 0x12, 0x0b, - 0x0a, 0x07, 0x46, 0x49, 0x4e, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, 0x35, 0x5a, 0x33, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, - 0x2f, 0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2f, - 0x70, 0x62, -} + 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x39, + 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x49, 0x4e, 0x10, 0x00, 0x12, + 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, + 0x46, 0x49, 0x4e, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x67, + 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2f, 0x70, 0x62, +}) var ( file_p2p_transport_webrtc_pb_message_proto_rawDescOnce sync.Once - file_p2p_transport_webrtc_pb_message_proto_rawDescData = file_p2p_transport_webrtc_pb_message_proto_rawDesc + file_p2p_transport_webrtc_pb_message_proto_rawDescData []byte ) func file_p2p_transport_webrtc_pb_message_proto_rawDescGZIP() []byte { file_p2p_transport_webrtc_pb_message_proto_rawDescOnce.Do(func() { - file_p2p_transport_webrtc_pb_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_p2p_transport_webrtc_pb_message_proto_rawDescData) + file_p2p_transport_webrtc_pb_message_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_p2p_transport_webrtc_pb_message_proto_rawDesc), len(file_p2p_transport_webrtc_pb_message_proto_rawDesc))) }) return file_p2p_transport_webrtc_pb_message_proto_rawDescData } @@ -199,7 +208,7 @@ func file_p2p_transport_webrtc_pb_message_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_p2p_transport_webrtc_pb_message_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_p2p_transport_webrtc_pb_message_proto_rawDesc), len(file_p2p_transport_webrtc_pb_message_proto_rawDesc)), NumEnums: 1, NumMessages: 1, NumExtensions: 0, @@ -211,7 +220,6 @@ func file_p2p_transport_webrtc_pb_message_proto_init() { MessageInfos: file_p2p_transport_webrtc_pb_message_proto_msgTypes, }.Build() File_p2p_transport_webrtc_pb_message_proto = out.File - file_p2p_transport_webrtc_pb_message_proto_rawDesc = nil file_p2p_transport_webrtc_pb_message_proto_goTypes = nil file_p2p_transport_webrtc_pb_message_proto_depIdxs = nil } diff --git a/p2p/transport/webrtc/pb/message.proto b/p2p/transport/webrtc/pb/message.proto index aab885b0da..2401f7c4d2 100644 --- a/p2p/transport/webrtc/pb/message.proto +++ b/p2p/transport/webrtc/pb/message.proto @@ -21,4 +21,6 @@ message Message { optional Flag flag=1; optional bytes message = 2; + + optional uint32 errorCode = 3; } diff --git a/p2p/transport/webrtc/stream.go b/p2p/transport/webrtc/stream.go index 56f869f5e1..39873c9d66 100644 --- a/p2p/transport/webrtc/stream.go +++ b/p2p/transport/webrtc/stream.go @@ -11,7 +11,7 @@ import ( "github.com/libp2p/go-msgio/pbio" "github.com/pion/datachannel" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" ) const ( @@ -69,8 +69,9 @@ type stream struct { // readerMx ensures that only a single goroutine reads from the reader. Read is not threadsafe // But we may need to read from reader for control messages from a different goroutine. - readerMx sync.Mutex - reader pbio.Reader + readerMx sync.Mutex + reader pbio.Reader + readError error // this buffer is limited up to a single message. Reason we need it // is because a reader might read a message midway, and so we need a @@ -82,6 +83,7 @@ type stream struct { writeStateChanged chan struct{} sendState sendState writeDeadline time.Time + writeError error controlMessageReaderOnce sync.Once // controlMessageReaderEndTime is the end time for reading FIN_ACK from the control @@ -146,6 +148,10 @@ func (s *stream) Close() error { } func (s *stream) Reset() error { + return s.ResetWithError(0) +} + +func (s *stream) ResetWithError(errCode network.StreamErrorCode) error { s.mx.Lock() isClosed := s.closeForShutdownErr != nil s.mx.Unlock() @@ -154,8 +160,8 @@ func (s *stream) Reset() error { } defer s.cleanup() - cancelWriteErr := s.cancelWrite() - closeReadErr := s.CloseRead() + cancelWriteErr := s.cancelWrite(errCode) + closeReadErr := s.closeRead(errCode, false) s.setDataChannelReadDeadline(time.Now().Add(-1 * time.Hour)) return errors.Join(closeReadErr, cancelWriteErr) } @@ -175,19 +181,20 @@ func (s *stream) SetDeadline(t time.Time) error { return s.SetWriteDeadline(t) } -// processIncomingFlag process the flag on an incoming message +// processIncomingFlag processes the flag(FIN/RST/etc) on msg. // It needs to be called while the mutex is locked. -func (s *stream) processIncomingFlag(flag *pb.Message_Flag) { - if flag == nil { +func (s *stream) processIncomingFlag(msg *pb.Message) { + if msg.Flag == nil { return } - switch *flag { + switch msg.GetFlag() { case pb.Message_STOP_SENDING: // We must process STOP_SENDING after sending a FIN(sendStateDataSent). Remote peer // may not send a FIN_ACK once it has sent a STOP_SENDING if s.sendState == sendStateSending || s.sendState == sendStateDataSent { s.sendState = sendStateReset + s.writeError = &network.StreamError{Remote: true, ErrorCode: network.StreamErrorCode(msg.GetErrorCode())} } s.notifyWriteStateChanged() case pb.Message_FIN_ACK: @@ -206,6 +213,11 @@ func (s *stream) processIncomingFlag(flag *pb.Message_Flag) { case pb.Message_RESET: if s.receiveState == receiveStateReceiving { s.receiveState = receiveStateReset + s.readError = &network.StreamError{Remote: true, ErrorCode: network.StreamErrorCode(msg.GetErrorCode())} + } + if s.sendState == sendStateSending || s.sendState == sendStateDataSent { + s.sendState = sendStateReset + s.writeError = &network.StreamError{Remote: true, ErrorCode: network.StreamErrorCode(msg.GetErrorCode())} } s.spawnControlMessageReader() } @@ -235,7 +247,7 @@ func (s *stream) spawnControlMessageReader() { s.readerMx.Unlock() if s.nextMessage != nil { - s.processIncomingFlag(s.nextMessage.Flag) + s.processIncomingFlag(s.nextMessage) s.nextMessage = nil } var msg pb.Message @@ -266,7 +278,7 @@ func (s *stream) spawnControlMessageReader() { } return } - s.processIncomingFlag(msg.Flag) + s.processIncomingFlag(&msg) } }() }) diff --git a/p2p/transport/webrtc/stream_read.go b/p2p/transport/webrtc/stream_read.go index 80d99ea91c..003d5f563e 100644 --- a/p2p/transport/webrtc/stream_read.go +++ b/p2p/transport/webrtc/stream_read.go @@ -22,7 +22,7 @@ func (s *stream) Read(b []byte) (int, error) { case receiveStateDataRead: return 0, io.EOF case receiveStateReset: - return 0, network.ErrReset + return 0, s.readError } if len(b) == 0 { @@ -52,10 +52,11 @@ func (s *stream) Read(b []byte) (int, error) { // datachannel. For these implementations a stream reset will be observed as an // abrupt closing of the datachannel. s.receiveState = receiveStateReset - return 0, network.ErrReset + s.readError = &network.StreamError{Remote: true} + return 0, s.readError } if s.receiveState == receiveStateReset { - return 0, network.ErrReset + return 0, s.readError } if s.receiveState == receiveStateDataRead { return 0, io.EOF @@ -73,7 +74,7 @@ func (s *stream) Read(b []byte) (int, error) { } // process flags on the message after reading all the data - s.processIncomingFlag(s.nextMessage.Flag) + s.processIncomingFlag(s.nextMessage) s.nextMessage = nil if s.closeForShutdownErr != nil { return read, s.closeForShutdownErr @@ -82,7 +83,7 @@ func (s *stream) Read(b []byte) (int, error) { case receiveStateDataRead: return read, io.EOF case receiveStateReset: - return read, network.ErrReset + return read, s.readError } } } @@ -101,12 +102,18 @@ func (s *stream) setDataChannelReadDeadline(t time.Time) error { } func (s *stream) CloseRead() error { + return s.closeRead(0, false) +} + +func (s *stream) closeRead(errCode network.StreamErrorCode, remote bool) error { s.mx.Lock() defer s.mx.Unlock() var err error if s.receiveState == receiveStateReceiving && s.closeForShutdownErr == nil { - err = s.writer.WriteMsg(&pb.Message{Flag: pb.Message_STOP_SENDING.Enum()}) + code := uint32(errCode) + err = s.writer.WriteMsg(&pb.Message{Flag: pb.Message_STOP_SENDING.Enum(), ErrorCode: &code}) s.receiveState = receiveStateReset + s.readError = &network.StreamError{Remote: remote, ErrorCode: errCode} } s.spawnControlMessageReader() return err diff --git a/p2p/transport/webrtc/stream_test.go b/p2p/transport/webrtc/stream_test.go index 0f57f44f79..4153ff830a 100644 --- a/p2p/transport/webrtc/stream_test.go +++ b/p2p/transport/webrtc/stream_test.go @@ -17,7 +17,7 @@ import ( "github.com/pion/datachannel" "github.com/pion/sctp" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/p2p/transport/webrtc/stream_write.go b/p2p/transport/webrtc/stream_write.go index 534a8d8e60..01fddac331 100644 --- a/p2p/transport/webrtc/stream_write.go +++ b/p2p/transport/webrtc/stream_write.go @@ -24,7 +24,7 @@ func (s *stream) Write(b []byte) (int, error) { } switch s.sendState { case sendStateReset: - return 0, network.ErrReset + return 0, s.writeError case sendStateDataSent, sendStateDataReceived: return 0, errWriteAfterClose } @@ -48,7 +48,7 @@ func (s *stream) Write(b []byte) (int, error) { } switch s.sendState { case sendStateReset: - return n, network.ErrReset + return n, s.writeError case sendStateDataSent, sendStateDataReceived: return n, errWriteAfterClose } @@ -119,7 +119,7 @@ func (s *stream) availableSendSpace() int { return availableSpace } -func (s *stream) cancelWrite() error { +func (s *stream) cancelWrite(errCode network.StreamErrorCode) error { s.mx.Lock() defer s.mx.Unlock() @@ -129,10 +129,12 @@ func (s *stream) cancelWrite() error { return nil } s.sendState = sendStateReset + s.writeError = &network.StreamError{Remote: false, ErrorCode: errCode} // Remove reference to this stream from data channel s.dataChannel.OnBufferedAmountLow(nil) s.notifyWriteStateChanged() - return s.writer.WriteMsg(&pb.Message{Flag: pb.Message_RESET.Enum()}) + code := uint32(errCode) + return s.writer.WriteMsg(&pb.Message{Flag: pb.Message_RESET.Enum(), ErrorCode: &code}) } func (s *stream) CloseWrite() error { diff --git a/p2p/transport/webrtc/transport.go b/p2p/transport/webrtc/transport.go index c4c16fd402..c54865fc57 100644 --- a/p2p/transport/webrtc/transport.go +++ b/p2p/transport/webrtc/transport.go @@ -9,13 +9,13 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/x509" - "encoding/binary" "errors" "fmt" "net" "time" - mrand "golang.org/x/exp/rand" + mrand "math/rand/v2" + "google.golang.org/protobuf/proto" "github.com/libp2p/go-libp2p/core/connmgr" @@ -35,7 +35,7 @@ import ( "github.com/multiformats/go-multihash" "github.com/pion/datachannel" - "github.com/pion/webrtc/v3" + "github.com/pion/webrtc/v4" ) var webrtcComponent *ma.Component @@ -420,15 +420,15 @@ func genUfrag() string { uFragLength = len(uFragPrefix) + uFragIdLength ) - seed := [8]byte{} + seed := [32]byte{} rand.Read(seed[:]) - r := mrand.New(mrand.NewSource(binary.BigEndian.Uint64(seed[:]))) + r := mrand.New(mrand.New(mrand.NewChaCha8(seed))) b := make([]byte, uFragLength) for i := 0; i < len(uFragPrefix); i++ { b[i] = uFragPrefix[i] } for i := len(uFragPrefix); i < uFragLength; i++ { - b[i] = uFragAlphabet[r.Intn(len(uFragAlphabet))] + b[i] = uFragAlphabet[r.IntN(len(uFragAlphabet))] } return string(b) } diff --git a/p2p/transport/webrtc/udpmux/mux.go b/p2p/transport/webrtc/udpmux/mux.go index 85392c5d56..f01facae32 100644 --- a/p2p/transport/webrtc/udpmux/mux.go +++ b/p2p/transport/webrtc/udpmux/mux.go @@ -14,7 +14,7 @@ import ( logging "github.com/ipfs/go-log/v2" pool "github.com/libp2p/go-buffer-pool" - "github.com/pion/ice/v2" + "github.com/pion/ice/v4" "github.com/pion/stun" ) diff --git a/p2p/transport/websocket/conn.go b/p2p/transport/websocket/conn.go index ce51611703..1c2ecd03df 100644 --- a/p2p/transport/websocket/conn.go +++ b/p2p/transport/websocket/conn.go @@ -1,6 +1,7 @@ package websocket import ( + "crypto/tls" "errors" "io" "net" @@ -142,6 +143,13 @@ func (c *Conn) 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 } diff --git a/p2p/transport/websocket/listener.go b/p2p/transport/websocket/listener.go index dd399aa079..93131a2e07 100644 --- a/p2p/transport/websocket/listener.go +++ b/p2p/transport/websocket/listener.go @@ -137,9 +137,9 @@ func (l *listener) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } select { - case l.incoming <- NewConn(c, l.isWss): + case l.incoming <- nc: case <-l.closed: - c.Close() + nc.Close() } // The connection has been hijacked, it's safe to return. } diff --git a/p2p/transport/websocket/websocket.go b/p2p/transport/websocket/websocket.go index e24cb88c6d..97402b9a3b 100644 --- a/p2p/transport/websocket/websocket.go +++ b/p2p/transport/websocket/websocket.go @@ -160,6 +160,8 @@ func (t *WebsocketTransport) Resolve(_ context.Context, maddr ma.Multiaddr) ([]m return []ma.Multiaddr{parsed.toMultiaddr()}, nil } +// Dial will dial the given multiaddr and expect the given peer. If an +// HTTPS_PROXY env is set, it will use that for the dial out. func (t *WebsocketTransport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (transport.CapableConn, error) { connScope, err := t.rcmgr.OpenConnection(network.DirOutbound, true, raddr) if err != nil { @@ -191,7 +193,11 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma return nil, err } isWss := wsurl.Scheme == "wss" - dialer := ws.Dialer{HandshakeTimeout: 30 * time.Second} + dialer := ws.Dialer{ + HandshakeTimeout: 30 * time.Second, + // Inherit the default proxy behavior + Proxy: ws.DefaultDialer.Proxy, + } if isWss { sni := "" sni, err = raddr.ValueForProtocol(ma.P_SNI) @@ -203,17 +209,23 @@ func (t *WebsocketTransport) maDial(ctx context.Context, raddr ma.Multiaddr) (ma copytlsClientConf := t.tlsClientConf.Clone() copytlsClientConf.ServerName = sni dialer.TLSClientConfig = copytlsClientConf - ipAddr := wsurl.Host - // Setting the NetDial because we already have the resolved IP address, so we don't want to do another resolution. + ipPortAddr := wsurl.Host // We set the `.Host` to the sni field so that the host header gets properly set. + wsurl.Host = sni + ":" + wsurl.Port() + // Setting the NetDial because we already have the resolved IP address, so we can avoid another resolution. dialer.NetDial = func(network, address string) (net.Conn, error) { - tcpAddr, err := net.ResolveTCPAddr(network, ipAddr) + var tcpAddr *net.TCPAddr + var err error + if address == wsurl.Host { + tcpAddr, err = net.ResolveTCPAddr(network, ipPortAddr) // Use our already resolved IP address + } else { + tcpAddr, err = net.ResolveTCPAddr(network, address) + } if err != nil { return nil, err } return net.DialTCP("tcp", nil, tcpAddr) } - wsurl.Host = sni + ":" + wsurl.Port() } else { dialer.TLSClientConfig = t.tlsClientConf } diff --git a/p2p/transport/websocket/websocket_test.go b/p2p/transport/websocket/websocket_test.go index 9ca03775a2..b112ebaea4 100644 --- a/p2p/transport/websocket/websocket_test.go +++ b/p2p/transport/websocket/websocket_test.go @@ -1,6 +1,7 @@ package websocket import ( + "bytes" "context" "crypto/ecdsa" "crypto/elliptic" @@ -15,10 +16,12 @@ import ( "math/big" "net" "net/http" + "net/url" "strings" "testing" "time" + gws "github.com/gorilla/websocket" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" @@ -548,3 +551,75 @@ func TestResolveMultiaddr(t *testing.T) { }) } } + +func TestSocksProxy(t *testing.T) { + testCases := []string{ + "/ip4/1.2.3.4/tcp/1/ws", // No TLS + "/ip4/1.2.3.4/tcp/1/tls/ws", // TLS no SNI + "/ip4/1.2.3.4/tcp/1/tls/sni/example.com/ws", // TLS with an SNI + } + + for _, tc := range testCases { + t.Run(tc, func(t *testing.T) { + proxyServer, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + proxyServerErr := make(chan error, 1) + + go func() { + defer proxyServer.Close() + c, err := proxyServer.Accept() + if err != nil { + proxyServerErr <- err + return + } + defer c.Close() + + req := [32]byte{} + _, err = io.ReadFull(c, req[:3]) + if err != nil { + proxyServerErr <- err + return + } + + // Handshake a SOCKS5 client: https://www.rfc-editor.org/rfc/rfc1928.html#section-3 + if !bytes.Equal([]byte{0x05, 0x01, 0x00}, req[:3]) { + t.Log("expected SOCKS5 connect request") + proxyServerErr <- err + return + } + _, err = c.Write([]byte{0x05, 0x00}) + if err != nil { + proxyServerErr <- err + return + } + + proxyServerErr <- nil + }() + + orig := gws.DefaultDialer.Proxy + defer func() { gws.DefaultDialer.Proxy = orig }() + + proxyUrl, err := url.Parse("socks5://" + proxyServer.Addr().String()) + require.NoError(t, err) + gws.DefaultDialer.Proxy = http.ProxyURL(proxyUrl) + + tlsConfig := &tls.Config{InsecureSkipVerify: true} // Our test server doesn't have a cert signed by a CA + _, u := newSecureUpgrader(t) + tpt, err := New(u, &network.NullResourceManager{}, nil, WithTLSClientConfig(tlsConfig)) + require.NoError(t, err) + + // This can be any wss address. We aren't actually going to dial it. + maToDial := ma.StringCast(tc) + _, err = tpt.Dial(context.Background(), maToDial, "") + require.ErrorContains(t, err, "failed to read connect reply from SOCKS5 proxy", "This should error as we don't have a real socks server") + + select { + case <-time.After(1 * time.Second): + case err := <-proxyServerErr: + if err != nil { + t.Fatal(err) + } + } + }) + } +} diff --git a/p2p/transport/webtransport/cert_manager.go b/p2p/transport/webtransport/cert_manager.go index d48a0aa537..4401175363 100644 --- a/p2p/transport/webtransport/cert_manager.go +++ b/p2p/transport/webtransport/cert_manager.go @@ -71,7 +71,7 @@ func newCertManager(hostKey ic.PrivKey, clock clock.Clock) (*certManager, error) return m, nil } -// getCurrentTimeBucket returns the canonical start time of the given time as +// getCurrentBucketStartTime returns the canonical start time of the given time as // bucketed by ranges of certValidity since unix epoch (plus an offset). This // lets you get the same time ranges across reboots without having to persist // state. diff --git a/p2p/transport/webtransport/conn.go b/p2p/transport/webtransport/conn.go index d914398e0e..f76ad10438 100644 --- a/p2p/transport/webtransport/conn.go +++ b/p2p/transport/webtransport/conn.go @@ -78,6 +78,10 @@ func (c *conn) Close() error { return err } +func (c *conn) CloseWithError(_ network.ConnErrorCode) error { + return c.Close() +} + func (c *conn) IsClosed() bool { return c.session.Context().Err() != nil } func (c *conn) Scope() network.ConnScope { return c.scope } func (c *conn) Transport() tpt.Transport { return c.transport } diff --git a/p2p/transport/webtransport/crypto.go b/p2p/transport/webtransport/crypto.go index bdc121c52a..90504ead01 100644 --- a/p2p/transport/webtransport/crypto.go +++ b/p2p/transport/webtransport/crypto.go @@ -86,6 +86,15 @@ func generateCert(key ic.PrivKey, start, end time.Time) (*x509.Certificate, *ecd return ca, caPrivateKey, nil } +type ErrCertHashMismatch struct { + Expected []byte + Actual [][]byte +} + +func (e ErrCertHashMismatch) Error() string { + return fmt.Sprintf("cert hash not found: %x (expected: %#x)", e.Expected, e.Actual) +} + func verifyRawCerts(rawCerts [][]byte, certHashes []multihash.DecodedMultihash) error { if len(rawCerts) < 1 { return errors.New("no cert") @@ -105,7 +114,7 @@ func verifyRawCerts(rawCerts [][]byte, certHashes []multihash.DecodedMultihash) for _, h := range certHashes { digests = append(digests, h.Digest) } - return fmt.Errorf("cert hash not found: %#x (expected: %#x)", hash, digests) + return ErrCertHashMismatch{Expected: hash[:], Actual: digests} } cert, err := x509.ParseCertificate(leaf) diff --git a/p2p/transport/webtransport/stream.go b/p2p/transport/webtransport/stream.go index 0849fc9f38..83ee52a5d1 100644 --- a/p2p/transport/webtransport/stream.go +++ b/p2p/transport/webtransport/stream.go @@ -56,6 +56,17 @@ func (s *stream) Reset() error { return nil } +// ResetWithError resets the stream ignoring the error code. Error codes aren't +// specified for WebTransport as the current implementation of WebTransport in +// browsers(https://www.ietf.org/archive/id/draft-kinnear-webtransport-http2-02.html) +// only supports 1 byte error codes. For more details, see +// https://github.com/libp2p/specs/blob/4eca305185c7aef219e936bef76c48b1ab0a8b43/error-codes/README.md?plain=1#L84 +func (s *stream) ResetWithError(_ network.StreamErrorCode) error { + s.Stream.CancelRead(reset) + s.Stream.CancelWrite(reset) + return nil +} + func (s *stream) Close() error { s.Stream.CancelRead(reset) return s.Stream.Close() diff --git a/p2p/transport/webtransport/transport.go b/p2p/transport/webtransport/transport.go index acb40f0b89..0e35b44398 100644 --- a/p2p/transport/webtransport/transport.go +++ b/p2p/transport/webtransport/transport.go @@ -175,10 +175,12 @@ func (t *transport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p pee sconn, err := t.upgrade(ctx, sess, p, certHashes) if err != nil { sess.CloseWithError(1, "") + qconn.CloseWithError(1, "") return nil, err } if t.gater != nil && !t.gater.InterceptSecured(network.DirOutbound, p, sconn) { sess.CloseWithError(errorCodeConnectionGating, "") + qconn.CloseWithError(errorCodeConnectionGating, "") return nil, fmt.Errorf("secured connection gated") } conn := newConn(t, sess, sconn, scope, qconn) diff --git a/p2p/transport/webtransport/transport_test.go b/p2p/transport/webtransport/transport_test.go index f58f6cc009..0d43f0d30c 100644 --- a/p2p/transport/webtransport/transport_test.go +++ b/p2p/transport/webtransport/transport_test.go @@ -179,7 +179,11 @@ func TestHashVerification(t *testing.T) { var trErr *quic.TransportError require.ErrorAs(t, err, &trErr) require.Equal(t, quic.TransportErrorCode(0x12a), trErr.ErrorCode) - require.Contains(t, errors.Unwrap(trErr).Error(), "cert hash not found") + var errMismatchHash libp2pwebtransport.ErrCertHashMismatch + require.ErrorAs(t, err, &errMismatchHash) + + e := sha256.Sum256([]byte("foobar")) + require.EqualValues(t, e[:], errMismatchHash.Actual[0]) }) t.Run("fails when adding a wrong hash", func(t *testing.T) { diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 0000000000..7371c9e452 --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1,2 @@ +protobuf-bin/ +protoc-gen-go diff --git a/scripts/download-protoc.sh b/scripts/download-protoc.sh new file mode 100755 index 0000000000..6870c22c9f --- /dev/null +++ b/scripts/download-protoc.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -eou pipefail + +# Specify the protobuf release version +PROTOBUF_VERSION="29.2" + +# Define SHA-256 hashes for each supported platform +# Update these hashes by running ./print-protoc-hashes.sh +declare -A SHA256_HASHES=( + ["linux-aarch64"]="0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5" + ["linux-x86_64"]="52e9e7ece55c7e30e7e8bbd254b4b21b408a5309bca826763c7124b696a132e9" + ["darwin-aarch64"]="0e153a38d6da19594c980e7f7cd3ea0ddd52c9da1068c03c0d8533369fbfeb20" +) + +# Determine the platform +OS="$(uname -s | tr '[:upper:]' '[:lower:]')" +ARCH="$(uname -m)" +[[ "${ARCH}" == "arm64" ]] && ARCH="aarch64" + +PLATFORM="${OS}-${ARCH}" + +# Set the download URL based on the platform +case "${PLATFORM}" in +linux-x86_64) + PROTOC_ZIP="protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" + ;; +linux-aarch64) + PROTOC_ZIP="protoc-${PROTOBUF_VERSION}-linux-aarch64.zip" + ;; +darwin-aarch64) + PROTOC_ZIP="protoc-${PROTOBUF_VERSION}-osx-aarch_64.zip" + ;; +*) + echo "Unsupported platform: ${PLATFORM}" >&2 + exit 1 + ;; +esac + +# Download the specified version of protobuf +DOWNLOAD_URL="https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_ZIP}" +echo "Downloading from: ${DOWNLOAD_URL}" >&2 +curl -LO "${DOWNLOAD_URL}" + +# Verify checksum +EXPECTED_SHA256="${SHA256_HASHES[${PLATFORM}]}" +if command -v shasum >/dev/null 2>&1; then + ACTUAL_SHA256=$(shasum -a 256 "${PROTOC_ZIP}" | cut -d' ' -f1) +else + ACTUAL_SHA256=$(sha256sum "${PROTOC_ZIP}" | cut -d' ' -f1) +fi + +if [[ "${ACTUAL_SHA256}" != "${EXPECTED_SHA256}" ]]; then + echo "Checksum verification failed!" >&2 + echo "Expected: ${EXPECTED_SHA256}" >&2 + echo "Got: ${ACTUAL_SHA256}" >&2 + rm "${PROTOC_ZIP}" + exit 1 +fi + +echo "Checksum verified successfully" >&2 + +# Create a directory for extraction +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INSTALL_DIR="$SCRIPT_DIR/protobuf-bin/protoc-${PROTOBUF_VERSION}" +mkdir -p "${INSTALL_DIR}" + +# Unzip the downloaded file +unzip -q -o "${PROTOC_ZIP}" -d "${INSTALL_DIR}" + +# Clean up the zip file +rm "${PROTOC_ZIP}" + +# Return a new PATH with the protobuf binary +PROTOC_BIN="${INSTALL_DIR}/bin" +echo "Installed protoc ${PROTOBUF_VERSION} to ${INSTALL_DIR}" >&2 + +# Return the protoc bin path to stdout +printf "${PROTOC_BIN}" diff --git a/scripts/gen-proto.sh b/scripts/gen-proto.sh index 32c4274ecc..dac2cff2f9 100755 --- a/scripts/gen-proto.sh +++ b/scripts/gen-proto.sh @@ -4,24 +4,32 @@ set -eou pipefail root=$1 proto_array=( - core/crypto/pb/crypto.proto - core/record/pb/envelope.proto - core/peer/pb/peer_record.proto - core/sec/insecure/pb/plaintext.proto - p2p/host/autonat/pb/autonat.proto - p2p/security/noise/pb/payload.proto - p2p/transport/webrtc/pb/message.proto - p2p/protocol/identify/pb/identify.proto - p2p/protocol/circuitv2/pb/circuit.proto - p2p/protocol/circuitv2/pb/voucher.proto - p2p/protocol/autonatv2/pb/autonatv2.proto - p2p/protocol/holepunch/pb/holepunch.proto - p2p/host/peerstore/pstoreds/pb/pstore.proto + core/crypto/pb/crypto.proto + core/record/pb/envelope.proto + core/peer/pb/peer_record.proto + core/sec/insecure/pb/plaintext.proto + p2p/host/autonat/pb/autonat.proto + p2p/security/noise/pb/payload.proto + p2p/transport/webrtc/pb/message.proto + p2p/protocol/identify/pb/identify.proto + p2p/protocol/circuitv2/pb/circuit.proto + p2p/protocol/circuitv2/pb/voucher.proto + p2p/protocol/autonatv2/pb/autonatv2.proto + p2p/protocol/holepunch/pb/holepunch.proto + p2p/host/peerstore/pstoreds/pb/pstore.proto ) proto_paths="" for path in "${proto_array[@]}"; do - proto_paths+="$path " + proto_paths+="$path " done -protoc --proto_path=$root --go_out=$root --go_opt=paths=source_relative $proto_paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROTOC_BIN_PATH="$("${SCRIPT_DIR}/download-protoc.sh")" +export PATH="$PROTOC_BIN_PATH:$PATH" + +echo protoc --version $(protoc --version) +(cd ${SCRIPT_DIR} && go build -o protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go) + +echo protoc-gen-go --version $(${SCRIPT_DIR}/protoc-gen-go --version) +protoc --plugin="${SCRIPT_DIR}/protoc-gen-go" --proto_path=$root --go_out=$root --go_opt=paths=source_relative $proto_paths diff --git a/scripts/print-protoc-hashes.sh b/scripts/print-protoc-hashes.sh new file mode 100755 index 0000000000..9a9d270a30 --- /dev/null +++ b/scripts/print-protoc-hashes.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -eou pipefail + +# Specify the protobuf release version +PROTOBUF_VERSION="29.2" + +# Define the platforms +PLATFORMS=("linux-x86_64" "linux-aarch64" "darwin-aarch64") + +# Array to store the hashes +declare -A HASHES + +# Function to download and calculate the SHA-256 hash +calculate_hash() { + local platform=$1 + local protoc_zip + + case "${platform}" in + linux-x86_64) + protoc_zip="protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" + ;; + linux-aarch64) + protoc_zip="protoc-${PROTOBUF_VERSION}-linux-aarch64.zip" + ;; + darwin-aarch64) + protoc_zip="protoc-${PROTOBUF_VERSION}-osx-aarch_64.zip" + ;; + *) + echo "Unsupported platform: ${platform}" + exit 1 + ;; + esac + + # Download the specified version of protobuf + download_url="https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/${protoc_zip}" + echo "Downloading from: ${download_url}" + curl -LO "${download_url}" + + # Calculate the SHA-256 hash + if command -v shasum >/dev/null 2>&1; then + sha256_hash=$(shasum -a 256 "${protoc_zip}" | cut -d' ' -f1) + else + sha256_hash=$(sha256sum "${protoc_zip}" | cut -d' ' -f1) + fi + + # Store the hash in the array + HASHES["${platform}"]="${sha256_hash}" + + # Clean up the zip file + rm "${protoc_zip}" +} + +# Iterate over the platforms and calculate the hashes +for platform in "${PLATFORMS[@]}"; do + calculate_hash "${platform}" +done + +# Print all the hashes together at the end +echo "Expected SHA-256 hashes for protobuf ${PROTOBUF_VERSION}:" +for platform in "${!HASHES[@]}"; do + echo "[\"${platform}\"]=\"${HASHES[${platform}]}\"" +done diff --git a/scripts/test_analysis/go.mod b/scripts/test_analysis/go.mod index 84ffc92b36..89f60f029e 100644 --- a/scripts/test_analysis/go.mod +++ b/scripts/test_analysis/go.mod @@ -1,6 +1,6 @@ module github.com/libp2p/go-libp2p/scripts/test_analysis -go 1.22 +go 1.23 require github.com/glebarez/go-sqlite v1.22.0 diff --git a/test-plans/go.mod b/test-plans/go.mod index be83100fcf..5b513d3ba9 100644 --- a/test-plans/go.mod +++ b/test-plans/go.mod @@ -1,13 +1,11 @@ module github.com/libp2p/go-libp2p/test-plans/m/v2 -go 1.22.0 - -toolchain go1.22.1 +go 1.23 require ( github.com/go-redis/redis/v8 v8.11.5 github.com/libp2p/go-libp2p v0.0.0 - github.com/multiformats/go-multiaddr v0.13.0 + github.com/multiformats/go-multiaddr v0.14.0 ) require ( @@ -16,7 +14,6 @@ require ( 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -28,28 +25,28 @@ require ( 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-20241017200806-017d972448fc // indirect + github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/huin/goupnp v1.3.0 // indirect - github.com/ipfs/go-cid v0.4.1 // indirect + github.com/ipfs/go-cid v0.5.0 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/koron/go-ssdp v0.0.5 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.2.0 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect + github.com/libp2p/go-netroute v0.2.2 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect + github.com/libp2p/go-yamux/v5 v5.0.0 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.62 // indirect + github.com/miekg/dns v1.1.63 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -64,53 +61,53 @@ require ( github.com/multiformats/go-multistream v0.6.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.20.2 // 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.9 // indirect + github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect - github.com/pion/ice/v2 v2.3.36 // indirect + github.com/pion/dtls/v3 v3.0.4 // indirect + github.com/pion/ice/v4 v4.0.6 // indirect github.com/pion/interceptor v0.1.37 // indirect - github.com/pion/logging v0.2.2 // indirect - github.com/pion/mdns v0.0.12 // indirect + github.com/pion/logging v0.2.3 // indirect + github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.9 // indirect - github.com/pion/sctp v1.8.33 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.20 // indirect + github.com/pion/rtcp v1.2.15 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sctp v1.8.35 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect + github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun v0.6.1 // indirect + github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v2 v2.2.10 // indirect - github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.3.4 // indirect + 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.9 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.60.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.48.2 // indirect + github.com/quic-go/quic-go v0.49.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/stretchr/testify v1.9.0 // indirect github.com/wlynxg/anet v0.0.5 // indirect go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect - golang.org/x/tools v0.26.0 // indirect - google.golang.org/protobuf v1.35.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + golang.org/x/crypto v0.33.0 // indirect + golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect + golang.org/x/tools v0.30.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/test-plans/go.sum b/test-plans/go.sum index 36002223f5..84327a939b 100644 --- a/test-plans/go.sum +++ b/test-plans/go.sum @@ -91,9 +91,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs= -github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= @@ -105,8 +104,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -121,10 +120,10 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= +github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -146,12 +145,12 @@ github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0 github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= +github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po= +github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= @@ -161,8 +160,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= -github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= +github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= +github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -183,8 +182,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= -github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= +github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= github.com/multiformats/go-multiaddr-dns v0.4.1 h1:whi/uCLbDS3mSEUMb1MsoT4uzUeZB0N32yzufqS0i5M= github.com/multiformats/go-multiaddr-dns v0.4.1/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -208,58 +207,58 @@ github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/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= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.36 h1:SopeXiVbbcooUg2EIR8sq4b13RQ8gzrkkldOVg+bBsc= -github.com/pion/ice/v2 v2.3.36/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ= +github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= +github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= +github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM= +github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= -github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= +github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= +github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw= -github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk= -github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA= +github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= +github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= +github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= +github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= -github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.3.4 h1:v2heQVnXTSqNRXcaFQVOhIOYkLMxOu1iJG8uy1djvkk= -github.com/pion/webrtc/v3 v3.3.4/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE= +github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= +github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= +github.com/pion/webrtc/v4 v4.0.9 h1:PyOYMRKJgfy0dzPcYtFD/4oW9zaw3Ze3oZzzbj2LV9E= +github.com/pion/webrtc/v4 v4.0.9/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= @@ -272,15 +271,15 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= -github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= -github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= +github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= +github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= 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= @@ -321,7 +320,6 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -330,8 +328,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/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= @@ -374,11 +372,11 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= -golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -390,8 +388,8 @@ 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= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -414,8 +412,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -431,8 +429,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-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= @@ -455,11 +453,10 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -475,8 +472,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -495,8 +492,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +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= @@ -517,11 +514,10 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= diff --git a/version.json b/version.json index 707e97ed5b..785ed558c2 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v0.37.0" + "version": "v0.40.0" }