/

問題文

近年のゲーム市場拡大に感化され我が社でも仮想遊戯開発部が新設された。
新サービスに向けてオンラインゲームを試作し、制作環境での複数人対戦は仕様書通りの動作が確認されている。
しかし、ステージング環境ではなんらかの設定ミスにより動作に支障が生じた。
原因を調べ、仕様書通りに動作するようにしてほしい。
また、ゲームの仕様に脆弱性があれば合わせて報告してほしい。

制約

ゲーム自体のソースコードの改変は禁止。

スタート

ゲーム開始後、ユーザ登録を行ってもmainシーンに遷移しない。

ゴール

仕様通りにゲームがプレイできる。
local portが枯渇する仕様やパフォーマンスを指摘できている。
スコアを無限に増やせる脆弱性等を指摘できている。

解説

この問題は、取引先から仕様書を渡され、仕様通りにオンラインゲームを動作させるというものでした。

トラブルの内容

Webサーバ上では、以下のような現象が発生していました。
– ゲームがスタートしない
– 攻撃ができない・アイテムが取れない
– ランキングが反映されない

これらは、以下に挙げるトラブルが原因でした。

1. Redisの使用できるメモリが足りない

参加者の情報は、Redisサーバで管理されていましたが、設定ミスでmaxmemoryを1にしてしまっていました。
そのため、/etc/redis/redis.conf内のmaxmemoryを1gなどに変更する必要がありました。

2. ufwの開放しているポートが間違っている

ufwをセキュリティを考慮して有効にしていましたが、ゲームで使うポートを開けていないトラブルがありました。
そのため、正しく使うポートのみを解放する必要がありました。

3. 使えるローカルポートの数が制限されている

通常、ネットワーク通信をする側はローカルポートを消費します。使えるローカルポートの範囲はカーネルパラメータで設定することができます。このゲームは、redisにたくさんコネクションを貼るため、sysctlでパラメータをいじったのですが、ip_local_port_rangeの値を間違えて設定していたため、疎通が取れなくなっていました。
そのため、ポートの範囲を広げる必要がありました。

その他

このゲームはできるだけ短い間隔でudpによる通信を行い、その度に新しいコネクションをredisにはる仕様になっていました。
このため、パフォーマンスがどうしても制限されてしまいます。

また、ユーザIDは他のプレイヤーに通知されない仕組みになっていましたが、自分のIDはわかるため高さを偽装しスコアを伸ばす、または任意の座標に攻撃を行うことができる仕様的な脆弱性がありました。

そのため、この2点について言及されていた場合は加点の対象としました。

 /

ICTSC9 では問題 VM およびライフサーバ等の基盤としてオープンソースのプライベートクラウド基盤である OpenStack を使いました。バージョンは OpenStack Pike です。以下では、今回の OpenStack でどのような構成をとったかを解説します。

続きを読む

 /

クソ上司とはクソな上司のことです。今回のクソ上司は自分が納得しないと話に応じてくれないタイプの、いわば頑固な上司でした。
なぜ彼が生まれたかについては諸説ありますが、「ちょっと特殊な技術を触ってみたら思いのほかいろいろな問題を踏み抜いた」というのが実情のようです。
ちなみに当日「クソ神上司」の名札を付けて歩いていた人物はおそらく無関係でしょう。たぶん。

1問目

問題文

最近Webアプリを動かしているサーバーへの負荷が高かったので、業者に頼んで負荷を分散できる構成にしてもらった。
現在は192.168.21.20で動作しているらしいが、どうやらアプリケーションが不安定のようだ。トラブルを解決するためにはいくつかの情報が必要だが、正当な理由なくサーバーへのアクセスが許可されていない。
幸いにも同じセグメントにあるマシンは使えるので、まずはこの負荷分散の名前がどのようなものか知りたい。
このマシンを用いて、負荷分散の名前を理由とともに上司(運営)に報告すること。

注意事項

必ずclientを使うこと。clientを使わずに回答は不可能である。
動作確認にWebブラウザは使わずにcurlなどで確認すること。使った場合の動作は保証されない。

トラブルの概要

負荷分散の形式がわからない(これはトラブルですか?)

解説

最初のトラブル(?)は負荷分散の形式を特定する問題でした。
ポイントとなるのは注意事項にある「必ずclientを使うこと。clientを使わずに回答は不可能である。」の文言です。
同じセグメントにあるマシンを使わないと解けないということは、少なくともL2に関する何かが絡んでいるというところです。この点でピンときたチームもいるのではないでしょうか。

まずcurlなどで192.168.21.20へリクエストを送ってみると、レスポンスが返ってこないことがあるものの、Webページらしきものが見えます。
ここでtcpdumpを使いながらリクエストとレスポンスを眺めると、取得成功時に行きと帰りでMACアドレスが異なっていることに気づきます。
これはDSR (Direct Server Return) と呼ばれる手法で、レスポンスをリアルサーバから直接返すことでLBを経由せず、負荷をかけないようにすることができます。

よってMACアドレスが異なることをふまえた上でDSRであることが指摘できていれば正解です。

2問目

問題文

DSRであることを上司に伝えると、LB1台、アプリケーションサーバー2台という構成であることがわかった。
最初にも述べたが、ブラウザ (Chrome, Firefox, Safariなど) からアクセスすると他のマシンから一切アプリケーションに繋がらない。
DSRであることがわかったのでLBへのアクセスは許可されたが、まだアプリケーションサーバーへのアクセスは許可されていない。上司によると、パケットキャプチャを見ているとアプリケーションサーバーの片方にしかリクエストが来ていないので、負荷分散についてはLBに問題があると疑ってやまないようだ。
LBの設定を調査して、ブラウザからアクセスしても正常に動作するようにしてほしい。たまにレスポンスが返ってこないのはアプリケーションサーバーの問題だと確信しているが、LBの設定を直さないことには上司がアプリケーションサーバーへのアクセスを許可してくれない。

トラブルの概要

192.168.21.20にブラウザで接続したときにそれ以降のリクエストが届かなくなる

解説

この問題ではLBサーバへのアクセスが与えられます。
ログインして設定をいろいろ見てみると、keepalived+ipvsadmでL2DSRを構築していることがわかります。
また、実際にブラウザで192.168.21.20へアクセスしてみると、そのブラウザは繋がるのに他のクライアントからは一切繋がらなくなるという現象に直面します。
まずipvsadmコマンドでLBの状況を確認してみると、

~$ sudo ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.21.20:80 lc
  -> 192.168.21.71:80                Route   1      1          3
  -> 192.168.21.72:80                Route   1      0          4

192.168.21.71:80に対してActiveConnがずっと1になっていることがわかります。
また、スケジューリングアルゴリズムがlc (Least Connection) であることから残りのリクエストがすべて192.168.21.72:80に転送されていることがわかります。

/etc/keepalived/keepalived.confの中身を見ると、

vrrp_instance VI_1 {
  state MASTER
  interface ens3
  virtual_router_id 51
  priority 100
  nopreempt
  advert_int 1
  virtual_ipaddress {
    192.168.21.20
  }
}

virtual_server_group app_servers {
  192.168.21.20 80
}

virtual_server group app_servers {
  delay_loop 10
  lvs_sched rr
  lvs_method DR
  lb_algo lc
  protocol TCP

  real_server 192.168.21.71 80 {
    TCP_CHECK {
      connect_timeout 10
    }
  }
  real_server 192.168.21.72 80 {
    TCP_CHECK {
      connect_timeout 10
    }
  }
}

となっています。注目すべきはvirtual_server group app_serversの中身で、

lvs_sched rr
lb_algo lc

においてlvs_schedおよびlb_algoは全く同じ意味をもつパラメータです。現在はlb_algoは古いパラメータですが、まだ有効であるためlvs_sched rrが上書きされてしまっています。
このことからもスケジューリングアルゴリズムがlcに設定されていることがわかります。

これらの点から、原因はスケジューリングアルゴリズムがlcであることと、ブラウザがずっとコネクションを保持しているために正常に応答が返ってこないもう片方のサーバ(192.168.21.72)へずっとリクエストが転送されていることを指摘できていれば正解です。

3問目

問題文

LBのスケジューリングを指摘したところ、上司はアプリケーションサーバーの片方に問題があることを認めて両方のサーバーへのアクセスを許可してくれた。
VIP192.168.21.20のアプリケーションが正しく動作するように修正してほしい。
また、セキュリティ上の観点から192.168.21.0/26から直接アプリケーションサーバーへHTTPアクセスができないようにして欲しい。
再起動した時も正常な状態が維持されるようにすること。

トラブルの概要

192.168.21.20へのリクエストが返ってこないことがある
192.168.21.{11,12}へのHTTPリクエストが成功する

解説

3問目は2台のリアルサーバへのアクセスが与えられます。
192.168.21.11(app1)と192.168.21.12(app2)の2台存在しますが、いずれもkeepalivedのヘルスチェックを通っているように、LBからのリクエストは正常に行えるため、まずは問題があるサーバを特定するのがスタート地点です。
どちらのサーバにもimgconvというサービスがsystemdで登録されており、/opt/imgconv/imgconvにあるバイナリを起動してこれが80番で動いていることがわかります。
2問目のようにipvsadmコマンドで確認すると、192.168.21.72側へ振り分けられていないことがわかるので、サーバにログインしてapp2(192.168.21.12@ens3, 192.168.21.72@ens4)側が原因であるとわかります。
適当にDSRやkeepalivedで検索すると設定方法が出てきます。やり方はいくつかありますが、app1にはiptables, カーネルパラメータの設定がされていることがわかります。ただしこれらは永続化されていないため、iptables -Lsysctl -aなどで見つける必要があります。
app1に入っていた設定は以下の通りです。

iptables

*nat
-A PREROUTING -d 192.168.21.20/32 -j REDIRECT

sysctl (カーネルパラメータ)

net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.ens3.rp_filter=0
net.ipv4.conf.ens4.rp_filter=0

iptablesにはVIPへのリクエストをそのまま受け取るための設定が、sysctlにはMACアドレス書き換えに伴ったLinuxのセキュリティ機構を無効化するための設定が書かれています。
これらをapp2も適用するとまずはVIP(192.168.21.20)に対して常にリクエストが返ってくることが確認できます。

次に192.168.21.{11,12}へ直接HTTPリクエストができないようにします。これは単純にiptablesを書くだけで良いです。謝ってtcp/22を閉じて締め出されないようにするのを忘れないでください。

-A INPUT -i ens3 -p tcp --dport 22 -j ACCEPT
-A INPUT -i ens4 -j ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -j DROP

講評

1問目を正解できたチームは2チームのみで、いずれのチームも2問目も突破していました。DSR自体を知っていないと回答するのは難しかったように思います。
よくある誤答としてはVRRPがありました。VRRPはfirst hopで到達するルータが物理的に複数台ある構成のため、今回の問題とは全く関係がありません。keepalivedがVIPを使うためにVRRPを内部で使用しているため、頻繁に飛んでくるVRRPのパケットに気づいてそれについて答えた競技者がかなり多かったようです。
また、VRRPは負荷分散というよりかは冗長化を目的としています。今回のテーマが冗長化であっただけにちょっと意地悪だったかもしれません。ちなみに今回会場提供いただいたさくらインターネット様のサービス「さくらの専用サーバ」のロードバランサーにはDSR・非DSR構成の選択オプションがあります。意図せずしてわかりにくいヒントができてしまったのですが、気づいた方はいらっしゃいましたか?

 /

どうも、作問者のnasuと言います。

問題文

あるドメイン ict2.local はここ最近なりすまし対策・スパム対策に力を入れている。
そのため、送信ドメイン認証DMARC,SPFとDKIMの両方をpassしないとメールを受信してくれない。
自前に検証用のドメイン( ict1.local )・DNSサーバ・メールサーバを用意し、
送信ドメイン認証を導入して ict2.local にメールが届くように構築をしているのだがエラーが起きてメールが届かないようだ。
諸君にはエラーを解決し、 ict2.local にメールを届くようにしてほしい。

スタート

ict2.local に対してメールが送れない。

ゴール

ict2.local に無事メールが届き自動返信メールの中身を報告出来たらゴール。

情報

参加者が操作出来るサーバとインストールされているパッケージは以下の通りである。

  • 参加者側のドメイン情報: ict1.local
  • メールサーバ
  • postfix
  • mailx
  • opendkim
  • DNSサーバ
  • ssh情報
  • bind
  • 解答先のドメイン情報: ict2.local

トラブルの概要

この問題のトラブルは大きく3つあります。

  • mxレコードが解決されない
  • メールを送るとMXレコードが解決できないというログが/var/log/maillogから確認が出来ます。これはDNSサーバの53番ポートがfirewalldによって閉じられている為です。
  • SPF認証に失敗する
  • ict1.localのゾーンファイルのSPFレコードの書式が間違っている為失敗します。この問題はオンライン予選にも出ました。勉強してきた方はすぐに分かったのではないでしょうか。正しい書式に直してください。
  • dkim認証に失敗する
  • ict1.localのゾーンファイルに記載されている公開鍵が間違っているためdkim認証に失敗します。正しい鍵をゾーンファイルに記載してください。

解説

この問題を簡単に解くカギは/var/log/maillogを読んでいくことです。
メールが届かない原因がmaillogには書かれています。

解答例

  • mxレコードが解決されない
    dnsサーバ
$firewall-cmd --add-service=dns --permanent
$firewall-cmd --reload

別解はiptablesで開ける方法。

  • SPF認証に失敗する
/etc/named/ict1.zone
IN TXT "v=spf1 +ip4:192.168.10.11 ~all"
  • dkim認証に失敗する
  • 解答方法1 あらかじめmail.ict1.localサーバにおいてある正しいキーをゾーンファイルに記載して更新する
  • 解答方法2 新たに公開鍵と秘密鍵を生成してゾーンファイルに記載して更新する

採点基準

  • 自動返信の中身を報告 → 基準点
  • 中身を報告且つトラブル原因への言及 → 満点

講評

15チーム中4チームから解答があり3チームには基準点、1チームには満点を与えました。
どのトラブルもそうですが、ログを確認することを頭に入れておきましょう。

 /

問題文

VXLANでの通信を検証するように依頼された。
異なるサーバ上のVXLANインターフェースがお互いに通信できるようにしてほしいとのことだ。サーバ同士はソフトウェアルータを介してL3の疎通性がある。VXLANのアンダーレイ通信には、マルチキャストルーティングを利用してほしいそうだ。
前任者も設定を行ったようなのだが、上手くいかずに諦めてしまったらしい。どうにか設定を変更して、VXLANインターフェース同士が通信できるようにしてほしい。

制約

VXLANインターフェース間の通信は、マルチキャストルーティングを用いたVXLAN通信でなければならない。

スタート地点

Server 1/2のVXLANインターフェース vxlan42 から Server 2/1のVXLANインターフェース vxlan42ping が通らない。

ゴール地点

Server 1/2のVXLANインターフェース vxlan42 から Server 2/1のVXLANインターフェース vxlan42ping が通る。

トラブルの概要

「VXLANが繋がらない」は、L2延伸技術であるVXLANを用います。VXLANは、パケットをカプセル化することでL3ネットワークを超えてL2ネットワークを構成します。
この問題のトポロジーは以下のようになっています。

2台のVMが異なるL2ネットワークに属しており、VyOSによってルーティングされます。それぞれのVMの中にはVXLAN用のインターフェースがあり、これらは仮想的に同じL2ネットワークにあります。
この図のvxlan42から出たパケットがens3でカプセル化され、もう一方のVMのens3を通ってvxlan42に届き、カプセル化が解除されます。
VMのens3とVyOSによって作られるL3ネットワークをアンダーレイ、vxlan42によって作られるL2ネットワークをオーバーレイと呼びます。
一般に、VXLANでは、アンダーレイでのブロードキャストをオーバーレイでのマルチキャストで実装します。ブロードキャストはARPに必要です。オーバーレイがL3ネットワークなので、マルチキャストルーティングを行う必要があります。

この問題では、vxlan42同士が通信できないというトラブルが起こっています。 .67 の方のVMで以下を実行しても疎通が取れません。

$ ping -I vxlan42 10.0.0.3

解説

この問題で起こっているトラブルには要因が2つあります。
– vxlan42 から送られるパケットの TTL が 1 になっている
– VyOS がマルチキャストルーティングを扱えない

TTLについては、VMのVXLANインターフェースが原因です。VXLANインターフェースにTTLを明示的に設定しない場合、TTLが1のパケットが送信されます。 TTLはルーティングの度にデクリメントされ、0になるとパケットが破棄されてしまいます。そこで、VXLANインターフェースの設定を変更する必要があります。

VXLANはマルチキャストルーティングを用いると述べました。実際には、マルチキャストを用いない例もあるのですが、この問題ではマルチキャストを使うよう制約を設けました。ところが、VyOSの config をどのように設定してもマルチキャストルーティングを行うことができません。そのような設定項目がないからです。この問題では VyOS 1.1.7 を使っていますが、私の知る限りは設定方法がありません。
VyOSがマルチキャストルーティングを行うことができないので、パケットが破棄されてしまいます。
しかし、VyOSはDebianをベースにしたソフトウェアルータなので、様々な外部のパッケージを導入することができます。これにより、マルチキャストルーティングを行うことができるようになります。

解答例

まずはVMのVXLANインターフェースのTTLを増やします。
今回、VMのOSはUbuntu 16.04です。はじめ、/etc/network/interfaces に以下のようにVXLANインターフェースの設定が書いてあります。

auto vxlan42
iface vxlan42 inet manual
    pre-up ip link add vxlan42 type vxlan id 42 group 239.255.255.255 || true
    up ip address add 10.0.0.2/24 dev vxlan42 && ip link set vxlan42 up
    down ip link set vxlan42 down
    post-down ip link del vxlan42 || true

これを下記のように書き換えます。

auto vxlan42
iface vxlan42 inet manual
    pre-up ip link add vxlan42 type vxlan id 42 group 239.255.255.255 ttl 2 || true
    up ip address add 10.0.0.2/24 dev vxlan42 && ip link set vxlan42 up
    down ip link set vxlan42 down
    post-down ip link del vxlan42 || true

追加した項目は2行目の ttl 2 のみです。これで送信するパケットのTTLが設定されます。今回はルータを1台はさむ構成なので、TTLが2以上であれば良いです。

$ sudo service networking restart

以上のコマンドを実行すれば設定が反映されます。

続いて、VyOSがマルチキャストルーティングできるようにします。
これはあくまで一例ですが、以下のようにして、外部のリポジトリを登録します。

$ conf
$ set system package repository squeeze components 'main contrib non-free'
$ set system package repository squeeze distribution 'squeeze'
$ set system package repository squeeze url 'http://archive.debian.org/debian'
$ commit; save

ただし、このままでは以下のコマンドでのパッケージのアップデートに失敗します。

$ sudo aptitude update

これは、DNSサーバが設定されていないためです。

$ vi /etc/resolve.conf
nameserver 8.8.8.8

このように /etc/resolve.conf などを修正すれば、アップデートが実行できるようになります。
そして、マルチキャストルーティングのプロトコルであるPIMを扱うために、PIMDをインストールします。

$ sudo aptitude install pimd

インストールすれば自動的にプロセスが立ち上がり、マルチキャストルーティングが動作するようになります。ただし、インストールしてから動作するまでは少し時間がかかります。

以上の項目を完了すれば、以下のコマンドで疎通が取れるはずです。

$ ping -I vxlan42 10.0.0.3

講評

この問題を完全に解くことができたのは1チームだけでした。

余談

ちなみに、この問題はICTSC 8の運営での経験から思いつきました。ICTSC 8ではVXLANを使うことで、Mと手元機材が同じL2ネットワークにあるように見せました。この際、アンダーレイはOpenStackとJuniper機器で構成しました。

OpenStack では以下の設定を変える必要がありました。

  • VXLANインターフェースのTTL
    • OpenStackの設定で変更することができます
  • VXLANインターフェースのマルチキャストグループ
    • デフォルトではリンクローカルの 224.0.0.0/4 になっているので別のものに変更する
  • VXLANのポート番号
    • Juniperの機器はVXLANのポート番号として4789を使うのですが、Linuxのデフォルトは8742になっています
    • Linuxのカーネルパラメータで変更することができます

これらの経験から、TTLの変更を問題にすることを思いつきました。また、VyOSでVXLANを行うにあたって、マルチキャストルーティングができなさそうなことが検証段階で分かったので、それもトラブルとして加えました。