Files
wolfenstein-et/relay/README.md
T

3.2 KiB

etrelay

UDP relay + master heartbeat for the Wolfenstein: Enemy Territory server, running on the front server (replaces its UDP 27960 DNAT rule / nginx stream block).

players / masters ──> front :27960 (etrelay) ══wg══> 10.66.0.10:27960 (nginx stream) ──> ET 10.0.1.103:27960
  • Proxy: one upstream socket per client address, packets forwarded as-is both ways, session dropped after 2 min of silence.
  • Heartbeat: every 5 min, getinfo to the ET server; if it answers, heartbeat EnemyTerritory-1 to the masters from the public socket. When it stops answering, one heartbeat ETFlatline-1.

Masters check (getChallenge, getInfo) the address the heartbeat came from: the public :27960. Those packets go through the relay like any client, the ET server answers them, and the master lists the front public address.

How it works in detail, with diagrams: ENGINE.md.

Usage

etrelay <UPSTREAM> [--listen 0.0.0.0:27960] [--master host:port]... [--debug]

Default masters: etmaster.idsoftware.com:27950 (id Software, the one ET 2.60b clients query) and etmaster.net:27950 (ET: Legacy community). Passing --master replaces both.

--debug logs sessions (open/close, packet counts), connectionless packets by command name only (getinfo, getstatus, connect...: no arguments, connect carries the userinfo), probes and heartbeats. In-game packets are only counted.

probe 10.66.0.10:27960: up
ET server 10.66.0.10:27960 is up
heartbeat EnemyTerritory-1 -> etmaster.net:27950 (91.220.53.121:27950)
session + 91.220.53.121:27950 (2 active)
91.220.53.121:27950 -> ET  getChallenge (27 B)
91.220.53.121:27950 <- ET  challengeResponse (32 B)
91.220.53.121:27950 -> ET  getInfo (22 B)
91.220.53.121:27950 <- ET  infoResponse (303 B)
session - <player>:27960: 5321 packets to ET, 4876 from ET

Deploy with it: make deploy ARGS=--debug, back to normal with make deploy.

Build

make build     # dynamic (glibc)
make static    # static (musl), runs on any x86_64 Linux
make release   # both

Artifacts land in dist/, named <name>-v<version>-<target triple> with a .sha256 checksum:

dist/etrelay-v0.1.0-x86_64-unknown-linux-gnu    # dynamic
dist/etrelay-v0.1.0-x86_64-unknown-linux-musl   # static

Deploy

  1. Relay (static binary + systemd unit on ionos): make deploy
  2. Front: remove what captured UDP 27960 before etrelay, or players bypass it:
    • the DNAT rule (PostUp/PostDown in /etc/wireguard/wg0.conf, then wg-quick down wg0 && wg-quick up wg0); iptables -t nat -S | grep 27960 must print nothing
    • the nginx stream block (proxy/nginx/nginx.conf in the pve repo): make -C proxy deploy-nginx from there
  3. ET server server.cfg: stop its own heartbeats, they leave through the home box with the wrong IP:
    set sv_master1 ""
    set sv_master2 ""
    set sv_master3 ""
    set sv_master4 ""
    set sv_master5 ""
    

Check

make logs                                        # "ET server ... is up"
ssh ionos tcpdump -ni any udp port 27950         # heartbeat out, getChallenge/getInfo in, answers out

The server then shows up on the master (in-game server browser).