Maple

Maple

Explore the best networking technology for Civilization 6 - WireGuard + udp2raw

Design Concept#

The multiplayer online mode of Civilization VI has long been criticized.

The official "Internet" online mode is undoubtedly unfriendly to Chinese players, as unstable international links combined with occasional firewall interference result in extremely high latency and frequent disconnections. Since Civilization's online play is based on the UDP protocol, many players have thought of using tools like Zerotier/easyN2N to create a virtual local area network, directly using P2P tunneling, along with WinIPBroadcast to forward the game's 255.255.255.255 room search broadcasts to the virtual network card, or using a more advanced tool—injciv6. It hooks into Civilization's sending and receiving operations, changing the original broadcast to unicast (which allows it to route correctly to the virtual network card). However, new issues arose during actual gameplay: ISPs implemented very unfriendly QoS policies for UDP traffic, often leading to packet loss after a period of time. Once critical packets are lost, Civilization temporarily kicks players out of the room for reloading, displaying "Player data is out of sync," which usually takes nearly half a minute, greatly affecting game progress. (In our group of six, at least one person disconnects almost every two turns, and occasionally everyone disconnects.)

To address this, we can disguise UDP packets as TCP packets through some clever means to gain the trust of ISPs and reduce the frequency of packet loss. If everyone played Civilization on Linux machines, using the more efficient phantun would be great; however, this is not very realistic, so we opted for the multi-platform supported udp2raw.

Placing udp2raw at the exit of each player's networking tool while ensuring that each guest player can connect to the host player makes P2P networking impractical. We need a virtual local area network relayed by a supernode to ensure that data between nodes is bi-directionally reachable. Therefore, we adopted WireGuard (a UDP-based communication tunneling tool) as the networking solution, deploying the WireGuard server and udp2raw (in server mode) on a public server, and then deploying the WireGuard client and udp2raw (in client mode) on each player's personal computer to meet our needs!

The designed topology is roughly as follows, with udp2raw layered over WireGuard:

network

Server Deployment Method#

Prerequisites: A public IP address. The system is based on the Debian 11 distribution.

Install Software#

sudo apt update
sudo apt install wireguard

# Download the udp2raw release from GitHub, install it to /usr/local/bin/ and ensure PATH includes it
# Test
udp2raw --help

Enable System Port Forwarding#

Uncomment/add the following content in /etc/sysctl.conf:

net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Execute the following command to apply the settings:

sudo sysctl -p

Generate Key Pairs#

cd /etc/wireguard

# Adjust the default permissions of files in the directory to 600
umask 077

wg genkey | tee server.key | wg pubkey > server.key.pub

This will create the server's private key file server.key and public key file server.key.pub in the current directory.

Then generate key pairs for each client one by one:

# Change the "10" number to n, generating (n-1) key pairs, starting from index 2
seq 2 10 | xargs -I{} sh -c 'wg genkey | tee client{}.key | wg pubkey > client{}.key.pub'

Write WireGuard Configuration File#

sudo su

echo "
[Interface]
PrivateKey = $(cat server.key)
Address = 10.8.0.1/24
DNS = 8.8.8.8
MTU = 1280
ListenPort = 4321

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE;
PostUp = rm -f /var/log/udp2raw.log
PostUp = nohup udp2raw -s -l 0.0.0.0:54321 -r 127.0.0.1:4321 -a -k 'testpasswd' --raw-mode faketcp &> /var/log/udp2raw.log &
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE
PostDown = killall udp2raw || true
" > wg0.conf

# Loop through each client public key file and append corresponding [Peer] entries
for client_key in client*.key.pub; do
    public_key=$(cat "$client_key")
    peer_number=$(echo "$client_key" | grep -o '[0-9]\+')
    # Calculate AllowedIPs based on the peer number (must NOT have client1)
    allowed_ip="10.8.0.${peer_number}/32"
    echo "[Peer]
PublicKey = $public_key
AllowedIPs = $allowed_ip
" >> wg0.conf
done

Note that we silently started udp2raw when starting WireGuard and redirected its logs to /var/log/udp2raw.log.

Start the Service and Configure the Firewall#

sudo systemctl enable wg-quick@wg0 --now
sudo ufw allow 54321/udp

Client Configuration Method#

First, securely transfer the client key pairs generated on the server.

Install and Configure WireGuard#

Download WireGuard from the official website. After downloading, install it normally, and then create a new configuration. (Using client3 as an example, the Address needs to be changed accordingly)

[Interface]
PrivateKey = .....   # client3.key
Address = 10.8.0.3/24  # your private IP
DNS = 8.8.8.8
MTU = 1280

[Peer]
PublicKey = .....   # server.key.pub
Endpoint = 127.0.0.1:3333
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25

Install and Configure udp2raw#

First, download udp2raw_multiplatform from GitHub and place the executable file in a directory included in your PATH.

The udp2raw faketcp on Windows is a bit more complicated and requires manual firewall configuration. Ensure that your Windows native firewall is enabled, then execute this command in an administrative shell. The -g option means it won't start any services but will output two commands that you need to execute manually to adjust the firewall settings. Note: If the public IP changes later, this step needs to be redone.

# Replace 123.xxx.xx.x with the actual public IP
udp2raw -c -l 0.0.0.0:3333 -r 123.xxx.xx.x:54321 -k "testpasswd" --raw-mode faketcp -g

This step may prompt you to install a certain network module for Windows; just search online to install it. If successful, copy and execute the last two commands it gives you. Finally, execute the command without -g in a normal shell, and never close this shell.

# Replace 123.xxx.xx.x with the actual public IP
udp2raw -c -l 0.0.0.0:3333 -r 123.xxx.xx.x:54321 -k "testpasswd" --raw-mode faketcp

Usage#

Keep udp2raw running in the foreground, start the WireGuard tunnel, and use UDP testing tools like easyN2N to test connectivity between clients.

Then start Civilization VI, and on each guest computer, use injciv6 in client mode to inject, entering the host's virtual LAN IP 10.8.0.2, and you will be able to discover and join the room!

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.