|
| 1 | +// Copyright 2022 Protocol Labs. |
| 2 | +// |
| 3 | +// Permission is hereby granted, free of charge, to any person obtaining a |
| 4 | +// copy of this software and associated documentation files (the "Software"), |
| 5 | +// to deal in the Software without restriction, including without limitation |
| 6 | +// the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 7 | +// and/or sell copies of the Software, and to permit persons to whom the |
| 8 | +// Software is furnished to do so, subject to the following conditions: |
| 9 | +// |
| 10 | +// The above copyright notice and this permission notice shall be included in |
| 11 | +// all copies or substantial portions of the Software. |
| 12 | +// |
| 13 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 14 | +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 15 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 16 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 17 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 18 | +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 19 | +// DEALINGS IN THE SOFTWARE. |
| 20 | + |
| 21 | +//! # Hole Punching Tutorial |
| 22 | +//! |
| 23 | +//! This tutorial shows hands-on how to overcome firewalls and NATs with libp2p's hole punching |
| 24 | +//! mechanism. Before we get started, please read the [blog |
| 25 | +//! post](https://github.com/ipfs/ipfs-blog/pull/375) to familiarize yourself with libp2p's hole |
| 26 | +//! punching mechanism on a conceptual level. |
| 27 | +//! |
| 28 | +//! We will be using the [Circuit Relay v2](crate::relay::v2) and the [Direct Connection |
| 29 | +//! Upgrade through Relay (DCUtR)](crate::dcutr) protocol. |
| 30 | +//! |
| 31 | +//! You will need 3 machines for this tutorial: |
| 32 | +//! |
| 33 | +//! - A relay server |
| 34 | +//! - Any public server will do, e.g. a cloud provider VM. |
| 35 | +//! - A listening client. |
| 36 | +//! - Any computer connected to the internet, but not reachable from outside its own network, |
| 37 | +//! works. |
| 38 | +//! - This can e.g. be your friends laptop behind their router (firewall + NAT). |
| 39 | +//! - This can e.g. be some cloud provider VM, shielded from incoming connections e.g. via |
| 40 | +//! Linux's UFW on the same machine. |
| 41 | +//! - Don't use a machine that is in the same network as the dialing client. (This would require |
| 42 | +//! NAT hairpinning.) |
| 43 | +//! - A dialing client. |
| 44 | +//! - Like the above, any computer connected to the internet, but not reachable from the outside. |
| 45 | +//! - Your local machine will likely fulfill these requirements. |
| 46 | +//! |
| 47 | +//! ## Setting up the relay server |
| 48 | +//! |
| 49 | +//! Hole punching requires a public relay node for the two private nodes to coordinate their hole |
| 50 | +//! punch via. For that we need a public server somewhere in the Internet. In case you don't have |
| 51 | +//! one already, any cloud provider VM will do. |
| 52 | +//! |
| 53 | +//! Either on the server directly, or on your local machine, compile the example relay server: |
| 54 | +//! |
| 55 | +//! ``` bash |
| 56 | +//! ## Inside the rust-libp2p repository. |
| 57 | +//! cargo build --example relay_v2 -p libp2p-relay |
| 58 | +//! ``` |
| 59 | +//! |
| 60 | +//! You can find the binary at `target/debug/examples/relay_v2`. In case you built it locally, copy |
| 61 | +//! it to your server. |
| 62 | +//! |
| 63 | +//! On your server, start the relay server binary: |
| 64 | +//! |
| 65 | +//! ``` bash |
| 66 | +//! ./relay_v2 --port 4001 --secret-key-seed 0 |
| 67 | +//! ``` |
| 68 | +//! |
| 69 | +//! Now let's make sure that the server is public, in other words let's make sure one can reach it |
| 70 | +//! through the Internet. From the dialing client: |
| 71 | +//! |
| 72 | +//! 1. Test that you can connect on Layer 3 (IP). |
| 73 | +//! |
| 74 | +//! ``` bash |
| 75 | +//! ping $RELAY_SERVER_IP |
| 76 | +//! ``` |
| 77 | +//! |
| 78 | +//! 2. Test that you can connect on Layer 4 (TCP). |
| 79 | +//! |
| 80 | +//! ``` bash |
| 81 | +//! telnet $RELAY_SERVER_IP 4001 |
| 82 | +//! ``` |
| 83 | +//! |
| 84 | +//! 3. Test that you can connect via libp2p using [`libp2p-lookup`](https://github.com/mxinden/libp2p-lookup). |
| 85 | +//! |
| 86 | +//! ``` bash |
| 87 | +//! ## For IPv4 |
| 88 | +//! libp2p-lookup direct --address /ip4/$RELAY_SERVER_IP |
| 89 | +//! ## For IPv6 |
| 90 | +//! libp2p-lookup direct --address /ip6/$RELAY_SERVER_IP |
| 91 | +//! ``` |
| 92 | +//! |
| 93 | +//! ## Setting up the listening client |
| 94 | +//! |
| 95 | +//! Either on the listening client machine directly, or on your local machine, compile the example |
| 96 | +//! DCUtR client: |
| 97 | +//! |
| 98 | +//! ``` bash |
| 99 | +//! ## Inside the rust-libp2p repository. |
| 100 | +//! cargo build --example client -p libp2p-dcutr |
| 101 | +//! ``` |
| 102 | +//! |
| 103 | +//! You can find the binary at `target/debug/examples/client`. In case you built it locally, copy |
| 104 | +//! it to your listening client machine. |
| 105 | +//! |
| 106 | +//! On the listening client machine |
| 107 | +//! |
| 108 | +//! ``` bash |
| 109 | +//! RUST_LOG=info ./client --secret-key-seed 1 --mode listen --relay-address /dns4/$RELAY_SERVER_IP/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN |
| 110 | +//! ``` |
| 111 | +//! |
| 112 | +//! Now let's make sure that the listening client is not public, in other words let's make sure one |
| 113 | +//! can not reach it directly through the Internet. From the dialing client test that you can not |
| 114 | +//! connect on Layer 4 (TCP): |
| 115 | +//! |
| 116 | +//! ``` bash |
| 117 | +//! telnet $RELAY_SERVER_IP 4001 |
| 118 | +//! ``` |
| 119 | +//! |
| 120 | +//! ## Connecting to the listening client from the dialing client |
| 121 | +//! |
| 122 | +//! ``` bash |
| 123 | +//! RUST_LOG=info ./client --secret-key-seed 2 --mode dial --relay-address /dns4/$RELAY_SERVER_IP/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN --remote-peer-id 12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X |
| 124 | +//! ``` |
| 125 | +//! |
| 126 | +//! You should see the following logs appear: |
| 127 | +//! |
| 128 | +//! 1. The dialing client establishing a relayed connection to the listening client via the relay |
| 129 | +//! server. Note the [`/p2p-circuit` protocol](crate::multiaddr::Protocol::P2pCircuit) in the |
| 130 | +//! [`Multiaddr`](crate::Multiaddr). |
| 131 | +//! |
| 132 | +//! ``` ignore |
| 133 | +//! [2022-01-30T12:54:10Z INFO client] Established connection to PeerId("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") via Dialer { address: "/ip4/$RELAY_PEER_ID/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN/p2p-circuit/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X", role_override: Dialer } |
| 134 | +//! ``` |
| 135 | +//! |
| 136 | +//! 2. The listening client initiating a direct connection upgrade for the new relayed connection. |
| 137 | +//! Reported by [`dcutr`](crate::dcutr) through |
| 138 | +//! [`Event::RemoteInitiatedDirectConnectionUpgrade`](crate::dcutr::behaviour::Event::RemoteInitiatedDirectConnectionUpgrade). |
| 139 | +//! |
| 140 | +//! ``` ignore |
| 141 | +//! [2022-01-30T12:54:11Z INFO client] RemoteInitiatedDirectConnectionUpgrade { remote_peer_id: PeerId("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X"), remote_relayed_addr: "/ip4/$RELAY_PEER_ID/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN/p2p-circuit/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" } |
| 142 | +//! ``` |
| 143 | +//! |
| 144 | +//! 3. The direct connection upgrade, also known as hole punch, succeeding. Reported by |
| 145 | +//! [`dcutr`](crate::dcutr) through |
| 146 | +//! [`Event::RemoteInitiatedDirectConnectionUpgrade`](crate::dcutr::behaviour::Event::DirectConnectionUpgradeSucceeded). |
| 147 | +//! |
| 148 | +//! ``` ignore |
| 149 | +//! [2022-01-30T12:54:11Z INFO client] DirectConnectionUpgradeSucceeded { remote_peer_id: PeerId("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") } |
| 150 | +//! ``` |
0 commit comments