ICTSC2025 本戦 問題解説: [5023] 今夜のIRC
問題文
概要
[22:10:45] * wind ([email protected]) has joined #home-lan
[22:10:50] <wind> ついに建ててしまったな
[22:11:05] <~wave> お家ネットワークでIRC始めた
[22:11:20] <wind> わろた 時代錯誤も甚だしいな
[22:11:45] <~wave> あ、なんかお前のIP 10.0.0.2 だけど
[22:12:02] <wind> そういうお前も 10.0.0.2。
[22:12:15] <~wave> ほんとうだ、なんでだろう
[22:12:40] <~wave> あと新しいマシンいれたけど
[22:12:55] <~wave> なんかうまくlinkしてくれない
[22:13:10] <wind> ドキュメント読んだか?
制約
- 各ホスト
5023-sv1,5023-sv2で、 docker stack を用いて、 InspIRCd が TLS モードで起動している- stack 名は
irc, service 名はirc_inspircd - コンテナの image は InspIRCd
- ローカルの認証局(step-ca)が環境に存在しており、
5023-caが担っている- 各ホストマシンは、その認証局を信頼するよう設定済みである
- 証明書は
acme.shを用いて発行済で、service に secret として組み込まれている - 証明書について、その有効期間が本日もつならば、十分であるとしてよい
- stack 名は
- ホスト名
vespertilio.irc.internal,myotis.irc.internalそれぞれは 各マシンの/etc/hostsに登録されており、それぞれ10.200.1.1,10.200.1.2が割り当てられている10.200.1.1,10.200.1.2は5023-sv1,5023-sv2がそれぞれ持っている
- ホスト名
ca.internalは 各マシンの/etc/hostsに登録されており、10.200.1.100が割り当てられており、 それは5023-caが持っている - IRCクライアントとサーバーの接続およびサーバー間リンクでは、TLSを使用すること
初期状態
5023-h1からweechatを起動しvespertilio.irc.internalにつないだうえで- サーバが認識する当該クライアントの接続元アドレスが
10.200.1.200ではない /linksと打ってmyotis.irc.internalとの link が確認できない
- サーバが認識する当該クライアントの接続元アドレスが
5023-h1からweechatを起動しmyotis.irc.internalにつないだうえで- サーバが認識する当該クライアントの接続元アドレスが
10.200.1.200ではない /linksと打ってvespertilio.irc.internalとの link が確認できない
- サーバが認識する当該クライアントの接続元アドレスが
終了状態
5023-h1からweechatを起動してvespertilio.irc.internalにつないだうえで- サーバが認識する当該クライアントの接続元アドレスが
10.200.1.200である /linksと打ってmyotis.irc.internalとの link が確認できる
- サーバが認識する当該クライアントの接続元アドレスが
5023-h1からweechatを起動してmyotis.irc.internalにつないだうえで- サーバが認識する当該クライアントの接続元アドレスが
10.200.1.200である /linksと打ってvespertilio.irc.internalとの link が確認できる
- サーバが認識する当該クライアントの接続元アドレスが
- 上記の状態が永続化されている
- 特に
docker service update --force irc_inspircdなどによって container が再作成されても、終了状態が維持される
- 特に
接続情報
| ホスト名 | IPアドレス | ユーザ | パスワード |
|---|---|---|---|
5023-sv1 |
192.168.23.1 |
user |
ictsc2025 |
5023-sv2 |
192.168.23.2 |
user |
ictsc2025 |
5023-ca |
192.168.23.3 |
user |
ictsc2025 |
5023-h1 |
192.168.23.4 |
user |
ictsc2025 |
解説
証明書の有効期限が切れている
acme.sh を使って、証明書を再作成する。
acme.sh --install-cert -d vespertilio.irc.internal \
--key-file /srv/inspircd/tls/key.pem \
--fullchain-file /srv/inspircd/tls/fullchain.pem
acme.sh --install-cert -d myotis.irc.internal \
--key-file /srv/inspircd/tls/key.pem \
--fullchain-file /srv/inspircd/tls/fullchain.pem
有効期限は1日だが、制約は満たしているので問題ない。
送信元が10.0.0.2になる問題
docker ingressを介さず、直接hostから受けるようにする。
stack.yml の ports の項目を以下に変更
ports:
- target: 6697
published: 6697
protocol: tcp
mode: host
- target: 7001
published: 7001
protocol: tcp
mode: host
これによって NAT されないので、送信元の IP アドレスが観測できるようになる。
linkが立ち上がらない問題
環境変数による設定がうまくいかないため、代わりに conf を作成し流し込む。
今回は mount を用いる。
すべての stack.yml
volumes:
- /srv/inspircd/conf/conf.d:/inspircd/conf.d:ro
LINK 系の環境変数は消しているとより丁寧である。
sv1 の /srv/inspircd/conf/conf.d/links.conf
<link name="myotis.irc.internal"
ipaddr="10.200.1.2"
port="7001"
sendpass="vesp-to-myo"
recvpass="myo-to-vesp"
sslprofile="main">
sv2 の /srv/inspircd/conf/conf.d/links.conf
<link name="vespertilio.irc.internal"
ipaddr="10.200.1.1"
port="7001"
sendpass="myo-to-vesp"
recvpass="vesp-to-myo"
sslprofile="main">
<autoconnect period="30s"
server="vespertilio.irc.internal">
- sslprofile の名前は既存設定から探す
- ipaddr は直打ちが前提で、そうでないと container 上で名前解決をする必要があり、地獄を見る
docker stack rm irc
docker stack deploy -c stack.yml irc
で container が再作成されても、設定が維持されることを確認する。
採点基準
300点
- 証明書を作成し直した(加点なし)
- 接続元が 10.200.1.200 と認識された 50点
- linkが成立した 250点
講評
Internet Relay Chat と呼ばれる、古き良きプロトコルを使用した、「今の時代に IRC !?」としたかった問題でした。
15チーム中9チーム満点で、おそらく初見、もしくはほとんど触ったことないであろうプロトコルをその場で解決したのでしょうか。拍手👏
……と言っても、この問題の本筋は IRC はあまり関係ないというオチでした。
見掛け倒しな問題になってしまってすみません。
解法についてですが、どのチームも作問者が想定していた解答ではありませんでした。
7000番ポートを開いたり(本当は7000は plain text な link で使うべき)、同一 Docker Swarm 内で link 張ったり(独立したホスト同士で繋げてほしかった)、設定の生成スクリプトを直に変更したりなど……。
わざと制約は緩くして、好きに解いていただきたいと思っていましたが、正直、IRC の自由度の高さをナメていました。
ところで今の時代に IRC はどうなんでしょうか……。
個人を認証するのに外部のサービスが必要って時点で、今の時代には合わないものになっているかなぁ……。
雑記
vespertilio は ヒナコウモリ属、myotis は ホオヒゲコウモリ属である。(それぞれのリンクは、その属の代表的な種)
これらは、とあるゲームで知ったので組み込んでみた。
この問題のタイトルも、そのゲーム関連が由来である。