Overview
Apex is a lab machine located in E4-07-11. It uses two network interfaces with policy-based routing:
- WiFi (
wlo1) — default route, internet, Tailscale - Ethernet (
enp6s0) — NUS campus network, inbound access (SSH, ping)
The system uses dual policy routing (interface-based + source-based) to ensure traffic arriving on Ethernet replies via Ethernet, avoiding asymmetric routing failures.
Network Interfaces
| Interface | Role | IP |
|---|---|---|
wlo1 | Default route, internet, Tailscale | 172.24.x.x |
enp6s0 | Campus network access | 10.246.87.232 |
tailscale0 | Overlay network | Bound to WiFi |
Network Topology
graph TB subgraph Internet WEB["🌐 Internet"] TS["🔒 Tailscale Network"] end subgraph "NUS Campus" GW["NUS Gateway<br/>10.246.80.1"] CAMPUS["Campus Devices<br/>(SSH, ping)"] end subgraph "Apex — E4-07-11" WIFI["wlo1 (WiFi)<br/>172.24.x.x<br/>Primary route"] ETH["enp6s0 (Ethernet)<br/>10.246.87.232<br/>Campus route"] HOST["Apex<br/>Linux Host"] end WEB <-->"default route<br/>(table main)"<--> WIFI TS <--> "tailscale0<br/>(bound to wlo1)" <--> WIFI CAMPUS <--> "campus traffic<br/>(table campus)" <--> ETH WIFI --- HOST ETH --- HOST style WIFI fill:#4a9,color:#fff style ETH fill:#48d,color:#fff style HOST fill:#f90,color:#fff style GW fill:#999,color:#fff
Routing Logic
flowchart LR IN["Incoming packet<br/>from campus"] --> ETH["Arrives on<br/>enp6s0"] ETH --> RULE1{"iif enp6s0<br/>rule match?"} RULE1 -->|"Yes"| CAMPUS["→ table campus<br/>→ reply via enp6s0"] LOCAL["Local process<br/>generates reply"] --> RULE2{"from 10.246.87.232<br/>rule match?"} RULE2 -->|"Yes"| CAMPUS OUT["Outbound traffic<br/>(internet)"] --> MAIN["→ table main<br/>→ via wlo1"] style RULE1 fill:#48d,color:#fff style RULE2 fill:#48d,color:#fff style CAMPUS fill:#4a9,color:#fff style MAIN fill:#f90,color:#fff
The Problem
Without policy routing:
- Incoming campus traffic arrives via
enp6s0 - Replies go out via
wlo1(default route) - Connection fails due to asymmetric routing
Using only iif enp6s0 is not enough — locally generated replies also need to go via enp6s0.
Setup
1. Disable default route on Ethernet
nmcli connection modify enp6s0 ipv4.never-default yes
nmcli connection modify enp6s0 ipv4.ignore-auto-dns yes2. Add routing table
Edit /etc/iproute2/rt_tables, add:
100 campus
3. Add both policy routing rules
ip rule add from 10.246.87.232 lookup campus
ip rule add iif enp6s0 lookup campus| Rule | Purpose |
|---|---|
from 10.246.87.232 | Routes locally generated replies via enp6s0 |
iif enp6s0 | Routes forwarded/arriving traffic back via enp6s0 |
4. Add campus route
ip route add default via 10.246.80.1 dev enp6s0 table campus5. Make it persistent
Create /etc/NetworkManager/dispatcher.d/10-enp6s0-policy-routing:
#!/bin/bash
IFACE="$1"
if [ "$IFACE" = "enp6s0" ]; then
ip route replace default via 10.246.80.1 dev enp6s0 table campus
ip rule show | grep -q "from 10.246.87.232 lookup campus" || \
ip rule add from 10.246.87.232 lookup campus
ip rule show | grep -q "iif enp6s0 lookup campus" || \
ip rule add iif enp6s0 lookup campus
fichmod +x /etc/NetworkManager/dispatcher.d/10-enp6s0-policy-routingTraffic Summary
| Traffic Type | Interface |
|---|---|
| Internet / Tailscale | wlo1 |
| Campus inbound (SSH, ping) | enp6s0 |
| Replies to campus traffic | enp6s0 |
Verification
ip rule
# Expected:
# from 10.246.87.232 lookup campus
# from all iif enp6s0 lookup campus
ip route show table campus
# Expected: default via 10.246.80.1 dev enp6s0Key Insight
Multi-NIC asymmetric routing requires both rules:
- Interface-based (
iif) — handles forwarded traffic - Source-based (
from) — handles locally generated replies
Using only one will fail silently.
See Also
- NUS Network Configuration — 802.1X and general NUS network setup