Files
fips/src/node/tests/mod.rs
OceanSlim 774e33fd27 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.
2026-04-11 18:31:48 +01:00

83 lines
2.5 KiB
Rust

use super::*;
use crate::PeerIdentity;
use crate::transport::{LinkDirection, TransportAddr, packet_channel};
use crate::utils::index::SessionIndex;
use std::time::Duration;
#[cfg(target_os = "linux")]
mod ble;
mod bloom;
mod disconnect;
mod discovery;
#[cfg(unix)]
mod ethernet;
mod forwarding;
mod handshake;
mod routing;
mod session;
mod spanning_tree;
mod tcp;
mod unit;
pub(super) fn make_node() -> Node {
let config = Config::new();
Node::new(config).unwrap()
}
#[allow(dead_code)]
pub(super) fn make_node_addr(val: u8) -> NodeAddr {
let mut bytes = [0u8; 16];
bytes[0] = val;
NodeAddr::from_bytes(bytes)
}
pub(super) fn make_peer_identity() -> PeerIdentity {
let identity = Identity::generate();
PeerIdentity::from_pubkey(identity.pubkey())
}
/// Create a PeerConnection with a completed Noise IK handshake.
///
/// Returns (connection, peer_identity) where the connection is outbound,
/// in Complete state, with session, indices, and transport info set.
pub(super) fn make_completed_connection(
node: &mut Node,
link_id: LinkId,
transport_id: TransportId,
current_time_ms: u64,
) -> (PeerConnection, PeerIdentity) {
let peer_identity_full = Identity::generate();
// Must use from_pubkey_full to preserve parity for ECDH
let peer_identity = PeerIdentity::from_pubkey_full(peer_identity_full.pubkey_full());
// Create outbound connection
let mut conn = PeerConnection::outbound(link_id, peer_identity, current_time_ms);
// Run initiator side of handshake
let our_keypair = node.identity.keypair();
let msg1 = conn
.start_handshake(our_keypair, node.startup_epoch, current_time_ms)
.unwrap();
// Run responder side to generate msg2
let mut resp_conn = PeerConnection::inbound(LinkId::new(999), current_time_ms);
let peer_keypair = peer_identity_full.keypair();
let mut resp_epoch = [0u8; 8];
rand::Rng::fill_bytes(&mut rand::rng(), &mut resp_epoch);
let msg2 = resp_conn
.receive_handshake_init(peer_keypair, resp_epoch, &msg1, current_time_ms)
.unwrap();
// Complete initiator handshake
conn.complete_handshake(&msg2, current_time_ms).unwrap();
// Set indices and transport info
let our_index = node.index_allocator.allocate().unwrap();
conn.set_our_index(our_index);
conn.set_their_index(SessionIndex::new(42));
conn.set_transport_id(transport_id);
conn.set_source_addr(TransportAddr::from_string("127.0.0.1:5000"));
(conn, peer_identity)
}