設計思路#
文明 6(Civilization VI)このゲームのマルチプレイヤーオンラインは常に批判されています。
公式の「インターネット」オンラインモードは、中国のプレイヤーにとっては明らかに不親切です。なぜなら、不安定な国際回線とファイアウォールの時折の干渉により、非常に高い遅延と頻繁な切断が発生するからです。文明のオンラインは UDP プロトコルに基づいているため、多くのプレイヤーは Zerotier/easyN2N などのツールを使って仮想 LAN を構築し、直接 p2p で穴を開けることを考えました。さらに、WinIPBroadcastを使用して、文明の255.255.255.255
の部屋検索ブロードキャストを仮想ネットワークカードに転送するか、より高度なツールであるinjciv6を使用します。これは、文明の送信、受信などの操作をフックし、元のブロードキャストを直接ユニキャストに変更します(これにより、ルーティングテーブルに従って仮想ネットワークカードに正しくルーティングされます)。しかし、実際のプレイ中に新たな問題が浮上しました。プロバイダーが UDP トラフィックに対して非常に不親切な QoS ポリシーを適用しており、一定の時間が経過するとパケットロスが発生することがよくあります。そして、重要なデータパケットが失われると、文明はプレイヤーを一時的に部屋から追い出して再読み込みを行い、「プレイヤーのデータが同期していません」と表示されます。通常、再読み込みには約 30 秒かかり、ゲームの進行に非常に影響を与えます。(私たち 6 人はほぼ毎 2 ターンごとに少なくとも 1 人が切断され、時には全員が切断されます)
これに対処するために、UDP パケットをいくつかの巧妙な手段で TCP パケットに偽装し、プロバイダーの信頼を得て、パケットロスの発生頻度を減らすことができます。すべての人が Linux マシンで文明をプレイする場合、性能の良いphantunを選択するのが良いですが、これは現実的ではないため、マルチプラットフォームをサポートするudp2rawを選択します。
udp2raw を各プレイヤーのネットワークツールの出口に配置し、各ゲストプレイヤーがホストプレイヤーに接続できるようにするのはあまり現実的ではありません。ノード間のデータが双方向に到達可能であることを保証するためには、スーパーノードを中継する仮想 LAN が必要です。したがって、WireGuard(UDP ベースの通信トンネルツール)をネットワーク構築のソリューションとして採用し、WireGuard サーバーと udp2raw(サーバーモード)を公衆インターネット上のサーバーにデプロイし、WireGuard クライアントと udp2raw(クライアントモード)を各プレイヤーの個人コンピュータにデプロイすることで、私たちの要求を実現できます!
設計のトポロジー図は大体以下の通りで、udp2raw は WireGuard の外側にあります:
サーバーのデプロイ方法#
前提条件:パブリック IP アドレスを持っていること。システムは Debian 11 ディストリビューションを例にします。
ソフトウェアのインストール#
sudo apt update
sudo apt install wireguard
# GitHubからudp2rawリリースをwgetし、/usr/local/bin/にインストールし、PATHに含まれていることを確認
# テスト
udp2raw --help
システムのポートフォワーディングを有効にする#
/etc/sysctl.conf
に以下の内容を uncomment/add します:
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
以下のコマンドを実行して設定を有効にします:
sudo sysctl -p
キーペアの生成#
cd /etc/wireguard
# ディレクトリ内のファイルのデフォルト権限を変更、つまりデフォルト600
umask 077
wg genkey | tee server.key | wg pubkey > server.key.pub
これにより、現在のディレクトリにサーバーの秘密鍵server.key
ファイルと公開鍵server.key.pub
ファイルが作成されます。
次に、各クライアントのキーペアを一つずつ生成します:
# "10"の数字をnに変更し、(n-1)個のキーペアを生成、番号は2から始まります
seq 2 10 | xargs -I{} sh -c 'wg genkey | tee client{}.key | wg pubkey > client{}.key.pub'
WireGuard 設定ファイルの作成#
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
# 各クライアントの公開鍵ファイルをループして、対応する[Peer]エントリを追加
for client_key in client*.key.pub; do
public_key=$(cat "$client_key")
peer_number=$(echo "$client_key" | grep -o '[0-9]\+')
# ピア番号に基づいてAllowedIPsを計算(client1は含めてはいけません)
allowed_ip="10.8.0.${peer_number}/32"
echo "[Peer]
PublicKey = $public_key
AllowedIPs = $allowed_ip
" >> wg0.conf
done
WireGuard を起動する際に udp2raw を静かに起動し、そのログを/var/log/udp2raw.log
に出力することに注意してください。
サービスを起動し、ファイアウォールを設定#
sudo systemctl enable wg-quick@wg0 --now
sudo ufw allow 54321/udp
クライアントの設定方法#
まず、サーバーで生成したクライアントのキーペアを安全な手段で送信します。
WireGuard のインストールと設定#
公式サイトからWireGuardをダウンロードします。ソフトウェアを正常にインストールした後、新しい設定を作成します。(client3 を例に、Address は自分で変更する必要があります)
[Interface]
PrivateKey = ..... # client3.key
Address = 10.8.0.3/24 # あなたのプライベート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
udp2raw のインストールと設定#
まず、GitHub からudp2raw_multiplatformをダウンロードし、実行可能ファイルを環境変数 PATH のどこかのディレクトリに配置します。
Windows システム上の udp2raw faketcp は少し面倒で、手動でファイアウォールを設定する必要があります。Windows のネイティブファイアウォールが有効な状態であることを確認し、管理者シェルでこのコマンドを実行します。-g
は、サービスを起動せず、手動で実行する必要のある 2 つのコマンドを出力します。ファイアウォール設定を調整するためのものです。【注意:もし後でパブリック IP が変わった場合、このステップを再度行う必要があります】
# 123.xxx.xx.xを実際のパブリックIPに変更
udp2raw -c -l 0.0.0.0:3333 -r 123.xxx.xx.x:54321 -k "testpasswd" --raw-mode faketcp -g
このステップでは、Windows の特定のネットワークモジュールが不足しているというメッセージが表示されるかもしれません。インターネットで検索してインストールしてください。成功した場合、最後に表示された 2 つのコマンドを一つずつコピーして実行します。最後に、通常のシェルで-g
を外したコマンドを実行し、このシェルを常に閉じないでください。
# 123.xxx.xx.xを実際のパブリックIPに変更
udp2raw -c -l 0.0.0.0:3333 -r 123.xxx.xx.x:54321 -k "testpasswd" --raw-mode faketcp
使用方法#
udp2raw を前面で実行し、WireGuard トンネルを起動し、easyN2N などの UDP テストツールでクライアント間の接続性をテストします。
その後、文明 6 を起動し、各ゲストコンピュータでinjciv6をクライアントモードで注入し、アドレスにホストの仮想 LAN IP 10.8.0.2
を入力すると、部屋を発見して参加できるようになります!