概要

Sudden Strike 2 Gold に代表される古いゲームはマルチプレイモードに際し、 メーカーが中央集権的なサーバを持たずプレイヤー同士が P2P で接続することになっているものが多い。 一般的な家庭のデスクトップコンピュータで P2P 通信をするのは必要な設定が煩雑になりがちである。 特にコネクションをホストし待ち受ける側はコンピュータやブロードバンドルータのファイヤウォールの例外設定が必要になる。 加えて、ブロードバンドルータのセキュリティ設定に例外を設定することは外部からの不正アクセスのきっかけとなりやすい (要出典)。

本稿では、プレイヤーどうしが VPN で仮想ローカルネットワークに接続し、仮想的な P2P コネクションを張ってマルチプレイモードを遊ぶために必要な手順を記録する。 AWS EC2 インスタンスで wireguard VPN サーバを動作させ、また Windows Defender Firewall の設定をする。 この方法により、ブロードバンドルータは家庭用の標準的な設定のみで (incoming exception を設定せずに) P2P コネクションを確立できる。

現時点 2023-10-30T11:24:56+09:00 では、Windows Defender Firewall の設定が完成せず、ゲーム中は Windows Defender Firewall を無効にする必要がある。 Windows Defender Firewall が有効なまま、マルチプレイモードをプレイするために必要な適切で最小限な設定に関する考察と今後の展望は節 考察と展望 に示す。

以下インスタンスの設定・起動と VPN サーバ (wireguard) の設定・起動の手順を示す。

インスタンスを起動

EC2 インスタンスでは VPN サーバである wireguard を動かすだけなので、スペックは低くてもよい。 今回は、ブラウザによるインスタンス作成画面を眺めてて一番安そうだった t2.nano を選択した。 起動後にブラウザに表示された、今後 cli で起動するのに便利なコンフィグファイルを以下に記録しておく。 また、インスタンスイメージは特に理由はないが Amazon Linux にした。 今回は Amazon Linux のパッケーにマネージャ dnf から wireguard をインストールしているが、将来的にソースからビルドしたいので そのうち本当になんでもよくなる。

RunInstances

{
  "MaxCount": 1,
  "MinCount": 1,
  "ImageId": "ami-0bcf3ca5a6483feba",
  "InstanceType": "t2.nano",
  "KeyName": "ac2",
  "EbsOptimized": false,
  "BlockDeviceMappings": [
    {
      "DeviceName": "/dev/xvda",
      "Ebs": {
        "Encrypted": false,
        "DeleteOnTermination": true,
        "SnapshotId": "snap-084c2075ab6dfcdeb",
        "VolumeSize": 8,
        "VolumeType": "standard"
      }
    }
  ],
  "NetworkInterfaces": [
    {
      "AssociatePublicIpAddress": true,
      "DeviceIndex": 0,
      "Groups": [
        "<groupId of the new security group created below>"
      ]
    }
  ],
  "TagSpecifications": [
    {
      "ResourceType": "instance",
      "Tags": [
        {
          "Key": "Name",
          "Value": "ss2_vps"
        }
      ]
    }
  ],
  "PrivateDnsNameOptions": {
    "HostnameType": "ip-name",
    "EnableResourceNameDnsARecord": true,
    "EnableResourceNameDnsAAAARecord": false
  }
}

CreateSecurityGroup

{
  "GroupName": "launch-wizard-1",
  "Description": "launch-wizard-1 created 2023-10-28T06:00:55.874Z",
  "VpcId": "vpc-fca0ad9b"
}

AuthorizeSecurityGroupIngress

{
  "GroupId": "<groupId of the security group created above>",
  "IpPermissions": [
    {
      "IpProtocol": "tcp",
      "FromPort": 22,
      "ToPort": 22,
      "IpRanges": [
        {
          "CidrIp": "0.0.0.0/0"
        }
      ]
    }
  ]
}

インスタンスのポートを開ける

インスタンスのセキュリティグループ→インバウンドルールを編集して、 SSH 用の通信と wireguard 用の通信を許可する。 デフォルト設定を使うならば大抵の場合、22 tcp と 51820 tcp & udp を開けることになる。 51820 は tcp か udp のどちらかのみでよいかもしれない。

この設定も CLI でできるようにする。

インスタンスに wireguard をインストール・起動

アプリケーションのインストール

$ sudo dnf install wireguard-tools

インターフェースの設定

sysctl net.ipv4.ip_forward=1           # 永続化する場合は別コマンドが必要。今回は都度インスタンスを作成するイメージなため永続化なし。
ip link add dev wg0 type wireguard
ip a
ip address add dev wg0 172.16.100.1/24
wg setconf wg0 myconfig.conf
umask 077
wg genkey > privatekey
wg pubkey < privatekey > publickey

public key はプレイヤ (peer) に共有する。

wiregurad のコンフィグ

ゲームをプレイするだけなら、下記 AllowedIPsx.x.x.x/32 として割り当ててしまったほうが管理しやすい。

[root@ip-172-31-32-29 wireguard]# cat /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
ListenPort = 51820

[Peer]
PublicKey = <PEER1_PUBLIC_KEY>
AllowedIPs = 172.16.100.0/24    ; An acceptable address range for a peer to use in CIDR format.
[Peer]
PublicKey = <PEER2_PUBLIC_KEY>
AllowedIPs = 172.16.100.0/24

wireguard の有効化

wg setconf wg0 wg0.conf

クライアントの設定

ここまででサーバーができたので、あとはクライアントに wireguard クライアントをそれぞれインストールする。

[Interface]
PrivateKey = <PEER1_PRIVATE_KEY>
Address = 172.16.100.6/24          ; A desired address of your computer itself in the virtual LAN.

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
AllowedIPs = 172.16.100.0/24       ; An acceptable adress range determined by the server
Endpoint = xxx.xxx.xxx.xxx:pppp    ; The address & port of the VPN server

接続確認

wireguard による VPN に接続てきているか確認

wireguard クライアントの ‘ログ’ タブで、接続に成功すれば

2023-10-28 18:17:02.510: [TUN] [sudden_vpn] Receiving handshake response from peer 1 (52.195.222.216:51820)

というメッセージが現れ、keepalive packet をやり取りしているようなログが現れる。接続できていないと、handshake に失敗した旨が表示される。

2023-10-29 16:30:33.310: [TUN] [sudden_vpn] Handshake for peer 1 (52.195.222.216:51820) did not complete after 5 seconds, retrying (try 2)

wireguard クライアントは、接続に失敗しても目立ったエラーを出さないので注意。

また、サーバで wg コマンドを発行すれば接続状況がわかる。

[root@ip-172-31-32-29 wireguard]# wg
interface: wg0
  public key: oF33SfCPSaA8J4kGdNxs4eX6xmwG3zA2du/BbYUlMRk=
  private key: (hidden)
  listening port: 51820

peer: KgT2btZJ7JUvzrxLtW6Xnwgx2Y/T0sirzxpzLqzRvno=
  endpoint: xxx.xxx.xxx.xxx:pppp
  allowed ips: 172.16.100.6/32
  latest handshake: 1 minute, 16 seconds ago
  transfer: 67.26 KiB received, 728 B sent

略

あとは python で webserver を建てるなどし、peer 同士で接続し合うことでも VPN の動作を確認できる。

client の firewall の設定

理想的には、ゲームをプレイするのに必要な適当で最小限な firewall rule を作成したいものだが、現状見つけられていない。 あまりよいワークアラウンドではないが、 Windows Defender Firewall を無効化すればゲームはできる。

考察と展望

可能ならば Firewall を完全に無効にはしたくないので、どうにか例外を設定することで Firewall は動作させたままゲームをしたい。 Windows Defender Firewall は、プロセス単位で incoming packet をポート番号ごとに許可したり禁止したりをやるのが一般的なようだ。 firewall の詳細設定を除くと、許可されたプロセスは追加の設定をしない限り、任意のポートで incoming packet が許可されることが伺われる。

Windows Defender Firewall による通信可能アプリケーションの設定

今回、上図のように GAME_EXE (sudden strike 2 の実行可能ファイル名。‘詳細’ から確認可能) を許可してみたが、マルチプレイはできなかった。 具体的にはホストされたゲームを発見できず、片方のプレイヤが join できない。

Windows Defender Firewall を無効にすればマルチプレイができることを確認したことから、Windows Defender Firewall が原因であり、設定で適当でない可能性がかなり高い。 Windows Defender Firewall は例外として指定されたプロセスについてすべての通信を許可するという過程が正しければ、通信を担うのは GAME_EXE ではない異なるプロセスなのだろう。

タスクマネージャを確認したところ、GAME_EXE のエントリーのカラムの先頭に展開できそうな右三角アイコンがあり、 これをクリックすると「Microsoft DirectPlay ヘルパー」と呼ばれるプロセスが現れた。

Sudden Strike 2 の子プロセスのようなもの

Microsoft DirectPlay ヘルパーが通信を担っている可能性があるので、これを例外に追加し (画像左ウィンドウ)、マルチプレイを試してみる。 もしこれがそうではない場合は、特定は難しい。 やれることとしては、linux でいう binutils のようなツール find_syscalls でバイナリから fork などの systemcall を探して生成しているプロセスを探したり system_uses_fork、 または Sudden Strike 2 のマルチプレイ部屋を作成する前と後でプロセスリストの diff をとったりする方法が考えられる。

References