design.md 2.5 KB

Context

Both servers (relay and landing) run as proxy endpoints. Clients are already configured to route China traffic directly via Surge rules. Any China-destined traffic that reaches the servers is unwanted. We need server-side enforcement to drop outbound connections to CN IP ranges.

Goals / Non-Goals

Goals:

  • Block outbound TCP/UDP to China IP ranges on both servers using ipset + iptables
  • Automate CN IP list download and periodic refresh
  • Idempotent Ansible role applicable to all hosts

Non-Goals:

  • Blocking inbound from China (servers need to accept connections from Chinese clients)
  • DNS-level blocking
  • Application-layer filtering

Decisions

1. ipset + iptables over raw iptables rules

Use ipset to store the China CIDR list as a hash:net set, then a single iptables rule referencing the set. This is far more efficient than thousands of individual iptables rules.

Why over nftables: iptables + ipset is universally available on Ubuntu/Debian and simpler to manage via Ansible. nftables sets would also work but add migration complexity.

2. IP list source: ipdeny.com aggregated zones

Use https://www.ipdeny.com/ipblocks/data/aggregated/cn-aggregated.zone for the China CIDR list. It's a widely-used, frequently updated, plain-text list of CIDR blocks.

Why over MaxMind GeoLite2: No account/license required. Plain text format is trivial to load into ipset. Aggregated format minimizes the number of entries.

3. Refresh via cron

A daily cron job downloads the latest CN zone file and reloads the ipset. The update script is idempotent — it creates a temporary set, swaps it atomically, then destroys the old one.

4. iptables rule placement

The iptables rule is inserted in the OUTPUT chain to block traffic originating from the server itself (proxy daemon forwarding). A corresponding FORWARD chain rule is not needed since these servers don't act as network routers.

Risks / Trade-offs

  • [IP list accuracy] → ipdeny.com may lag behind real-time IP allocations. Mitigation: daily refresh keeps it reasonably current; exact accuracy is not critical for this use case.
  • [Legitimate CN access blocked] → If a server needs to reach a Chinese API (unlikely for proxy servers), it would be blocked. Mitigation: add specific IPs to an allowlist variable if needed.
  • [ipset persistence across reboot] → ipset sets are in-memory and lost on reboot. Mitigation: the update script runs at boot via a systemd service, and the cron job refreshes daily.