$shibayu36->blog;

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

tracerouteの仕組みをtcpdumpとwiresharkで理解する

どうやってIPからMACアドレスを解決するか - ARPの挙動を調べた - $shibayu36->blog; に続き、マスタリングTCP/IPで気になったことの実践。tracerouteではIPヘッダのttlの値とICMPをうまく利用して、経路を教えてくれるというのを見たので、今回はそのパケットの様子をtcpdump + wiresharkを使って見てみることで、仕組みの理解を深めてみたい。

tracerouteの仕組み

まず手元でtracerouteを8.8.8.8に対して打つと、以下のように経路情報を教えてくれる。

$ traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 64 hops max, 52 byte packets
 1  aterm.me (192.168.10.1)  4.408 ms  3.977 ms  3.989 ms
 2  * * *
 3  10.1.194.227 (10.1.194.227)  18.208 ms  18.145 ms  16.765 ms
 4  10.1.12.221 (10.1.12.221)  19.256 ms  25.289 ms  18.419 ms
 5  110-134-112-25.rev.home.ne.jp (110.134.112.25)  19.733 ms
    110-134-112-29.rev.home.ne.jp (110.134.112.29)  28.411 ms
    110-134-112-25.rev.home.ne.jp (110.134.112.25)  21.976 ms
 6  c3-be1.kb-dc.zaq.ad.jp (110.134.112.30)  15.741 ms
    c3-be2.kb-dc.zaq.ad.jp (110.134.112.26)  17.432 ms  20.679 ms
 7  gw1-be3.dj-dc.zaq.ad.jp (220.152.35.34)  16.314 ms  19.365 ms  21.640 ms
 8  74.125.48.225 (74.125.48.225)  20.817 ms  22.107 ms  22.983 ms
 9  108.170.243.33 (108.170.243.33)  16.376 ms
    108.170.243.65 (108.170.243.65)  18.259 ms
    108.170.243.129 (108.170.243.129)  17.609 ms
10  72.14.237.127 (72.14.237.127)  19.487 ms
    108.177.3.85 (108.177.3.85)  18.998 ms
    108.170.235.47 (108.170.235.47)  22.041 ms
11  google-public-dns-a.google.com (8.8.8.8)

これはネットワーク入門 PartⅠ | 演習で学ぶネットワークに書いてあるとおりで、途中の経路でTTLが0になったらICMPのType11(時間超過)を返してくる特性を活かして、IPヘッダのTTLの値を1から順に2、3、4、...と増やしていきながらUDPパケットを送信し応答を使って経路を知るという仕組みになっている。

ただ仕組みを見ただけではちゃんと理解できているとはいえないと思ったので、実際にパケットの様子を見てみたい。

tcpdumpwiresharkでtracerouteのパケットを眺める

実際のパケットをtcpdumpwiresharkを使って眺めることにした。もちろん手元PCからtracerouteしようと思っているので、wiresharkだけでも見れるのだけど、tcpdumpの練習もしておいた方が良いと思い、tcpdumpで出力したdumpファイルをwiresharkで見るという方法を取ってみた。

まずtcpdumpはこういう感じ。

tcpdump -n -i en0 -w dump.cap \
  '(udp and ip[8] < 15 and dst 8.8.8.8) or (icmp and (icmp[icmptype] == 11 or icmp[icmptype] == 3))'

オプションは

  • -nオプションで名前逆引きをしない
  • -iオプションでen0のパケットをキャプチャ
  • -wで出力先ファイルを指定

あとはフィルタの説明。対象は送信するUDPと返ってくるICMPなので

  • (udp and ip[8] < 15 and dst 8.8.8.8)
    • UDP
    • dst 8.8.8.8: 8.8.8.8への送信である
    • ip[8] < 15: IPパケットのTTL(IPの中の9バイト目)が15未満で
      • UDP and 8.8.8.8の指定で十分なのだけど、TTLでの絞り込みもやってみたかったのでやっている
      • 通常TTLは64とかなので、TTLの絞り込みだけでも十分そうだけど、QUICとかのプロトコルTTLが4だったりしていらないパケットが流れてきたので、dst指定をした
  • icmp and (icmp[icmptype] == 11 or icmp[icmptype] == 3)
    • ICMPで
    • icmp[icmptype] == 11: ICMPのタイプがTime Exceeded
      • TTL切れたら返ってくるやつ
    • icmp[icmptype] == 3: ICMPのタイプがDestination Unreachable
      • 最後到達した時に、ポートが塞がれていてDestination Unreachableで返ってくることが多い


そしてこのdump.capファイルをWiresharkで眺めてみる。


こんな感じで、まずはTTLを1にしたUDPのパケットを3回投げて、ICMPのTime-to-live exceededが3つ返ってきて、TTLを2にしたUDPパケットを3つ投げて、・・・と繰り返していき、最後に8.8.8.8に到達して、ICMPのDestination Unreachableが返ってくる様子が確認できた。まだなんでUDPを3回投げるのかとか、など少し疑問は残ったが、今回はこのあたりで追うのをやめておく。

どうやって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.って意味不明な文が書かれていて、は?ジャングルとかアニマルとか何いってんのってなったり、なんか英文がけっこうわかりづらかったり(古いから?)して、一回諦めたりした...

Mackerelの思想や出来ることを知る - Mackerelサーバ監視実践入門を読んだ

最近Mackerelを触ることが多く、Mackerelで何が出来るのかを知りたいと思い、Mackerelサーバ監視実践入門を読んだ。

この本では、Mackerelにはどのような機能があるのかを広く紹介している。また、実際に使っているユーザの事例もいくつか知ることができる。そのため、Mackerelでサーバを監視したい!と思っている人や、監視をし始めたけどさらにどういうことが出来るのか知りたいと思っている人には非常に参考になりそう。僕も、さらにどういうことが出来るのか知りたいという気持ちだったので、非常に参考になった。

個人的には、この本の内容から、Mackerelはサーバ監視サービスとしてだけではなくて、サーバ管理ツールとして使って欲しいという思いが伝わってきたのが良かった。ただ監視するだけではなくて、ホスト情報の統合管理場所として使い、例えばどのサーバにデプロイするかなどの判断するなどに使うという感じ。このように使うことで、日々サーバの台数が変わるような動的インフラストラクチャの世界でも簡単にホスト一覧やホスト情報を管理することができる。

さて、この本を読んだことで「何ができるか」については知れたものの、ではそれらの機能を使って「どう使うか」というのはまだちゃんと分かっていないと感じた。ただそのへんはまずは自分でいろいろと使ってみるところから始めたいと思った。

読書ノート

  • ロールグラフとは、同じロールに所属するホストが1つのグラフにまとめられたもの 651
  • PagerDuty連携を利用すると、通知先を時間で変更するなど、柔軟なアラート通知ができる 1575
  • メタデータプラグインはホストのメタデータを登録するプラグイン 1742
  • checkプラグインを作るときは、github.com/mackerelio/checkersを使うと便利 1979
  • MackerelはAPIを用いて、「ホスト情報を一元管理する」という思想を推奨している 2531
  • インテグレーションで対応していないクラウド製品との連携は、 2714
    • mkrでホストを作成
    • mkr throwで作成したホストに投稿
    • cronで定期的に送信
    • という方法でできる
  • ホストステータスの自動変更や自動退役 3127
    • mackerel-agentの[host_status]設定でon_start/on_stopを設定することで、ステータスを変更可能
  • mkr pullなどで取得したデータとリモートのデータがずれてないかをCIする 3352
  • 式を使って柔軟なグラフを書く 3371
  • GMOペパボでのMackerel活用事例 3759
    • デプロイ先のホスト一覧をmackerel経由で取得
    • hostsファイルの自動生成
    • 退役忘れホストの自動検知