48 lines
2.4 KiB
Markdown
48 lines
2.4 KiB
Markdown
# Egress of OpenVPN clients via a Hysteria2 tunnel (2026-09-30)
|
|||
|
|
|
||
|
|
Goal: all traffic of VPN clients leaves the internet through an exit node reached over an existing Hysteria2 client tunnel (`hytun`) on the VPN host.
|
||
|
|
|
||
|
|
```
|
||
|
|
OpenVPN client --udp/1194--> tun0 (172.20.1.1/24)
|
||
|
|
-> ip rule 102: from 172.20.1.0/24 -> table 100
|
||
|
|
-> table 100: default dev hytun (metric 10), blackhole default (metric 1000)
|
||
|
|
-> iptables nat POSTROUTING -s 172.20.1.0/24 -o hytun -j MASQUERADE
|
||
|
|
-> hytun (TUN of the Hysteria2 client) --QUIC/UDP 443--> exit node --> Internet
|
||
|
|
```
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- A running Hysteria2 client with a TUN device (`hytun`), a routing table (100) with `default dev hytun` and a `blackhole` fallback, and `rp_filter=2` (loose) on all/default/hytun (strict mode drops TUN replies).
|
||
|
|
- Hysteria server-side `socks5`/`http` outbounds are TCP-only, so UDP needs TUN + policy routing, not a SOCKS chain.
|
||
|
|
- The exit node needs no changes.
|
||
|
|
|
||
|
|
## Implementation (OpenRC service `ovpn-hytun`)
|
||
|
|
|
||
|
|
`depend: need hysteria-route; before openvpn`. On start:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
sysctl -qw net.ipv4.ip_forward=1
|
||
|
|
ip rule add priority 102 from 172.20.1.0/24 lookup 100
|
||
|
|
iptables -t nat -A POSTROUTING -s 172.20.1.0/24 -o hytun -j MASQUERADE
|
||
|
|
iptables -t mangle -A FORWARD -o hytun -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # and -i hytun
|
||
|
|
iptables -A FORWARD -s 172.20.1.0/24 ! -o hytun -j DROP # anti-leak
|
||
|
|
```
|
||
|
|
|
||
|
|
Rules are idempotent (`-C` before `-A`); `stop` removes them. Adjust `172.20.1.0/24` to the `server` network in `server.conf`. Persist `ip_forward` in `/etc/sysctl.d/`. Use POSIX `sh` in OpenRC scripts (no bash arrays).
|
||
|
|
|
||
|
|
## Properties
|
||
|
|
|
||
|
|
- Only the VPN subnet enters the tunnel; SSH, OpenVPN's own port (1194) and management traffic use the main table.
|
||
|
|
- If the Hysteria client dies, table 100 falls to `blackhole`: clients lose internet, they do not leak through `eth0`.
|
||
|
|
- Clients get public DNS (e.g. 1.1.1.1) that is resolved through the same tunnel.
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
| Check | Result |
|
||
|
|
|---|---|
|
||
|
|
| Node: TCP and UDP (DNS) through `hytun` | works |
|
||
|
|
| Reference (uid routed to `hytun`): external IP | exit node address |
|
||
|
|
| Real VPN client: `https://ifconfig.me` | exit node address (end-to-end test passed) |
|
||
|
|
| `ip rule`, `iptables -t nat -S POSTROUTING`, `rc-status` | rules present, services started |
|
||
|
|
|
||
|
|
Testing tip: a network namespace test that reuses the VPN subnet conflicts with a live `tun0`; test with a real client or a different, temporary subnet added to the rules.
|