アドレスを計算する道具を作る
目標
アドレスとマスクを受け取って、ネットワークアドレス・ブロードキャスト・使える範囲・ホスト数を計算するツールをPythonで作り、そのツールで、同じサブネットかどうかの判定、アドレス範囲の分類、重なりの検査を行います。最後に、要求されたホスト数に合うプレフィックスを選んで、設計メモを残します。
なぜ重要なのか
ファイアウォールのルールも、ネットワークポリシーも、VPCの設計も、すべてこの計算の上に成り立っています。ところが、手で繰り返すと、いつか必ず間違え、間違いはたいてい障害が起きたあとで表に出ます。そのため、1回作っておいて使い続けるほうがよいのです。
特に/31と/32が重要です。ホスト数を「全体から2を引く」とだけ書いておくと、この2つで0と-1が出ますが、ツールは何のエラーも出さず、その値をそのまま返します。チェッカーが見つけてくれない種類のウソなので、例外を知っている人だけが避けられます。
ステップ
- 3つのアドレス範囲を手で計算し、
/root/cidr/01-hand.txtファイルに1行ずつ書いてください。アドレス範囲は192.168.40.130/26、10.10.6.75/20、172.20.200.9/23で、各行にCIDR・ネットワークアドレス・ブロードキャスト・最初のホスト・最後のホスト・ホスト数がすべて入っている必要があります。 /root/cidr/subnet.pyファイルを作成してください。python3 subnet.py 203.0.113.77/28とpython3 subnet.py 203.0.113.77 255.255.255.240が同じ答えを出す必要があり、出力はprefix=network=broadcast=first=last=hosts=の6行です。2回実行した結果を、/root/cidr/02-tool.txtファイルに保存してください。- ツールが
/31と/32を正しく扱うように直してください。この2つはbroadcast=noneで、/31は2つのアドレスがどちらもホスト(hosts=2)、/32は自分自身1つ(hosts=1)です。10.0.0.5/31と10.0.0.5/32を実行した結果と、なぜそうなるのかを、/root/cidr/03-edge.txtファイルに書いてください。 /root/cidr/same.pyファイルを作成してください。python3 same.py <주소/프리픽스> <상대주소>(プレースホルダーはアドレス/プレフィックスと相手のアドレスです)が、sameまたはdifferentの一語だけを出力します。5組を実行し、/root/cidr/04-same.txtファイルに주소/프리픽스 상대주소 판정(プレースホルダーはアドレス/プレフィックス、相手のアドレス、判定です)として保存してください。/root/cidr/classify.pyファイルを作成してください。python3 classify.py <주소>(プレースホルダーはアドレスです)が、privatelink-localloopbackcgnatmulticastpublicのうち1つを出力します。9個のアドレスを実行し、/root/cidr/05-class.txtファイルに주소 분류(プレースホルダーはアドレスと分類です)として保存してください。10.60.8.0/22を/24の4つに分割し、/root/cidr/06-split.txtファイルに1行に1つずつ、네트워크/24 first= last= hosts=(プレースホルダーはネットワークです)の形式で書いてください。- 既存の4つのアドレス範囲と重なるかを判定し、
/root/cidr/07-overlap.txtファイルに書いてください。重なるなら후보 overlap=겹치는대역、重ならないなら후보 freeです(プレースホルダーは、候補と、重なっているアドレス範囲です)。 /root/cidr/08-report.mdファイルに、設計メモを書いてください。要求ホスト数3つ(120台・600台・30台)に合う最小のプレフィックス、アドレス範囲を連続して配置すると何が得なのか、/31と/32をいつ使うかが入っている必要があります。
参考
- 標準ライブラリの
ipaddressだけを使います。このPodは外へ出られないので、pip installはできません。 ipaddress.ip_network("10.10.6.75/20", strict=False)は、ホストアドレスを渡しても、そのアドレスが属するアドレス範囲として読んでくれます。strict=True(既定)だとエラーになります。- ステップ4の5組:
10.30.4.9/22 10.30.7.250、10.30.4.9/23 10.30.7.250、192.168.9.60/26 192.168.9.65、172.20.15.1/12 172.31.255.254、100.64.3.1/10 100.127.0.9。最初の2組は、アドレスが同じで、マスクだけが違います。 - ステップ5の9個のアドレス:
10.4.4.4、172.31.255.1、172.32.0.1、192.168.0.1、169.254.10.9、127.0.0.53、100.100.5.5、224.0.0.251、8.8.8.8。 - ステップ7の既存のアドレス範囲:
10.10.0.0/16、10.20.0.0/16、10.244.0.0/16、172.17.0.0/16。候補:10.20.5.0/24、10.100.0.0/16、172.17.30.0/24、10.245.0.0/16。 - 172のプライベート範囲の境界(
/12なので172.16–172.31)と100.64.0.0/10(CGNAT)が落とし穴です。 - 採点ツールは、作成したツールを指示文にない値でも、もう一度実行してみます。答えを埋め込んでおくと、その場で不合格になります。
3つのアドレス範囲を手で計算する
プレフィックスが8の倍数でないときが、ミスの出る場所です。ブロックサイズ(2のホストビット乗)を求め、その倍数のうちアドレスが入るものを見つければ、それがネットワークアドレスです。
例えば/26はブロックサイズが64なので、境界は0、64、128、192です。130は128のブロックに入ります。
検算はpython3 -c "import ipaddress; n=ipaddress.ip_network('192.168.40.130/26', strict=False); print(n.network_address, n.broadcast_address, n.num_addresses-2)"で行います。
計算ツールを作る
/26と255.255.255.192は同じ意味です。引数が2つで来たら、주소/마스크(プレースホルダーはアドレスとマスクです)の形でつないで、同じ関数に渡せばよいです。
ipaddress.ip_network("203.0.113.77 255.255.255.240".replace(' ', '/'), strict=False)のようにです。
出力のキー名(prefix= network= broadcast= first= last= hosts=)は、採点ツールがそのまま探すので、変えないでください。ホスト数は、全アドレス数から、ネットワークアドレスとブロードキャストアドレスの2つを引いた値です。
/31と/32の例外を扱う
num_addresses - 2は、/31では0、/32では-1になります。ツールはエラーを出さずにその値をそのまま返すので、例外を知っている人だけが避けられます。
プレフィックスが31以上なら、別の分岐に送ってください。その分岐では、ブロードキャストアドレスを置かず(broadcast=none)、最初のホストはネットワークアドレスそのまま、最後のホストはアドレス範囲の最後のアドレス、ホスト数は全アドレス数です。
説明ファイルには、どのRFCが、どんなリンクに限ってこれを許可したかを書いてください。
同じサブネットかを判定する
判定は1行で終わります。相手のアドレスが自分の範囲の中にあるか。ipaddress.ip_address(other) in ipaddress.ip_network(mine, strict=False)です。
最初の2組は、アドレスが同じで、マスクだけが違います。マスクを1つ間違えると、隣の席のコンピューターが地球の反対側になることが、ここでわかります。
出力は、sameまたはdifferentの一語でなければなりません。採点ツールが、指示文にない組でも、もう一度聞いてきます。
アドレス範囲の性格を分類する
ルールの一覧を作って、上から合うものを探し、どこにも当てはまらなければpublicです。
必要な範囲は次のとおりです。ループバック127.0.0.0/8、リンクローカル169.254.0.0/16、CGNAT100.64.0.0/10、マルチキャスト224.0.0.0/4、プライベート10.0.0.0/8・172.16.0.0/12・192.168.0.0/16。
172.32.0.1と100.100.5.5が落とし穴です。172のプライベート範囲は/12なので172.16から172.31までで、100.64.0.0/10は通信事業者が加入者に割り当てるアドレスなので、プライベートでもグローバルでもありません。
アドレス範囲を細かく分ける
/22を/24で切ると、2の(24-22)乗、つまり4つになります。ipaddress.ip_network("10.60.8.0/22").subnets(new_prefix=24)が、その4つを順に返します。
各行に、ネットワーク(プレフィックス込み)・最初のホスト・最後のホスト・ホスト数を入れてください。分割したアドレス範囲ごとに、ホストは254個です。
アドレス範囲が重なるかを見る
重なりは目で見ると必ず間違えます。ipaddressのoverlaps()が、2つの範囲が1つでもアドレスを共有しているかを教えてくれます。
172.17.0.0/16が一覧にあるのには理由があります。Dockerの標準ブリッジがその範囲なので、社内ネットワークが172.17を使っていると、コンテナから社内サーバーに行けません。
重なるなら후보 overlap=겹치는대역、重ならないなら후보 freeと書いてください(プレースホルダーは、候補と、重なっているアドレス範囲です)。
設計メモを残す
必要なホスト数に2を足した値が入る、最も小さい2の累乗を探せばよいです。120台なら122以上が必要なので128、つまりホストビット7個で、プレフィックスは/25です。
連続配置の話は、隣接するアドレス範囲を1つにまとめてアドバタイズできるということです。それが、クラスが消えた実質的な理由でもあります。
クラウドでは、予約アドレスをさらに引く必要があることも、一緒に書いておくとよいです。