Skip to content

Commit 41facf0

Browse files
HX2012dariusc93
andauthored
feat: implement Configuration for Connecting to IPFS Private Network (pnet) (#398)
Co-authored-by: Darius Clark <dariusc93@users.noreply.github.com>
1 parent cb8fdcf commit 41facf0

File tree

4 files changed

+205
-1
lines changed

4 files changed

+205
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ zeroize.workspace = true
139139
futures-timer.workspace = true
140140
fs2.workspace = true
141141
hickory-resolver.workspace = true
142-
libp2p = { features = ["gossipsub", "autonat", "relay", "dcutr", "identify", "kad", "websocket", "tcp", "macros", "tokio", "noise", "tls", "ping", "yamux", "dns", "mdns", "ed25519", "secp256k1", "ecdsa", "rsa", "serde", "request-response", "json", "cbor", "rendezvous", "upnp", "quic", ], workspace = true }
142+
libp2p = { features = ["gossipsub", "autonat", "relay", "dcutr", "identify", "kad", "websocket", "tcp", "macros", "tokio", "noise", "tls", "ping", "yamux", "dns", "mdns", "ed25519", "secp256k1", "ecdsa", "rsa", "serde", "request-response", "json", "cbor", "rendezvous", "upnp", "quic", "pnet" ], workspace = true }
143143
libp2p-webrtc = { workspace = true, features = ["tokio", ], optional = true }
144144
rcgen.workspace = true
145145
rlimit.workspace = true

examples/ipfs-pnet.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
use clap::Parser;
2+
use libp2p::pnet::PreSharedKey;
3+
use rand::Rng;
4+
use rust_ipfs::Ipfs;
5+
use rust_ipfs::Keypair;
6+
use rust_ipfs::UninitializedIpfs;
7+
use std::str::FromStr;
8+
9+
#[derive(Debug, Parser)]
10+
#[clap(name = "ipfs-pnet")]
11+
struct Opt {
12+
#[clap(required = false)]
13+
psk: Option<String>,
14+
}
15+
fn generate_psk() -> PreSharedKey {
16+
let mut key_bytes = [0u8; 32];
17+
rand::thread_rng().fill(&mut key_bytes);
18+
PreSharedKey::new(key_bytes)
19+
}
20+
21+
/// you can provide a PSK as an argument
22+
/// example: cargo run --example 8ab6e6aeb73353791b88c3c73e3d9a5111273e6d89edcbfb8be783f1e595617b
23+
///
24+
/// or create a random one without providing any argument
25+
/// example: cargo run --example ipfs-pnet
26+
#[tokio::main]
27+
async fn main() -> anyhow::Result<()> {
28+
tracing_subscriber::fmt::init();
29+
30+
let keypair = Keypair::generate_ed25519();
31+
let local_peer_id = keypair.public().to_peer_id();
32+
33+
let opt = Opt::parse();
34+
let psk = {
35+
match opt.psk {
36+
Some(psk) => {
37+
let formatted_psk = format!("/key/swarm/psk/1.0.0/\n/base16/\n{}", psk);
38+
match PreSharedKey::from_str(&formatted_psk) {
39+
Ok(psk) => psk,
40+
Err(_) => {
41+
println!("Invalid PSK , generating a random PSK");
42+
generate_psk()
43+
}
44+
}
45+
}
46+
None => generate_psk(),
47+
}
48+
};
49+
println!("PSK: {:?}", psk);
50+
51+
// Initialize the repo and start a daemon
52+
let ipfs: Ipfs = UninitializedIpfs::new()
53+
.with_default()
54+
.set_keypair(&keypair)
55+
.add_listening_addr("/ip4/0.0.0.0/tcp/0".parse()?)
56+
.with_mdns()
57+
.with_pnet(psk)
58+
.with_custom_behaviour(ext_behaviour::Behaviour::new(local_peer_id))
59+
.start()
60+
.await?;
61+
62+
ipfs.default_bootstrap().await?;
63+
ipfs.bootstrap().await?;
64+
65+
// Used to wait until the process is terminated instead of creating a loop
66+
tokio::signal::ctrl_c().await?;
67+
ipfs.exit_daemon().await;
68+
Ok(())
69+
}
70+
71+
mod ext_behaviour {
72+
use libp2p::swarm::derive_prelude::PortUse;
73+
use libp2p::{
74+
core::Endpoint,
75+
swarm::{
76+
ConnectionDenied, ConnectionId, FromSwarm, NewListenAddr, THandler, THandlerInEvent,
77+
THandlerOutEvent, ToSwarm,
78+
},
79+
Multiaddr, PeerId,
80+
};
81+
use rust_ipfs::NetworkBehaviour;
82+
use std::convert::Infallible;
83+
use std::{
84+
collections::HashSet,
85+
task::{Context, Poll},
86+
};
87+
88+
#[derive(Default, Debug)]
89+
pub struct Behaviour {
90+
addrs: HashSet<Multiaddr>,
91+
}
92+
93+
impl Behaviour {
94+
pub fn new(local_peer_id: PeerId) -> Self {
95+
println!("PeerID: {}", local_peer_id);
96+
Self {
97+
addrs: Default::default(),
98+
}
99+
}
100+
}
101+
102+
impl NetworkBehaviour for Behaviour {
103+
type ConnectionHandler = rust_ipfs::libp2p::swarm::dummy::ConnectionHandler;
104+
type ToSwarm = Infallible;
105+
106+
fn handle_pending_inbound_connection(
107+
&mut self,
108+
_: ConnectionId,
109+
_: &Multiaddr,
110+
_: &Multiaddr,
111+
) -> Result<(), ConnectionDenied> {
112+
Ok(())
113+
}
114+
115+
fn handle_pending_outbound_connection(
116+
&mut self,
117+
_: ConnectionId,
118+
_: Option<PeerId>,
119+
_: &[Multiaddr],
120+
_: Endpoint,
121+
) -> Result<Vec<Multiaddr>, ConnectionDenied> {
122+
Ok(vec![])
123+
}
124+
125+
fn handle_established_inbound_connection(
126+
&mut self,
127+
_: ConnectionId,
128+
_: PeerId,
129+
_: &Multiaddr,
130+
_: &Multiaddr,
131+
) -> Result<THandler<Self>, ConnectionDenied> {
132+
Ok(rust_ipfs::libp2p::swarm::dummy::ConnectionHandler)
133+
}
134+
135+
fn handle_established_outbound_connection(
136+
&mut self,
137+
_: ConnectionId,
138+
_: PeerId,
139+
_: &Multiaddr,
140+
_: Endpoint,
141+
_: PortUse,
142+
) -> Result<THandler<Self>, ConnectionDenied> {
143+
Ok(rust_ipfs::libp2p::swarm::dummy::ConnectionHandler)
144+
}
145+
146+
fn on_connection_handler_event(
147+
&mut self,
148+
peerid: PeerId,
149+
_: ConnectionId,
150+
_: THandlerOutEvent<Self>,
151+
) {
152+
println!("Connection established with {peerid}");
153+
}
154+
155+
fn on_swarm_event(&mut self, event: FromSwarm) {
156+
match event {
157+
FromSwarm::NewListenAddr(NewListenAddr { addr, .. }) => {
158+
if self.addrs.insert(addr.clone()) {
159+
println!("Listening on {addr}");
160+
}
161+
}
162+
FromSwarm::ExternalAddrConfirmed(ev) => {
163+
if self.addrs.insert(ev.addr.clone()) {
164+
println!("Listening on {}", ev.addr);
165+
}
166+
}
167+
_ => {}
168+
}
169+
}
170+
171+
fn poll(&mut self, _: &mut Context) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
172+
Poll::Pending
173+
}
174+
}
175+
}

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ pub use libp2p::{
112112
Multiaddr, PeerId,
113113
};
114114

115+
#[cfg(not(target_arch = "wasm32"))]
116+
use libp2p::pnet::PreSharedKey;
115117
use libp2p::swarm::ConnectionId;
116118
use libp2p::{
117119
core::{muxing::StreamMuxerBox, transport::Boxed},
@@ -876,6 +878,14 @@ impl<C: NetworkBehaviour<ToSwarm = Infallible> + Send> UninitializedIpfs<C> {
876878
self
877879
}
878880

881+
/// Set pnet
882+
#[cfg(not(target_arch = "wasm32"))]
883+
pub fn with_pnet(mut self, psk: PreSharedKey) -> Self {
884+
self.options.transport_configuration.enable_pnet = true;
885+
self.options.transport_configuration.pnet_psk = Some(psk);
886+
self
887+
}
888+
879889
/// Set file desc limit
880890
pub fn fd_limit(mut self, limit: FDLimit) -> Self {
881891
self.fdlimit = Some(limit);

src/p2p/transport.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use libp2p::core::transport::upgrade::Version;
1515
use libp2p::core::transport::{Boxed, MemoryTransport, OrTransport};
1616
#[cfg(not(target_arch = "wasm32"))]
1717
use libp2p::dns::{ResolverConfig, ResolverOpts};
18+
#[cfg(not(target_arch = "wasm32"))]
19+
use libp2p::pnet::{PnetConfig, PreSharedKey};
1820
use libp2p::relay::client::Transport as ClientTransport;
1921
use libp2p::yamux::Config as YamuxConfig;
2022
use libp2p::{identity, noise};
@@ -42,6 +44,10 @@ pub struct TransportConfig {
4244
pub support_quic_draft_29: bool,
4345
pub enable_webrtc: bool,
4446
pub webrtc_pem: Option<String>,
47+
#[cfg(not(target_arch = "wasm32"))]
48+
pub enable_pnet: bool,
49+
#[cfg(not(target_arch = "wasm32"))]
50+
pub pnet_psk: Option<PreSharedKey>,
4551
}
4652

4753
impl Default for TransportConfig {
@@ -66,6 +72,10 @@ impl Default for TransportConfig {
6672
quic_keep_alive: Some(Duration::from_millis(100)),
6773
dns_resolver: None,
6874
version: UpgradeVersion::default(),
75+
#[cfg(not(target_arch = "wasm32"))]
76+
enable_pnet: false,
77+
#[cfg(not(target_arch = "wasm32"))]
78+
pnet_psk: None,
6979
}
7080
}
7181
}
@@ -138,6 +148,8 @@ pub(crate) fn build_transport(
138148
webrtc_pem,
139149
websocket_pem,
140150
enable_webtransport: _,
151+
enable_pnet,
152+
pnet_psk,
141153
}: TransportConfig,
142154
) -> io::Result<TTransport> {
143155
use crate::p2p::transport::dual_transport::SelectSecurityUpgrade;
@@ -227,6 +239,13 @@ pub(crate) fn build_transport(
227239
None => Either::Right(transport),
228240
};
229241

242+
let transport = match (enable_pnet, pnet_psk) {
243+
(true, Some(psk)) => Either::Left(
244+
transport.and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)),
245+
),
246+
_ => Either::Right(transport),
247+
};
248+
230249
let transport = transport
231250
.upgrade(version.into())
232251
.authenticate(config)

0 commit comments

Comments
 (0)