- ブラウザURL入力
- DNS名前→IP
- ルータ経路選択今ここ
- ロードバランサ振り分け
- Nginx受け口
- アプリ処理
- DB保存
リクエストがアプリケーションに届くまでには、いくつもの装置を通ります。今回はそのうち「ルータが次の行き先を決める」部分だけを扱います。DNSで宛先IPが分かった後、そのIPへどう向かうかを決める段階です。
まず結論
ルータは、宛先に当てはまる行の中から「最も細かく指定している行」を選びます。これを最長一致(longest prefix match)といいます。
表の上から順に見て最初に当たった行、ではありません。ここを取り違えると、通信が想定と違う経路へ流れた理由が永久に分かりません。
あるサーバのルーティング表に、次の3行が入っています。宛先 192.168.1.130 宛てのパケットは、どの行に従って送られるでしょうか。 ① default (=0.0.0.0/0) ② 192.168.1.0/24 ③ 192.168.1.128/25
当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。
ルータが持っているのは「宛先の範囲 → 出口」の対応表
ルータやサーバは、パケットを受け取ると、その宛先IPアドレスを見て「どこへ流すか」を決めます。このとき参照するのがルーティング表です。ひとことで言えば「この範囲の宛先なら、この出口へ」という対応表です。
ここで最初の引っかかりどころが出てきます。表の各行は、1つのアドレスではなく範囲を指しています。範囲である以上、ある宛先アドレスが複数の行の範囲に同時に入ることが起こります。むしろそれが普通です。
- ・3つとも「当てはまっている」。どれか1つだけが正しいのではない
- ・だからこそ、この中から1つを選ぶ規則が必要になる
したがってルータには、当てはまった複数の行から1つを選ぶ規則が必要です。その規則が最長一致です。
実際のルーティング表を見る
Linuxで ip route show と打つと、そのマシンのルーティング表が出てきます。次は、192.168.1.0/24 のネットワークに繋がった、Dockerも動いているサーバの実際の出力です。
default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.50 metric 100172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.50
1行目の default が「他のどれにも当てはまらなかったとき」の行、いわゆるデフォルトゲートウェイです。3行目が自分のいるネットワークを表します。/24 や /16 の数字が、範囲の細かさを表しています。
ここで大事なのは、この数字の意味です。/24 は「先頭から24ビットが一致していればこの行に当てはまる」という意味です。IPアドレスは32ビットなので、/24 なら残り8ビットが自由、つまり256個のアドレスを含む範囲になります。数字が大きいほど自由な部分が減り、範囲が狭く、指定が細かくなります。
/24 と /25 では、どちらが「細かい指定」でしょうか。
なぜ「細かい方」が勝つのか
最長一致という規則は、当てはまった行のうち、一致を求めるビット数が最も多い行を選ぶ、というものです。ではなぜ細かい方を選ぶのでしょうか。
「細かい方が具体的だから」と答えたくなりますが、それでは説明になっていません。細かい方が勝つと決めたから細かい方が具体的に見えるだけで、理由を言い換えているにすぎないからです。本当の理由は、経路の集約という運用上の必要から来ています。
- ・もし逆の規則(粗い方が勝つ)だったら、例外を作るたびに集約を解体しなければならない
- ・つまり最長一致は「細かい方が偉い」ではなく、集約を成立させるための仕組み
インターネットの経路情報は膨大なので、上流のルータは「この大きな塊は全部こちら」という粗い案内にまとめて広告します。これが集約です。ところが、その塊の中の一部分だけを別の場所へ向けたいことがあります。このとき最長一致があれば、粗い案内はそのままに、細かい行を1本足すだけで済みます。
順序の話も押さえておきます。最長一致で複数の行が残った場合に初めて、メトリック(経路の優先度を表す数値)の比較に進みます。逆ではありません。メトリックがどれだけ良くても、範囲が粗ければ細かい行には勝てません。
実際に照合してみる
宛先 192.168.1.130 が 192.168.1.128/25 に入るかどうかを、ビットで確かめます。/25 は4オクテット目の先頭1ビットまでを見る、という意味です。つまり4オクテット目が128以上か未満かで、範囲が上下に二分されます。
値 2進数 /25 の判定ビット 属する範囲130 10000010 先頭が 1 192.168.1.128/25 (上半分)127 01111111 先頭が 0 192.168.1.0/25 (下半分)
Linuxには、この判定を実際にカーネルに尋ねるコマンドがあります。ip route get です。man-pageには「そのパスに沿ってパケットを送るのと同等」と書かれており、表を眺めるのではなく本物の経路検索を実行します。さらに fibmatch を付けると、勝った行そのものを表示してくれます。
192.168.1.128/25 via 192.168.1.254 dev eth0
192.168.1.0/24(メトリック 0)と 192.168.1.128/25(メトリック 9999)の2行があるとき、宛先 192.168.1.130 はどちらの行に従いますか。
よくある誤解 — 上から順に見ているわけではない
ここが本レッスンで最も間違えられる点です。ルーティング表は、上から順に見て最初に当たった行を使う、という仕組みではありません。
実際、表示される順番と判定の順番は無関係です。Linuxカーネルの内部では、ルーティング表はそもそも上から順に読む一覧ではなく、LC-trie という木構造で保持されています。上から順に見るための「先頭」という概念自体がありません。表示が整列されて見えるのは、人間が読みやすいようにしているだけです。
そしてデフォルトルートも、特別扱いされた「最後の砦」ではありません。0.0.0.0/0 という、一致を求めるビット数が0本の、ごく普通の1行です。0ビットの一致でよいので全宛先に当てはまりますが、他のどんな行も1ビット以上は求めるため、必ず負けます。結果として「他に何もなければこれ」という振る舞いになるだけです。
判定を1行ずつ追う
宛先 192.168.1.130 に対して、表の全行がどう判定されるかを並べます。上から順に打ち切るのではなく、全行を照合してから最も細かいものを選んでいることに注目してください。
- ・記述順を入れ替えても結果は変わらない
- ・「当てはまる行が複数ある」のは異常ではなく通常の状態
ルーティング表 — 細かさで選ぶ
3行とも 192.168.1.130 に当てはまりますが、選ばれるのは最も細かい /25 の行です。書かれている位置は結果に影響しません。/25 を表の一番下に書いても勝ちます。
行 一致ビット数 当てはまる? 選ばれる?0.0.0.0/0 0 ○ ×192.168.1.0/24 24 ○ ×192.168.1.128/25 25 ○ ○ ← 最も細かい
ファイアウォール — 順序で選ぶ
こちらは上から順に評価し、最初に当たった行で決着します。2行目の広い許可ルールが先にあるため、3行目の細かい拒否ルールには到達しません。行を入れ替えると結果が変わります。
1: deny from 10.0.0.5 → 当たらない2: allow from 192.168.1.0/24 → 当たる ★ここで確定3: deny from 192.168.1.130 → 評価されない
この2つは、どちらも「当てはまる候補が複数あるときに1つを選ぶ」仕組みです。選び方の違いは何で、なぜその違いが生まれるのでしょうか。
どちらも同じ「表」の形をしています。違うのは選び方の規則です。少し考えてから開いてください。
この章のまとめ
- ルーティング表の各行は1つのアドレスではなく範囲を指すので、1つの宛先に複数の行が当てはまるのが普通。
- その中から選ぶ規則が最長一致。一致を求めるビット数が最も多い(最も細かい)行が勝つ。
- メトリックが比較されるのは最長一致で絞った後だけ。メトリックがいくら良くても粗い行は細かい行に勝てない。
- 「上から順に最初に当たった行」ではない。それはファイアウォールの規則であって、ルーティングの規則ではない。
- デフォルトルートは特別な最後の砦ではなく、一致ビット数0の普通の行。0ビットなので全部に当てはまり、そして必ず負ける。
自分の現場で確かめる
読んだだけでは身につきません。手元の環境で実際に見てみてください。
理解度チェック
読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。
ルーティング表に 10.0.0.0/8、10.5.0.0/16、10.5.4.0/24 の3行があります。宛先 10.5.4.9 はどの行に従いますか。
用語集(5語)
- 最長一致 (longest prefix match)
- 宛先に当てはまる複数の経路から、一致を求めるビット数が最も多い(最も範囲が狭い)ものを選ぶ規則。RFC 1812 が定める判定順序の2番目に位置する。
- プレフィックス長 (/24 などの数字)
- アドレスの先頭から何ビットの一致を求めるか。IPv4は32ビットなので、/24 なら残り8ビットが自由となり256アドレスの範囲を表す。数字が大きいほど範囲は狭い。
- デフォルトルート
- 0.0.0.0/0。一致ビット数が0なので全宛先に当てはまるが、他に当てはまる行があれば必ず負ける。結果として「他になければこれ」として働く。
- メトリック
- 経路の優先度を表す数値。小さいほど優先される。ただし比較されるのは最長一致で絞った後、同じ細かさの行が複数残ったときだけ。
- 経路集約 (CIDR)
- 複数の小さな範囲を1つの大きな範囲にまとめて広告すること。最長一致があるおかげで、集約した粗い経路を維持したまま、一部だけを細かい経路で上書きできる。