Skip to content

Commit 14fc7fd

Browse files
authored
Merge pull request #963 from yashksaini-coder/Fix/failed-KAD-test
Fix/failed kad test
2 parents f9f8cea + 9651240 commit 14fc7fd

File tree

3 files changed

+192
-1
lines changed

3 files changed

+192
-1
lines changed

libp2p/tools/constants.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from collections.abc import (
22
Sequence,
33
)
4+
import ipaddress
5+
import os
46
from typing import (
57
NamedTuple,
68
)
@@ -21,7 +23,32 @@
2123
MAX_READ_LEN = 65535
2224

2325

24-
LISTEN_MADDR = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/0")
26+
def _validate_ipv4_address(address: str) -> str:
27+
"""
28+
Validate that the given address is a valid IPv4 address.
29+
30+
Args:
31+
address: The IP address string to validate
32+
33+
Returns:
34+
The validated IPv4 address, or "127.0.0.1" if invalid
35+
36+
"""
37+
try:
38+
# Validate that it's a valid IPv4 address
39+
ipaddress.IPv4Address(address)
40+
return address
41+
except (ipaddress.AddressValueError, ValueError):
42+
# If invalid, return the secure default
43+
return "127.0.0.1"
44+
45+
46+
# Default bind address configuration with environment variable override
47+
# DEFAULT_BIND_ADDRESS defaults to "127.0.0.1" (secure) but can be overridden
48+
# via LIBP2P_BIND environment variable (e.g., "0.0.0.0" for tests)
49+
# Invalid IPv4 addresses will fallback to "127.0.0.1"
50+
DEFAULT_BIND_ADDRESS = _validate_ipv4_address(os.getenv("LIBP2P_BIND", "127.0.0.1"))
51+
LISTEN_MADDR = multiaddr.Multiaddr(f"/ip4/{DEFAULT_BIND_ADDRESS}/tcp/0")
2552

2653

2754
FLOODSUB_PROTOCOL_ID = floodsub.PROTOCOL_ID

newsfragments/964.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added IPv4 address validation for LIBP2P_BIND environment variable to prevent invalid addresses from causing runtime errors. Invalid addresses now fallback to the secure default of 127.0.0.1.
2+
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
"""
2+
Test for environment variable configuration of LIBP2P_BIND.
3+
4+
This test verifies that PR #892's fix for the DHT performance issue works correctly
5+
by allowing configurable bind addresses via the LIBP2P_BIND environment variable.
6+
"""
7+
8+
import importlib
9+
import os
10+
11+
import pytest
12+
import multiaddr
13+
14+
15+
def test_default_bind_address_secure():
16+
"""Test that default binding is secure (127.0.0.1)."""
17+
# Clear any existing environment variable
18+
if "LIBP2P_BIND" in os.environ:
19+
del os.environ["LIBP2P_BIND"]
20+
21+
# Reload the constants module to get fresh configuration
22+
import libp2p.tools.constants
23+
24+
importlib.reload(libp2p.tools.constants)
25+
26+
# Verify default is secure
27+
assert libp2p.tools.constants.DEFAULT_BIND_ADDRESS == "127.0.0.1"
28+
assert str(libp2p.tools.constants.LISTEN_MADDR) == "/ip4/127.0.0.1/tcp/0"
29+
30+
31+
def test_environment_variable_override():
32+
"""Test that LIBP2P_BIND environment variable overrides default."""
33+
# Set environment variable
34+
os.environ["LIBP2P_BIND"] = "0.0.0.0"
35+
36+
# Reload the constants module to pick up new environment
37+
import libp2p.tools.constants
38+
39+
importlib.reload(libp2p.tools.constants)
40+
41+
# Verify override works
42+
assert libp2p.tools.constants.DEFAULT_BIND_ADDRESS == "0.0.0.0"
43+
assert str(libp2p.tools.constants.LISTEN_MADDR) == "/ip4/0.0.0.0/tcp/0"
44+
45+
# Clean up
46+
del os.environ["LIBP2P_BIND"]
47+
48+
49+
def test_custom_ip_address_override():
50+
"""Test that custom IP addresses work via environment variable."""
51+
custom_ip = "192.168.1.100"
52+
os.environ["LIBP2P_BIND"] = custom_ip
53+
54+
# Reload the constants module
55+
import libp2p.tools.constants
56+
57+
importlib.reload(libp2p.tools.constants)
58+
59+
# Verify custom IP works
60+
assert libp2p.tools.constants.DEFAULT_BIND_ADDRESS == custom_ip
61+
assert str(libp2p.tools.constants.LISTEN_MADDR) == f"/ip4/{custom_ip}/tcp/0"
62+
63+
# Clean up
64+
del os.environ["LIBP2P_BIND"]
65+
66+
67+
def test_multiaddr_construction():
68+
"""Test that the constructed multiaddr is valid."""
69+
os.environ["LIBP2P_BIND"] = "0.0.0.0"
70+
71+
# Reload the constants module
72+
import libp2p.tools.constants
73+
74+
importlib.reload(libp2p.tools.constants)
75+
76+
# Verify multiaddr is properly constructed and valid
77+
maddr = libp2p.tools.constants.LISTEN_MADDR
78+
assert isinstance(maddr, multiaddr.Multiaddr)
79+
80+
# Verify it has the expected components
81+
protocols = list(maddr.protocols())
82+
assert len(protocols) == 2
83+
assert protocols[0].name == "ip4"
84+
assert protocols[1].name == "tcp"
85+
86+
# Verify the address value
87+
assert maddr.value_for_protocol("ip4") == "0.0.0.0"
88+
assert maddr.value_for_protocol("tcp") == "0"
89+
90+
# Clean up
91+
del os.environ["LIBP2P_BIND"]
92+
93+
94+
def test_invalid_ipv4_address_fallback():
95+
"""Test that invalid IPv4 addresses fallback to 127.0.0.1."""
96+
invalid_addresses = [
97+
"17.0.0.", # Incomplete IP address
98+
"256.1.1.1", # Invalid octet
99+
"not.an.ip", # Non-numeric
100+
"192.168.1", # Missing octet
101+
"192.168.1.1.1", # Too many octets
102+
"::1", # IPv6 address
103+
"", # Empty string
104+
"localhost", # Hostname
105+
]
106+
107+
for invalid_addr in invalid_addresses:
108+
os.environ["LIBP2P_BIND"] = invalid_addr
109+
110+
# Reload the constants module
111+
import libp2p.tools.constants
112+
113+
importlib.reload(libp2p.tools.constants)
114+
115+
# Verify fallback to secure default
116+
assert libp2p.tools.constants.DEFAULT_BIND_ADDRESS == "127.0.0.1"
117+
assert str(libp2p.tools.constants.LISTEN_MADDR) == "/ip4/127.0.0.1/tcp/0"
118+
119+
# Clean up
120+
del os.environ["LIBP2P_BIND"]
121+
122+
123+
def test_valid_ipv4_addresses():
124+
"""Test that various valid IPv4 addresses work correctly."""
125+
valid_addresses = [
126+
"127.0.0.1", # Localhost
127+
"0.0.0.0", # All interfaces
128+
"192.168.1.1", # Private network
129+
"10.0.0.1", # Private network
130+
"172.16.0.1", # Private network
131+
"8.8.8.8", # Public DNS
132+
"255.255.255.255", # Broadcast
133+
]
134+
135+
for valid_addr in valid_addresses:
136+
os.environ["LIBP2P_BIND"] = valid_addr
137+
138+
# Reload the constants module
139+
import libp2p.tools.constants
140+
141+
importlib.reload(libp2p.tools.constants)
142+
143+
# Verify the address is used as-is
144+
assert libp2p.tools.constants.DEFAULT_BIND_ADDRESS == valid_addr
145+
assert str(libp2p.tools.constants.LISTEN_MADDR) == f"/ip4/{valid_addr}/tcp/0"
146+
147+
# Clean up
148+
del os.environ["LIBP2P_BIND"]
149+
150+
151+
@pytest.fixture(autouse=True)
152+
def cleanup_environment():
153+
"""Ensure clean environment after each test."""
154+
yield
155+
# Clean up after each test
156+
if "LIBP2P_BIND" in os.environ:
157+
del os.environ["LIBP2P_BIND"]
158+
159+
# Reload with clean environment
160+
import libp2p.tools.constants
161+
162+
importlib.reload(libp2p.tools.constants)

0 commit comments

Comments
 (0)