diff --git a/docker-compose.yml b/docker-compose.yml index 5573cce5..6d94aa8e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: ports: - target: 9091 published: 9091 - protocol: udp + protocol: tcp mode: host deploy: replicas: 1 @@ -35,7 +35,7 @@ services: ports: - target: 9092 published: 9092 - protocol: udp + protocol: tcp mode: host deploy: replicas: 1 @@ -57,7 +57,7 @@ services: ports: - target: 9093 published: 9093 - protocol: udp + protocol: tcp mode: host deploy: replicas: 1 @@ -80,7 +80,7 @@ services: ports: - target: 9094 published: 9094 - protocol: udp + protocol: tcp mode: host deploy: replicas: 1 diff --git a/packages/ciphernode/Cargo.lock b/packages/ciphernode/Cargo.lock index 0684a617..9271771d 100644 --- a/packages/ciphernode/Cargo.lock +++ b/packages/ciphernode/Cargo.lock @@ -1606,6 +1606,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher 0.4.4", + "poly1305", + "zeroize", +] + [[package]] name = "cipher" version = "0.1.0" @@ -1628,6 +1652,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -3528,11 +3553,13 @@ dependencies = [ "libp2p-kad", "libp2p-mdns", "libp2p-metrics", + "libp2p-noise", "libp2p-ping", "libp2p-quic", "libp2p-swarm", "libp2p-tcp", "libp2p-upnp", + "libp2p-yamux", "multiaddr", "pin-project", "rw-stream-sink", @@ -3751,6 +3778,32 @@ dependencies = [ "web-time", ] +[[package]] +name = "libp2p-noise" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b137cb1ae86ee39f8e5d6245a296518912014eaa87427d24e6ff58cfc1b28c" +dependencies = [ + "asynchronous-codec", + "bytes", + "curve25519-dalek", + "futures", + "libp2p-core", + "libp2p-identity", + "multiaddr", + "multihash", + "once_cell", + "quick-protobuf", + "rand", + "sha2", + "snow", + "static_assertions", + "thiserror", + "tracing", + "x25519-dalek", + "zeroize", +] + [[package]] name = "libp2p-ping" version = "0.45.0" @@ -3884,6 +3937,21 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-yamux" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788b61c80789dba9760d8c669a5bedb642c8267555c803fabd8396e4ca5c5882" +dependencies = [ + "either", + "futures", + "libp2p-core", + "thiserror", + "tracing", + "yamux 0.12.1", + "yamux 0.13.3", +] + [[package]] name = "libredox" version = "0.1.3" @@ -4216,6 +4284,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -4725,6 +4799,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" version = "0.6.2" @@ -5776,6 +5861,23 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "snow" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" +dependencies = [ + "aes-gcm", + "blake2", + "chacha20poly1305", + "curve25519-dalek", + "rand_core", + "ring 0.17.8", + "rustc_version 0.4.0", + "sha2", + "subtle", +] + [[package]] name = "socket2" version = "0.4.10" @@ -6981,6 +7083,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + [[package]] name = "x509-parser" version = "0.16.0" @@ -7013,6 +7127,37 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "yamux" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot 0.12.3", + "pin-project", + "rand", + "static_assertions", +] + +[[package]] +name = "yamux" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot 0.12.3", + "pin-project", + "rand", + "static_assertions", + "web-time", +] + [[package]] name = "yasna" version = "0.5.2" diff --git a/packages/ciphernode/net/Cargo.toml b/packages/ciphernode/net/Cargo.toml index 91ecb570..fe070ad7 100644 --- a/packages/ciphernode/net/Cargo.toml +++ b/packages/ciphernode/net/Cargo.toml @@ -23,6 +23,9 @@ libp2p = { workspace = true, features = [ "ping", "quic", "tokio", + "tcp", + "noise", + "yamux" ] } tokio = { workspace = true, features = ["full"] } tracing = { workspace = true } diff --git a/packages/ciphernode/net/src/network_peer.rs b/packages/ciphernode/net/src/network_peer.rs index 17151076..a5be7edb 100644 --- a/packages/ciphernode/net/src/network_peer.rs +++ b/packages/ciphernode/net/src/network_peer.rs @@ -5,10 +5,10 @@ use libp2p::{ gossipsub, identify::{self, Behaviour as IdentifyBehaviour}, identity::Keypair, - kad::{store::MemoryStore, Behaviour as KademliaBehaviour}, - mdns, + kad::{self, store::MemoryStore, Behaviour as KademliaBehaviour}, + mdns, noise, swarm::{behaviour::toggle::Toggle, NetworkBehaviour, SwarmEvent}, - Multiaddr, Swarm, + tcp, yamux, Multiaddr, StreamProtocol, Swarm, }; use std::hash::{Hash, Hasher}; use std::{hash::DefaultHasher, io::Error, time::Duration}; @@ -51,7 +51,11 @@ impl NetworkPeer { let swarm = libp2p::SwarmBuilder::with_existing_identity(id.clone()) .with_tokio() - .with_quic() + .with_tcp( + tcp::Config::default(), + noise::Config::new, + yamux::Config::default, + )? .with_behaviour(|key| create_mdns_kad_behaviour(enable_mdns, key))? .with_swarm_config(|c| c.with_idle_connection_timeout(Duration::from_secs(60))) .build(); @@ -81,8 +85,8 @@ impl NetworkPeer { pub async fn start(&mut self) -> Result<()> { let addr = match self.udp_port { - Some(port) => format!("/ip4/0.0.0.0/udp/{}/quic-v1", port), - None => "/ip4/0.0.0.0/udp/0/quic-v1".to_string(), + Some(port) => format!("/ip4/0.0.0.0/tcp/{}", port), + None => "/ip4/0.0.0.0/tcp/0".to_string(), }; info!("Requesting node.listen_on('{}')", addr); @@ -90,12 +94,15 @@ impl NetworkPeer { .behaviour_mut() .gossipsub .subscribe(&self.topic)?; - self.swarm.listen_on(addr.parse()?)?; + + if let Err(e) = self.swarm.listen_on(addr.parse()?) { + warn!("Failed to listen on {addr}: {e}"); + } info!("Peers to dial: {:?}", self.peers); for addr in self.peers.clone() { let multiaddr: Multiaddr = addr.parse()?; - self.swarm.dial(multiaddr)?; + self.swarm.dial(multiaddr)? } loop { @@ -109,7 +116,7 @@ impl NetworkPeer { } event = self.swarm.select_next_some() => { - process_swarm_event(&mut self.swarm, &mut self.to_bus_tx, event).await? + process_swarm_event(self, event).await? } } } @@ -122,9 +129,10 @@ fn create_mdns_kad_behaviour( ) -> std::result::Result> { let connection_limits = connection_limits::Behaviour::new(ConnectionLimits::default()); let identify_config = IdentifyBehaviour::new( - identify::Config::new("/kad/0.1.0".into(), key.public()) + identify::Config::new("/kad/1.0.0".into(), key.public()) .with_interval(Duration::from_secs(60)), ); + let kad_config = kad::Config::new(StreamProtocol::new("/kad/1.0.0")); let message_id_fn = |message: &gossipsub::Message| { let mut s = DefaultHasher::new(); @@ -133,6 +141,9 @@ fn create_mdns_kad_behaviour( }; let gossipsub_config = gossipsub::ConfigBuilder::default() + .mesh_n(3) + .mesh_n_low(2) + .mesh_outbound_min(1) .heartbeat_interval(Duration::from_secs(10)) .validation_mode(gossipsub::ValidationMode::Strict) .message_id_fn(message_id_fn) @@ -155,9 +166,10 @@ fn create_mdns_kad_behaviour( Ok(NodeBehaviour { gossipsub, - kademlia: KademliaBehaviour::new( + kademlia: KademliaBehaviour::with_config( key.public().to_peer_id(), MemoryStore::new(key.public().to_peer_id()), + kad_config, ), mdns, connection_limits, @@ -166,38 +178,76 @@ fn create_mdns_kad_behaviour( } async fn process_swarm_event( - swarm: &mut Swarm, - to_bus_tx: &mut Sender>, + network_peer: &mut NetworkPeer, event: SwarmEvent, ) -> Result<()> { match event { - SwarmEvent::ConnectionEstablished { peer_id, .. } => { + SwarmEvent::ConnectionEstablished { + peer_id, endpoint, .. + } => { info!("Connected to {peer_id}"); + + let remote_addr = endpoint.get_remote_address().clone(); + network_peer + .swarm + .behaviour_mut() + .kademlia + .add_address(&peer_id, remote_addr); + info!("Added address to kademlia"); } SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => { warn!("Failed to dial {peer_id:?}: {error}"); + + if let Some(peer_id) = peer_id { + let addr = network_peer + .peers + .iter() + .find(|addr| addr.contains(&peer_id.to_string())); + if let Some(addr) = addr { + let multiaddr: Multiaddr = match addr.parse() { + Ok(maddr) => maddr, + Err(e) => { + warn!("Invalid address {addr}: {e}"); + return Ok(()); + } + }; + if let Err(e) = network_peer.swarm.dial(multiaddr.clone()) { + warn!("Failed to redial peer {peer_id}: {e}"); + } else { + info!("Redialing peer {peer_id}..."); + } + } + } } SwarmEvent::IncomingConnectionError { error, .. } => { warn!("{:#}", anyhow::Error::from(error)) } - SwarmEvent::Behaviour(NodeBehaviourEvent::Kademlia(e)) => { - debug!("Kademlia event: {:?}", e); - } + SwarmEvent::Behaviour(NodeBehaviourEvent::Kademlia(e)) => match e { + kad::Event::InboundRequest { request } => { + debug!("Inbound Kademlia request: {:?}", request); + } + _ => debug!("Other Kademlia event: {:?}", e), + }, SwarmEvent::Behaviour(NodeBehaviourEvent::Mdns(mdns::Event::Discovered(list))) => { for (peer_id, _multiaddr) in list { trace!("mDNS discovered a new peer: {peer_id}"); - swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id); + network_peer + .swarm + .behaviour_mut() + .gossipsub + .add_explicit_peer(&peer_id); } } SwarmEvent::Behaviour(NodeBehaviourEvent::Mdns(mdns::Event::Expired(list))) => { for (peer_id, _multiaddr) in list { trace!("mDNS discover peer has expired: {peer_id}"); - swarm + network_peer + .swarm .behaviour_mut() .gossipsub .remove_explicit_peer(&peer_id); @@ -211,7 +261,7 @@ async fn process_swarm_event( })) => { trace!("Got message with id: {id} from peer: {peer_id}",); trace!("{:?}", message); - to_bus_tx.send(message.data).await?; + network_peer.to_bus_tx.send(message.data).await?; } SwarmEvent::NewListenAddr { address, .. } => { warn!("Local node is listening on {address}");