diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2583bfc..4e813a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,9 +35,12 @@ cargo test ``` The pinned toolchain in [rust-toolchain.toml](rust-toolchain.toml) is -used for deterministic builds. On Debian/Ubuntu, BLE-capable builds -need `bluez`, `libdbus-1-dev`, and `pkg-config` installed; the default -build picks up BLE if those are present and skips it cleanly if not. +used for deterministic builds. On Linux, a source build requires +`libclang` (`sudo apt install libclang-dev` on Debian/Ubuntu): the LAN +gateway's nftables bindings are generated by `bindgen` at build time +and fail without it. BLE-capable builds additionally need `bluez`, +`libdbus-1-dev`, and `pkg-config` installed; the default build picks +up BLE if those are present and skips it cleanly if not. For multi-node integration runs, Docker is required. The harness under [testing/](testing/) starts containerized topologies and diff --git a/README.md b/README.md index 796e735..d37dcdb 100644 --- a/README.md +++ b/README.md @@ -122,8 +122,16 @@ supported; transport availability varies by platform. | Tor | ✅ | ✅ | ✅ | ✅ | | BLE | ✅ | ❌ | ❌ | ❌ | -On Linux, BLE requires BlueZ and libdbus -(`sudo apt install bluez libdbus-1-dev` on Debian / Ubuntu) and is +On Linux, a source build requires `libclang` — the LAN gateway's +nftables bindings are generated by `bindgen` at build time, which +needs `libclang.so` on the build host. Install it before building +(`sudo apt install libclang-dev` on Debian / Ubuntu); without it the +build fails inside the `rustables` crate with an "Unable to find +libclang" error. This is a build-time prerequisite only — it is not a +runtime dependency, and the pre-built `.deb` artifacts do not need it. + +BLE is optional and, on Linux, requires BlueZ and libdbus +(`sudo apt install bluez libdbus-1-dev` on Debian / Ubuntu). It is gated on a build-script probe — install the dependencies first and the `cargo build` line above picks it up. The OpenWrt ipk omits BLE because libdbus is not available on the target. diff --git a/packaging/README.md b/packaging/README.md index 7147728..d5d9644 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -15,6 +15,28 @@ make zip # Windows .zip package make all # deb + tarball (default) ``` +## Build Prerequisites + +These targets build FIPS from source, so the host needs a build +environment in addition to a Rust toolchain (the version pinned in +`rust-toolchain.toml` is auto-installed by rustup). + +On Linux, `libclang` is **required**: the LAN gateway's nftables +bindings are generated by `bindgen` at build time, which needs +`libclang.so` on the build host. Without it the build fails inside the +`rustables` crate with an "Unable to find libclang" error. + +```sh +sudo apt install libclang-dev # Debian / Ubuntu +``` + +This is a build-time prerequisite only — it is not a runtime +dependency, so hosts installing a pre-built `.deb` do not need it. + +BLE support is optional and, when building with it, additionally needs +`bluez`, `libdbus-1-dev`, and `pkg-config`; the build picks up BLE if +those are present and skips it cleanly if not. + ## Directory Structure ```text diff --git a/src/transport/ble/discovery.rs b/src/transport/ble/discovery.rs index 364b677..8db9736 100644 --- a/src/transport/ble/discovery.rs +++ b/src/transport/ble/discovery.rs @@ -34,7 +34,7 @@ impl DiscoveryBuffer { pub fn add_peer(&self, addr: &BleAddr) { let ta = addr.to_transport_addr(); let peer = DiscoveredPeer::new(self.transport_id, ta.clone()); - let mut peers = self.peers.lock().unwrap(); + let mut peers = self.peers.lock().unwrap_or_else(|e| e.into_inner()); // Deduplicate by address string let addr_str = addr.to_string_repr(); peers.retain(|p| p.addr.as_str() != Some(addr_str.as_str())); @@ -49,7 +49,7 @@ impl DiscoveryBuffer { pub fn add_peer_with_pubkey(&self, addr: &BleAddr, pubkey: XOnlyPublicKey) { let ta = addr.to_transport_addr(); let peer = DiscoveredPeer::with_hint(self.transport_id, ta.clone(), pubkey); - let mut peers = self.peers.lock().unwrap(); + let mut peers = self.peers.lock().unwrap_or_else(|e| e.into_inner()); let addr_str = addr.to_string_repr(); peers.retain(|p| p.addr.as_str() != Some(addr_str.as_str())); peers.push(peer); @@ -57,7 +57,7 @@ impl DiscoveryBuffer { /// Drain all discovered peers since the last call. pub fn take(&self) -> Vec { - let mut peers = self.peers.lock().unwrap(); + let mut peers = self.peers.lock().unwrap_or_else(|e| e.into_inner()); std::mem::take(&mut *peers) } } diff --git a/src/transport/ble/io.rs b/src/transport/ble/io.rs index 16c6c5c..178a8a2 100644 --- a/src/transport/ble/io.rs +++ b/src/transport/ble/io.rs @@ -634,7 +634,10 @@ impl MockBleIo { where F: Fn(&BleAddr, u16) -> Result + Send + Sync + 'static, { - *self.connect_handler.lock().unwrap() = Some(Box::new(handler)); + *self + .connect_handler + .lock() + .unwrap_or_else(|e| e.into_inner()) = Some(Box::new(handler)); } } @@ -654,7 +657,10 @@ impl BleIo for MockBleIo { } async fn connect(&self, addr: &BleAddr, psm: u16) -> Result { - let handler = self.connect_handler.lock().unwrap(); + let handler = self + .connect_handler + .lock() + .unwrap_or_else(|e| e.into_inner()); match handler.as_ref() { Some(f) => f(addr, psm), None => Err(TransportError::ConnectionRefused), diff --git a/src/transport/ethernet/discovery.rs b/src/transport/ethernet/discovery.rs index 7130b53..26ff75e 100644 --- a/src/transport/ethernet/discovery.rs +++ b/src/transport/ethernet/discovery.rs @@ -65,7 +65,7 @@ impl DiscoveryBuffer { pub fn add_peer(&self, src_mac: [u8; 6], pubkey: XOnlyPublicKey) { let addr = TransportAddr::from_bytes(&src_mac); let peer = DiscoveredPeer::with_hint(self.transport_id, addr, pubkey); - let mut peers = self.peers.lock().unwrap(); + let mut peers = self.peers.lock().unwrap_or_else(|e| e.into_inner()); // Deduplicate by MAC address — keep the latest peers.retain(|p| p.addr.as_bytes() != src_mac); peers.push(peer); @@ -73,7 +73,7 @@ impl DiscoveryBuffer { /// Drain all discovered peers since the last call. pub fn take(&self) -> Vec { - let mut peers = self.peers.lock().unwrap(); + let mut peers = self.peers.lock().unwrap_or_else(|e| e.into_inner()); std::mem::take(&mut *peers) } } diff --git a/src/transport/ethernet/socket_macos.rs b/src/transport/ethernet/socket_macos.rs index b31eaf5..2ddb187 100644 --- a/src/transport/ethernet/socket_macos.rs +++ b/src/transport/ethernet/socket_macos.rs @@ -214,7 +214,7 @@ impl PacketSocket { /// parses the next frame from the internal buffer, stripping the /// Ethernet header. Returns `(payload_bytes, source_mac)`. pub fn recv_from(&self, buf: &mut [u8]) -> std::io::Result<(usize, [u8; 6])> { - let mut state = self.read_state.lock().unwrap(); + let mut state = self.read_state.lock().unwrap_or_else(|e| e.into_inner()); let state = &mut *state; loop { // Try to parse the next frame from the read buffer diff --git a/src/transport/udp/mod.rs b/src/transport/udp/mod.rs index bd00fd8..3728fb9 100644 --- a/src/transport/udp/mod.rs +++ b/src/transport/udp/mod.rs @@ -144,7 +144,7 @@ impl UdpTransport { // Check cache { - let cache = self.dns_cache.lock().unwrap(); + let cache = self.dns_cache.lock().unwrap_or_else(|e| e.into_inner()); if let Some((resolved, cached_at)) = cache.get(addr) && cached_at.elapsed() < DNS_CACHE_TTL { @@ -157,7 +157,7 @@ impl UdpTransport { // Store in cache { - let mut cache = self.dns_cache.lock().unwrap(); + let mut cache = self.dns_cache.lock().unwrap_or_else(|e| e.into_inner()); cache.insert(addr.clone(), (resolved, Instant::now())); } @@ -230,14 +230,14 @@ impl UdpTransport { if let Some(ref name) = self.name { info!( name = %name, - local_addr = %self.local_addr.unwrap(), + local_addr = %self.local_addr.map_or_else(|| "".to_string(), |a| a.to_string()), recv_buf = actual_recv, send_buf = actual_send, "UDP transport started" ); } else { info!( - local_addr = %self.local_addr.unwrap(), + local_addr = %self.local_addr.map_or_else(|| "".to_string(), |a| a.to_string()), recv_buf = actual_recv, send_buf = actual_send, "UDP transport started" @@ -289,14 +289,14 @@ impl UdpTransport { if let Some(ref name) = self.name { info!( name = %name, - local_addr = %self.local_addr.unwrap(), + local_addr = %self.local_addr.map_or_else(|| "".to_string(), |a| a.to_string()), recv_buf = actual_recv, send_buf = actual_send, "UDP transport adopted existing socket" ); } else { info!( - local_addr = %self.local_addr.unwrap(), + local_addr = %self.local_addr.map_or_else(|| "".to_string(), |a| a.to_string()), recv_buf = actual_recv, send_buf = actual_send, "UDP transport adopted existing socket"