- 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.2k
 
Open
Description
Version: v0.42.1-0.20250702212416-7b7c3ed4ce0
Stack trace:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x9abe95]
goroutine 1 [running]:
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*refcountedTransport).Listen(0x13e6618?, 0x0?, 0xc000000001?)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/p2p/transport/quicreuse/reuse.go:149 +0x15
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.newQuicListener({0x13f3b30, 0xc000487140}, 0xc000139680)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/p2p/transport/quicreuse/listener.go:74 +0x264
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*ConnManager).ListenQUICAndAssociate(0xc0003f8a50, {0x0, 0x0}, {0xc0004a4200?, 0x1?, 0x13f36d0?}, 0xc0004a83c0, 0x12cbd28)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/p2p/transport/quicreuse/connmgr.go:231 +0x3ec
github.com/libp2p/go-libp2p/p2p/transport/quicreuse.(*ConnManager).ListenQUIC(...)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/p2p/transport/quicreuse/connmgr.go:202
main.main.func1({0xc3, 0x85, 0xf, 0x39, 0x3e, 0x3a, 0xa2, 0x76, 0x19, 0xb1, ...}, ...)
        /home/ddz/Lab/nunet/go-libp2p-duplicate-quic-bug/main.go:128 +0x317
reflect.Value.call({0xe96840?, 0x12cbd20?, 0x416f14?}, {0x1039b73, 0x4}, {0xc0004a7860, 0x2, 0x500010000000003?})
        /snap/go/10907/src/reflect/value.go:584 +0xca6
reflect.Value.Call({0xe96840?, 0x12cbd20?, 0x0?}, {0xc0004a7860?, 0xc00029d1d8?, 0x471b93?})
        /snap/go/10907/src/reflect/value.go:368 +0xb9
go.uber.org/fx.paramTagsAnnotation.build.func1({0xc0004a7860?, 0x2?, 0x2?})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/annotated.go:258 +0x54
reflect.Value.call({0xe96840?, 0xc00049ce40?, 0x30?}, {0x1039b73, 0x4}, {0xc0004a73e0, 0x2, 0x10?})
        /snap/go/10907/src/reflect/value.go:584 +0xca6
reflect.Value.Call({0xe96840?, 0xc00049ce40?, 0x4179a5?}, {0xc0004a73e0?, 0xf345c0?, 0xc0004a7801?})
        /snap/go/10907/src/reflect/value.go:368 +0xb9
go.uber.org/dig.defaultInvoker({0xe96840?, 0xc00049ce40?, 0xc00029deb0?}, {0xc0004a73e0?, 0x2?, 0x13fe770?})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/container.go:257 +0x25
go.uber.org/dig.(*constructorNode).Call(0xc000485a00, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/constructor.go:198 +0x472
go.uber.org/dig.paramSingle.Build({{0x0, 0x0}, 0x0, {0x1403340, 0xfd6020}}, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:288 +0x34d
go.uber.org/dig.paramList.BuildList({{0x1403340, 0xea2c40}, {0xc0003a3440, 0x3, 0x3}}, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:151 +0xad
go.uber.org/dig.(*constructorNode).Call(0xc0001172b0, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/constructor.go:160 +0x137
go.uber.org/dig.paramSingle.Build({{0x0, 0x0}, 0x0, {0x1403340, 0x1021140}}, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:288 +0x34d
go.uber.org/dig.paramObjectField.Build(...)
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:485
go.uber.org/dig.paramObject.Build({{0x1403340, 0xc000486f00}, {0xc000137b80, 0x2, 0x2}, {0x0, 0x0, 0x0}}, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:413 +0x5d2
go.uber.org/dig.paramList.BuildList({{0x1403340, 0xc000137b30}, {0xc0004ae4e0, 0x1, 0x1}}, {0x13fe770, 0xc00015b600})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/param.go:151 +0xad
go.uber.org/dig.(*Scope).Invoke(0xc00015b600, {0xc000137b30, 0xc0004a6cf0}, {0x0, 0x0, 0x470c01?})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/invoke.go:123 +0x313
go.uber.org/dig.(*Container).Invoke(0xc0003f88f0?, {0xc000137b30?, 0xc0004a6cf0?}, {0x0?, 0x20?, 0xc00029e9f8?})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/invoke.go:83 +0x25
go.uber.org/fx.runInvoke({0x776a10c89998, 0xc00011c4d8}, {{0xfdc9c0, 0xc00015b4a0}, {0xc0003a0b40, 0x6, 0x7}})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/invoke.go:107 +0x129
go.uber.org/fx.(*module).invoke(0xc000116dd0, {{0xfdc9c0, 0xc00015b4a0}, {0xc0003a0b40, 0x6, 0x7}})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/module.go:335 +0x145
go.uber.org/fx.(*module).invokeAll(0xc000116dd0)
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/module.go:321 +0xda
go.uber.org/fx.New({0xc0003ae008, 0x24, 0x7?})
        /home/ddz/go/pkg/mod/go.uber.org/[email protected]/app.go:507 +0x8b8
github.com/libp2p/go-libp2p/config.(*Config).NewNode(0xc000164508)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/config/config.go:610 +0x13d6
github.com/libp2p/go-libp2p.NewWithoutDefaults({0xc0003961c0, 0xf, 0x1c})
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/libp2p.go:67 +0x65
github.com/libp2p/go-libp2p.New(...)
        /home/ddz/go/pkg/mod/github.com/libp2p/[email protected]/libp2p.go:53
main.main()
        /home/ddz/Lab/nunet/go-libp2p-duplicate-quic-bug/main.go:199 +0xf6d
exit status 2
Script to reproduce:
package main
import (
	"context"
	"crypto/rand"
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"time"
	"github.com/libp2p/go-libp2p"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	"github.com/libp2p/go-libp2p/core/crypto"
	"github.com/libp2p/go-libp2p/core/host"
	"github.com/libp2p/go-libp2p/core/peer"
	"github.com/libp2p/go-libp2p/core/protocol"
	"github.com/libp2p/go-libp2p/core/routing"
	"github.com/libp2p/go-libp2p/p2p/host/autorelay"
	"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
	"github.com/libp2p/go-libp2p/p2p/net/connmgr"
	"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
	"github.com/libp2p/go-libp2p/p2p/security/noise"
	libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
	libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
	"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
	"github.com/libp2p/go-libp2p/p2p/transport/tcp"
	ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
	webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
	ma "github.com/multiformats/go-multiaddr"
	"github.com/quic-go/quic-go"
)
func main() {
	// Generate a private key for testing
	privKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
	if err != nil {
		log.Fatalf("Failed to generate private key: %v", err)
	}
	// Create the libp2p config with duplicate QUIC listen addresses
	listenAddresses := []string{
		"/ip4/0.0.0.0/tcp/0",
		"/ip4/0.0.0.0/udp/1234/quic-v1", // First QUIC address
		// "/ip4/0.0.0.0/udp/1234/quic-v1", // Duplicate QUIC address - this triggers the bug
	}
	// Create connection manager
	connmgr, err := connmgr.NewConnManager(
		100,
		400,
		connmgr.WithGracePeriod(10*time.Second),
	)
	if err != nil {
		log.Fatalf("Failed to create connection manager: %v", err)
	}
	// Create peerstore
	ps, err := pstoremem.NewPeerstore()
	if err != nil {
		log.Fatalf("Failed to create peerstore: %v", err)
	}
	// Set up resource manager
	mem := int64(1024 * 1024 * 1024) // 1GB
	fds := 512
	limits := rcmgr.DefaultLimits
	limits.SystemBaseLimit.ConnsInbound = 512
	limits.SystemBaseLimit.ConnsOutbound = 512
	limits.SystemBaseLimit.Conns = 1024
	limits.SystemBaseLimit.StreamsInbound = 8192
	limits.SystemBaseLimit.StreamsOutbound = 8192
	limits.SystemBaseLimit.Streams = 16384
	scaled := limits.Scale(mem, fds)
	mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(scaled))
	if err != nil {
		log.Fatalf("Failed to create resource manager: %v", err)
	}
	// Create QUIC reuse function that demonstrates the bug
	newReuse := func(statelessResetKey quic.StatelessResetKey, tokenGeneratorKey quic.TokenGeneratorKey) (*quicreuse.ConnManager, error) {
		udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 1234})
		if err != nil {
			return nil, fmt.Errorf("failed to create UDP listener: %w", err)
		}
		reuse, err := quicreuse.NewConnManager(statelessResetKey, tokenGeneratorKey)
		if err != nil {
			return nil, fmt.Errorf("failed to create reuse: %w", err)
		}
		// This is where the bug should occur - trying to lend the same transport twice
		trDone, err := reuse.LendTransport("udp4", nil, udpConn)
		if err != nil {
			return nil, fmt.Errorf("failed to add transport to reuse: %w", err)
		}
		go func() {
			<-trDone
			fmt.Println("closing UDP connection")
			udpConn.Close()
		}()
		_, err = reuse.ListenQUIC(
			ma.StringCast(fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1", 1234)),
			&tls.Config{NextProtos: []string{"raw"}},
			func(*quic.Conn, uint64) bool { return false },
		)
		if err != nil {
			return nil, fmt.Errorf("failed to listen quic: %w", err)
		}
		return reuse, nil
	}
	// Create libp2p options
	var libp2pOpts []libp2p.Option
	dhtOpts := []dht.Option{
		dht.ProtocolPrefix(protocol.ID("/nunet")),
		dht.Mode(dht.ModeAutoServer),
	}
	libp2pOpts = append(libp2pOpts,
		libp2p.ListenAddrStrings(listenAddresses...),
		libp2p.ResourceManager(mgr),
		libp2p.Identity(privKey),
		libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
			idht, err := dht.New(context.Background(), h, dhtOpts...)
			return idht, err
		}),
		libp2p.Peerstore(ps),
		libp2p.Security(libp2ptls.ID, libp2ptls.New),
		libp2p.Security(noise.ID, noise.New),
		libp2p.ChainOptions(
			libp2p.Transport(tcp.NewTCPTransport),
			libp2p.Transport(libp2pquic.NewTransport),
			libp2p.Transport(webtransport.New),
			libp2p.Transport(ws.New),
		),
		libp2p.ConnectionManager(connmgr),
		libp2p.EnableRelay(),
		libp2p.EnableHolePunching(),
		libp2p.EnableRelayService(
			relay.WithLimit(&relay.RelayLimit{
				Duration: 5 * time.Minute,
				Data:     1 << 21, // 2 MiB
			}),
		),
		libp2p.EnableAutoRelayWithPeerSource(
			func(ctx context.Context, num int) <-chan peer.AddrInfo {
				r := make(chan peer.AddrInfo)
				go func() {
					defer close(r)
					for i := 0; i < num; i++ {
						select {
						case <-ctx.Done():
							return
						default:
							// No peers to provide
						}
					}
				}()
				return r
			},
			autorelay.WithBootDelay(time.Minute),
			autorelay.WithBackoff(30*time.Second),
			autorelay.WithMinCandidates(2),
			autorelay.WithMaxCandidates(3),
			autorelay.WithNumRelays(2),
		),
		libp2p.QUICReuse(newReuse),
	)
	// This is where the bug should occur
	host, err := libp2p.New(libp2pOpts...)
	if err != nil {
		fmt.Printf("Error creating libp2p host: %v\n", err)
		fmt.Println("This confirms the bug is reproducible with duplicate QUIC addresses!")
		return
	}
	// Clean up
	if host != nil {
		host.Close()
	}
}
Metadata
Metadata
Assignees
Labels
No labels