diff --git a/docs/examples.circuit_relay.rst b/docs/examples.circuit_relay.rst index 2a14c3c51..85326b005 100644 --- a/docs/examples.circuit_relay.rst +++ b/docs/examples.circuit_relay.rst @@ -41,7 +41,7 @@ Create a file named ``relay_node.py`` with the following content: logger = logging.getLogger("relay_node") async def run_relay(): - listen_addr = multiaddr.Multiaddr("/ip4/0.0.0.0/tcp/9000") + listen_addr = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/9000") host = new_host() config = RelayConfig( @@ -139,7 +139,7 @@ Create a file named ``destination_node.py`` with the following content: Run a simple destination node that accepts connections. This is a simplified version that doesn't use the relay functionality. """ - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/9001") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/9001") host = new_host() # Configure as a relay receiver (stop) @@ -259,7 +259,7 @@ Create a file named ``source_node.py`` with the following content: async def run_source(relay_peer_id=None, destination_peer_id=None): # Create a libp2p host - listen_addr = multiaddr.Multiaddr("/ip4/0.0.0.0/tcp/9002") + listen_addr = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/9002") host = new_host() # Configure as a relay client @@ -428,7 +428,7 @@ Running the Example Relay node multiaddr: /ip4/127.0.0.1/tcp/9000/p2p/QmaUigQJ9nJERa6GaZuyfaiX91QjYwoQJ46JS3k7ys7SLx ================================================== - Listening on: [] + Listening on: [] Protocol service started Relay service started successfully Relay limits: RelayLimits(duration=3600, data=10485760, max_circuit_conns=8, max_reservations=4) @@ -447,7 +447,7 @@ Running the Example Use this ID in the source node: QmPBr38KeQG2ibyL4fxq6yJWpfoVNCqJMHBdNyn1Qe4h5s ================================================== - Listening on: [] + Listening on: [] Registered echo protocol handler Protocol service started Transport created @@ -469,7 +469,7 @@ Running the Example $ python source_node.py Source node started with ID: QmPyM56cgmFoHTgvMgGfDWRdVRQznmxCDDDg2dJ8ygVXj3 - Listening on: [] + Listening on: [] Protocol service started No relay peer ID provided. Please enter the relay\'s peer ID: Enter relay peer ID: QmaUigQJ9nJERa6GaZuyfaiX91QjYwoQJ46JS3k7ys7SLx diff --git a/docs/examples.identify.rst b/docs/examples.identify.rst index 9623f112f..ba3e13c43 100644 --- a/docs/examples.identify.rst +++ b/docs/examples.identify.rst @@ -12,7 +12,7 @@ This example demonstrates how to use the libp2p ``identify`` protocol. $ identify-demo First host listening. Run this from another console: - identify-demo -p 8889 -d /ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM + identify-demo -p 8889 -d /ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Waiting for incoming identify request... @@ -21,13 +21,13 @@ folder and paste it in: .. code-block:: console - $ identify-demo -p 8889 -d /ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM - dialer (host_b) listening on /ip4/0.0.0.0/tcp/8889 + $ identify-demo -p 8889 -d /ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM + dialer (host_b) listening on /ip4/127.0.0.1/tcp/8889 Second host connecting to peer: QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Starting identify protocol... Identify response: Public Key (Base64): CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC6c/oNPP9X13NDQ3Xrlp3zOj+ErXIWb/A4JGwWchiDBwMhMslEX3ct8CqI0BqUYKuwdFjowqqopOJ3cS2MlqtGaiP6Dg9bvGqSDoD37BpNaRVNcebRxtB0nam9SQy3PYLbHAmz0vR4ToSiL9OLRORnGOxCtHBuR8ZZ5vS0JEni8eQMpNa7IuXwyStnuty/QjugOZudBNgYSr8+9gH722KTjput5IRL7BrpIdd4HNXGVRm4b9BjNowvHu404x3a/ifeNblpy/FbYyFJEW0looygKF7hpRHhRbRKIDZt2BqOfT1sFkbqsHE85oY859+VMzP61YELgvGwai2r7KcjkW/AgMBAAE= - Listen Addresses: ['/ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM'] + Listen Addresses: ['/ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM'] Protocols: ['/ipfs/id/1.0.0', '/ipfs/ping/1.0.0'] Observed Address: ['/ip4/127.0.0.1/tcp/38082'] Protocol Version: ipfs/0.1.0 diff --git a/docs/examples.identify_push.rst b/docs/examples.identify_push.rst index 5b217d38f..614d37bd7 100644 --- a/docs/examples.identify_push.rst +++ b/docs/examples.identify_push.rst @@ -34,11 +34,11 @@ There is also a more interactive version of the example which runs as separate l ==== Starting Identify-Push Listener on port 8888 ==== Listener host ready! - Listening on: /ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM + Listening on: /ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Peer ID: QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Run dialer with command: - identify-push-listener-dialer-demo -d /ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM + identify-push-listener-dialer-demo -d /ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Waiting for incoming connections... (Ctrl+C to exit) @@ -47,12 +47,12 @@ folder and paste it in: .. code-block:: console - $ identify-push-listener-dialer-demo -d /ip4/0.0.0.0/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM + $ identify-push-listener-dialer-demo -d /ip4/127.0.0.1/tcp/8888/p2p/QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM ==== Starting Identify-Push Dialer on port 8889 ==== Dialer host ready! - Listening on: /ip4/0.0.0.0/tcp/8889/p2p/QmZyXwVuTaBcDeRsSkJpOpWrSt + Listening on: /ip4/127.0.0.1/tcp/8889/p2p/QmZyXwVuTaBcDeRsSkJpOpWrSt Connecting to peer: QmUiN4R3fNrCoQugGgmmb3v35neMEjKFNrsbNGVDsRHWpM Successfully connected to listener! diff --git a/docs/examples.pubsub.rst b/docs/examples.pubsub.rst index f3a8500f1..8990e5c08 100644 --- a/docs/examples.pubsub.rst +++ b/docs/examples.pubsub.rst @@ -15,7 +15,7 @@ This example demonstrates how to create a chat application using libp2p's PubSub 2025-04-06 23:59:17,471 - pubsub-demo - INFO - Your selected topic is: pubsub-chat 2025-04-06 23:59:17,472 - pubsub-demo - INFO - Using random available port: 33269 2025-04-06 23:59:17,490 - pubsub-demo - INFO - Node started with peer ID: QmcJnocH1d1tz3Zp4MotVDjNfNFawXHw2dpB9tMYGTXJp7 - 2025-04-06 23:59:17,490 - pubsub-demo - INFO - Listening on: /ip4/0.0.0.0/tcp/33269 + 2025-04-06 23:59:17,490 - pubsub-demo - INFO - Listening on: /ip4/127.0.0.1/tcp/33269 2025-04-06 23:59:17,490 - pubsub-demo - INFO - Initializing PubSub and GossipSub... 2025-04-06 23:59:17,491 - pubsub-demo - INFO - Pubsub and GossipSub services started. 2025-04-06 23:59:17,491 - pubsub-demo - INFO - Pubsub ready. @@ -35,7 +35,7 @@ Copy the line that starts with ``pubsub-demo -d``, open a new terminal and paste 2025-04-07 00:00:59,846 - pubsub-demo - INFO - Your selected topic is: pubsub-chat 2025-04-07 00:00:59,846 - pubsub-demo - INFO - Using random available port: 51977 2025-04-07 00:00:59,864 - pubsub-demo - INFO - Node started with peer ID: QmYQKCm95Ut1aXsjHmWVYqdaVbno1eKTYC8KbEVjqUaKaQ - 2025-04-07 00:00:59,864 - pubsub-demo - INFO - Listening on: /ip4/0.0.0.0/tcp/51977 + 2025-04-07 00:00:59,864 - pubsub-demo - INFO - Listening on: /ip4/127.0.0.1/tcp/51977 2025-04-07 00:00:59,864 - pubsub-demo - INFO - Initializing PubSub and GossipSub... 2025-04-07 00:00:59,864 - pubsub-demo - INFO - Pubsub and GossipSub services started. 2025-04-07 00:00:59,865 - pubsub-demo - INFO - Pubsub ready. diff --git a/docs/examples.random_walk.rst b/docs/examples.random_walk.rst index baa3f81f2..ea9ea220b 100644 --- a/docs/examples.random_walk.rst +++ b/docs/examples.random_walk.rst @@ -23,7 +23,7 @@ The Random Walk implementation performs the following key operations: 2025-08-12 19:51:25,424 - random-walk-example - INFO - Mode: server, Port: 0 Demo interval: 30s 2025-08-12 19:51:25,426 - random-walk-example - INFO - Starting server node on port 45123 2025-08-12 19:51:25,426 - random-walk-example - INFO - Node peer ID: 16Uiu2HAm7EsNv5vvjPAehGAVfChjYjD63ZHyWogQRdzntSbAg9ef - 2025-08-12 19:51:25,426 - random-walk-example - INFO - Node address: /ip4/0.0.0.0/tcp/45123/p2p/16Uiu2HAm7EsNv5vvjPAehGAVfChjYjD63ZHyWogQRdzntSbAg9ef + 2025-08-12 19:51:25,426 - random-walk-example - INFO - Node address: /ip4/127.0.0.1/tcp/45123/p2p/16Uiu2HAm7EsNv5vvjPAehGAVfChjYjD63ZHyWogQRdzntSbAg9ef 2025-08-12 19:51:25,427 - random-walk-example - INFO - Initial routing table size: 0 2025-08-12 19:51:25,427 - random-walk-example - INFO - DHT service started in SERVER mode 2025-08-12 19:51:25,430 - libp2p.discovery.random_walk.rt_refresh_manager - INFO - RT Refresh Manager started diff --git a/examples/advanced/network_discover.py b/examples/advanced/network_discover.py index 87b44ddf3..71edd2094 100644 --- a/examples/advanced/network_discover.py +++ b/examples/advanced/network_discover.py @@ -18,7 +18,7 @@ except ImportError: # Fallbacks if utilities are missing def get_available_interfaces(port: int, protocol: str = "tcp"): - return [Multiaddr(f"/ip4/0.0.0.0/{protocol}/{port}")] + return [Multiaddr(f"/ip4/127.0.0.1/{protocol}/{port}")] def expand_wildcard_address(addr: Multiaddr, port: int | None = None): if port is None: @@ -27,7 +27,7 @@ def expand_wildcard_address(addr: Multiaddr, port: int | None = None): return [Multiaddr(addr_str + f"/{port}")] def get_optimal_binding_address(port: int, protocol: str = "tcp"): - return Multiaddr(f"/ip4/0.0.0.0/{protocol}/{port}") + return Multiaddr(f"/ip4/127.0.0.1/{protocol}/{port}") def main() -> None: diff --git a/examples/bootstrap/bootstrap.py b/examples/bootstrap/bootstrap.py index af7d08cc9..93a6913af 100644 --- a/examples/bootstrap/bootstrap.py +++ b/examples/bootstrap/bootstrap.py @@ -59,7 +59,7 @@ async def run(port: int, bootstrap_addrs: list[str]) -> None: key_pair = create_new_key_pair(secret) # Create listen address - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Register peer discovery handler peerDiscovery.register_peer_discovered_handler(on_peer_discovery) diff --git a/examples/chat/chat.py b/examples/chat/chat.py index 05a9b918d..c06e20a77 100755 --- a/examples/chat/chat.py +++ b/examples/chat/chat.py @@ -40,7 +40,7 @@ async def write_data(stream: INetStream) -> None: async def run(port: int, destination: str) -> None: - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") host = new_host() async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: # Start the peer-store cleanup task diff --git a/examples/doc-examples/example_encryption_insecure.py b/examples/doc-examples/example_encryption_insecure.py index c15368080..089fb72fd 100644 --- a/examples/doc-examples/example_encryption_insecure.py +++ b/examples/doc-examples/example_encryption_insecure.py @@ -40,7 +40,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_encryption_noise.py b/examples/doc-examples/example_encryption_noise.py index a2a4318c5..7d037610b 100644 --- a/examples/doc-examples/example_encryption_noise.py +++ b/examples/doc-examples/example_encryption_noise.py @@ -41,7 +41,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_encryption_secio.py b/examples/doc-examples/example_encryption_secio.py index 603ad6ea0..3b1cb4056 100644 --- a/examples/doc-examples/example_encryption_secio.py +++ b/examples/doc-examples/example_encryption_secio.py @@ -34,7 +34,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_multiplexer.py b/examples/doc-examples/example_multiplexer.py index 0d6f26622..6963ace01 100644 --- a/examples/doc-examples/example_multiplexer.py +++ b/examples/doc-examples/example_multiplexer.py @@ -41,7 +41,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_net_stream.py b/examples/doc-examples/example_net_stream.py index d8842beab..a77a75094 100644 --- a/examples/doc-examples/example_net_stream.py +++ b/examples/doc-examples/example_net_stream.py @@ -173,7 +173,7 @@ async def run_enhanced_demo( """ Run enhanced echo demo with NetStream state management. """ - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Generate or use provided key if seed: diff --git a/examples/doc-examples/example_peer_discovery.py b/examples/doc-examples/example_peer_discovery.py index 7ceec3754..eb3e19145 100644 --- a/examples/doc-examples/example_peer_discovery.py +++ b/examples/doc-examples/example_peer_discovery.py @@ -44,7 +44,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_running.py b/examples/doc-examples/example_running.py index a01699310..7f3ade321 100644 --- a/examples/doc-examples/example_running.py +++ b/examples/doc-examples/example_running.py @@ -41,7 +41,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/doc-examples/example_transport.py b/examples/doc-examples/example_transport.py index e981fa7d1..8f4c9fa10 100644 --- a/examples/doc-examples/example_transport.py +++ b/examples/doc-examples/example_transport.py @@ -21,7 +21,7 @@ async def main(): # Configure the listening address port = 8000 - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Start the host async with host.run(listen_addrs=[listen_addr]): diff --git a/examples/identify/identify.py b/examples/identify/identify.py index 98980f99f..445962c38 100644 --- a/examples/identify/identify.py +++ b/examples/identify/identify.py @@ -58,7 +58,7 @@ def print_identify_response(identify_response: Identify): async def run(port: int, destination: str, use_varint_format: bool = True) -> None: - localhost_ip = "0.0.0.0" + localhost_ip = "127.0.0.1" if not destination: # Create first host (listener) @@ -79,10 +79,9 @@ async def run(port: int, destination: str, use_varint_format: bool = True) -> No # Start the peer-store cleanup task nursery.start_soon(host_a.get_peerstore().start_cleanup_task, 60) - # Get the actual address and replace 0.0.0.0 with 127.0.0.1 for client - # connections + # Get the actual address server_addr = str(host_a.get_addrs()[0]) - client_addr = server_addr.replace("/ip4/0.0.0.0/", "/ip4/127.0.0.1/") + client_addr = server_addr format_name = "length-prefixed" if use_varint_format else "raw protobuf" format_flag = "--raw-format" if not use_varint_format else "" diff --git a/examples/identify_push/identify_push_listener_dialer.py b/examples/identify_push/identify_push_listener_dialer.py index c23e62bb4..a9974b82b 100644 --- a/examples/identify_push/identify_push_listener_dialer.py +++ b/examples/identify_push/identify_push_listener_dialer.py @@ -216,7 +216,7 @@ async def run_listener( ) # Start listening - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") try: async with host.run([listen_addr]): @@ -275,7 +275,7 @@ async def run_dialer( ) # Start listening on a different port - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") async with host.run([listen_addr]): logger.info("Dialer host ready!") diff --git a/examples/mDNS/mDNS.py b/examples/mDNS/mDNS.py index d3f11b567..499ca2248 100644 --- a/examples/mDNS/mDNS.py +++ b/examples/mDNS/mDNS.py @@ -33,7 +33,7 @@ def onPeerDiscovery(peerinfo: PeerInfo): async def run(port: int) -> None: secret = secrets.token_bytes(32) key_pair = create_new_key_pair(secret) - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") peerDiscovery.register_peer_discovered_handler(onPeerDiscovery) diff --git a/examples/ping/ping.py b/examples/ping/ping.py index d1a5daae4..bb47bd95d 100644 --- a/examples/ping/ping.py +++ b/examples/ping/ping.py @@ -55,7 +55,7 @@ async def send_ping(stream: INetStream) -> None: async def run(port: int, destination: str) -> None: - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") host = new_host(listen_addrs=[listen_addr]) async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: diff --git a/examples/pubsub/pubsub.py b/examples/pubsub/pubsub.py index 41545658d..843a28292 100644 --- a/examples/pubsub/pubsub.py +++ b/examples/pubsub/pubsub.py @@ -109,7 +109,7 @@ async def run(topic: str, destination: str | None, port: int | None) -> None: port = find_free_port() logger.info(f"Using random available port: {port}") - listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") # Create a new libp2p host host = new_host( diff --git a/examples/random_walk/random_walk.py b/examples/random_walk/random_walk.py index 845ccd57b..b90d63041 100644 --- a/examples/random_walk/random_walk.py +++ b/examples/random_walk/random_walk.py @@ -130,7 +130,7 @@ async def run_node(port: int, mode: str, demo_interval: int = 30) -> None: # Create host and DHT key_pair = create_new_key_pair(secrets.token_bytes(32)) host = new_host(key_pair=key_pair, bootstrap=DEFAULT_BOOTSTRAP_NODES) - listen_addr = Multiaddr(f"/ip4/0.0.0.0/tcp/{port}") + listen_addr = Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: # Start maintenance tasks @@ -139,7 +139,7 @@ async def run_node(port: int, mode: str, demo_interval: int = 30) -> None: peer_id = host.get_id().pretty() logger.info(f"Node peer ID: {peer_id}") - logger.info(f"Node address: /ip4/0.0.0.0/tcp/{port}/p2p/{peer_id}") + logger.info(f"Node address: /ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}") # Create and start DHT with Random Walk enabled dht = KadDHT(host, dht_mode, enable_random_walk=True) diff --git a/libp2p/utils/address_validation.py b/libp2p/utils/address_validation.py index 77b797a19..106772412 100644 --- a/libp2p/utils/address_validation.py +++ b/libp2p/utils/address_validation.py @@ -99,7 +99,7 @@ def get_available_interfaces(port: int, protocol: str = "tcp") -> list[Multiaddr # Fallback if nothing discovered if not addrs: - addrs.append(Multiaddr(f"/ip4/0.0.0.0/{protocol}/{port}")) + addrs.append(Multiaddr(f"/ip4/127.0.0.1/{protocol}/{port}")) return addrs @@ -148,8 +148,8 @@ def is_non_loopback(ma: Multiaddr) -> bool: if "/ip4/127." in str(c) or "/ip6/::1" in str(c): return c - # As a final fallback, produce a wildcard - return Multiaddr(f"/ip4/0.0.0.0/{protocol}/{port}") + # As a final fallback, produce a loopback address + return Multiaddr(f"/ip4/127.0.0.1/{protocol}/{port}") __all__ = [ diff --git a/newsfragments/885.feature.rst b/newsfragments/885.feature.rst new file mode 100644 index 000000000..e0566b6af --- /dev/null +++ b/newsfragments/885.feature.rst @@ -0,0 +1,2 @@ +Enhanced security by defaulting to loopback address (127.0.0.1) instead of wildcard binding. +All examples and core modules now use secure default addresses to prevent unintended public exposure. diff --git a/tests/examples/test_examples_bind_address.py b/tests/examples/test_examples_bind_address.py new file mode 100644 index 000000000..1045c90ba --- /dev/null +++ b/tests/examples/test_examples_bind_address.py @@ -0,0 +1,110 @@ +""" +Tests to verify that all examples use 127.0.0.1 instead of 0.0.0.0 +""" + +from pathlib import Path + + +class TestExamplesBindAddress: + """Test suite to verify all examples use secure bind addresses""" + + def get_example_files(self): + """Get all Python files in the examples directory""" + examples_dir = Path("examples") + return list(examples_dir.rglob("*.py")) + + def check_file_for_wildcard_binding(self, filepath): + """Check if a file contains 0.0.0.0 binding""" + with open(filepath, encoding="utf-8") as f: + content = f.read() + + # Check for various forms of wildcard binding + wildcard_patterns = [ + "0.0.0.0", + "/ip4/0.0.0.0/", + ] + + found_wildcards = [] + for line_num, line in enumerate(content.splitlines(), 1): + for pattern in wildcard_patterns: + if pattern in line and not line.strip().startswith("#"): + found_wildcards.append((line_num, line.strip())) + + return found_wildcards + + def test_no_wildcard_binding_in_examples(self): + """Test that no example files use 0.0.0.0 for binding""" + example_files = self.get_example_files() + + # Skip certain files that might legitimately discuss wildcards + skip_files = [ + "network_discover.py", # This demonstrates wildcard expansion + ] + + files_with_wildcards = {} + + for filepath in example_files: + if any(skip in str(filepath) for skip in skip_files): + continue + + wildcards = self.check_file_for_wildcard_binding(filepath) + if wildcards: + files_with_wildcards[str(filepath)] = wildcards + + # Assert no wildcards found + if files_with_wildcards: + error_msg = "Found wildcard bindings in example files:\n" + for filepath, occurrences in files_with_wildcards.items(): + error_msg += f"\n{filepath}:\n" + for line_num, line in occurrences: + error_msg += f" Line {line_num}: {line}\n" + + assert False, error_msg + + def test_examples_use_loopback_address(self): + """Test that examples use 127.0.0.1 for local binding""" + example_files = self.get_example_files() + + # Files that should contain listen addresses + files_with_networking = [ + "ping/ping.py", + "chat/chat.py", + "bootstrap/bootstrap.py", + "pubsub/pubsub.py", + "identify/identify.py", + ] + + for filename in files_with_networking: + filepath = None + for example_file in example_files: + if filename in str(example_file): + filepath = example_file + break + + if filepath is None: + continue + + with open(filepath, encoding="utf-8") as f: + content = f.read() + + # Check for proper loopback usage + has_loopback = "127.0.0.1" in content or "localhost" in content + has_multiaddr_loopback = "/ip4/127.0.0.1/" in content + + assert has_loopback or has_multiaddr_loopback, ( + f"{filepath} should use loopback address (127.0.0.1)" + ) + + def test_doc_examples_use_loopback(self): + """Test that documentation examples use secure addresses""" + doc_examples_dir = Path("examples/doc-examples") + if not doc_examples_dir.exists(): + return + + doc_example_files = list(doc_examples_dir.glob("*.py")) + + for filepath in doc_example_files: + wildcards = self.check_file_for_wildcard_binding(filepath) + assert not wildcards, ( + f"Documentation example {filepath} contains wildcard binding" + ) diff --git a/tests/utils/test_default_bind_address.py b/tests/utils/test_default_bind_address.py new file mode 100644 index 000000000..b8a501d2e --- /dev/null +++ b/tests/utils/test_default_bind_address.py @@ -0,0 +1,182 @@ +""" +Tests for default bind address changes from 0.0.0.0 to 127.0.0.1 +""" + +import pytest +from multiaddr import Multiaddr + +from libp2p import new_host +from libp2p.utils.address_validation import ( + get_available_interfaces, + get_optimal_binding_address, +) + + +class TestDefaultBindAddress: + """ + Test suite for verifying default bind addresses use + secure addresses (not 0.0.0.0) + """ + + def test_default_bind_address_is_not_wildcard(self): + """Test that default bind address is NOT 0.0.0.0 (wildcard)""" + port = 8000 + addr = get_optimal_binding_address(port) + + # Should NOT return wildcard address + assert "0.0.0.0" not in str(addr) + + # Should return a valid IP address (could be loopback or local network) + addr_str = str(addr) + assert "/ip4/" in addr_str + assert f"/tcp/{port}" in addr_str + + def test_available_interfaces_includes_loopback(self): + """Test that available interfaces always includes loopback address""" + port = 8000 + interfaces = get_available_interfaces(port) + + # Should have at least one interface + assert len(interfaces) > 0 + + # Should include loopback address + loopback_found = any("127.0.0.1" in str(addr) for addr in interfaces) + assert loopback_found, "Loopback address not found in available interfaces" + + # Should not have wildcard as the only option + if len(interfaces) == 1: + assert "0.0.0.0" not in str(interfaces[0]) + + def test_host_default_listen_address(self): + """Test that new hosts use secure default addresses""" + # Create a host with a specific port + port = 8000 + listen_addr = Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + host = new_host(listen_addrs=[listen_addr]) + + # Verify the host configuration + assert host is not None + # Note: We can't test actual binding without running the host, + # but we've verified the address format is correct + + def test_no_wildcard_in_fallback(self): + """Test that fallback addresses don't use wildcard binding""" + # When no interfaces are discovered, fallback should be loopback + port = 8000 + + # Even if we can't discover interfaces, we should get loopback + addr = get_optimal_binding_address(port) + # Should NOT be wildcard + assert "0.0.0.0" not in str(addr) + + # Should be a valid IP address + addr_str = str(addr) + assert "/ip4/" in addr_str + assert f"/tcp/{port}" in addr_str + + @pytest.mark.parametrize("protocol", ["tcp", "udp"]) + def test_different_protocols_use_secure_addresses(self, protocol): + """Test that different protocols still use secure addresses by default""" + port = 8000 + addr = get_optimal_binding_address(port, protocol=protocol) + + # Should NOT be wildcard + assert "0.0.0.0" not in str(addr) + assert protocol in str(addr) + + # Should be a valid IP address + addr_str = str(addr) + assert "/ip4/" in addr_str + assert f"/{protocol}/{port}" in addr_str + + def test_security_no_public_binding_by_default(self): + """Test that no public interface binding occurs by default""" + port = 8000 + interfaces = get_available_interfaces(port) + + # Check that we don't expose on all interfaces by default + wildcard_addrs = [addr for addr in interfaces if "0.0.0.0" in str(addr)] + assert len(wildcard_addrs) == 0, ( + "Found wildcard addresses in default interfaces" + ) + + # Verify optimal address selection doesn't choose wildcard + optimal = get_optimal_binding_address(port) + assert "0.0.0.0" not in str(optimal), "Optimal address should not be wildcard" + + # Should be a valid IP address (could be loopback or local network) + addr_str = str(optimal) + assert "/ip4/" in addr_str + assert f"/tcp/{port}" in addr_str + + def test_loopback_is_always_available(self): + """Test that loopback address is always available as an option""" + port = 8000 + interfaces = get_available_interfaces(port) + + # Loopback should always be available + loopback_addrs = [addr for addr in interfaces if "127.0.0.1" in str(addr)] + assert len(loopback_addrs) > 0, "Loopback address should always be available" + + # At least one loopback address should have the correct port + loopback_with_port = [ + addr for addr in loopback_addrs if f"/tcp/{port}" in str(addr) + ] + assert len(loopback_with_port) > 0, ( + f"Loopback address with port {port} should be available" + ) + + def test_optimal_address_selection_behavior(self): + """Test that optimal address selection works correctly""" + port = 8000 + interfaces = get_available_interfaces(port) + optimal = get_optimal_binding_address(port) + + # Should never return wildcard + assert "0.0.0.0" not in str(optimal) + + # Should return one of the available interfaces + optimal_str = str(optimal) + interface_strs = [str(addr) for addr in interfaces] + assert optimal_str in interface_strs, ( + f"Optimal address {optimal_str} should be in available interfaces" + ) + + # If non-loopback interfaces are available, should prefer them + non_loopback_interfaces = [ + addr for addr in interfaces if "127.0.0.1" not in str(addr) + ] + if non_loopback_interfaces: + # Should prefer non-loopback when available + assert "127.0.0.1" not in str(optimal), ( + "Should prefer non-loopback when available" + ) + else: + # Should use loopback when no other interfaces available + assert "127.0.0.1" in str(optimal), ( + "Should use loopback when no other interfaces available" + ) + + def test_address_validation_utilities_behavior(self): + """Test that address validation utilities behave as expected""" + port = 8000 + + # Test that we get multiple interface options + interfaces = get_available_interfaces(port) + assert len(interfaces) >= 2, ( + "Should have at least loopback + one network interface" + ) + + # Test that loopback is always included + has_loopback = any("127.0.0.1" in str(addr) for addr in interfaces) + assert has_loopback, "Loopback should always be available" + + # Test that no wildcards are included + has_wildcard = any("0.0.0.0" in str(addr) for addr in interfaces) + assert not has_wildcard, "Wildcard addresses should never be included" + + # Test optimal selection + optimal = get_optimal_binding_address(port) + assert optimal in interfaces, ( + "Optimal address should be from available interfaces" + )