diff --git a/README.md b/README.md index 3af6938..0f0c7f5 100644 --- a/README.md +++ b/README.md @@ -131,9 +131,10 @@ cargo run -p lanparty-client-win -- \ The Windows client binary currently connects to the relay as `role = client` with a generated locally administered virtual MAC persisted in `lanparty-client-identity.json`, completes the control-stream hello/welcome -handshake, snapshots the current relay route, and then bridges Ethernet frames -between the relay and the first TAP-Windows6 adapter until shutdown. +handshake, pins a host route for the relay IP on the current pre-TAP interface, +and then bridges Ethernet frames between the relay and the first TAP-Windows6 +adapter until shutdown. `--virtual-mac` can still override the stored identity for manual testing. On Windows it marks the TAP media connected and reports the driver MAC/MTU before -forwarding frames. Route pinning and automatic TAP MAC/MTU configuration are -not wired yet. +forwarding frames. Default-route takeover neutralization and automatic TAP +MAC/MTU configuration are not wired yet. diff --git a/crates/lanparty-client-win/src/main.rs b/crates/lanparty-client-win/src/main.rs index f34b76c..012d20d 100644 --- a/crates/lanparty-client-win/src/main.rs +++ b/crates/lanparty-client-win/src/main.rs @@ -13,7 +13,7 @@ use lanparty_client_core::{ ClientIdentity, ClientIdentityStore, ClientSession, ClientSessionConfig, connect_client, }; #[cfg(windows)] -use lanparty_client_route::RouteSnapshot; +use lanparty_client_route::{PinnedRelayRoute, RouteSnapshot}; #[cfg(windows)] use lanparty_client_tap::TapAdapter; use lanparty_ctrl::RoomCode; @@ -100,17 +100,28 @@ async fn main() -> Result<()> { session.welcome().room_id(), session.welcome().effective_tap_mtu() ); + #[cfg(windows)] + let relay_route_pin = match pin_relay_route_before_tap(session.config().relay_addr().ip()) { + Ok(pin) => pin, + Err(error) => { + session.shutdown("client startup failed").await; + return Err(error); + } + }; let run_result = run_client(&session).await; session.shutdown("client shutting down").await; + #[cfg(windows)] + drop(relay_route_pin); run_result } #[cfg(windows)] async fn run_client(session: &ClientSession) -> Result<()> { - log_relay_route_before_tap(session.config().relay_addr().ip()); let tap = open_tap_adapter(session)?; - println!("bridging TAP frames; route pinning is not wired yet; press Ctrl-C to stop"); + println!( + "bridging TAP frames; relay route is pinned; default-route neutralization is not wired yet; press Ctrl-C to stop" + ); tokio::select! { result = run_tap_frame_pump(session.relay_io(), tap) => result, @@ -129,13 +140,15 @@ async fn run_client(session: &ClientSession) -> Result<()> { } #[cfg(windows)] -fn log_relay_route_before_tap(destination: std::net::IpAddr) { - match lanparty_client_route::best_route_to(destination) { - Ok(route) => print_relay_route(&route), - Err(error) => eprintln!( - "failed to inspect relay route before TAP activation; route pinning is not wired yet: {error:#}" - ), - } +fn pin_relay_route_before_tap(destination: std::net::IpAddr) -> Result { + let route = lanparty_client_route::best_route_to(destination) + .context("failed to inspect relay route before TAP activation")?; + print_relay_route(&route); + let pin = lanparty_client_route::pin_relay_route(&route) + .context("failed to pin relay route before TAP activation")?; + print_pinned_relay_route(&pin); + + Ok(pin) } #[cfg(windows)] @@ -155,6 +168,19 @@ fn print_relay_route(route: &RouteSnapshot) { ); } +#[cfg(windows)] +fn print_pinned_relay_route(route: &PinnedRelayRoute) { + println!( + "relay route pinned before TAP: destination {} next hop {} interface index {} LUID {}", + route.destination(), + route + .next_hop() + .map_or_else(|| "on-link".to_string(), |next_hop| next_hop.to_string()), + route.interface_index(), + route.interface_luid() + ); +} + #[cfg(windows)] fn open_tap_adapter(session: &ClientSession) -> Result { let tap = lanparty_client_tap::open_first_adapter()?;