ICTSC2025 本戦 問題解説: [1360] 通ってもいいですか

問題文

概要

あなたは拠点間接続について学ぶため、自宅と友達の家でWireGuardを使ってVPN接続を構築することになりました。 友達の家のサーバは、先輩から譲り受けた環境のIPアドレスだけを書き換えて wg-server として流用し、自宅のサーバは新しく wg-client としてWireGuardの設定を行いました。 しかし、設定を終えてインターフェースを起動したものの、互いの通信は全く確立せず、pingの応答が返ってきません。

制約

  • wg-server がListenしているWireGuardのポート番号を変更しないこと。
  • 各インターフェースに割り当てられたIPアドレスを変更してはならない。
  • WireGuardのインターフェース名を変更してはならない。
  • WireGuardの設定ファイルを新規作成してはならない。
  • 両サーバ共にreboot後も終了状態が維持されていること。

初期状態

  • wg-client からping 10.0.8.1を実行しても応答がない。

  • wg-server からping 10.0.8.2を実行しても応答がない。

終了状態

  • wg-client からping 10.0.8.1を実行すると応答が返ってくる。

  • wg-server からping 10.0.8.2を実行すると応答が返ってくる。


解説

クライアント側では公開鍵の不一致、エンドポイントのポート指定誤り、AllowedIPsによるCryptokey Routingの制限という3つの設定ミスが存在し、ハンドシェイクが成立しません。

サーバ側のOSには前の使用者が過去のコンテナ検証等で作成し、放置された仮想ブリッジインターフェース(VPNと重複するIP帯を主張している)が技術的負債として残置されており、ルーティングが競合している。

想定解法

clientのwireguardの設定を見にいくと、Peerセクションが色々間違っていることに気づく(PublicKey,Endpoint,AllowedIPs)

これを修正するため、先にserver側にログインして、publickeyを取得しておく

そして下記のように編集する

sudo su
cd /etc/wireguard/
vim wg0.conf

wg0.conf

[Interface]
PrivateKey = 0P9dze15vQgwsPm4VQ6blbloRdSdejhsROF3I9ELIWE=
Address = 10.0.8.2/24

[Peer]
PublicKey = bBl2BUud/HOxC7b1QoDyromN64Qme6lB4LssUwLwVgk=
Endpoint = 10.128.160.1:51820
AllowedIPs = 10.0.8.0/24

修正が完了したらサービスをリスタートする

sudo systemctl restart wg-quick@wg0

少し時間を置いてから、 wg showコマンドを打つ

root@1360-wg-client:/etc/wireguard# wg show
interface: wg0
  public key: K4yDJfilzgEOcQosbegaLfK/fz2Hr6tUoYnXMzuZkws=
  private key: (hidden)
  listening port: 45966

peer: bBl2BUud/HOxC7b1QoDyromN64Qme6lB4LssUwLwVgk=
  endpoint: 10.128.160.1:51820
  allowed ips: 10.0.8.0/24
  latest handshake: 1 minute, 20 seconds ago
  transfer: 124 B received, 532 B sent

これによりハンドシェイクはできていることが確認できるが、この時点ではpingは通らない

sudo tcpdump -i wg0 -n icmp というコマンドをserver側で打ったあとPingを打つ

ping 10.0.8.1

こうすることによって、server側で

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
16:29:45.723797 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 1, length 64
16:29:46.771987 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 2, length 64
16:29:47.795783 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 3, length 64
16:29:48.820007 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 4, length 64
16:29:49.843653 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 5, length 64
16:29:50.869558 IP 10.0.8.2 > 10.0.8.1: ICMP echo request, id 1105, seq 6, length 64
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

という結果が出来上がる

ここで、requestは届くが、応答がwg0から出ていないことが確認できます。

次に応答パケットがどこにあるかを確認するため、ip routeコマンドを使います

root@1360-wg-server:/home/ictsc# ip route
default via 192.168.60.254 dev eth0 proto static
10.0.8.0/25 dev br-40e13be8dda7 proto kernel scope link src 10.0.8.126 linkdown
10.0.8.0/24 dev wg0 proto kernel scope link src 10.0.8.1
10.128.160.0/30 dev eth1 proto kernel scope link src 10.128.160.1
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.60.0/24 dev eth0 proto kernel scope link src 192.168.60.1

この結果から、10.0.8.0/25 dev br-68da01e7461eと、dockerの存在が確認でき、Dockerが邪魔をしていることが確認できます。

次にこれを破壊するため、docker network lsで確認しに行きます

root@1360-wg-server:/home/ictsc# docker network ls
NETWORK ID     NAME               DRIVER    SCOPE
e69108b61e33   bridge             bridge    local
0eb441368479   host               host      local
c97d361ce96d   none               null      local
40e13be8dda7   old-k8s-test-net   bridge    local

そして最後、こいつを消します

root@1360-wg-server:/etc/wireguard# sudo docker network rm old-k8s-test-net
old-k8s-test-net

結果、pingが通るようになります。

root@1360-wg-server:/etc/wireguard# ping 10.0.8.2
PING 10.0.8.2 (10.0.8.2) 56(84) bytes of data.
64 bytes from 10.0.8.2: icmp_seq=1 ttl=64 time=1.39 ms
64 bytes from 10.0.8.2: icmp_seq=2 ttl=64 time=1.53 ms
root@1360-wg-client:/etc/wireguard# ping 10.0.8.1
PING 10.0.8.1 (10.0.8.1) 56(84) bytes of data.
64 bytes from 10.0.8.1: icmp_seq=1 ttl=64 time=4.66 ms
64 bytes from 10.0.8.1: icmp_seq=2 ttl=64 time=0.964 ms

ちなみにDocker自体を消してもOKだと思っています。

採点基準

  • PublicKey に wg-server の正しい公開鍵を指定している: 10%

  • Endpoint のポート番号を正しい値(51820)に修正している: 10%

  • AllowedIPs を自身のIPから、対向のネットワーク(10.0.8.0/24 等)に修正している: 10%

  • ルーティングを阻害しているDockerネットワークを特定し、無効化あるいは削除することでPingの応答を成立させている: 50%

  • 再起動後もDockerネットワークが復活せず、終了状態(疎通可能な状態)が維持されている: 20%

注意点

  • Dockerネットワークが原因として確認できていない場合、50%の分を無効にしました。(原因が特定できていないのにできた、はダメだと個人的に思うため。)

  • 制約違反の場合、点数は0としている。

講評

簡単な問題で、AIを使えば絶対に解ける問題でした。これからも発展していき、どんな問題も簡単に解決できるようになっていくのだと思います。
この問題のことと、私個人の意見として、原因を特定し、それがこれからも必要なのか、必要でないか、根本の意味を理解し、正しく取捨選択できるエンジニアになって欲しいと思います。