$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

どうやってIPからMACアドレスを解決するか - ARPの挙動を調べた

自分はアプリケーションエンジニアでネットワークを触ることは少ないのだけど、ネットワークも関わるタスクや障害が現れた時に話についていけないのは良くないと思い、マスタリングTCP/IP 入門編を今読んでいる。データリンク層の章まで読み、この章ではデータリンク層の通信ではMACアドレスを用いて通信していると書かれていた。

しかし、読むだけではまだ理解が足りてないなと思い、pingをサブネット内のホストに打ちながらWiresharkでフレームを眺めるということをしていた。特にIPからMACアドレスの解決をどのようにしているのかと思い、192.168.10.7から192.168.10.4にpingしながら、ARPのフレームを眺めていると、

No.	Time	Source	Destination	Protocol	Length	Info
1811	87.235306	Apple_42:64:b2	Apple_70:ce:22	ARP	42	Who has 192.168.10.4? Tell 192.168.10.7
1836	87.769342	Apple_70:ce:22	Apple_42:64:b2	ARP	42	192.168.10.4 is at 98:01:a7:70:ce:22

というものが流れてきた。これを見て、いやいや192.168.10.4のMACアドレスを解決したいのに、なんでARP送る時にすでにApple_42:64:b2というMACアドレス知ってるんだと疑問に思ったので、ARPの挙動について調べてみた。

ちなみにネットワーク初心者なので、間違ったことが書いてあれば教えてください...

ARPは要求をブロードキャストし、応答を待つ

まず参考にした資料は

これらによるとARPの基本動作は

  1. 通信したいIPアドレスからMACアドレスを解決したいノード(Senderとする)は、自分のIPアドレスMACアドレスを送信元にセットし、ARP Requestをブロードキャストする
    • つまり、サブネット内の全ノードにARP Requestが飛ぶ
  2. ARP Requestを受け取ったノード達は、SenderのIPアドレスMACアドレスを自分のARPテーブルにキャッシュする
  3. ARP Requestを受け取ったノード達の中で、自分のIPアドレスに対するRequestであれば、自分のIPアドレスMACアドレスを送信元にしたARP ReplyをSenderに向けて送信する
  4. SenderはARP Replyを受け取ったら、返ってきたIPアドレスMACアドレスを自分のARPテーブルにキャッシュする

となっているようだ。

送信元は基本的にはこれから通信したいノードのIPアドレスを知っていてもMACアドレスが知らないはずなので、ブロードキャストして通信したいノードからMACアドレスを教えてもらう、と考えたらすんなり理解できた。

またここで受信した全てのノードは、Request送信元のIPアドレスMACアドレスの組を学習するというのも重要な挙動に見える。


さて、ここまでは良いが、ここで最初の疑問に戻る。ではなぜブロードキャストではなくMACアドレスを指定したARP Requestが流れていたのか。

ARPのキャッシュテーブルを更新する時、ARPは該当のMACアドレスを指定してARPする

参考にした資料は ARPトラブルあるある - Qiita

これによると、自分のARPテーブルに存在するIPアドレスMACアドレスを更新したい場合、宛先のMACアドレスも指定してARP Requestを飛ばすようだ。これで同じ結果が返ってくれば、自分のARPテーブルを更新すれば良い。

挙動は確認していないが、もし宛先指定で送った相手のIPアドレスが違えば、ARP Replyが返ってこないはずである。その場合はもう一度ブロードキャストする、という挙動になるのではないだろうか。

これで最初に見かけた宛先指定のArp Requestフレームの意味が理解できた。

ARPでは一番最初に応答したものを正解とする

ARPについてTwitterでつぶやいていたら、さらに「ARPでは一番最初に応答したものを正解とするという挙動も覚えておくと良いです」と教えてもらえた。


このため、悪意がなくとも、自分以外を対象としたARP Requestに返答してMACアドレス詐称をしてしまった場合、ネットワークは不安定となる。また、悪意があった場合、通信を乗っ取ることも出来る。

このようにARP解決におけるIPアドレスの詐称をARP Spoofingだったり、ARP cache poisoningだったりと言うのだけど、実際に起こった事例が http://irs.ietf.to/past/docs_20080808/20080808-irs17-arpspoofing-post.pdf に載っていた。


ちなみに悪意がある人がARP Replyじゃなくて、ARP Requestで詐称をしてブロードキャストし続けると、サブネットにあるノード達は全員詐称されたもので自身のARPテーブルに記録しそうだけど、どうなんだろうな...

実際に実践してみる

ここまで挙動が理解できたので、実際に実践をしてみる。

まず自分のPCのARPテーブルを眺めてみる。

$ arp -anl
Neighbor                Linklayer Address Expire(O) Expire(I)    Netif Refs Prbs
169.254.169.254         (incomplete)      (none)    (none)         en0
192.168.10.1            98:f1:99:8d:b1:70 59s       59s            en0    1
192.168.10.2            c8:63:f1:31:5f:1a expired   expired        en0    1
192.168.10.3            0:25:dc:68:52:12  expired   2m1s           en0    1
192.168.10.255          ff:ff:ff:ff:ff:ff (none)    (none)         en0

ここでexpiredしている192.168.10.2に対してpingしてみる。すると、以下のようにMACアドレス指定でARP Requestしている様子を検出できた。

No.	Time	Source	Destination	Protocol	Length	Info
168760	3813.834355	Apple_42:64:b2	SonyInte_31:5f:1a	ARP	42	Who has 192.168.10.2? Tell 192.168.10.7
168763	3813.838617	SonyInte_31:5f:1a	Apple_42:64:b2	ARP	60	192.168.10.2 is at c8:63:f1:31:5f:1a

次はブロードキャストの様子も見たい。この192.168.10.2をARPテーブル自体から削除する。

$ sudo arp -d 192.168.10.2
192.168.10.2 (192.168.10.2) deleted
$ arp -anl
Neighbor                Linklayer Address Expire(O) Expire(I)    Netif Refs Prbs
192.168.10.1            98:f1:99:8d:b1:70 59s       59s            en0    1
192.168.10.3            0:25:dc:68:52:12  expired   2m19s          en0    1
192.168.10.255          ff:ff:ff:ff:ff:ff (none)    (none)         en0

これでping 192.168.10.2すると、

No.	Time	Source	Destination	Protocol	Length	Info
186782	4320.812608	Apple_42:64:b2	Broadcast	ARP	42	Who has 192.168.10.2? Tell 192.168.10.7
186783	4320.817633	SonyInte_31:5f:1a	Apple_42:64:b2	ARP	60	192.168.10.2 is at c8:63:f1:31:5f:1a

とブロードキャストしている様子が観察できた!めでたい!

蛇足

ちなみに最初はRFC( https://tools.ietf.org/html/rfc826 )に当たったのだけど、最初からThe world is a jungle in general, and the networking game contributes many animals.って意味不明な文が書かれていて、は?ジャングルとかアニマルとか何いってんのってなったり、なんか英文がけっこうわかりづらかったり(古いから?)して、一回諦めたりした...