diff --git a/libp2p/transports/quictransport.nim b/libp2p/transports/quictransport.nim index d48711ffe0..bc642608c8 100644 --- a/libp2p/transports/quictransport.nim +++ b/libp2p/transports/quictransport.nim @@ -613,6 +613,17 @@ proc listenerEndpointFor( return ok(Opt.none(QuicEndpoint)) matchedEndpoint = Opt.some(endpoint) + if matchedEndpoint.isSome() or address.family != AddressFamily.IPv4: + return ok(matchedEndpoint) + + for endpoint in self.listeners: + let local = endpoint.localAddress() + if local.family == AddressFamily.IPv6 and local.isAnyLocal() and + endpoint.datagramTransport().fd.getDualstack().get(false): + if matchedEndpoint.isSome(): + return ok(Opt.none(QuicEndpoint)) + matchedEndpoint = Opt.some(endpoint) + ok(matchedEndpoint) proc newDialEndpoint( diff --git a/tests/libp2p/transports/test_quic.nim b/tests/libp2p/transports/test_quic.nim index c3aa76827f..349549c9f1 100644 --- a/tests/libp2p/transports/test_quic.nim +++ b/tests/libp2p/transports/test_quic.nim @@ -322,6 +322,27 @@ suite "Quic transport": # same port as the IPv6 listener means that listener was reused extractPort(serverConn.observedAddr.get()) == dialerIPv6Port + asyncTest "IPv4 dial reuses an IPv6 wildcard listener": + let dialer = await createQuicTransport( + isServer = true, addresses = @[ma("/ip6/::/udp/0/quic-v1")] + ) + let server = + await createQuicTransport(isServer = true, addresses = @[QuicAutoAddressIP4]) + defer: + await allFutures(dialer.stop(), server.stop()) + + let dialerPort = extractPort(dialer.addrs[0]) + + let acceptFut = server.accept() + let dialerConn = await dialer.dial("", server.addrs[0]) + let serverConn = await acceptFut + defer: + await allFutures(dialerConn.close(), serverConn.close()) + + check: + serverConn.observedAddr.isSome() + extractPort(serverConn.observedAddr.get()) == dialerPort + asyncTest "dial uses an IPv6 dial-only endpoint when only an IPv4 listener exists": # An IPv4 socket cannot carry an IPv6 dial, so the IPv4 listener cannot be # reused and a separate IPv6 dial-only endpoint has to be opened.