この記事は 天久保 Advent Calendar 2022 の 18 日目の記事です。
はじめに
最近、コンピュータネットワーク周辺に興味のある私の友達が AS 番号を取得していました。なんとなく面白そうだったので、私も取得してみることにしました。
すると、契約時になぜか 280 個のグローバル IPv6 アドレスが無料で付いてきたのです。今回はこの資源を利用した遊びの 1 つを紹介します。
AS 番号とは
AS 番号とは、世界中にある Autonomous System(自律システム)それぞれを一意に定めるための番号です。では、自律システムとは何でしょうか。
ASは、統一された運用ポリシーによって管理されたネットワークの集まりであり、 BGPのような外部経路制御プロトコルによる管理対象となります。
統一された運用ポリシー……?よくわからないので、実在する AS を見てみることにしましょう。例えば、以下のような AS が存在します。
名前 | AS 番号 |
---|---|
So-net | AS2527 |
筑波大学 | AS37917 |
さくらインターネット | AS9370, AS9371, AS7684, …… |
AS15169, …… |
これらの AS を持つ組織は、その内に様々な部署や研究室、または拠点を持っており、そこで利用されているネットワークの資源を何らかの方法で管理していることが推測されます。それなりの規模がある組織で AS 番号が取得されている様子がわかります。
上に挙げた「さくらインターネット」は複数個の AS 番号を持っていますが、https://www.sakura.ad.jp/peering/ によればリージョンごとに上 3 つの AS 番号を利用してネットワークの運用をしているようです。このように、必ずしも 1 組織 1 AS のみ持つという訳ではありません。
Google も AS 番号を持っていますが、検索結果に 32 個も出てきたので省略しました*1。おそらく、買収した企業の AS 番号を Google LCC 名義に変更するのを何度も繰り返すなどのことをしているからではないかと思います。
AS 番号とグローバル IPv6 アドレスの取得
AS 番号とグローバル IPv6 アドレスは https://www.securebit.ch/internet/resources/autonomous_system から取得することができました。このとき、RIPE NCC の地域に住んでいない人は https://www.securebit.ch/server/internet_exchange から IX サーバーを借りる必要もありました。これら 2 つの費用を合わせると、初期費用 43,368 円(2022/10/03 時点)が必要でした。
/44 Bundle と書いてあるのに /48 の prefix がバンドルされていましたが、むしろ /48 よりも大きなものを頂いても困ってしまうので助かったような気分になりました*2。
AS 番号新規登録申請をした際には、上記ウェブサイトでは特にグローバル IPv6 アドレスが付いてくる旨は商品一覧ページに記載されていなかった気がします。しかし、申請フォームに各種情報を入力していたところ、「もしグローバル IP アドレスを持っていないなら無料で /48 のグローバル IPv6 アドレスを貸してあげるよ」という文言が書いてある欄を発見し、これはとんでもなく太っ腹であることだな、と思いながら BGP で広報できるグローバル IPv6 アドレスを 280 個*3貸していただくことにしました。
しかしながら、/48 のグローバル IPv6 アドレスを一人で使い切ることなどできるでしょうか(いや、できません)。そこで、贅沢なことですが 264 個のグローバル IPv6 アドレスを用いたクイズを作成してみることにしました。もっとも、これだけ使ってみたところで、まだ全体の 1/65536 しか使えていない計算になる訳ですが……。
AnyIP について
通常、Linux では、ある 1 つの IPv6 アドレス(ここでは 2001:db8:beef:cafe::1
とする)に対する通信を受け取ってアプリケーションで処理するには ip addr add local 2001:db8:beef:cafe::1/64 dev dummy1
のようなコマンドを発行し、ネットワークインターフェイスに 1 個ずつ IP アドレスを割り振ってあげる必要があります。
しかしながら、この理屈でいくと、仮に 2001:db8:beef:cafe:babe::/80
以下のすべてのアドレスに応答したいとなったら、前述のコマンドを 248 個の IP アドレスの分だけ叩くことになりそうですね。そんなことは到底していられません。
そこで、Linux カーネルには AnyIP と名付けられた機能が実装されています。
The AnyIP feature of the Linux kernel allows you to bind a complete IPv4 or IPv6 subnet to your system.
Instead of adding all addresses manually to the kernel you can tell it to bind a complete subnet.
これは、例えば 2001:db8:beef:cafe:babe::/80
以下のすべてのアドレスに応答したいとなったら ip -6 route add local 2001:db8:beef:cafe:babe::/80 dev lo
と一度叩くだけでそれを実現させてくれる機能です。今回は、この機能を活用して 264 個のグローバル IP アドレスを用いたクイズを作ってみることにします。
問題!正解のグローバル IPv6 アドレスはどれかな?
注意:このクイズは、IPv6 の接続性がある環境でしか遊べません……。もし繋がらなかった場合は、IPv6 の接続性を持つマシン(大学の計算機など)に SSH して、そのマシンから curl
コマンドを使ってアクセスするなどの工夫をしてみてください。
問題文:
http://[2a10:2f00:18a:2000::]:8080/
(問題文おわり)
上記の情報のみで、それっぽい正解が見つけられた方は、おめでとうございます。
ヒント
↓
↓
↓
↓
↓
(はてなブログって IPv6 アドレスを直接書いてリンクにすることができないようですね。もしクリックしてアクセスできないことに困っている場合は、コピーしてブラウザの上部バーに貼り付けてみてください)
↓
↓
↓
↓
↓
(もうすぐヒントが見えます)
↓
↓
↓
↓
↓
- (念のため):
http://[2a10:2f00:18a:2000::1]:8080/challenge
にアクセスしてみましたか? - 264 個のグローバル IPv6 アドレスを用いたクイズであることに注意
- IPv6 アドレスの表記方法:https://www.nic.ad.jp/ja/basics/terms/ipv6-text-representation.html
2a10:2f00:18a:2000
から始まる様々な IPv6 アドレスを指定してアクセスしてみよう- 要素数が 264 の全順序集合と考えると、使えるアルゴリズムは……?
- 頭から確定させてみよう
正解
http://[2a10:2f00:18a:2000:2525:beef:4649:babe]:8080/challenge
見つけられた方は、おめでとうございます!!*4
ブラウザの URL 入力欄で少しずつ数値を変えていけば、いつか見つけられるはずです。賢くやるならば、64 回ぐらい試行錯誤することで正解に辿りつけたのではないかと思います。
もっとも、16 進数が使える場面で書かれがちなフレーズが含まれているので、カンが良い方は 64 回以下で当てたかもしれません。
想定解法(その 1)
まず http://[2a10:2f00:18a:2000::]:8080/
にアクセスしてみると、
You can make requests to: /host, /challenge
というメッセージが表示されます。そこで、http://[2a10:2f00:18a:2000::]:8080/host
にアクセスしてみると、自分がアクセスしている IPv6 アドレスと同一のものが帰ってくることがわかります。また、http://[2a10:2f00:18a:2000::]:8080/challenge
にアクセスしてみると、何やら意味深なコメントが含まれた JSON が帰ってきます。
{"result":-1,"comment":"Too poor to be true (The answer is greater than the value you specified)"}
ここで、そういえばこれは 264 個もの IPv6 アドレスを使ったクイズであったということを思い出します。
2a10:2f00:18a:2000::/64
以下の IPv6 アドレスでアクセス可能なものは 2a10:2f00:18a:2000::
から 2a10:2f00:18a:2000:ffff:ffff:ffff:ffff
の 264 個です。
そこで、試しに http://[2a10:2f00:18a:2000:ffff::]:8080/challenge
にアクセスしてみます。すると、メッセージは以下の形式に変化します。
{"result":1,"comment":"Too rich to be true (The answer is smaller than the value you specified)"}
今度は「値」が大きすぎるという旨のメッセージに変わりました。ここまで来れば、だいたい察しがつきますね。
いろいろ試してみると、
http://[2a10:2f00:18a:2000:2fff::]:8080/challenge
では大きすぎて、
http://[2a10:2f00:18a:2000:1fff::]:8080/challenge
では小さすぎる
というメッセージを受け取るので、次に探索すべきは
2a10:2f00:18a:2000:2000
から
2a10:2f00:18a:2000:2fff
の間である、ということが判明します。これで、IPv6 アドレス下位 64 ビットのうちの上位 4 ビットを特定することができました。
これ以降は、この「大きすぎる」と「小さすぎる」の間をどんどん深掘りしていく作業になります。
想定解法(その 2)
以下のようなプログラムを書くことでも答えを導くことができました。
バグらせて無限にリクエストを送ることがないように注意!
おわりに
IPv6 アドレスがまだまだ余っているので、もし他によい遊び方がありましたら、ぜひ教えてください!*5
また、当 AS とピアリングすることに興味が出ましたら、ぜひご相談ください。当方、ピアリングの実験をしてみたいと常々思っています。
おまけ
サーバーで動いているプログラムのソースコードは以下のリンクから見ることができます。
https://gist.github.com/private-yusuke/d1bc5f3edaf720eb92747f305824f9d6