Commit Graph

21 Commits

Author SHA1 Message Date
ddidderr d15031c9d1 fix(client): clear gateway status from welcome identity
The client initialized gateway connectivity from ServerWelcome, but welcome only
exposed a boolean. If a gateway disconnected before the client saw the catch-up
PeerJoined event, the later unknown PeerLeft could not be tied to the gateway
and the status could stay connected.

Carry an optional gateway peer id in ServerWelcome. The relay fills it from the
joining gateway or the existing room gateway, and the Windows client stores it
so a matching unknown PeerLeft clears gateway connectivity. The boolean remains
for wire compatibility with older welcomes that do not carry the id.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-ctrl server_welcome
- cargo test -p lanparty-relay accepts_gateway_and_client_into_room
- cargo test -p lanparty-relay reports_missing_gateway_to_client_joining_first
- cargo test -p lanparty-client-win relay_lifecycle
- cargo test -p lanparty-client-win \
  clears_gateway_status_when_welcome_gateway_leaves_before_join_event
- cargo test -p lanparty-relay bridges_real_client_and_gateway_sessions
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo build --release -p lanparty-relay -p lanparty-gateway
- git diff --check
- git diff --cached --check

Refs: MVP lifecycle cleanup
2026-05-22 07:22:06 +02:00
ddidderr bd22a68a6f fix(tunnel): enforce negotiated TAP MTU
The MVP tunnel negotiates an effective TAP MTU and configures the Windows TAP IP
interface to that value, but the forwarding path only rejected frames that were
standard-Ethernet jumbo frames or exceeded the QUIC datagram budget. A frame
could therefore be larger than the negotiated TAP MTU while still fitting inside
the QUIC datagram budget.

Make the TAP-MTU frame limit an explicit shared protocol helper and enforce it
at every data-path boundary: Windows client send/receive, Linux gateway
send/receive, and relay forwarding. Such frames now produce TapMtuExceeded in
logs and counters instead of being forwarded until a later layer drops or
accepts them implicitly.

This keeps the no-fragmentation contract honest: one Ethernet frame still maps
to one QUIC datagram, but only if that frame also fits the room's negotiated TAP
MTU.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-proto tap_mtu
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client
- cargo test -p lanparty-gateway connects_to_relay_control_stream_as_gateway
- cargo test -p lanparty-relay drops_frames_above_effective_tap_mtu
- cargo test -p lanparty-relay rate_limits_client_total_bandwidth_after_burst
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo build --release -p lanparty-relay -p lanparty-gateway
- git diff --check
- git diff --cached --check

Refs: MVP no-fragmentation tunnel MTU contract
2026-05-22 07:15:11 +02:00
ddidderr 234bece265 fix(client): drop misdirected relayed unicast frames
The relay should only send a remote client unicast traffic for that client's
virtual MAC, while broadcast and multicast traffic fan out to every relevant
peer. The Windows client is still the last boundary before TAP, so it should not
write a relayed unicast frame for some other MAC into the adapter if the relay
or a future code path misroutes it.

Add a receive-side destination guard in client-core. Relayed frames now reach
TAP only when their destination is the client's virtual MAC or a
broadcast/multicast address; other unicast frames are counted and skipped.

Extend the client relay-session test with a wrong-client unicast before the
valid frame, and document the client-side skip in the README.

Test Plan:
- cargo test -p lanparty-client-core
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo fmt --check
- git diff --check

Refs: PLAN.md LAN frames to matching remote clients
2026-05-22 05:31:37 +02:00
ddidderr da937a50c4 fix(proto): reject reserved overlay flags
The MVP overlay reserves its flags field for later features such as
fragmentation or payload encryption, but version 1 does not define any flag
semantics. Accepting nonzero flags would let unknown behavior silently traverse
the relay and reach the tunnel endpoints.

Make zero the only valid v1 flag value. Overlay encoding and decoding now reject
reserved nonzero flags, production send paths use the explicit
OVERLAY_FLAGS_NONE constant, and the relay emits forwarded datagrams with the
same zero-flag policy instead of preserving peer-supplied bits.

Document the reserved-flag rule in the protocol crate overview.

Test Plan:
- cargo test -p lanparty-proto overlay
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo fmt --check
- git diff --check

Refs: PLAN.md no-fragmentation MVP overlay format
2026-05-22 05:28:52 +02:00
ddidderr 0a97b77ad9 fix(client): filter relayed LAN frames before TAP writes
LAN-to-remote switch-control filtering is enforced by the gateway and relay,
but the Windows client is the final boundary before frames enter the TAP
adapter. A malformed or buggy relay path should not be able to make the client
write LAN control traffic, invalid-source frames, or jumbo frames into TAP.

Reuse the shared gateway/LAN safety classifier on received relay Ethernet
frames. Filtered frames are counted and skipped, and recv_ethernet only returns
frames that are safe to hand to the platform TAP writer.

Extend the client relay-session test so the mock relay sends a filtered frame
before the valid one, then document the receive-side TAP boundary in the
README.

Test Plan:
- cargo test -p lanparty-client-core
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo fmt --check
- git diff --check

Refs: PLAN.md LAN-to-remote control-plane filtering
2026-05-22 05:25:53 +02:00
ddidderr a3ff75b29f refactor(proto): share Ethernet safety classification
Safety filtering now applies at several tunnel boundaries. The relay remains
the trust boundary, while the client and gateway also drop unsafe frames before
spending relay bandwidth. Duplicating EtherType and IPv4/IPv6 parsers across
crates would make those rules drift as the MVP grows.

Move the Ethernet safety classifiers into lanparty-proto, expose typed safety
drop reasons, and map them back into the existing DropReason vocabulary. The
relay now uses the shared client and gateway classifiers, the gateway keeps its
local LAN-send drops through the shared classifier, and the client drops the
same remote-to-LAN safety cases before QUIC DATAGRAM encoding.

Document the client-side local drops and list the additional suspicious drop
reasons in the manual MVP test guide.

Test Plan:
- cargo test -p lanparty-proto safety
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client
- cargo test -p lanparty-gateway connects_to_relay_control_stream_as_gateway
- cargo test -p lanparty-relay
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo check -p lanparty-client-tap --target x86_64-pc-windows-gnu --tests
- cargo check -p lanparty-client-route --target x86_64-pc-windows-gnu --tests
- cargo check -p lanparty-client-tap --target x86_64-pc-windows-msvc --tests
- cargo check -p lanparty-client-route --target x86_64-pc-windows-msvc --tests
- git diff --check

Refs: PLAN.md safety filters and client source-MAC isolation
2026-05-22 05:16:33 +02:00
ddidderr 3c1a35ea00 fix(client): enforce virtual MAC before relay send
The relay already rejects client frames whose source MAC does not match the
announced virtual MAC. The Windows bridge can still see those frames from TAP,
though, and sending them to the relay wastes datagram budget and makes the
client-side counters less useful during manual tests.

Carry the configured virtual MAC into ClientRelayIo and drop invalid or
unauthorized TAP source MACs before QUIC DATAGRAM encoding. The relay keeps the
same checks as the trust boundary, but client diagnostics now account for these
drops locally.

Document the local source-MAC check and list InvalidSourceMac as a suspicious
manual-test drop reason.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md source-MAC authorization and safety filters
2026-05-22 04:58:12 +02:00
ddidderr e69d41691a feat(client): report relay RTT diagnostics
Expose the active QUIC connection RTT in shared client diagnostics and in the
Windows client status line. This gives operators a live relay-path latency
signal without pretending to measure end-to-end gateway or LAN latency.

The new diagnostics field defaults to unknown when older JSON snapshots omit it,
so consumers can read pre-change snapshots without special migration code. The
user-facing diagnostics now print Relay RTT only when the client has an active
QUIC measurement.

Test Plan:
- cargo fmt --check
- git diff --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings

Refs: PLAN.md logging and diagnostics section
2026-05-21 23:00:18 +02:00
ddidderr cd8a536771 fix(client): drop unsendable TAP frames locally
The Windows TAP pump used the same send helper as direct callers, so malformed,
jumbo, or over-budget TAP frames were reported as errors that stopped the
bridge. That is too brittle for the no-fragmentation MVP: local frames that
cannot fit the tunnel should be counted and dropped, while real QUIC send
failures should still surface as fatal.

Add a client send outcome that reports whether a frame was sent or locally
dropped. The existing send_ethernet API still returns an error for direct
callers when the outcome is a local drop. The live TAP pump uses the outcome API
so it can log the drop reason and keep forwarding later frames.

Document the new client behavior in the README.

Test Plan:
- cargo fmt --check
- git diff --check
- cargo test -p lanparty-client-core
- cargo test -p lanparty-client-win
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings

Attempted:
- cargo check -p lanparty-client-win --target x86_64-pc-windows-msvc
  (blocked by missing MSVC lib.exe on this Linux host)

Refs: PLAN.md
2026-05-21 22:47:08 +02:00
ddidderr 325e5651a2 feat(proto): validate negotiated datagram budgets
PLAN.md keeps MVP traffic to one Ethernet frame per QUIC datagram with no
fragmentation. The relay already negotiates a datagram budget, but the client
and gateway send paths still relied on Quinn to reject oversized encoded
Ethernet datagrams.

Add a shared protocol validation helper for encoded datagram length versus the
negotiated QUIC budget. Thread the negotiated budget into client and gateway
send boundaries, reject oversized datagrams before send, and count those valid
but unsent frames as local drops.

Document the budget check in the workspace decomposition and gateway behavior.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-proto -p lanparty-client-core -p lanparty-gateway
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 22:03:15 +02:00
ddidderr 21a69626e0 feat(obs): report broadcast frame counters
PLAN.md calls out "Broadcast traffic flowing" as a user-facing diagnostic.
The tunnel stats only reported total Ethernet frame counts, so the client
could not distinguish whether broadcast traffic was actually crossing the
tunnel.

Add defaulted broadcast tx/rx counters to TunnelStats while preserving the
existing constructor and old JSON compatibility. Client and gateway accounting
now increments those counters from validated Ethernet frames, and the client
diagnostics line reports the broadcast flow next to total frame counts.

Relay peer stats logs include the new counters so operators can see broadcast
activity from forwarded stats snapshots too.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-obs -p lanparty-client-core -p lanparty-gateway \
  -p lanparty-client-win -p lanparty-relay
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 21:54:35 +02:00
ddidderr 546060568b feat(ctrl): send graceful disconnects
The relay already accepts post-handshake Disconnect control messages, but the
client and gateway shutdown paths only sent a QUIC application close. That made
normal shutdown indistinguishable from transport closure until the relay
inferred a generic Normal leave.

Client and gateway shutdown now send a best-effort Disconnect message with the
human-readable shutdown reason before closing QUIC. The client-core drain uses
Quinn's runtime timer instead of taking a Tokio runtime dependency. The gateway
uses its existing Tokio runtime and applies the same short drain window on both
explicit shutdown and Ctrl-C in the Linux bridge loop.

The endpoint integration tests now assert that the server receives Disconnect
after the stats stream, which also protects against closing too quickly and
aborting the control stream.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core \
  connects_to_relay_control_stream_as_client -- --nocapture
- cargo test -p lanparty-gateway \
  connects_to_relay_control_stream_as_gateway -- --nocapture
- cargo test -p lanparty-client-core
- cargo test -p lanparty-gateway
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo clippy -p lanparty-gateway --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 21:07:47 +02:00
ddidderr 60c41471fb feat(client): send stats snapshots to relay
Client counters were only local diagnostics even though the control protocol and
relay now understand Stats messages. Add a client-core sender that opens a
peer-to-relay unidirectional stream with the current TunnelStats snapshot.

The Windows client reports stats whenever it prints its diagnostics snapshot.
Failures are logged instead of stopping the frame pump because stats reporting
is diagnostic and should not be the reason a live tunnel goes down.

The client-core integration test now has the server decode the stats stream
before shutdown so the send path is covered without a timing race.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core \
  connects_to_relay_control_stream_as_client -- --nocapture
- cargo test -p lanparty-client-core
- cargo test -p lanparty-client-win
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo clippy -p lanparty-client-win --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 20:53:37 +02:00
ddidderr 20bed4b45e feat(client): receive relay control events
ClientSession can now accept one-frame relay control events sent on reliable
unidirectional QUIC streams. This gives the Windows client a core API for the
PeerJoined and PeerLeft lifecycle messages that the relay now emits.

The implementation stays in client-core because it shares the relay connection
and control codec with the handshake. Client UI/status handling remains a
separate slice so this commit only establishes the tested transport boundary.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client \
  -- --nocapture
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 20:34:57 +02:00
ddidderr 0824f60548 feat(ctrl): report gateway presence in welcome
ServerWelcome now carries an initial gateway_connected flag with serde defaulting
for older welcome payloads. The relay sets it from room admission state so a
gateway sees itself as connected, clients joining behind an existing gateway see
yes, and clients that arrive first see no.

The Windows client prints that handshake fact at startup. This does not replace
the later peer-event stream; it gives phase-1 diagnostics an immediate answer
for whether the relay already has a LAN gateway in the room.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
  -p lanparty-client-win
- cargo clippy -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
  -p lanparty-client-win --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 20:24:33 +02:00
ddidderr e8d7cf7ff5 feat(client): retain QUIC datagram diagnostics
Client connection setup already fails when QUIC DATAGRAM is unavailable and
clamps the advertised datagram budget before sending hello. Keep that clamped
value on ClientSession and expose it through QuicDiagnostics so the Windows
client can report the negotiated budget without recomputing handshake details.

The value remains owned by client-core because it is derived from the live
quinn connection and the configured client budget during handshake. TAP and UI
code can sample the snapshot later alongside tunnel counters.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 20:13:52 +02:00
ddidderr 802fe3d082 feat(client): expose tunnel traffic counters
Client relay I/O now shares atomic tunnel counters across cloned
ClientRelayIo handles and the owning ClientSession. The counters cover
successful Ethernet frame rx/tx, relay datagram rx/tx, and dropped or
malformed frames so client diagnostics have the traffic totals called
out in PLAN.md.

The counters live in client-core because that crate owns relay datagram
classification and Ethernet payload validation. The Windows TAP runner can
later sample this snapshot without duplicating protocol decisions.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
2026-05-21 20:11:11 +02:00
ddidderr c5fc13d892 feat(client): expose cloneable relay I/O handle
The Windows client frame pump needs one side reading TAP frames and sending them
to the relay while another side receives relay datagrams and writes them to TAP.
That should not require the binary to reach into `ClientSession` internals.

Introduce `ClientRelayIo`, a cloneable handle around the accepted QUIC
connection and server welcome. It owns the Ethernet datagram send/receive logic
that previously lived directly on `ClientSession`, while `ClientSession` keeps
convenience forwarding methods for existing callers.

This is an enabling slice only. TAP frame pumping can now hold independent relay
I/O handles without broadening the platform-specific TAP crate.

Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- Windows-target cargo clippy for lanparty-client-tap with -D warnings
- git diff --check

Refs: PLAN.md Windows TAP frame pump
2026-05-21 18:53:07 +02:00
ddidderr a3d24a1173 feat(client): persist virtual MAC identity
Remote clients need a stable locally administered MAC address so the relay,
gateway, DHCP lease, and LAN peers keep seeing the same tunnel identity across
runs. Requiring users to pass `--virtual-mac` made that responsibility manual.

Add a platform-neutral client identity store that loads a JSON identity file or
generates a new valid virtual MAC with OS randomness and persists it. The file
stores the MAC in the same string form shown by the CLI. The Windows client now
uses `lanparty-client-identity.json` by default while keeping `--virtual-mac` as
a manual test override.

TAP binding still remains future work; this slice only owns the client identity
that will be assigned to the TAP adapter.

Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md MAC identity
2026-05-21 18:35:20 +02:00
ddidderr 914bd48346 feat(client): add relay session core
lanparty-client-core now owns the platform-neutral remote client relay session.
It validates relay trust input, room, virtual MAC identity, and datagram budget,
then connects to the relay, sends a client hello, and stores the assigned
welcome metadata.

The session exposes Ethernet datagram send and receive helpers that stamp
outgoing frames with the relay-assigned room and peer ids, ignore frames for
other rooms or from itself, and reject malformed Ethernet payloads before
handing them to the future TAP bridge.

The loopback Quinn test verifies the full client-side control and datagram path
without requiring Windows TAP access: pinned certificate trust, role = client
hello, announced virtual MAC, welcome parsing, and Ethernet datagrams in both
directions.

Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings

Refs: PLAN.md Windows client relay connection and QUIC datagrams
2026-05-21 18:19:11 +02:00
ddidderr 3c395db3df chore: first project structure 2026-05-21 16:55:51 +02:00