CIDR プレフィックスからネットマスクを作る

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

CIDR プレフィックスからネットマスクを作る

このレッスンで分かること

  • CIDR の n は 0 以上 32 以下の整数です
  • たとえば 192.168.1.42192.168.1.0/24 に属するかは、両者を 0xFFFFFF00 で AND して下位 8bit を捨て、上位 24bit が一致するかを見るだけです
  • 192.168.1.0/24 のような CIDR 表記は、IPv4 アドレスのうち何ビットがネットワーク部かを /n で表します

CIDR プレフィックスからネットマスク とは

/24 のような CIDR プレフィックスから、対応する 32bit のネットマスク (上位 prefix bit が 1) を返します。

192.168.1.0/24 のような CIDR 表記は、IPv4 アドレスのうち何ビットがネットワーク部かを /n で表します。今回はその n (プレフィックス長) を受け取り、対応するネットマスク (32bit 整数) を作る関数を実装します。

CIDR とは何か

以前はネットマスクを 255.255.255.0 のようにドット区切り 10 進でフル表記していましたが、現代ではすべて CIDR (Classless Inter-Domain Routing) で表記します。/24上位 24bit がネットワーク部、残り 8bit がホスト部 という意味で、255.255.255.0 (= 0xFFFFFF00) に対応します。

CIDR の n は 0 以上 32 以下の整数です。/0 はすべての IPv4 (0.0.0.0)、/32 は 1 つの IP だけを示します。

計算の考え方

プレフィックス n から 32bit のネットマスクを作るには、上位 n ビットを 1 にし、下位 32 - n ビットを 0 にすればよいです。これは「すべて 1 の 32bit 値」を、下位 32 - n ビット分だけ左にシフトすれば得られます。

mask = (0xFFFFFFFF << (32 - n)) & 0xFFFFFFFF

外側で & 0xFFFFFFFF を付ける理由は、n = 0 のときに (0xFFFFFFFF << 32) をすると、言語によっては未定義動作や 0 にならない結果になるからです。32bit に正規化する 保険 として AND を付けておきます。

diagram (will load when visible)

具体例

プレフィックス n と期待されるマスクの対応表は次の通りです。

  • n = 00
  • n = 80xFF000000 = 4278190080
  • n = 160xFFFF0000 = 4294901760
  • n = 240xFFFFFF00 = 4294967040
  • n = 320xFFFFFFFF = 4294967295

16 進数で書くと 0xFF (= 8bit が全部 1) のブロックがいくつ並んでいるかが見えやすくなります。/24 なら FF.FF.FF.00/16 なら FF.FF.00.00 のように。

Python 実装

Python

def cidrMask(n): if n <= 0: return 0 if n >= 32: return 0xFFFFFFFF return ((0xFFFFFFFF << (32 - n)) & 0xFFFFFFFF)

Python の int は任意精度なので、<< 32 はオーバーフローしませんが、安全のため n = 0n = 32早期 return で分岐しています。

JavaScript 実装

JavaScript

function cidrMask(n) { if (n <= 0) return 0; if (n >= 32) return 4294967295; return (Math.pow(2, 32) - Math.pow(2, 32 - n)); }

JavaScript ではビットシフトが 32bit 符号付きで挙動が読みづらいので、累乗 を使って書きました。2^32 - 2^(32-n) は「上位 n bit だけが 1 の値」と同値です。たとえば n = 24 なら 2^32 - 2^8 = 4294967296 - 256 = 4294967040 です。

累乗で書くと 32bit 符号の罠を回避できます。Math.pow(2, 32) - 10xFFFFFFFF の値です。

なぜマスクが大切なのか

IP アドレス ip がサブネット net/n に属するかを判定するには、次のように bit AND を取って比較します。

(ip & mask) == (net & mask)

たとえば 192.168.1.42192.168.1.0/24 に属するかは、両者を 0xFFFFFF00 で AND して下位 8bit を捨て、上位 24bit が一致するかを見るだけです。ルーティングテーブルの 最長一致 もこの仕組みで O(プレフィックス長) で実装できます。

よくある間違い

  • n32 - n を取り違える (向きが逆になる)
  • 0xFFFFFFFF << 32 を呼び出してしまい、言語によって結果が 0xFFFFFFFF のままだったり 0 だったり未定義だったりする
  • JavaScript で << を使うと負の数になるケースを忘れる
  • n の範囲チェック (0 〜 32) を省き、/40 のような不正値で 巨大な数 が返る
  • ネットワーク部とホスト部を逆向きに作り、下位 n bit が 1 のマスクになる

やってみよう

関数 cidrMask(n) を実装してください。n0 以上 32 以下の整数で、対応する 32bit ネットマスク (上位 n bit が 1) の整数を返します。n = 0 のときは 0n = 32 のときは 4294967295 を返します。

よくある質問

Q. このトピックを覚える意味は何ですか?

A. CIDR表記はIPアドレスの世界の共通言語です。サブネット設計、ファイアウォールルール、クラウドのVPC設定など、ネットワークに関わる作業をするなら避けて通れません。ビット演算でネットマスクを作れるようになると、「なぜこのIPはこのサブネットに属するのか」を暗算で判断できるようになります。

Q. 実務でこの知識を使う場面は?

A. AWS VPCやセキュリティグループのCIDR範囲設定、社内ネットワークのサブネット分割設計、アクセス制御リスト(ACL)でのIP範囲指定など、インフラ構築・運用のあらゆる場面で登場します。

Q. 他の章とどう繋がりますか?

A. 前の章で扱ったビット演算(AND, シフト)がそのまま計算の核になります。次の単純チェックサムのレッスンでも、32bit整数をビット単位で操作する視点を引き続き使います。

次のレッスン

次は 単純チェックサム に進みましょう。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. CIDR マスク の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. CIDR マスク とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. 上位 n bit が 1、下位 (32 - n) bit が 0 の 32bit 整数を返す
  2. n=0 のとき 0、n=32 のとき 4294967295 を返す
  3. n の範囲は 0 から 32

入出力例

test-cases.txt

cidrMask(0)0 cidrMask(8)4278190080 cidrMask(16)4294901760 cidrMask(24)4294967040 cidrMask(32)4294967295 cidrMask(1)2147483648 cidrMask(4)4026531840 cidrMask(28)4294967280

ヒント

main.py
main.py
学習モード

メモ

CIDR プレフィックスからネットマスクを作る

⌘S で保存