ARP と MAC:tcpdump で同じセグメント内の通信を捕まえる
Chapter 1 で読んだ IP と経路表の下で、実際には MAC アドレスへの変換が毎回働いています。learner01 から l3router01 のゲートウェイへ通信し、ARP request はブロードキャスト、reply はユニキャストで返ることを tcpdump で確認します。
| 所要時間 | 約 60 分 |
|---|---|
| 章タイプ | standard |
| 前提知識 | Part 2 Chapter 1(IP / サブネット / 経路表)/ Part 1 Chapter 4(grep とパイプ)/ Part 1 Chapter 7(sudo の考え方) |
| 使用機材 | workstation01 → ssh student@learner01、VLAN10: 172.16.10.20/24、GW: l3router01 172.16.10.1 |
| 関連章 | 前: Chapter 1「IP・サブネット・ルーティング」/ 次: Chapter 3「Linux Bridge と VLAN」 |
IP の下で、表札を引いてから届ける
Chapter 1 では ip addr と ip route で、「自分の住所」と「町の外へ出る出口」を読みました。この章ではその一段下、同じ VLAN10 の中で相手の MAC アドレスをどう知るかを見ます。
通信先が同じセグメントにいるとき、Linux はいきなり IP パケットを相手へ投げません。まず ARP で「172.16.10.1 の MAC を知っている人は?」と同じセグメント全体へ聞きます。l3router01 が「それは私です」と返すと、learner01 は宛先 MAC を埋めてフレームを送れます。
VLAN10 (172.16.10.0/24)
learner01 172.16.10.20
|
| ARP request: who-has 172.16.10.1 tell 172.16.10.20
| ARP reply: 172.16.10.1 is-at GW の MAC
|
l3router01 172.16.10.1 = default gateway
VLAN10 の中では L2 の MAC、VLAN10 の外へ出る判断は L3 の経路表。
learner01 上で ip neigh、sudo arping、sudo tcpdump -i ens20.10 -nn -e arp を使い、ARP request がブロードキャスト、ARP reply がユニキャストで返ることを説明できる。この章を終えるとできること
ARP / MAC を読む 4 動作を、すべて learner01 上で練習します。
MAC アドレスを見る
隣人帳として読む
ARP だけを発生させる
見たい MAC だけ絞る
MAC、ARP、L2 と L3 を分けて考える
1. MAC は同じセグメント内で使う名札
IP アドレスは「どのネットワークにいるか」を含む住所です。MAC アドレスは NIC の名札で、同じ L2 セグメントの中でフレームを届けるために使います。VLAN10 の learner01 が l3router01 へ届くとき、最後は l3router01 の VLAN10 側 MAC へ Ethernet フレームを送ります。
| 項目 | IP | MAC |
|---|---|---|
| 役割 | どのネットワークにいるかを示す住所 | 同じ L2 内で届けるための NIC の名札 |
| 例 | 172.16.10.1 | bc:24:11:aa:bb:cc |
| 見るコマンド | ip addr / ip route | ip -br link / ip neigh |
| 対応する層 | L3(IP / ルーティング) | L2(Ethernet / ARP) |
2. ARP request はブロードキャスト、reply はユニキャスト
ARP の会話は単純です。まず質問者が「誰か知っている?」と VLAN10 全体へ聞きます。これはブロードキャストです。該当する IP を持つ相手だけが「私です」と質問者へ返します。これはユニキャストです。
172.16.10.20l3router01 の MAC をまだ知らない
ff:ff:ff:ff:ff:ff同じセグメント全員へ届く
172.16.10.1自分の IP なので返事する
ip neigh に GW の MAC が入るrequestwho-has 172.16.10.1 tell 172.16.10.20宛先 MAC はブロードキャスト
reply172.16.10.1 is-at xx:xx:xx:xx:xx:xx宛先 MAC は learner01
3. L2 は「隣町の中」、L3 は「町の外への道」
Chapter 1 の ip route は L3 の話でした。default via 172.16.10.1 は「VLAN10 の外へ出るなら l3router01 に渡す」という判断です。ただし、その l3router01 へ渡す直前には、L2 の ARP で 172.16.10.1 の MAC を引きます。
ip route に道があるのに ip neigh が INCOMPLETE なら、「L3 の道はあるが、L2 の相手の名札が取れていない」と説明できます。learner01 で ARP を捕まえる
この章のコマンドは learner01 上で実行します。sudo arping と sudo tcpdump はパケットを直接扱うため sudo が必要です。ip neigh flush はネットワーク設定を壊す操作ではありません。learner01 が覚えている「相手の MAC メモ」を GW 1件だけ消して、ARP の会話をもう一度見えるようにする操作です。Ch5 で扱う iptables / tc の sudo 操作より前に、sudo が必要な観察系コマンドに慣れる位置づけです。
詰まったときは、受講者が実際に打つコマンドと実機の実行結果をここで再生できます(速度変更・ステップ停止つき)。各 STEP の「▶ ここを再生」を押すと、その場面から再生します。
STEP 01 · learner01 に入り、VLAN10 の NIC を確認する
受講者の出発点は workstation01 です。そこから ssh student@learner01 で入り、VLAN10 の IP が付いた NIC を探します。例では ens20.10 とします。
ssh student@learner01 hostname ip -br addr ip -br link IF=ens20.10 ip -br addr show dev $IF
172.16.10.x/24 が付いている NIC がこの章の観察対象です。ip -br link の 3列目に出る bc:24:11:... が learner01 側の MAC です。
STEP 02 · ゲートウェイへ ping して ARP テーブルを見る
VLAN10 の default gateway は l3router01 172.16.10.1 です。まず ping で通信し、ip neigh に GW の MAC が入ることを確認します。
GW=172.16.10.1 ping -c 3 $GW ip neigh show $GW GW_MAC=$(ip neigh show $GW | awk '/lladdr/{print $5; exit}') echo GW_MAC=$GW_MAC
172.16.10.1 dev ens20.10 lladdr bc:24:11:aa:bb:cc REACHABLE GW_MAC=bc:24:11:aa:bb:cc
lladdr の後ろが、l3router01 の VLAN10 側 MAC です。状態は REACHABLE または STALE なら問題ありません。
STEP 03 · arping で ARP だけを起こす
ping は ICMP ですが、arping は ARP だけを発生させます。sudo が必要です。
sudo arping -c 3 -I $IF $GW
ARPING 172.16.10.1 42 bytes from bc:24:11:aa:bb:cc (172.16.10.1): index=0 time=232.586 usec 42 bytes from bc:24:11:aa:bb:cc (172.16.10.1): index=1 time=198.341 usec 42 bytes from bc:24:11:aa:bb:cc (172.16.10.1): index=2 time=211.804 usec
42 bytes from <MAC> (172.16.10.1) の行が返ってくれば、ARP request に対して GW が返事した証拠です。
STEP 04 · tcpdump で request と reply を捕まえる
tcpdump を動かしている間に GW の ARP エントリを消して ping し、その瞬間の request と reply をファイルへ保存します。-i ens20.10 は VLAN10 の NIC だけを観察するため、-e は Ethernet の送信元/宛先 MAC を見るために付けます。--immediate-mode は、捕まえたパケットを溜め込まずその場で出力させる指定で、これが無いと短い観測ではファイルに何も残らないことがあります。timeout 10 を付けると、ARP がほとんど流れない静かなセグメントでも 10 秒で自動終了するので、wait が固まりません(パケット数だけで待つ -c 20 だと 20 本流れるまで戻らず固まることがあります)。
timeout 10 は tcpdump を起動した瞬間から 数え始めます。tcpdump の部分と ping の部分を別々に入力すると、入力している間に 10 秒が過ぎて tcpdump が先に終わってしまい、ログに何も残りません(0 packets captured だけが出ます)。そうならないよう、「観測を始める」と「ARP を起こす」をまとめて 1 行にしてあります。コピーボタンを使うのが確実です。timeout 10 sudo tcpdump -l -i ens20.10 -nn -e --immediate-mode arp > /tmp/ch2-arp.log 2>&1 & sleep 2; sudo ip neigh flush $GW dev $IF; ping -c 2 $GW; wait grep -i -E 'who-has|is-at' /tmp/ch2-arp.log
bc:24:11:11:22:33 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 172.16.10.1 tell 172.16.10.20, length 28 bc:24:11:aa:bb:cc > bc:24:11:11:22:33, ethertype ARP (0x0806), length 42: Reply 172.16.10.1 is-at bc:24:11:aa:bb:cc, length 28
注意: -i ens20.10 は VLAN10 の NIC だけを捕まえる指定です。管理用 NIC 側の ARP を混ぜないため、この章では -i any は使いません。重要なのは who-has と is-at の部分です。
1行目は request(who-has)、2行目は reply(is-at)です。request は「誰か知っている?」なのでブロードキャスト、reply は「私です」なので learner01 へ返るユニキャストです。
何も出なかったときは: grep が 1 行も返さず、cat /tmp/ch2-arp.log に 0 packets captured とだけ書かれている場合は、1 行まるごとではなく途中で分けて実行された可能性が高いです。上の 1 行目をコピーボタンで貼り直して、もう一度実行してください。何度実行しても問題ありません。
STEP 05 · Part 1 Ch4 の grep とパイプで MAC を絞る
最後に、捕まえたログから GW の MAC だけを抜き出します。これは Part 1 Chapter 4 の grep と | の再利用です。ネットワーク調査でも、長い出力をそのまま読まず、見たい文字列で絞ります。
(1)まず、保存済みログを絞る —— STEP 04 で /tmp/ch2-arp.log に保存した内容から、GW の MAC を含む行だけを抜き出します。
echo $GW_MAC grep -i "$GW_MAC" /tmp/ch2-arp.log
(2)次に、流れているパケットをその場で絞る —— ここからは ターミナルを 2 つ使います。2 つ目は、ブラウザで Guacamole をもう 1 つのタブで開き、同じ workstation01 をクリックして、そこから ssh student@learner01 でログインします(同じ接続を同時に複数開けます)。先にターミナルA で待ち受け、10 秒以内に ターミナルB で arping を実行してください。待ち受け側は timeout 10 を付けているので、何も流れなくても 10 秒で自動終了します(静かなセグメントでも固まりません)。
timeout 10 sudo tcpdump -l -i ens20.10 -nn -e arp | grep --line-buffered -i "$GW_MAC"
-l は tcpdump の出力を 1 行ごとに流す 指定です。これが無いと、tcpdump はパイプに書くとき出力をまとめて溩め、10 秒経って終了するまで grep に 1 行も届きません(溩まったまま捨てられ、packets captured と出ているのに 1 行も表示されないこともあります)。--line-buffered は grep 側の指定なので、両方揃って初めて「流れているものをその場で見る」が成立します。
IF と GW は STEP 01・STEP 02 で ターミナルA の中だけ に作った変数です。新しく開いたターミナルB には引き継がれません(空のまま arping を打つと Interface "" is down のように失敗します)。下のとおり、B でもう一度 2 行を打ってから arping してください。IF=ens20.10 GW=172.16.10.1 sudo arping -c 3 -I $IF $GW
ターミナルA に GW の MAC を含む行が、arping を打ったその場で 流れれば成功です(3 行前後)。終わったらターミナルB のタブは閉じてかまいません。
packets captured と出たのに 1 行も表示されないとき: 捕まえること自体は成功しているので、ネットワークも変数も正しいと判断してください。まず echo $GW_MAC でターミナルA の変数が空になっていないか確かめ、次に -l を付け忘れていないか を見てください。コピーボタンで貼り直してもう一度実行すれば回復します。
(3)後始末 —— 保存したログを削除します。
rm -f /tmp/ch2-arp.log
この読み方は、「全部見る」のではなく「必要な行だけ拾う」現場の基本です。以後の章では、ルーティング、ファイアウォール、遅延の出力でも同じ絞り込みを使います。
見えないときの切り分け
1. まず NIC と VLAN10 の IP を確認する
tcpdump -i ens20.10 で見えない原因の多くは、NIC 名の思い込みです。この章では -i ens20.10 を基本にします。見えない場合は、必ず ip -br addr で 172.16.10.x/24 が付いたインターフェースを確認します。
ip -br addr ip route ip neigh show 172.16.10.1
2. tcpdump と arping は sudo が必要
tcpdump: You don't have permission to capture on that device のような表示なら、コマンドの前に sudo が足りません。arping も raw socket を使うため sudo が必要です。
timeout 10 sudo tcpdump -l -i ens20.10 -nn --immediate-mode arp & sleep 2; sudo arping -c 3 -I $IF 172.16.10.1; wait
ここも STEP 04 と同じ理由で 1 行にまとめて あります。分けて入力すると、arping を打つ前に tcpdump が終了してしまいます。
3. ARP が見えないのは、すでに覚えているからかもしれない
ip neigh が REACHABLE のままだと、次の ping では新しい ARP request が出ないことがあります。観察したい相手だけを flush してから再試行します。
sudo ip neigh flush 172.16.10.1 dev $IF || true ping -c 2 172.16.10.1 ip neigh show 172.16.10.1
AI に相談
詰まったら、出力を貼って「request は見えるが reply がない」「ip neigh が INCOMPLETE のまま」など、見えている事実から質問してください。
修了確認
問 1 · ARP request と reply を見分ける
tcpdump に次の 2 行が出ました。どちらがブロードキャストで、どちらがユニキャストですか?理由も 1 行で答えてください。
bc:24:11:11:22:33 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 172.16.10.1 tell 172.16.10.20, length 28 bc:24:11:aa:bb:cc > bc:24:11:11:22:33, ethertype ARP (0x0806), length 42: Reply 172.16.10.1 is-at bc:24:11:aa:bb:cc, length 28
解答を見る
ff:ff:ff:ff:ff:ff(=「誰か知っている?」を VLAN10 全体へ投げる)なのでブロードキャストです。2行目の Reply は宛先 MAC が learner01 の bc:24:11:11:22:33 で、l3router01 が learner01 だけに返す返事なのでユニキャストです。問 2 · L2 と L3 のどちらを見るか
ip route には default via 172.16.10.1 dev ens20.10 があるのに、ping 172.16.10.1 が失敗し、ip neigh show 172.16.10.1 は INCOMPLETE です。どの層の問題として切り分けますか?
解答を見る
INCOMPLETE は「MAC を問い合わせたが返事がない」状態なので、同じ VLAN10 上の接続、相手の稼働、NIC/VLAN 設定を確認します。修了確認の段階ヒント(問 1・問 2 共通)
段階ヒント 1 段目:単語をそのまま読む
who-has は質問、is-at は答えです。質問は相手が分からないから全員に聞き、答えは質問者だけに返します。段階ヒント 2 段目:見るコマンドを分ける
ip route、L2 の名札解決は ip neigh と tcpdump arp で見ます。ip route が正しくても ip neigh が INCOMPLETE なら ARP 側です。段階ヒント 3 段目:Ch1 の言葉に戻す
次は Linux Bridge と VLAN
この章では、VLAN10 の中で learner01 が l3router01 の MAC を引き、同じセグメント内の相手へフレームを届ける仕組みを見ました。ARP は 同じ L2 セグメントの中でだけ意味を持つ、というのが重要です。
次の Chapter 3 では、その「同じセグメント」を作る側へ進みます。Linux Bridge と VLAN によって、どこまでが同じ L2 で、どこからが別セグメントなのかを自分で区切ります。
- Linux Bridge は仮想スイッチとして動く
- VLAN タグで同じ物理配線の中に複数の L2 セグメントを作る
- ARP が届く範囲と届かない範囲を、bridge / VLAN の設定から説明する