autonat_client/
autonat_client.rs

1// Copyright 2021 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#![doc = include_str!("../../README.md")]
22
23use std::{error::Error, net::Ipv4Addr, time::Duration};
24
25use clap::Parser;
26use futures::StreamExt;
27use libp2p::{
28    autonat,
29    core::{multiaddr::Protocol, Multiaddr},
30    identify, identity, noise,
31    swarm::{NetworkBehaviour, SwarmEvent},
32    tcp, yamux, PeerId,
33};
34use tracing_subscriber::EnvFilter;
35
36#[derive(Debug, Parser)]
37#[command(name = "libp2p autonat")]
38struct Opt {
39    #[arg(long)]
40    listen_port: Option<u16>,
41
42    #[arg(long)]
43    server_address: Multiaddr,
44
45    #[arg(long)]
46    server_peer_id: PeerId,
47}
48
49#[tokio::main]
50async fn main() -> Result<(), Box<dyn Error>> {
51    let _ = tracing_subscriber::fmt()
52        .with_env_filter(EnvFilter::from_default_env())
53        .try_init();
54
55    let opt = Opt::parse();
56
57    let mut swarm = libp2p::SwarmBuilder::with_new_identity()
58        .with_tokio()
59        .with_tcp(
60            tcp::Config::default(),
61            noise::Config::new,
62            yamux::Config::default,
63        )?
64        .with_behaviour(|key| Behaviour::new(key.public()))?
65        .build();
66
67    swarm.listen_on(
68        Multiaddr::empty()
69            .with(Protocol::Ip4(Ipv4Addr::UNSPECIFIED))
70            .with(Protocol::Tcp(opt.listen_port.unwrap_or(0))),
71    )?;
72
73    swarm
74        .behaviour_mut()
75        .auto_nat
76        .add_server(opt.server_peer_id, Some(opt.server_address));
77
78    loop {
79        match swarm.select_next_some().await {
80            SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
81            SwarmEvent::Behaviour(event) => println!("{event:?}"),
82            e => println!("{e:?}"),
83        }
84    }
85}
86
87#[derive(NetworkBehaviour)]
88struct Behaviour {
89    identify: identify::Behaviour,
90    auto_nat: autonat::Behaviour,
91}
92
93impl Behaviour {
94    fn new(local_public_key: identity::PublicKey) -> Self {
95        Self {
96            identify: identify::Behaviour::new(identify::Config::new(
97                "/ipfs/0.1.0".into(),
98                local_public_key.clone(),
99            )),
100            auto_nat: autonat::Behaviour::new(
101                local_public_key.to_peer_id(),
102                autonat::Config {
103                    retry_interval: Duration::from_secs(10),
104                    refresh_interval: Duration::from_secs(30),
105                    boot_delay: Duration::from_secs(5),
106                    throttle_server_period: Duration::ZERO,
107                    only_global_ips: false,
108                    ..Default::default()
109                },
110            ),
111        }
112    }
113}