/
カテゴリー

ICTSC2021 夏の陣にご参加いただいた学生の皆様、お疲れ様でした。

今回のICTSC2021 夏の陣は前回のICTSC2020の運営と新しいメンバー、それに加えて機材の提供や作問などでご助力いただいたスポンサー様方のおかげでなんとか開催し無事終了することができました 。参加していただいた方々につきましては、ここで培った知識・技術を今後に活かしていただければと思います。

今回出題した問題の問題文、及び問題解説を公開します。
ぜひ今後の研鑽にご利用いただければと思います。

Container

止まらない

dockerをインストールしただけなのに…

k8s

クラウドネイティブは難しい…

Webサイトにアクセスできない

Linux

頑固なindex.html

キャッシュサーバ立てたけど…

Program

Webサーバが立ち上がらない

ンジンエックス

iscsi

iscsi targetにログインできない!

Routing

対向につながらにな。。

パケットが通らない!

なんでだ!?

Security

L or R?

DHCPv6

インターネット契約って大変だ!

アドレスが配布できない・・・

SSH

SSH繋がらなくなった

VPN

テレワーク推進部

Web

サーバ気象予報

何もしてないのに壊れた!

 /
カテゴリー

概要

Go言語でWebアプリ開発を行っています。アプリのプロジェクトディレクトリは/home/user/testにあり、このディレクトリでmake runを実行することでアプリを起動することができます。
しかし、Ctrl+Cで終了させることができないため、他のターミナルからdocker stopコマンドを叩いています。
大変なのでCtrl+Cで終了させたいです。どうすればできますか?

前提条件

  • host上に追加でパッケージをインストールしてはいけない。

初期状態

  • /home/user/testにGo言語で書かれたWebアプリがある
  • /home/user/testをカレントディレクトリにし、make runするとアプリを起動することができる
  • Ctrl+Cで終了できない
  • docker stopで終了させることができる

終了状態

  • サーバーの状態は採点には影響しません
  • 以下の内容を回答してください
    1. Ctrl+Cで終了させる方法
    2. Ctrl+Cで終了できない理由

解説

この問題では、docker runを実行する際に-itオプションを指定していないためCtrl+Cで終了できなくなっていました。

-i, –interactive コンテナの STDIN にアタッチ

-t, –tty 疑似ターミナル (pseudo-TTY) を割り当て

https://docs.docker.jp/engine/reference/commandline/run.html

 /
カテゴリー

概要

HostA から HostB への通信経路を冗長化しようとしているが、なぜかつながらない。原因を究明してつながるようにしてほしい。

前提条件

  • HostBは触れない
  • ルータのconfig を変更してはいけない

初期状態

HostA から HostB(192.168.19.129) に ping が通らない

終了状態

デフォルトゲートウェイの冗長化をして、HostA から HostB(192.168.19.129) に ping が通るようにしてほしい

解説

初期状態でRTA,SWB間は物理的に切れています。

HostAのstatic route を書き間違い
RTAにstatic route で流れているのでvrrp の仮想IPに設定しなおします

delete protocols static route 192.168.19.128/25 next-hop 192.168.19.2
set protocols static route 192.168.19.128/25 next-hop 192.168.19.126

VRRPで上流側のインターフェースのUP/DOWNを確認するヘルスチェックのスクリプトを書いたつもりが下流側のインターフェースをチェックしていたので下記のように書き換える

  • RTA(/config/scripts/vrrp-check.sh)
#!/bin/vbash
source /opt/vyatta/etc/functions/script-template
if ping -c 1 192.168.19.129 &> /dev/null
then
        configure
        set high-availability vrrp group group1 priority '150'
        commit
        exit
else
        configure
        set high-availability vrrp group group1 priority '50'
        commit
        exit
fi
  • RTB(/config/scripts/vrrp-check.sh)
#!/bin/vbash
source /opt/vyatta/etc/functions/script-template
if ping -c 1 192.168.19.129 &> /dev/null
then
        configure
        set high-availability vrrp group group1 priority '140'
        commit
        exit
else
        configure
        set high-availability vrrp group group1 priority '40'
        commit
        exit
fi
 /
カテゴリー

概要

あなたはネットワーク開発事業部で働いています。ある日、コーヒーを飲んでいると、あなたの上司は次のようなことをいいました。

今、我が社では、新しい技術を使ってみようという取り組みがあって、Segment Routingっていうのをやってみることになったんだ。だけど、上手く通信ができなくて困っているんだ。君はスーパーエンジニアだって聞いているからこんな問題ちょちょいのちょいだよな!

あなたはスーパーエンジニアなので、この問題を解決してください。

C11, C12, C21, C22

これらの機器は顧客を模した機器です。

ログイン情報

  • ホスト名: 192.168.12.1
  • ユーザ名: user
  • パスワード: ictsc2021

補足

ログイン情報に記されたマシンにログインすると以下のようなプロンプトが表示されます。この画面で1, 2, 3, 4を選択することで所望の機器にログインすることができます。これらの機器は顧客を模した環境なので、設定を変更してはいけません。

R1, R2

これらの機器では、顧客ごとにVPNの設定が行われています。このうち、R1のみが設定変更が可能です。R1, R2はFRRを用いて経路を交換しています。

ルータの初期設定に必要なファイルは、/data/setup-interfaces.sh に保存されており、setup-interfaces.service を用いて設定しています。

ログイン情報

  • ホスト名: 192.168.12.101
  • ユーザ名: user
  • パスワード: ictsc2021

前提条件

  • SRv6以外のプロトコルを利用してL3VPNを実現してはいけません
    • 上司が悲しんでしまいます

初期状態

  • C11 <-> C21, C12 <-> C22でpingを飛ばしても到達しない

終了状態

  • C11 <-> C21, C12 <-> C22でpingが通る
  • C11 <-> C22のように顧客をまたいだ通信ができない
    • 何らかの方法を用いて、顧客の仮想ネットワークが分離されていることを示してください

解説

こんにちは。この問題を作問したえると(proelbtn)です。この問題は、LinuxのネットワークスタックやSegment Routingに関する問題です。

背景

問題文にある通り、今回の問題では「R1, R2間でSegment Routingを使ってL3VPNを張りたいが、設定が上手く行ってないので疎通が取れない」という問題です。文章中のSegment Routingに触れる前に、普通のIPルーティングについて考えてみましょう。通常、ルータは、宛先IPアドレスのみを見てパケットを転送します。そのため、パケットがどこを中継して宛先に転送されるのかを、送信者が決定することはできません。

通常のルーティングに対し、送信者がパケットの経由地を指定することができるソースルーティングという転送方式があります。この方式では、送信者(もしくはパケットの転送者)が「そのパケットが通るべき経由地」をいくつか指定することができます。ソースルーティングには、パケットの経由地を全て指定するようなStrict Source Routingと、パケットの経由地をいくつか指定し、その間がどのように転送されるのかは問わないLoose Source Routingの二種類に分けることができます。そして、Segment Routingは後者のLoose Source Routingの一つです。

Segment Routingでは、Segmentと呼ばれるパケットに対する命令のリストをパケットにくっつけて転送することで、自由にパケットを操作することができるようになります。Segmentには様々な種類がありますが、よく使われるものについてはRFC8986で定義されています。例えば、次のようなものが定義されています。

  • End: 特に何もせずに次の経由地へ転送する
  • End.T: 指定されたIPv6ルーティングテーブルを見てパケットを転送する
  • End.DT4: パケットをdecapsし、指定されたIPv5ルーティングテーブルを見てパケットを転送する

パケットにSegmentのリストを格納する時に、何らかの形式にエンコードして格納する必要があります。MPLSのラベルとしてエンコードするような方式をSR-MPLSと、IPv6のアドレスとしてエンコードするような方式をSRv6と呼びます。SRv6の場合、Segmentの情報は以下のようにしてIPv6のアドレスにエンコードされます。

問題解説

まずはじめに、router01に入り、VRF100のルーティングテーブルを見てみます。すると、172.31.2.0/24は、encap seg6 mode encap segs 1 [ 2001:db8:2::100 ] dev eth1 scope linkという処理をするように設定されています。

[email protected]:~$ ip route show vrf vrf100
172.31.1.0/24 dev eth2 proto kernel scope link src 172.31.1.254
172.31.2.0/24  encap seg6 mode encap segs 1 [ 2001:db8:2::100 ] dev eth1 scope link

この処理中の、encap seg6というキーワードで検索をかけると、実際の設定がどのように行われるのか知ることができます。

https://www.apresiatac.jp/blog/20190311947/

先ほどのip routeの結果は、「2001:db8:2::100というセグメントを、Segment Routing Headerに付与してパケットを転送しようとしている」という意味です。ですが、tcpdumpでパケットを確認してみても、パケットが転送されている様子は見られません。

[email protected]:~$ sudo tcpdump -ni eth2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth2, link-type EN10MB (Ethernet), capture size 262144 bytes
11:02:57.970658 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 6039, seq 47, length 64
11:02:58.994595 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 6039, seq 48, length 64
11:03:00.018665 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 6039, seq 49, length 64
[email protected]:~$ sudo tcpdump -ni eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

カーネルパラメータを確認すると、以下のように、net.ipv4.ip_forwardが0になっています。この状態では、転送されるパケットはdropされてしまいます。同様に、net.ipv6.conf.all.forwardingも0になっています。

[email protected]:~$ sudo sysctl -a | grep net.ipv4.ip_forward
net.ipv4.ip_forward = 0
net.ipv4.ip_forward_update_priority = 1
net.ipv4.ip_forward_use_pmtu = 0

そのため、vtyshでFRRに入り、以下のような設定を行います。

[email protected]:~$ sudo vtysh

Hello, this is FRRouting (version 7.2.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

router01# conf t
router01(config)# ip forwarding
router01(config)# ipv6 forwarding
router01(config)#

この設定を入れると、パケットがSegment Routing Headerでカプセル化されて、eth1から送信されることが確認できます。ですが、この状態ではまだ、C21でパケットを受信しICMP Echo Replyが返るものの、C11でpingの応答を確認することはできません。同様に、C21からC11にpingを打つ場合でも、C11でパケットを受信することはできません。先ほどと同様にtcpdumpをすると、R1のeth1でパケットを受信できていないことが分かります。

R1のbgpdの様子を確認すると、R2から2001:db8:2::/64の経路を受信しています。今回の構成では、LocatorはBGPで広報されていることが分かりますが、R1はR2に2001:db8:1::/64を広報していません。この状態では、R2はパケットを転送することができません。そのため、R1のLocatorを広報するように設定します。

router01# show bgp ipv6 unicast
BGP table version is 2, local router ID is 192.168.12.101, vrf id 0
Default local pref 100, local AS 65001
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
               i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes:  i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
*  2001:db8::/64    fe80::9ea3:baff:fe2c:9be4
                                             0             0 65002 ?
*>                  ::                       0         32768 ?
*> 2001:db8:2::/64  fe80::9ea3:baff:fe2c:9be4
                                             0             0 65002 i

Displayed  2 routes and 3 total paths
[email protected]:~$ sudo vtysh

Hello, this is FRRouting (version 7.2.1).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

router01#
router01# conf t
router01(config)# router bgp 65001
router01(config-router)# address-family ipv6 unicast
router01(config-router-af)# network 2001:db8:1::/64

すると、C11から打ったpingの応答がR1のeth1までやってくることが分かります。そして、setup-interfaces.shで設定されたEnd.DT4に従って、パケットがdecapsされ、VRF100に転送されます。しかし、eth2からパケットは送出されません。

[email protected]:~$ sudo tcpdump -ni eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
08:24:54.616136 IP6 2001:db8::1 > 2001:db8:2::100: srcrt (len=2, type=4, segleft=0[|srcrt]
08:24:54.616606 IP6 2001:db8::2 > 2001:db8:1::100: srcrt (len=2, type=4, segleft=0[|srcrt]
08:24:55.640124 IP6 2001:db8::1 > 2001:db8:2::100: srcrt (len=2, type=4, segleft=0[|srcrt]
08:24:55.640715 IP6 2001:db8::2 > 2001:db8:1::100: srcrt (len=2, type=4, segleft=0[|srcrt]
08:24:56.664126 IP6 2001:db8::1 > 2001:db8:2::100: srcrt (len=2, type=4, segleft=0[|srcrt]
08:24:56.664688 IP6 2001:db8::2 > 2001:db8:1::100: srcrt (len=2, type=4, segleft=0[|srcrt]
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

[email protected]:~$ sudo tcpdump -ni vrf100
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vrf100, link-type EN10MB (Ethernet), capture size 262144 bytes
08:26:13.464173 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2347, length 64
08:26:13.464922 IP 172.31.2.1 > 172.31.1.1: ICMP echo reply, id 827, seq 2347, length 64
08:26:14.488462 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2348, length 64
08:26:14.489234 IP 172.31.2.1 > 172.31.1.1: ICMP echo reply, id 827, seq 2348, length 64
08:26:15.512094 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2349, length 64
08:26:15.512605 IP 172.31.2.1 > 172.31.1.1: ICMP echo reply, id 827, seq 2349, length 64
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel

[email protected]:~$ sudo tcpdump -ni eth2
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth2, link-type EN10MB (Ethernet), capture size 262144 bytes
08:26:18.584126 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2352, length 64
08:26:19.608089 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2353, length 64
08:26:20.632100 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2354, length 64
08:26:21.656082 IP 172.31.1.1 > 172.31.2.1: ICMP echo request, id 827, seq 2355, length 64
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel

これは、逆経路フィルターによってパケットが破棄されています。これは「あるパケットの応答は、受信したインターフェースから送られるか」どうかをチェックしています。End.DT4を実行した時点で、入ってきたインターフェースはVRFデバイスになっているものの、172.31.2.0/24の経路はeth1から送り出すというようになっています。このデバイスの不一致が原因でパケットが破棄されています。そのため、逆経路フィルターを無効化する必要があります。

[email protected]:~$ ip route show vrf vrf100
172.31.1.0/24 dev eth2 proto kernel scope link src 172.31.1.254
172.31.2.0/24  encap seg6 mode encap segs 1 [ 2001:db8:2::100 ] dev eth1 scope link
sudo sysctl net.ipv4.conf.all.rp_filter=0
sudo sysctl net.ipv4.conf.vrf100.rp_filter=0
sudo sysctl net.ipv4.conf.vrf200.rp_filter=0

すると、パケットが通ることが確認できます。

部分点について

  • net.ipv4.ip_forward, net.ipv6.conf.*.forwardingを有効にする(100点)
  • R1のLocatorを広報する(100点)
  • 逆経路フィルターを無効にする(100点)

感想

Linuxのネットワークスタックの設定のちょっとニッチな部分を突くような問題にしようと思っていたのですが、思いの他、Locatorの広報の部分で引っかかってしまっていて、解いてほしい部分じゃない部分に引っかかりを作ってしまったなとちょっと反省しています。ですが、最初想像していたよりは多くのチームが回答をしてくれていたのでとても嬉しかったです。

参考

  • https://datatracker.ietf.org/doc/html/rfc8402
  • https://www.segment-routing.net/images/201901-SRv6.pdf
 /
カテゴリー

概要

あなたはISPの従業員です。お客さんと契約し、お客さんの自宅にインターネット回線を提供します。
このISPはPPPoEではなくIPoE方式で接続します。
また通信はIPv6のみで行い、IPv4は使わないません。
IPv6アドレスはDHCPv6 Prefix delegationで降ってきます。

ところが、お客さんかISPのどちらかの設定ミスで、お客さんに正しくIPアドレスが割り振られないようです。

あなたはなんとかしてIPアドレスが割り振られるように直さないといけません。

問題環境

  • お客さんの自宅にはクライアント機器(client)があります
  • ISPにはエッジルーターがあり、ISP内部ネットワークと繋がっています。お客さんとも繋がっています。

前提条件・注意事項

  • client-router間の接続を、DHCPv6 PDとRA+SLAACを利用した接続方法から変更しないでください。
  • できて間もないISPなため、お客さんはまだ一人しかいません。そのため必要であれば機器に割り当てるIPアドレス帯やIPアドレスを自由かつ大幅に変更しても構いません。
  • ICTSCの仕様上、 実際のIPv6インターネットを調達できなかったため初期状態以下のように擬似的にインターネットを再現しています。 先述したようにこれは変更しても構いません。
    • 擬似インターネット空間: 2001:db8::/32
    • 今回舞台となるISP用の空間: 2001:db8:0070::/32
    • クライアント用空間: 2001:db8:0070:2000::/52
      • クライアント1: 2001:db8:0070:2100::/56
      • クライアント2: 2001:db8:0070:2200::/56
      • クライアントn: 2001:db8:0070:2n00::/56
    • ISP内部ネットワーク用の空間: fd9b:b0bc:3e87:e000::/52
  • IPv6インターネットを用意できなかったので、実際には存在しないですがrouterのeth0より先にはプロバイダのネットワークが、またさらにその先にはインターネットが存在すると想定してください。
    • そのため、クライアントがrouterやインターネットに疎通できることを、routerのeth1に割り当てられたアドレスに疎通できることと見做しています。
  • 回答する際には、設定したコマンドだけではなく「なぜ動かなかったのか」の原因も究明し言及してください。
  • vyosの仕様上、DHCPv6 PDの使用時に委譲したプレフィックスのルートがルーターに注入されないバグがあります。それは仕様のため問題とは関係ありません。

初期状態

clientのeth1に、ルーターがRA+SLAACしているアドレスが自動設定されない

終了状態

clientのeth1に、ルーターがRA+SLAACしているアドレスが自動設定される

解説

この問題は、DHCPv6 PD の問題に見せかけた RA 問題でした。
まず、ISP側のルーターには初期状態で以下のような設定が入っています。

set interfaces ethernet eth1 address 'fd9b:b0bc:3e87:e000::1/64'
set service router-advert interface eth1 prefix 2001:db8:0070:2000::/52
// 以下略

これにより、eth1(クライアントとの接続NIC)に割り当てられたアドレスが管理用のULAなのに対して、RAでは2001:db8:0070:2000::/52という奇妙なアドレスを広告しています。これによりRAが失敗しているので、解決方法としてはRAを修正します。

delete service router-advert interface eth1
set service router-advert interface eth1 prefix ::/64

別解

アドレスを変更しても良い、という断りがあったため、ISP-クライアント間のネットワークで扱うアドレスをGUAに変更する場合も解答としてみなしました。

delete interfaces ethernet eth1 address 'fd9b:b0bc:3e87:e000::1/64'
set interfaces ethernet eth1 address '2001:db8:0070:1000::1/64'
set service router-advert interface eth1 prefix 2001:db8:0070:1000::/64

またこの場合、RAだけ変更してもeth1のアドレスを変更していない場合は、RA自体は飛びLLAでのルーティングはできますが、ルーターがGUAを使ってクライアントに疎通できない(GUAに対する経路が入らない)ため部分点としています。

補足

  • GUA: グローバルユニキャストアドレス
  • ULA: ユニークローカルアドレス
  • LLA: リンクローカルアドレス
  • DHCPv6 PD: DHCPv6 Prefix Delegation

総評

DHCPv6 PDのサーバー側を触ったことがないと、つい移譲するアドレスと移譲に扱うネットワークのアドレスを混同しがちなので、二つのアドレスは異なるサブネットでも良い、と気づけるかがポイントでした。

DHCPv6 PDのクライアントやプロキシーは、自宅ラックをNTTのNGNなどに接続する際によく使いますが、サーバーとしての設定をしたことがある人はおそらく少ないと思います。
それにもかかわらず、粘り強く問題を解き見事正解の解答を導き出したチームが複数おり、作問者として大変嬉く思います。