You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem: When attempting to create peers that communicate over IPv6, the code fails with:
ProtocolLookupError: MultiAddr '/ip6/::1/tcp/0' does not contain protocol Protocol(code=4, name='ip4', codec='ip4')
The error occurs because the codebase has hardcoded IPv4 protocol lookups in multiple places, preventing IPv6 addresses from being properly handled.
Root Cause Analysis
The codebase currently assumes IPv4 addresses in several critical areas:
TCP transport hardcodes ip4 protocol lookups
WebSocket transport has some IPv6 support but inconsistent handling
Network swarm resource manager only checks for ip4
Socket address conversion assumes IPv4 format
Address validation utilities have IPv6 disabled with TODO comments
Modules and Files Requiring Modification
1. Core Transport Layer
1.1 TCP Transport
File: libp2p/transport/tcp/tcp.py
Issues:
Line 91: ip4_host_str = maddr.value_for_protocol("ip4") - Hardcoded IPv4 lookup in TCPListener.listen()
Line 141: host_str = maddr.value_for_protocol("ip4") - Hardcoded IPv4 lookup in TCP.dial()
Line 198: _multiaddr_from_socket() function always creates /ip4/... multiaddr regardless of actual socket family
Required Changes:
Replace hardcoded value_for_protocol("ip4") with a helper function that tries both ip4 and ip6
Update _multiaddr_from_socket() to detect socket family (AF_INET vs AF_INET6) and create appropriate multiaddr
Ensure trio.serve_tcp() and trio.open_tcp_stream() work correctly with IPv6 addresses
Priority: CRITICAL - This is the primary source of the reported error
1.2 WebSocket Transport
File: libp2p/transport/websocket/transport.py
Current State: Partially supports IPv6 (has fallback logic)
Issues:
Lines 589, 682, 764: Multiple places check ip4 first, then ip6 as fallback
While this works, the pattern should be standardized across all transports
Required Changes:
Standardize IPv6/IPv4 handling to use a shared helper function
Ensure consistent behavior across all WebSocket connection paths
Priority: MEDIUM - Already has some IPv6 support but needs standardization
File: libp2p/transport/websocket/listener.py
Current State: Has IPv6 detection logic (lines 299-323)
Issues:
Line 229: Checks ip4 first, then ip6 - should use helper function
IPv6 detection logic exists but could be more robust
Required Changes:
Use standardized helper function for IP address extraction
Ensure socket family detection works correctly
Priority: LOW - Already has IPv6 support, needs minor refactoring
1.3 QUIC Transport
File: libp2p/transport/quic/utils.py
Current State: Already supports IPv6 properly in implementation
Evidence of IPv6 Support:
Lines 109-120: quic_multiaddr_to_endpoint() correctly handles both IPv4 and IPv6
# Try to get IPv4 addresstry:
host=maddr.value_for_protocol(multiaddr.protocols.P_IP4)
exceptException:
pass# Try to get IPv6 address if IPv4 not foundifhostisNone:
try:
host=maddr.value_for_protocol(multiaddr.protocols.P_IP6)
Lines 191-196: create_quic_multiaddr() correctly detects IP version using ipaddress module
Note: QUIC transport can serve as a reference implementation for how to properly handle IPv6 in other transports. See quic_multiaddr_to_endpoint() and _create_socket() methods.
Helper Function Implementation
Create a new utility function that can be shared across all modules:
Location: libp2p/utils/address_validation.py or new file libp2p/utils/multiaddr_utils.py
defextract_ip_from_multiaddr(maddr: Multiaddr) ->str|None:
""" Extract IP address (IPv4 or IPv6) from multiaddr. :param maddr: Multiaddr to extract from :return: IP address string or None if not found """# Try IPv4 first (for backward compatibility)try:
ip4=maddr.value_for_protocol("ip4")
ifip4:
returnip4exceptException:
pass# Try IPv6try:
ip6=maddr.value_for_protocol("ip6")
ifip6:
returnip6exceptException:
passreturnNonedefget_ip_protocol_from_multiaddr(maddr: Multiaddr) ->str|None:
""" Get the IP protocol name (ip4 or ip6) from multiaddr. :param maddr: Multiaddr to check :return: Protocol name ("ip4" or "ip6") or None """try:
maddr.value_for_protocol("ip4")
return"ip4"exceptException:
try:
maddr.value_for_protocol("ip6")
return"ip6"exceptException:
returnNonedefmultiaddr_from_socket(socket: trio.socket.SocketType) ->Multiaddr:
""" Create multiaddr from socket, detecting IPv4 or IPv6. :param socket: Socket to get address from :return: Multiaddr with appropriate IP protocol """ip, port=socket.getsockname()
family=socket.familyiffamily==socket.AF_INET6:
returnMultiaddr(f"/ip6/{ip}/tcp/{port}")
else:
# Default to IPv4 for AF_INET and unknown familiesreturnMultiaddr(f"/ip4/{ip}/tcp/{port}")
Additional Notes
Trio Socket Support: Trio's socket API supports IPv6, so the underlying transport should work. The issue is in the multiaddr protocol extraction.
Backward Compatibility: All changes should maintain backward compatibility with existing IPv4 code. The helper functions should try IPv4 first for compatibility.
Error Messages: Update error messages to mention both IPv4 and IPv6 when address extraction fails.
Documentation: Update docstrings and comments to reflect IPv6 support.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
IPv6 Support Analysis for py-libp2p
Issue Summary
GitHub Issue: #1111
Problem: When attempting to create peers that communicate over IPv6, the code fails with:
The error occurs because the codebase has hardcoded IPv4 protocol lookups in multiple places, preventing IPv6 addresses from being properly handled.
Root Cause Analysis
The codebase currently assumes IPv4 addresses in several critical areas:
ip4protocol lookupsip4Modules and Files Requiring Modification
1. Core Transport Layer
1.1 TCP Transport
File:
libp2p/transport/tcp/tcp.pyIssues:
ip4_host_str = maddr.value_for_protocol("ip4")- Hardcoded IPv4 lookup inTCPListener.listen()host_str = maddr.value_for_protocol("ip4")- Hardcoded IPv4 lookup inTCP.dial()_multiaddr_from_socket()function always creates/ip4/...multiaddr regardless of actual socket familyRequired Changes:
value_for_protocol("ip4")with a helper function that tries bothip4andip6_multiaddr_from_socket()to detect socket family (AF_INET vs AF_INET6) and create appropriate multiaddrtrio.serve_tcp()andtrio.open_tcp_stream()work correctly with IPv6 addressesPriority: CRITICAL - This is the primary source of the reported error
1.2 WebSocket Transport
File:
libp2p/transport/websocket/transport.pyCurrent State: Partially supports IPv6 (has fallback logic)
Issues:
ip4first, thenip6as fallbackRequired Changes:
Priority: MEDIUM - Already has some IPv6 support but needs standardization
File:
libp2p/transport/websocket/listener.pyCurrent State: Has IPv6 detection logic (lines 299-323)
Issues:
ip4first, thenip6- should use helper functionRequired Changes:
Priority: LOW - Already has IPv6 support, needs minor refactoring
1.3 QUIC Transport
File:
libp2p/transport/quic/utils.pyCurrent State: Already supports IPv6 properly in implementation
Evidence of IPv6 Support:
quic_multiaddr_to_endpoint()correctly handles both IPv4 and IPv6create_quic_multiaddr()correctly detects IP version usingipaddressmodulelibp2p/transport/quic/listener.py(lines 1241-1246): Socket creation detects IPv6 and usesAF_INET6Test Coverage:
tests/core/transport/quic/test_utils.py:test_ipv6_extraction()- Tests IPv6 address extraction (lines 86-96)test_ipv6_creation()- Tests IPv6 multiaddr creation (lines 160-169)/ip6/::1/udp/4001/quic-v1,/ip6/2001:db8::1/udp/5000/quictests/core/transport/quic/test_transport.py:test_can_dial_quic_addresses()includes IPv6 addresses in valid test cases (lines 68-70, 77-79)examples/interop/local_ping_test.py:_build_quic_addr()method handles IPv6 detection (lines 185-192)Required Changes:
Priority: VERIFICATION - Implementation appears correct, but should verify end-to-end IPv6 connectivity works in practice
File:
libp2p/transport/quic/listener.pyCurrent State: Uses
quic_multiaddr_to_endpoint()which handles IPv6Issues:
getsockname()returns address that may be IPv6create_quic_multiaddr()which should handle IPv6 correctlyRequired Changes:
create_quic_multiaddr()correctly handles IPv6 addresses fromgetsockname()Priority: LOW - Should work but needs verification
2. Network Layer
2.1 Swarm Resource Manager
File:
libp2p/network/swarm.pyIssues:
ep = addr.value_for_protocol("ip4")- Hardcoded IPv4 lookup for resource manager endpoint trackingRequired Changes:
Priority: HIGH - Affects connection management and resource limits
3. Address Utilities
3.1 Address Validation
File:
libp2p/utils/address_validation.pyIssues:
Required Changes:
get_wildcard_address()to support IPv6 wildcard (::)get_optimal_binding_address()to prefer IPv6 when availablePriority: MEDIUM - Should be enabled after transport fixes
3.2 Relay/NAT Utilities
File:
libp2p/relay/circuit_v2/nat.pyCurrent State: Has some IPv6 support
Issues:
ip_to_int()function handles both IPv4 and IPv6 (usesipaddressmodule)extract_ip_from_multiaddr()checks IPv4 first, then IPv6 (lines 147-152)Required Changes:
Priority: LOW - Already has IPv6 support, needs verification
4. Transport Registry
4.1 Transport Selection
File:
libp2p/transport/transport_registry.pyCurrent State: Already recognizes IPv6 in validation
Issues:
_is_valid_tcp_multiaddr()already checks for bothip4andip6protocolsRequired Changes:
Priority: NONE - No changes needed
5. Identity/Identify Protocol
5.1 Address Conversion
File:
libp2p/identity/identify/identify.pyCurrent State: Has IPv6 support
Issues:
_remote_address_to_multiaddr()correctly detects IPv6 by checking for:in host string/ip6/...or/ip4/...multiaddrRequired Changes:
Priority: NONE - No changes needed
6. I/O Layer
6.1 Trio I/O
File:
libp2p/io/trio.pyIssues:
get_remote_address()usesgetpeername()which may return IPv6 addressesRequired Changes:
Priority: LOW - Needs verification
Implementation Strategy
Phase 1: Core Transport Fixes (Critical)
Create helper function for IP address extraction:
Fix TCP transport (
libp2p/transport/tcp/tcp.py):ip4lookups with helper function_multiaddr_from_socket()to detect socket familyFix Swarm resource manager (
libp2p/network/swarm.py):Phase 2: Standardization (Medium Priority)
Phase 3: Testing and Verification (Low Priority)
Security Considerations
The TODO comment in
address_validation.pymentions security handshake issues with IPv6. These need to be investigated:Testing Requirements
Unit Tests
/ip6/::1/tcp/0)Integration Tests
Test Files to Update
tests/core/transport/tcp/test_tcp.py- Add IPv6 test casestests/core/transport/websocket/test_websocket.py- Add IPv6 test casestests/core/network/test_swarm.py- Add IPv6 test casestests/core/transport/test_ipv6_support.pyFiles Summary
Critical Changes Required
libp2p/transport/tcp/tcp.py- PRIMARY FIXlibp2p/network/swarm.py- Resource manager endpoint trackingMedium Priority Changes
libp2p/utils/address_validation.py- Re-enable IPv6 supportlibp2p/transport/websocket/transport.py- Standardize IPv6 handlinglibp2p/transport/websocket/listener.py- Minor refactoringLow Priority / Verification
libp2p/transport/quic/listener.py- Verify IPv6 handlinglibp2p/io/trio.py- Verify remote address handlinglibp2p/relay/circuit_v2/nat.py- Verify IPv6 extractionNo Changes Needed (Already Support IPv6)
libp2p/transport/quic/utils.py- Reference implementation for IPv6 supportlibp2p/transport/quic/listener.py- Socket creation handles IPv6 correctlylibp2p/transport/transport_registry.py- Validation accepts IPv6libp2p/identity/identify/identify.py- Address conversion handles IPv6Note: QUIC transport can serve as a reference implementation for how to properly handle IPv6 in other transports. See
quic_multiaddr_to_endpoint()and_create_socket()methods.Helper Function Implementation
Create a new utility function that can be shared across all modules:
Location:
libp2p/utils/address_validation.pyor new filelibp2p/utils/multiaddr_utils.pyAdditional Notes
Trio Socket Support: Trio's socket API supports IPv6, so the underlying transport should work. The issue is in the multiaddr protocol extraction.
Backward Compatibility: All changes should maintain backward compatibility with existing IPv4 code. The helper functions should try IPv4 first for compatibility.
Error Messages: Update error messages to mention both IPv4 and IPv6 when address extraction fails.
Documentation: Update docstrings and comments to reflect IPv6 support.
Example Code: The minimal example from issue ipv6 error: MultiAddr '/ip6/::1/tcp/0' does not contain protocol ip4 #1111 should work after these changes.
References
Beta Was this translation helpful? Give feedback.
All reactions