libp2p/tutorials/
hole_punching.rs

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://blog.ipfs.io/2022-01-20-libp2p-hole-punching/) to familiarize yourself with libp2p's hole
26//! punching mechanism on a conceptual level.
27//!
28//! We will be using the [Circuit Relay](crate::relay) 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 --bin relay-server-example
58//! ```
59//!
60//! You can find the binary at `target/debug/relay-server-example`. In case you built it locally,
61//! copy it to your server.
62//!
63//! On your server, start the relay server binary:
64//!
65//! ``` bash
66//! ./relay-server-example --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. First, either manually replace `$RELAY_SERVER_IP` in the following
71//! commands or `export RELAY_SERVER_IP=ipaddr` with the appropriate relay server `ipaddr` in
72//! the dialing client and listening client.
73//!
74//! Now, from the dialing client:
75//!
76//! 1. Test that you can connect on Layer 3 (IP).
77//!
78//!    ``` bash
79//!    ping $RELAY_SERVER_IP
80//!    ```
81//!
82//! 2. Test that you can connect on Layer 4 (TCP).
83//!
84//!    ``` bash
85//!    telnet $RELAY_SERVER_IP 4001
86//!    ```
87//!
88//! 3. Test that you can connect via libp2p using [`libp2p-lookup`](https://github.com/mxinden/libp2p-lookup).
89//!
90//!    ``` bash
91//!    ## For IPv4
92//!    libp2p-lookup direct --address /ip4/$RELAY_SERVER_IP/tcp/4001
93//!    ## For IPv6
94//!    libp2p-lookup direct --address /ip6/$RELAY_SERVER_IP/tcp/4001
95//!    ```
96//!
97//! The libp2p-lookup output should look something like:
98//!
99//!    ``` bash
100//!    $ libp2p-lookup direct --address /ip4/111.11.111.111/tcp/4001
101//!    Lookup for peer with id PeerId("12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN")
102//! succeeded.
103//!
104//!    Protocol version: "/TODO/0.0.1"
105//!    Agent version: "rust-libp2p/0.36.0"
106//!    Observed address: "/ip4/22.222.222.222/tcp/39212"
107//!    Listen addresses:
108//!            - "/ip4/127.0.0.1/tcp/4001"
109//!            - "/ip4/111.11.111.111/tcp/4001"
110//!            - "/ip4/10.48.0.5/tcp/4001"
111//!            - "/ip4/10.124.0.2/tcp/4001"
112//!    Protocols:
113//!            - "/libp2p/circuit/relay/0.2.0/hop"
114//!            - "/ipfs/ping/1.0.0"
115//!            - "/ipfs/id/1.0.0"
116//!            - "/ipfs/id/push/1.0.0"
117//!    ```
118//!
119//! ## Setting up the listening client
120//!
121//! Either on the listening client machine directly, or on your local machine, compile the example
122//! DCUtR client:
123//!
124//! ``` bash
125//! ## Inside the rust-libp2p repository.
126//! cargo build --bin dcutr-example
127//! ```
128//!
129//! You can find the binary at `target/debug/dcutr-example`. In case you built it locally, copy
130//! it to your listening client machine.
131//!
132//! On the listening client machine:
133//!
134//! ``` bash
135//! RUST_LOG=info ./dcutr-example --secret-key-seed 1 --mode listen --relay-address /ip4/$RELAY_SERVER_IP/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN
136//!
137//! [2022-05-11T10:38:52Z INFO  client] Local peer id: PeerId("XXX")
138//! [2022-05-11T10:38:52Z INFO  client] Listening on "/ip4/127.0.0.1/tcp/44703"
139//! [2022-05-11T10:38:52Z INFO  client] Listening on "/ip4/XXX/tcp/44703"
140//! [2022-05-11T10:38:54Z INFO  client] Relay told us our public address: "/ip4/XXX/tcp/53160"
141//! [2022-05-11T10:38:54Z INFO  client] Told relay its public address.
142//! [2022-05-11T10:38:54Z INFO  client] Relay accepted our reservation request.
143//! [2022-05-11T10:38:54Z INFO  client] Listening on "/ip4/$RELAY_SERVER_IP/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN/p2p-circuit/p2p/XXX"
144//! ```
145//!
146//! Now let's make sure that the listening client is not public, in other words let's make sure one
147//! can not reach it directly through the Internet. From the dialing client test that you can not
148//! connect on Layer 4 (TCP):
149//!
150//! ``` bash
151//! telnet $LISTENING_CLIENT_IP_OBSERVED_BY_RELAY 53160
152//! ```
153//!
154//! ## Connecting to the listening client from the dialing client
155//!
156//! ``` bash
157//! RUST_LOG=info ./dcutr-example --secret-key-seed 2 --mode dial --relay-address /ip4/$RELAY_SERVER_IP/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN --remote-peer-id 12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X
158//! ```
159//!
160//! You should see the following logs appear:
161//!
162//! 1. The dialing client establishing a relayed connection to the listening client via the relay
163//!    server. Note the [`/p2p-circuit` protocol](crate::multiaddr::Protocol::P2pCircuit) in the
164//!    [`Multiaddr`](crate::Multiaddr).
165//!
166//!    ``` ignore
167//!    [2022-01-30T12:54:10Z INFO  client] Established connection to
168//!    PeerId("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X") via Dialer { address:
169//!    "/ip4/$RELAY_PEER_ID/tcp/4001/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN/
170//!    p2p-circuit/p2p/12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X",
171//!    role_override: Dialer  }
172//!    ```
173//!
174//! 2. The direct connection upgrade, also known as hole punch, succeeding. Reported by
175//!    [`dcutr`](crate::dcutr) through [`Event`](crate::dcutr::Event) containing [`Result::Ok`] with
176//!    the [`ConnectionId`](libp2p_swarm::ConnectionId) of the new direct connection.
177//!
178//!    ``` ignore
179//!    [2022-01-30T12:54:11Z INFO  client] Event { remote_peer_id:
180//!    PeerId("12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X"), result: Ok(2) }
181//!    ```