justfile, AGENTS.md
This commit is contained in:
@@ -1,14 +1,23 @@
|
||||
# PLAN
|
||||
|
||||
What I want to do:
|
||||
|
||||
A simple one-click Layer 2 tunnel software (Windows 11 client) to bridge people who cannot participate in person at a LAN party to the LAN party. And a simple server endpoint (Linux) software that runs physically at the LAN party and bridges the tunneled traffic and the real LAN network.
|
||||
A simple one-click Layer 2 tunnel software (Windows 11 client) to bridge people
|
||||
who cannot participate in person at a LAN party to the LAN party. And a simple
|
||||
server endpoint (Linux) software that runs physically at the LAN party and
|
||||
bridges the tunneled traffic and the real LAN network.
|
||||
|
||||
I already talked a bit with different AIs about how to do this, here's the current plan:
|
||||
I already talked a bit with different AIs about how to do this, here's the
|
||||
current plan:
|
||||
|
||||
# LAN Party Tunnel Plan
|
||||
## LAN Party Tunnel Plan
|
||||
|
||||
Build a **TAP-based L2-over-QUIC tunnel**.
|
||||
|
||||
The remote Windows client gets a real virtual Ethernet adapter. Ethernet frames from that adapter are sent over QUIC to a public relay. The relay forwards them to a Linux gateway at the LAN party. The Linux gateway injects those frames onto the physical LAN and captures replies.
|
||||
The remote Windows client gets a real virtual Ethernet adapter. Ethernet frames
|
||||
from that adapter are sent over QUIC to a public relay. The relay forwards them
|
||||
to a Linux gateway at the LAN party. The Linux gateway injects those frames onto
|
||||
the physical LAN and captures replies.
|
||||
|
||||
```text
|
||||
Windows game
|
||||
@@ -21,13 +30,10 @@ Windows game
|
||||
⇄ physical Ethernet LAN
|
||||
```
|
||||
|
||||
No WireGuard.
|
||||
No Npcap.
|
||||
No Windows bridge.
|
||||
No packet rewriting from the user’s real NIC.
|
||||
No tunnel fragmentation for MVP.
|
||||
No WireGuard. No Npcap. No Windows bridge. No packet rewriting from the user’s
|
||||
real NIC. No tunnel fragmentation for MVP.
|
||||
|
||||
## Goal
|
||||
### Goal
|
||||
|
||||
The remote player should do this:
|
||||
|
||||
@@ -53,11 +59,12 @@ The public server does this:
|
||||
lanparty-relay --listen 443/udp
|
||||
```
|
||||
|
||||
UDP/443 is a good default, but the port must be configurable because some networks block QUIC/UDP.
|
||||
UDP/443 is a good default, but the port must be configurable because some
|
||||
networks block QUIC/UDP.
|
||||
|
||||
## Components
|
||||
### Components
|
||||
|
||||
### 1. Windows client: `lanparty-client.exe`
|
||||
#### 1. Windows client: `lanparty-client.exe`
|
||||
|
||||
Written in Rust.
|
||||
|
||||
@@ -75,9 +82,13 @@ Responsibilities:
|
||||
- keep the relay connection routed through the real internet NIC
|
||||
```
|
||||
|
||||
Use a real TAP/Ethernet adapter. `tap-windows6` is an NDIS TAP-Windows driver used by OpenVPN and other apps, which is the right class of device here because we need Ethernet frames, not just IP packets. ([GitHub][1])
|
||||
Use a real TAP/Ethernet adapter. `tap-windows6` is an NDIS TAP-Windows driver
|
||||
used by OpenVPN and other apps, which is the right class of device here because
|
||||
we need Ethernet frames, not just IP packets. ([GitHub][1])
|
||||
|
||||
Do **not** use Wintun for this design. Wintun is L3/TUN-style and does not give you the Ethernet/L2 behavior needed for ARP, DHCP, broadcast discovery, and old LAN games.
|
||||
Do **not** use Wintun for this design. Wintun is L3/TUN-style and does not give
|
||||
you the Ethernet/L2 behavior needed for ARP, DHCP, broadcast discovery, and old
|
||||
LAN games.
|
||||
|
||||
The TAP adapter is the remote player’s LAN-party identity.
|
||||
|
||||
@@ -88,7 +99,7 @@ Game sends ARP/broadcast/multicast through TAP
|
||||
Client tunnels the Ethernet frames
|
||||
```
|
||||
|
||||
### 2. Linux gateway: `lanparty-gateway`
|
||||
#### 2. Linux gateway: `lanparty-gateway`
|
||||
|
||||
Runs on the physical LAN party machine.
|
||||
|
||||
@@ -104,15 +115,23 @@ Responsibilities:
|
||||
- periodically refresh switch CAM table entries
|
||||
```
|
||||
|
||||
Use Linux `AF_PACKET` / `SOCK_RAW` on the real wired NIC. Packet sockets operate at device-driver / OSI Layer 2 level, and `SOCK_RAW` includes the link-layer header, which is exactly what we need for Ethernet frames. ([man7.org][2])
|
||||
Use Linux `AF_PACKET` / `SOCK_RAW` on the real wired NIC. Packet sockets operate
|
||||
at device-driver / OSI Layer 2 level, and `SOCK_RAW` includes the link-layer
|
||||
header, which is exactly what we need for Ethernet frames. ([man7.org][2])
|
||||
|
||||
For MVP, run as root. Later, reduce privileges. Opening raw sockets and changing/promiscuous network behavior needs elevated networking privileges; `CAP_NET_ADMIN` covers things like setting promiscuous mode, and `CAP_NET_RAW` covers raw packet access. ([man7.org][3])
|
||||
For MVP, run as root. Later, reduce privileges. Opening raw sockets and
|
||||
changing/promiscuous network behavior needs elevated networking privileges;
|
||||
`CAP_NET_ADMIN` covers things like setting promiscuous mode, and `CAP_NET_RAW`
|
||||
covers raw packet access. ([man7.org][3])
|
||||
|
||||
No Linux bridge is needed for MVP. No `br0`. No moving the host’s IP from `eth0` to a bridge. The gateway daemon directly captures and injects frames on the physical NIC.
|
||||
No Linux bridge is needed for MVP. No `br0`. No moving the host’s IP from `eth0`
|
||||
to a bridge. The gateway daemon directly captures and injects frames on the
|
||||
physical NIC.
|
||||
|
||||
Wired Ethernet only. No Wi-Fi gateway mode for MVP. Managed Wi-Fi NICs are not reliable for arbitrary source-MAC injection.
|
||||
Wired Ethernet only. No Wi-Fi gateway mode for MVP. Managed Wi-Fi NICs are not
|
||||
reliable for arbitrary source-MAC injection.
|
||||
|
||||
### 3. Public relay: `lanparty-relay`
|
||||
#### 3. Public relay: `lanparty-relay`
|
||||
|
||||
Runs on VPS/public server.
|
||||
|
||||
@@ -139,7 +158,7 @@ gateway → outbound QUIC → relay
|
||||
|
||||
No port forwarding. No NAT traversal pain. Direct P2P can come later.
|
||||
|
||||
## Transport
|
||||
### Transport
|
||||
|
||||
Use QUIC.
|
||||
|
||||
@@ -158,11 +177,16 @@ disconnect reason
|
||||
future auth
|
||||
```
|
||||
|
||||
Use QUIC DATAGRAM for Ethernet frames. QUIC DATAGRAM is specifically the unreliable datagram extension for QUIC, which fits Ethernet/game traffic better than reliable streams because old frames should not block newer frames. ([IETF Datatracker][4])
|
||||
Use QUIC DATAGRAM for Ethernet frames. QUIC DATAGRAM is specifically the
|
||||
unreliable datagram extension for QUIC, which fits Ethernet/game traffic better
|
||||
than reliable streams because old frames should not block newer frames. ([IETF
|
||||
Datatracker][4])
|
||||
|
||||
Rust QUIC implementation: start with `quinn`. It exposes `Connection::max_datagram_size()`, which returns the maximum datagram payload size or `None` if datagrams are unsupported/disabled. ([Docs.rs][5])
|
||||
Rust QUIC implementation: start with `quinn`. It exposes
|
||||
`Connection::max_datagram_size()`, which returns the maximum datagram payload
|
||||
size or `None` if datagrams are unsupported/disabled. ([Docs.rs][5])
|
||||
|
||||
## No fragmentation for MVP
|
||||
### No fragmentation for MVP
|
||||
|
||||
Do **not** fragment Ethernet frames inside the overlay.
|
||||
|
||||
@@ -200,9 +224,10 @@ tap_mtu <= quic_max_datagram_size
|
||||
- safety_margin
|
||||
```
|
||||
|
||||
No fragment table. No reassembly timeout. No “one lost fragment kills the whole Ethernet frame.” Add fragmentation later only if testing proves it is necessary.
|
||||
No fragment table. No reassembly timeout. No “one lost fragment kills the whole
|
||||
Ethernet frame.” Add fragmentation later only if testing proves it is necessary.
|
||||
|
||||
## Overlay frame format
|
||||
### Overlay frame format
|
||||
|
||||
Keep the outer routing header small and stable.
|
||||
|
||||
@@ -226,13 +251,16 @@ clear routing header
|
||||
encrypted Ethernet payload
|
||||
```
|
||||
|
||||
MVP can skip payload encryption beyond QUIC, but the wire format should not make later E2E encryption painful.
|
||||
MVP can skip payload encryption beyond QUIC, but the wire format should not make
|
||||
later E2E encryption painful.
|
||||
|
||||
## Trust model
|
||||
### Trust model
|
||||
|
||||
MVP relay sees plaintext Ethernet frames.
|
||||
|
||||
QUIC encrypts traffic on the wire, but because the relay terminates QUIC connections, it decrypts frames from clients and re-encrypts them to the gateway.
|
||||
QUIC encrypts traffic on the wire, but because the relay terminates QUIC
|
||||
connections, it decrypts frames from clients and re-encrypts them to the
|
||||
gateway.
|
||||
|
||||
That is acceptable for a LAN-party MVP, but it should be explicitly documented.
|
||||
|
||||
@@ -246,7 +274,7 @@ relay only sees room id, peer id, size, timing
|
||||
|
||||
Do not retrofit this into a bad packet format later. Reserve the shape now.
|
||||
|
||||
## Switching model
|
||||
### Switching model
|
||||
|
||||
Treat the whole thing as a tiny user-space Ethernet switch.
|
||||
|
||||
@@ -285,7 +313,7 @@ LAN frames go to matching remote client or all clients if broadcast/multicast
|
||||
|
||||
But MAC learning belongs in the real design.
|
||||
|
||||
## MAC identity
|
||||
### MAC identity
|
||||
|
||||
Each Windows client needs a unique locally administered unicast MAC.
|
||||
|
||||
@@ -295,7 +323,8 @@ Example range:
|
||||
02:xx:xx:xx:xx:xx
|
||||
```
|
||||
|
||||
Generate once per install or per profile. Store it. Configure TAP with it. Announce it during join.
|
||||
Generate once per install or per profile. Store it. Configure TAP with it.
|
||||
Announce it during join.
|
||||
|
||||
Relay must reject:
|
||||
|
||||
@@ -315,11 +344,13 @@ maybe 2 later for weird cases
|
||||
|
||||
This is your responsibility, not the user’s.
|
||||
|
||||
## Linux gateway CAM-table refresh
|
||||
### Linux gateway CAM-table refresh
|
||||
|
||||
The physical LAN switch must learn that remote clients’ MACs live behind the gateway port.
|
||||
The physical LAN switch must learn that remote clients’ MACs live behind the
|
||||
gateway port.
|
||||
|
||||
That happens when the gateway injects frames onto the LAN using the remote client’s source MAC.
|
||||
That happens when the gateway injects frames onto the LAN using the remote
|
||||
client’s source MAC.
|
||||
|
||||
But switch CAM entries age out. So the gateway should periodically refresh them.
|
||||
|
||||
@@ -330,7 +361,8 @@ for each connected remote MAC:
|
||||
inject a tiny harmless Ethernet frame with that MAC as source
|
||||
```
|
||||
|
||||
The exact frame can be decided during implementation, but the goal is simple: keep the LAN switch mapping the remote MAC to the gateway’s physical port.
|
||||
The exact frame can be decided during implementation, but the goal is simple:
|
||||
keep the LAN switch mapping the remote MAC to the gateway’s physical port.
|
||||
|
||||
Phase 1 success criterion:
|
||||
|
||||
@@ -340,9 +372,10 @@ remote client MAC appears in the LAN switch MAC table on the gateway port
|
||||
|
||||
If that is false, the L2 illusion is broken.
|
||||
|
||||
## Safety filters
|
||||
### Safety filters
|
||||
|
||||
Remote clients must not be allowed to spray arbitrary L2 control-plane junk onto the real LAN.
|
||||
Remote clients must not be allowed to spray arbitrary L2 control-plane junk onto
|
||||
the real LAN.
|
||||
|
||||
Drop remote → LAN unconditionally:
|
||||
|
||||
@@ -368,7 +401,8 @@ Also drop LAN → remote:
|
||||
|
||||
No remote Windows client needs to see switch/control-plane traffic.
|
||||
|
||||
EAPOL is especially important: remote clients should never be able to interfere with 802.1X or port authentication behavior on the physical switch.
|
||||
EAPOL is especially important: remote clients should never be able to interfere
|
||||
with 802.1X or port authentication behavior on the physical switch.
|
||||
|
||||
Add rate limits:
|
||||
|
||||
@@ -379,11 +413,12 @@ Add rate limits:
|
||||
- malformed packet disconnect threshold
|
||||
```
|
||||
|
||||
## Windows routing / metric handling
|
||||
### Windows routing / metric handling
|
||||
|
||||
The TAP adapter may receive DHCP from the party LAN. That is good.
|
||||
|
||||
But if DHCP gives it a default gateway, Windows might try to route the relay connection through the tunnel itself. That would break the tunnel.
|
||||
But if DHCP gives it a default gateway, Windows might try to route the relay
|
||||
connection through the tunnel itself. That would break the tunnel.
|
||||
|
||||
Client startup should:
|
||||
|
||||
@@ -396,7 +431,8 @@ Client startup should:
|
||||
6. detect and neutralize TAP default-route takeover
|
||||
```
|
||||
|
||||
The TAP should be preferred for the party LAN subnet, but it must not steal general internet traffic.
|
||||
The TAP should be preferred for the party LAN subnet, but it must not steal
|
||||
general internet traffic.
|
||||
|
||||
Also strongly recommend uncommon LAN party subnets:
|
||||
|
||||
@@ -409,9 +445,10 @@ bad: 192.168.178.0/24
|
||||
|
||||
Duplicate subnet with a remote user’s home LAN will be painful.
|
||||
|
||||
## Relay placement / latency
|
||||
### Relay placement / latency
|
||||
|
||||
Relay-as-data-path is the right MVP. It makes the product work through NAT immediately.
|
||||
Relay-as-data-path is the right MVP. It makes the product work through NAT
|
||||
immediately.
|
||||
|
||||
But latency becomes:
|
||||
|
||||
@@ -421,7 +458,10 @@ client → relay → gateway
|
||||
|
||||
So relay location matters.
|
||||
|
||||
For Europe/Germany-focused usage, put the relay near the expected players and LAN site, e.g. Frankfurt/Nuremberg/Amsterdam depending on hosting. Later, add direct QUIC path attempts with relay fallback, but do not block MVP on NAT traversal.
|
||||
For Europe/Germany-focused usage, put the relay near the expected players and
|
||||
LAN site, e.g. Frankfurt/Nuremberg/Amsterdam depending on hosting. Later, add
|
||||
direct QUIC path attempts with relay fallback, but do not block MVP on NAT
|
||||
traversal.
|
||||
|
||||
Design the room protocol so future modes are possible:
|
||||
|
||||
@@ -431,7 +471,7 @@ mode = direct-p2p
|
||||
mode = direct-failed-relay-fallback
|
||||
```
|
||||
|
||||
## Logging / diagnostics
|
||||
### Logging / diagnostics
|
||||
|
||||
Phase 1 should log heavily.
|
||||
|
||||
@@ -473,9 +513,9 @@ Broadcast traffic flowing
|
||||
Warning: TAP received default route, adjusted metric
|
||||
```
|
||||
|
||||
## Phase plan
|
||||
### Phase plan
|
||||
|
||||
### Phase 1: prove the illusion
|
||||
#### Phase 1: prove the illusion
|
||||
|
||||
Manual, ugly, real.
|
||||
|
||||
@@ -500,7 +540,7 @@ Success criteria:
|
||||
- one real LAN game discovers or joins a LAN server
|
||||
```
|
||||
|
||||
### Phase 2: multi-client
|
||||
#### Phase 2: multi-client
|
||||
|
||||
```text
|
||||
- multiple Windows clients
|
||||
@@ -512,7 +552,7 @@ Success criteria:
|
||||
- reconnect handling
|
||||
```
|
||||
|
||||
### Phase 3: safety and correctness
|
||||
#### Phase 3: safety and correctness
|
||||
|
||||
```text
|
||||
- L2 control-plane filters
|
||||
@@ -524,7 +564,7 @@ Success criteria:
|
||||
- better malformed-frame handling
|
||||
```
|
||||
|
||||
### Phase 4: product UX
|
||||
#### Phase 4: product UX
|
||||
|
||||
```text
|
||||
- Windows installer
|
||||
@@ -536,9 +576,11 @@ Success criteria:
|
||||
- logs export button
|
||||
```
|
||||
|
||||
Driver signing and TAP bundling must be validated early. `tap-windows6` is the right kind of driver, but Windows driver installation/signing is a product risk, not something to handwave. ([GitHub][1])
|
||||
Driver signing and TAP bundling must be validated early. `tap-windows6` is the
|
||||
right kind of driver, but Windows driver installation/signing is a product risk,
|
||||
not something to handwave. ([GitHub][1])
|
||||
|
||||
### Phase 5: better security and latency
|
||||
#### Phase 5: better security and latency
|
||||
|
||||
```text
|
||||
- invite tokens / auth
|
||||
@@ -549,7 +591,7 @@ Driver signing and TAP bundling must be validated early. `tap-windows6` is the r
|
||||
- regional relay selection
|
||||
```
|
||||
|
||||
## Explicit non-goals
|
||||
### Explicit non-goals
|
||||
|
||||
For MVP, do not build:
|
||||
|
||||
@@ -565,14 +607,29 @@ For MVP, do not build:
|
||||
- full internet VPN mode
|
||||
```
|
||||
|
||||
## One-sentence version
|
||||
### One-sentence version
|
||||
|
||||
Build a **Rust Windows TAP client + public QUIC relay + Linux AF_PACKET gateway** that carries one small-MTU Ethernet frame per QUIC datagram, gives each remote player a unique virtual MAC on the real LAN, filters dangerous L2 control traffic, and keeps the physical LAN gateway as the only machine touching the real LAN.
|
||||
Build a **Rust Windows TAP client + public QUIC relay + Linux AF_PACKET
|
||||
gateway** that carries one small-MTU Ethernet frame per QUIC datagram, gives
|
||||
each remote player a unique virtual MAC on the real LAN, filters dangerous L2
|
||||
control traffic, and keeps the physical LAN gateway as the only machine touching
|
||||
the real LAN.
|
||||
|
||||
[1]: https://github.com/OpenVPN/tap-windows6?utm_source=chatgpt.com "OpenVPN/tap-windows6: Windows TAP driver (NDIS 6)"
|
||||
[2]: https://man7.org/linux/man-pages/man7/packet.7.html?utm_source=chatgpt.com "packet(7) - Linux manual page"
|
||||
[3]: https://man7.org/linux/man-pages/man7/capabilities.7.html?utm_source=chatgpt.com "capabilities(7) - Linux manual page"
|
||||
[4]: https://datatracker.ietf.org/doc/html/rfc9221?utm_source=chatgpt.com "RFC 9221 - An Unreliable Datagram Extension to QUIC"
|
||||
[5]: https://docs.rs/quinn/latest/quinn/struct.Connection.html?utm_source=chatgpt.com "Connection in quinn - Rust"
|
||||
[1]:
|
||||
<https://github.com/OpenVPN/tap-windows6?utm_source=chatgpt.com>
|
||||
"OpenVPN/tap-windows6: Windows TAP driver (NDIS 6)"
|
||||
[2]:
|
||||
<https://man7.org/linux/man-pages/man7/packet.7.html?utm_source=chatgpt.com>
|
||||
"packet(7) - Linux manual page"
|
||||
[3]:
|
||||
<https://man7.org/linux/man-pages/man7/capabilities.7.html?utm_source=chatgpt.com>
|
||||
"capabilities(7) - Linux manual page"
|
||||
[4]:
|
||||
<https://datatracker.ietf.org/doc/html/rfc9221?utm_source=chatgpt.com>
|
||||
"RFC 9221 - An Unreliable Datagram Extension to QUIC"
|
||||
[5]:
|
||||
<https://docs.rs/quinn/latest/quinn/struct.Connection.html?utm_source=chatgpt.com>
|
||||
"Connection in quinn - Rust"
|
||||
|
||||
I want a mono-repo, Rust code, crates into a "crates" folder, one cargo workspace.
|
||||
I want a mono-repo, Rust code, crates into a "crates" folder, one cargo
|
||||
workspace.
|
||||
|
||||
Reference in New Issue
Block a user