mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 08:14:42 +00:00
Add Windows platform support (#45)
Gate platform-specific code behind cfg attributes and add full Windows
support: TUN device via wintun, TCP control socket on localhost:21210,
Windows Service lifecycle (--install-service/--uninstall-service/--service),
CI build and test matrix, and packaging with ZIP builder and PowerShell
service management scripts.
Key changes:
- Cargo.toml: move tun/libc/rtnetlink behind cfg(unix); add wintun and
windows-service dependencies for Windows
- upper/tun.rs: wintun-based TUN implementation with netsh configuration
for IPv6 address, MTU, and fd00::/8 routing
- control/mod.rs: split into unix_impl/windows_impl; Windows uses TCP on
localhost:21210 with shared connection handler
- bin/fips.rs: refactor main() into run_daemon() accepting a shutdown
signal; add Windows Service support via windows-service crate
- transport/udp/socket.rs: platform-gated modules; Windows uses
tokio::net::UdpSocket (kernel drop count unavailable, returns 0)
- transport/ethernet: gate to cfg(unix); add Windows stub types
- config: platform-conditional default paths (socket, hosts) for Windows
- CI: add windows-latest to build matrix and test-windows job with
cargo-nextest
- packaging/windows: build-zip.ps1, install-service.ps1,
uninstall-service.ps1, and package-windows.yml workflow
- README/docs: Windows build instructions, service management, and
control socket platform differences
Linux and macOS behavior is unchanged.
This commit is contained in:
+53
-38
@@ -30,6 +30,7 @@ use crate::bloom::BloomState;
|
||||
use crate::cache::CoordCache;
|
||||
use crate::node::session::SessionEntry;
|
||||
use crate::peer::{ActivePeer, PeerConnection};
|
||||
#[cfg(unix)]
|
||||
use crate::transport::ethernet::EthernetTransport;
|
||||
use crate::transport::tcp::TcpTransport;
|
||||
use crate::transport::tor::TorTransport;
|
||||
@@ -705,20 +706,24 @@ impl Node {
|
||||
transports.push(TransportHandle::Udp(udp));
|
||||
}
|
||||
|
||||
// Create Ethernet transport instances
|
||||
let eth_instances: Vec<_> = self
|
||||
.config
|
||||
.transports
|
||||
.ethernet
|
||||
.iter()
|
||||
.map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
|
||||
.collect();
|
||||
let xonly = self.identity.pubkey();
|
||||
for (name, eth_config) in eth_instances {
|
||||
let transport_id = self.allocate_transport_id();
|
||||
let mut eth = EthernetTransport::new(transport_id, name, eth_config, packet_tx.clone());
|
||||
eth.set_local_pubkey(xonly);
|
||||
transports.push(TransportHandle::Ethernet(eth));
|
||||
// Create Ethernet transport instances (Unix only — requires raw sockets)
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let eth_instances: Vec<_> = self
|
||||
.config
|
||||
.transports
|
||||
.ethernet
|
||||
.iter()
|
||||
.map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
|
||||
.collect();
|
||||
let xonly = self.identity.pubkey();
|
||||
for (name, eth_config) in eth_instances {
|
||||
let transport_id = self.allocate_transport_id();
|
||||
let mut eth =
|
||||
EthernetTransport::new(transport_id, name, eth_config, packet_tx.clone());
|
||||
eth.set_local_pubkey(xonly);
|
||||
transports.push(TransportHandle::Ethernet(eth));
|
||||
}
|
||||
}
|
||||
|
||||
// Create TCP transport instances
|
||||
@@ -812,39 +817,49 @@ impl Node {
|
||||
///
|
||||
/// Finds the Ethernet transport instance bound to the named interface
|
||||
/// and parses the MAC portion into a 6-byte TransportAddr.
|
||||
#[allow(unused_variables)]
|
||||
fn resolve_ethernet_addr(
|
||||
&self,
|
||||
addr_str: &str,
|
||||
) -> Result<(TransportId, TransportAddr), NodeError> {
|
||||
let (iface, mac_str) = addr_str.split_once('/').ok_or_else(|| {
|
||||
NodeError::NoTransportForType(format!(
|
||||
"invalid Ethernet address format '{}': expected 'interface/mac'",
|
||||
addr_str
|
||||
))
|
||||
})?;
|
||||
|
||||
// Find the Ethernet transport bound to this interface
|
||||
let transport_id = self
|
||||
.transports
|
||||
.iter()
|
||||
.find(|(_, handle)| {
|
||||
handle.transport_type().name == "ethernet"
|
||||
&& handle.is_operational()
|
||||
&& handle.interface_name() == Some(iface)
|
||||
})
|
||||
.map(|(id, _)| *id)
|
||||
.ok_or_else(|| {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let (iface, mac_str) = addr_str.split_once('/').ok_or_else(|| {
|
||||
NodeError::NoTransportForType(format!(
|
||||
"no operational Ethernet transport for interface '{}'",
|
||||
iface
|
||||
"invalid Ethernet address format '{}': expected 'interface/mac'",
|
||||
addr_str
|
||||
))
|
||||
})?;
|
||||
|
||||
let mac = crate::transport::ethernet::parse_mac_string(mac_str).map_err(|e| {
|
||||
NodeError::NoTransportForType(format!("invalid MAC in '{}': {}", addr_str, e))
|
||||
})?;
|
||||
// Find the Ethernet transport bound to this interface
|
||||
let transport_id = self
|
||||
.transports
|
||||
.iter()
|
||||
.find(|(_, handle)| {
|
||||
handle.transport_type().name == "ethernet"
|
||||
&& handle.is_operational()
|
||||
&& handle.interface_name() == Some(iface)
|
||||
})
|
||||
.map(|(id, _)| *id)
|
||||
.ok_or_else(|| {
|
||||
NodeError::NoTransportForType(format!(
|
||||
"no operational Ethernet transport for interface '{}'",
|
||||
iface
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok((transport_id, TransportAddr::from_bytes(&mac)))
|
||||
let mac = crate::transport::ethernet::parse_mac_string(mac_str).map_err(|e| {
|
||||
NodeError::NoTransportForType(format!("invalid MAC in '{}': {}", addr_str, e))
|
||||
})?;
|
||||
|
||||
Ok((transport_id, TransportAddr::from_bytes(&mac)))
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
Err(NodeError::NoTransportForType(
|
||||
"Ethernet transport is not supported on this platform".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve a BLE address string (`"adapter/AA:BB:CC:DD:EE:FF"`) to a
|
||||
|
||||
@@ -9,6 +9,7 @@ mod ble;
|
||||
mod bloom;
|
||||
mod disconnect;
|
||||
mod discovery;
|
||||
#[cfg(unix)]
|
||||
mod ethernet;
|
||||
mod forwarding;
|
||||
mod handshake;
|
||||
|
||||
Reference in New Issue
Block a user