Dev Study
← ネットワークの仕組み
レッスン 13 / 13·約 15 分·第2期 ネットワークの仕組み

パケットを自分の目で見る — 切り分けの型

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力今ここ
  2. DNS名前→IP今ここ
  3. ルータ経路選択今ここ
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理今ここ
  7. DB保存

第2期の最終回です。特定の段を学ぶのではなく、ここまでの全段を「どこで止まっているかを突き止める順序」として並べ直します。地図全体が今回の対象です。

まず結論

「つながらない」という報告は、それ自体では何も特定していません。第14週から積み上げてきた層は、ここで「どの段まで生きているかを下から順に確かめる」という手順に変わります。

そして観測には、観測器ごとの見える範囲があります。tcpdump はホストと網の境界を、strace はプロセスとカーネルの境界を記録します。どちらも「境界を通るものを全件書き出す」道具で、境界の外側で起きたことは原理的に映りません。

? 読む前に予測

traceroute の出力の途中に `* * *` という行が並んでいました。ここから確実に言えることはどれでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

「つながりません」は、何も言っていない

第2期の最終回です。新しい層は出てきません。ここまで積み上げた層を、実務の手順に組み直します。

現場で最も多く聞く報告は「つながりません」です。この一文は、状況の説明としては何も特定していません。名前が引けていないのか、相手まで届いていないのか、届いたが拒否されたのか、届いて受理されたがアプリが応答を返していないのか。どれでも同じ見え方をします。

ここで層が効いてきます。層とは第14週で見たとおり入れ子の一段一段でした。入れ子であるということは、内側の段は外側の段が生きていなければ絶対に成立しないということです。逆向きに読めば、下から順に確かめていけば、生きている範囲と死んでいる範囲の境目が必ずどこかに1つ見つかります。

下から順に、どこまで生きているかを確定させる
名前は引けているかDNS — 層の外側で全体に効く
引けたら
隣の機器と話せているかリンク層
話せていたら
相手のホストまで届くかIP層
届いていたら
そのポートは開いているかトランスポート層
開いていたら
アプリは応答を返すかアプリ層
  • ・下の段が死んでいれば、上の段は必ず失敗する
  • ・だから下から潰すと、一段ごとに原因の範囲が狭まる

DNSだけは順序が特殊です。 名前解決は特定の段の中の仕事ではなく、通信を始める前段で全体に効きます。名前が間違って引けていれば、そもそも見当違いの相手に対して以降の全段が正常に動いてしまう——つまりすべてが正常に見えるのに目的を達しないという、最もたちの悪い形になります。だから先に確認します。

具体実物

段ごとに、何を打つか

型として並べると次のようになります。コマンドを覚えることが目的ではなく、各段で何を問うているかが要点です。

段と、その段で確かめる問い表
段 何を問うているか 代表的なコマンド
DNS(先に) 名前は正しく引けているか dig
リンク層 隣の機器と話せているか ip link / ip neigh
IP層 相手のホストまで届くか ping / traceroute
トランスポート層 そのポートは開いているか ss -tan / nc -vz
アプリ層 アプリは応答を返すか curl -v

これらは第15週から第25週で扱ってきた段そのものです。学んだ順序が、そのまま確かめる順序になっています。

ただし、ここに落とし穴があります。各段の「確かめる」コマンドは、期待した答えを返さないことがあり、しかもそれが異常とは限らないのです。

✓ ここまでの確認

「ping が返ってこない」という事実から、宛先ホストが停止していると結論できますか。

抽象原理

沈黙は、故障の証拠ではない

最もよくある誤読が「ping が通らない = 故障」です。

ping が確かめているのは「相手が生きているか」ではありません。「相手が ICMP Echo に応答を返してくれるか」です。応答を返さない方針の機器は珍しくないので、沈黙から到達不能を結論することはできません。

同じことが traceroute にも起きます。traceroute は TTL を1ずつ増やしながらパケットを送り、TTL を使い切った機器が送り返す ICMP Time Exceeded(Type 11) を手がかりに、経路上の機器を手前から順に明らかにします。ここで、Time Exceeded を返さない方針の機器に当たると、その行は * になります。

もう一点、traceroute については用語の誤りが広く流通しています。「traceroute は ICMP を使う」は無条件には正しくありません。

traceroute が「送る」もの(返ってくるものとは別の話)表
環境 既定で送るもの
Linux traceroute UDP(ポート33434から1ずつ増やす)
macOS/BSD traceroute UDP(同上)
Windows tracert ICMP Echo Request
─────────────────────────────────────────────
Linux は -I で ICMP、-T で TCP に切り替わる

返ってくる Time Exceeded が ICMP であることと、送る側が何を使うかは別の話です。ここが混ざると「ICMP を止めているのに traceroute が動く/動かない」の理由が説明できなくなります。なお「Linux は UDP 固定」と覚えるのも誤りで、オプションで変わります。

⇄ 2つを見比べる
具体例 A

tcpdump — ホストと網の境界

自分のホストとネットワークの間を通るパケットを記録します。アプリが何のライブラリを使っていようと、暗号化していようと、線に出る以上は境界を通るので記録されます。逆に、別のインタフェースから出ていった通信や、そもそもホストの外に出なかった通信は映りません。

tcpdump が見ている境界表
境界の内側 自分のホスト(アプリもカーネルも含む)
境界そのもの ネットワークインタフェース ← ここを記録
境界の外側 網の先で起きること
────────────────────────────────────────
映らない例 別インタフェース経由 / フィルタ式に外れた通信
具体例 B

strace — プロセスとカーネルの境界(第13週)

第13週で見たとおり、プロセスがカーネルに出す依頼を記録します。アプリが何の言語で書かれていようと、ファイルを読むならカーネルに頼むしかないので記録されます。逆に、カーネルに入らない処理は映りません。vDSO 経由の呼び出しが strace に出ないのは、この境界を越えていないからでした。

strace が見ている境界表
境界の内側 プロセス(ユーザーモード)
境界そのもの システムコール ← ここを記録
境界の外側 カーネルの内部で起きること
────────────────────────────────────────
映らない例 vDSO経由の呼び出し(カーネルに入らない)

tcpdump と strace。見ているものはまったく違いますが、道具としての性格は同型です。共通する構造は何でしょうか。そして、その構造から必ず生じる限界は何でしょうか。

「何を全件記録できるのか」と「何が原理的に記録できないのか」を、それぞれについて言葉にしてから比べてください。

✓ ここまでの確認

tcpdump に目的の通信が1行も出てきませんでした。「パケットが送られていない」と断定できますか。

抽象原理

同じ語が、別のものを指している

切り分けの最中に用語を取り違えると、確かめたつもりの事実が事実でなくなります。第2期で何度も出てきた主題が、最後にもう一度現れます。

IPの TTL と DNSの TTL は、同じ略語ですが働きが違います。

同じ TTL という語の、2つの意味表
IPヘッダの TTL DNSレコードの TTL
実質の単位 ホップ数(規格上は秒) 秒数
減るきっかけ ルータを1つ越えるごと 時間の経過
0になると パケットが捨てられ、 キャッシュを捨てて
Time Exceeded が返る 引き直す

どちらも Time To Live の略で「寿命」という発想は共通していますが、片方の感覚でもう片方を読むと必ず誤ります。 「TTL が 300 なので5分でルータを越えられなくなる」といった説明が出てきたら、2つが混ざっています。

用語が一致していることと、意味が一致していることは別だ——第14週で RFC 1122 の層名について見たこと、第25週で DNS の語彙について見たことと、同じ構造です。

具体実物

第2期が残したもの

第14週で「層とは入れ子の一段のこと」から始め、下から順に一段ずつ登ってきました。最後にそれが、不具合を切り分ける手順という形に変わりました。

第2期で積み上げたものが、切り分けの型になる
第14週層という見方そのもの○ 入れ子 = 各段は自分の宛名だけを見る
第15〜16週目の前の線の段○ ip link / ip neigh で確かめる段
第17〜20週網をまたぐ段○ ping / traceroute で確かめる段
第21〜24週端点どうしの会話の段○ ss / nc で確かめる段
第25週名前○ 層の外側。最初に dig で確かめる
第26週観測○ どの段まで生きているかを下から確定させる
↓
層は覚えるための分類ではなく、原因の範囲を狭めるための区切りだった
  • ・各段には「何を問うているか」が対応している
  • ・観測器には見える範囲がある。範囲の外は「無い」ではなく「分からない」

第2期を通して繰り返してきた問い返しは、一貫して同じものでした。「それはどの文書に、どう書かれているか」、そして**「その観測器は、何を見ていて、何を見ていないか」**。

* * * を経路断と読むのも、空のキャプチャを「通信していない証拠」と読むのも、straceに出ないことを「呼ばれていない証拠」と読むのも、すべて同じ誤りの形をしています。観測されなかったものを、存在しなかったことにしているのです。

この章のまとめ

  • 「つながらない」は何も特定していない。層は原因の範囲を下から順に狭めるための区切りとして使う。
  • 順序は 名前解決(DNS)を先に → リンク層 ip link/ip neigh → IP層 ping/traceroute → トランスポート層 ss -tan/nc -vz → アプリ層 curl -v。DNSは層の外側で全体に効く。
  • ping が通らない = 故障ではない。 応答を返さない方針の機器がある。
  • traceroute の途中の * * * は経路断ではない。 Microsoft 公式が「一部のルータは Time Exceeded を返さず invisible」と明記し、公式の出力例でも14〜16ホップ目が * のまま17ホップ目で到達している。
  • ICMP Time Exceeded は Type 11(Type 3 は Destination Unreachable)。
  • 「traceroute は ICMP」は無条件には誤り。 Linux/BSD の既定は UDP(33434から)、Windows tracert は ICMP Echo。Linux も -I/-T で変わるので「UDP固定」も誤り。
  • tcpdump と strace は同型の観測器。前者はホスト/網の境界、後者はプロセス/カーネルの境界を全件記録する。どちらも境界の外は原理的に映らないので、出力が空でも「起きていない」の証明にはならない。
  • IPの TTL は実質ホップ数の上限(規格上の単位は秒)、DNSの TTL は秒数。 同じ略語でも働きが違う。
  • tcpdump の出力例は暗記しない。版やプロトコルで変わるので、自分の環境で1行取り、その環境の man ページと突き合わせる。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

「traceroute は ICMP を使って経路を調べるコマンドである」——この説明の評価として最も適切なのはどれですか。

用語集(6語)
TTL (IPヘッダ)
パケットが通過してよいルータの残り数。ルータを1つ越えるごとに1減り、0になったパケットは捨てられ、捨てたルータが ICMP Time Exceeded を送り返す。規格上の単位は秒だが(RFC 791)、ルータは必ず1以上減らすので実質はホップ数の上限として働く(RFC 1812 §5.3.1)。
TTL (DNSレコード)
そのレコードをキャッシュに保持してよい秒数。IPの TTL と同じ略語だが単位も意味も異なる。
ICMP Time Exceeded
TTL を使い切ったパケットを捨てたことを送信元へ知らせる ICMP メッセージ。Type 11(Code 0 が transit 中の TTL 超過)。Type 3 の Destination Unreachable とは別のメッセージ。
traceroute / tracert
TTL を1ずつ増やしながら送り、返ってくる Time Exceeded で経路上の機器を手前から明らかにするツール。Linux/BSD の traceroute は既定で UDP(ポート33434から)、Windows の tracert は ICMP Echo を使う。Linux でも -I で ICMP、-T で TCP に変えられる。
tcpdump
観測しているインタフェースを通過するパケットを記録するツール。ホストと網の境界を通るものを全件書き出すが、記録できるのはそのインタフェースを通ったものに限られる。
切り分け
不具合の原因がありうる範囲を、確かめられる事実によって段階的に狭めていく作業。層はその区切りとして使える。