ネットワークのトラブルシュートなどをする時にtcpdumpやwiresharkといったツールを使ってキャプチャデータを取得し、正常ではない通信を特定するなど分析します。その時にIPアドレスやポート番号といったことは当然確認すると思いますが、本記事ではそれ以外に分析に利用できそうな小技をいくつか紹介したいと思います。お題は以下のとおりです。
- MACアドレスからNICのベンダーが分かる
- IPヘッダからおおよそのホップ数が推測できる
- TCP/IPヘッダからOSを推定できる
- TCPの3-way-handshakeからネットワークの遅延を測れる
- TCPの再送状況からネットワーク品質の変化を見れる
- DHCP/mDNS/NBNS/LLMNR から同一ネットワーク内のホスト名がわかる
- TLSのclient helloから接続先のホスト名がわかる
【注意事項】
- 本職のネットワークエンジニアの方にとっては当たり前すぎる内容なので読む価値無しと思われます。むしろ自分が本職のネットワークエンジニアではないので、仕様の間違いのご指摘など歓迎です。
- ここで紹介する小技はネットワークキャプチャ以外の能動的なパケット送信ができない、あるいはしにくい状況を想定しており、能動的なパケット送信によっておおむね同じような情報を取得できる方法はあります
- ネットワークキャプチャはあくまで自分の管理権限がある箇所のみで実施してください。不用意なネットワークキャプチャは法に触れる可能性もありますのでご注意ください。
MACアドレスからNICのベンダーが分かる
無線にしろ有線にしろLAN(正しくはEthernet)に接続する場合はNIC(ネットワークインターフェースカード)にIPアドレスを割り当てて通信します。IPアドレスは時と場合によって変化しますが、NICに割り当てられているMACアドレスは基本的に変更されることはありません。
MACアドレスは6バイトで構成されていますが、先頭3バイトはOUI(Organizationally Unique Identifier)と呼ばれるベンダー固有のIDとなっており、IEEEのサイトで確認できます。
自分で探すこともできますが、Wiresharkを使うと勝手にベンダー名を表示してくれます。
これを使うことで、トラブルシュート時に対象になっているIPアドレスがどのベンダのNICを使っているかがわかり、対象ホストの絞込が(多少)容易になります。
IPヘッダからおおよそのホップ数が推測できる
IPヘッダにはパケットのループを防ぐためにTTL(Time To Live、パケット生存時間)という値が設定されており、これがルータを経由するたびに1ずつ減少して、0になるとパケットが破棄されます。このTTLは最大値が255とは決まっていますが、送信時にいくつに設定しなければいけないとは決まっていません。しかしOSごとにデフォルト値がきまっており、今日日よく使われているOSはだいたい2のn乗(32, 64, 128など)になっています。
Default TTL Values in TCP/IP
http://www.map.meteoswiss.ch/map-doc/ftp-probleme.htm
上記URLではMacOSは60となっていますが、手元のmacOS 10.12.4 は64になっていました。
よって、例えば観測されたパケットのTTLが 56
だったとしたら、それよりも大きい2のn乗の値である 64
がもともとのパケットのTTLであり、その送信元ホストは8ホップ先にいるのかな、ということをおおよそ推定することができます。
ただし、当然ながらデフォルトのTTL値は変更できるため、あくまでtracerouteなどのツールで正確なホップ数を計測できない時に推量するための方法になります。
TCP/IPヘッダからOSを推定できる
先述したとおり、TCP/IPパケットの中にはOSが勝手に値を決めたり、自由にオプションを設定していい項目というのがいくつか存在します。これを利用してnmapのように能動的なスキャンをせずとも、TCP/IPの通常のネットワーク通信を見てOSのデフォルト値などと比較し、送信元や宛先のホストのOSを特定するPassive OS fingerprintingという技術があります。代表的なものとしてp0fというツールがあります。例えば capture.pcap
というファイルにキャプチャデータが入っていた場合、以下のように利用できます。
$ p0f -r capture.pcap -o p0f.log
これによってp0f.logに結果が出力され、以下のように表示されます。
これによってトラブルシュートの対象のホストがどのようなOSを利用しているかを推定し、対象ホストの絞込などに活用できます。
この方法はパケットを送信することなく利用できるので、システムに影響を及ぼさない良い方法に思えますが、一方で推定に使える情報が限られているので概ね精度はあまり高くないという点に注意してください。
TCPの3-way-handshakeからネットワークの遅延を測れる
通常、ネットワークの往復応答時間(Round Trip Time, RTT)を測るためにはpingコマンドなどを用いたICMP echoを用いることが多いですが、能動的にpingをうつのがはばかられる場合や、ネットワーク監視で観測された宛先全体に対しての応答時間を調べたい場合などがあります(例えばあるサーバだけが遅いのか、上流で全体が詰まっているのかどうかの調査など)
そこでネットワークキャプチャだけでこれを調べる方法としてTCPの3-way-handshakeを利用する方法が考えられます。TCPは通信の開始時にSYNパケット、SYN-ACKパケット、ACKパケットをクライアント、サーバ間で相互に投げ合い、通信を確立します。ここでの処理は通常OSのカーネル空間のみで処理が完結し、さらにネットワーク以外のI/Oが発生することもあまりないため、パケットを受けてから返すまでの処理は比較的低遅延で実施されます。これを利用して「SYNパケットが観測されてからACKパケットが観測されるまでの時間」を見ることでおおよそのクライアント・サーバ間のRTTを知ることができます。図にすると以下のような感じです。
現実には監視ポイントはクライアント、あるいはサーバ側に極めて近いポイントであると考えられるため、SYNパケットとSYN-ACKパケットの差分時間、あるいはSYN-ACKパケットとACKパケットの差分時間でほとんどRTTに近い値が取れると思われます。
TCPの再送状況からネットワーク品質の変化を見れる
ブロードバンド環境の普及に伴い、一般の我々が使うネットワークの品質も大きく向上しましたが、手元のルータの不調や上流の回線・ISPの問題でパケットロスが発生することもままあります。これも通常は短い間隔で連続してICMP echo requestなどを送信しパケットロス率などを調査することがありますが、TCPの再送処理をみることでパケットロスが発生しているのかしていないのかをおおよそ把握することができます。
ストリーム型の通信を提供するTCPは送信したデータに対して受け手がACK(受領確認)を送信することで、正しくデータが届いたかどうかを送信側が確認しながら通信を続けます。そのため、再送処理が発生している=どこかでパケットロスなどが発生したと考えることができます。
Wiresharkのデフォルトの設定ではTCPの再送処理などに関連するパケットは黒色の行で表示されます。
上記の図では複数回黒い行が発生していますが、これはサーバから送信されたパケットが1つ欠損したのに対し、速く欠けたパケットを送れとクライアントが急かしているために送っているACKパケットも黒く表示されているだけで、パケットロス率が多くなっているわけではありません。
このように黒い行の数だけパケットロスが起こっているわけではないのですが、Wiresharkの画面で見るとすれば、この黒い行が継続して発生している場合はネットワークの品質が悪くなっている=パケットロスが継続的に発生していると考えることができます。
DHCP/mDNS/NBNS/LLMNR から同一ネットワーク内のホスト名がわかる
ネットワークにおけるトラブルシュートにおいて、問題を起こしているホストは誰がなんの目的で使っているのか、ということを知るのは問題解決において貴重な情報になります。それを知るための大きな手がかりとして対象ホストのホスト名が挙げられます。
ホスト名は固定ホストで逆引きの名前がしっかり設定してあれば容易に知ることができますが、動的なホストだったり管理が行き届いていなかったり使えるデータがキャプチャデータだけだった場合などは DHCP/mDNS/NetBIOS NS/LLMNR などのプロトコルで流れてきているデータを参照することでホスト名にあたりをつけることができます。
-
DHCP
: Dynamic Host Configuration Protocol, 主に動的なIPアドレス割り当てに利用されるプロトコル、UDP port 67, 68 -
mDNS
: multicast DNS, AppleのBonjourで使われている名前解決プロトコル, UDP port 5353 -
LLMNR
: Link Local Multicast Name Resolution, Windows用の名前解決プロトコルでVista以降に実装, UDP port 5355 -
NBNS
: NetBIOS Name Service, NetBIOSでホスト名を解決するプロトコル, UDP port 137
mDNS, LLMNR, NBNSはそれぞれ名前解決のためのプロトコルなので、その中にホスト名が含まれているのはある意味当然ですが、DHCPでもホスト名のやり取りがあります。ホストがネットワークに接続して最初にDHCPサーバを探索するDHCP discoverメッセージの中のオプションにHost Name Optionというものが含まれています。
なおmDNSやLLMNRはホストがネットワークに接続している状態であれば能動的に名前を問い合わせることもできます。(本来そういう目的のプロトコルなので)
TLSのclient helloから接続先のホスト名がわかる
近年HTTP通信を全てTLS化(HTTPS化)するという流れがあり、クライアント側からするとセキュリティ向上のためにはとても良いことなのですが、一方でネットワーク管理・トラブルシュートする側からすると問題を起こしているTCPセッションがどれなのかを特定するのが難しくなるという悩みがあります。特に同じIPアドレスに対して複数のドメイン名をホストしている場合だと、HTTPの中身は全く見えないためTCPセッションの区別が極めて難しくなります。
そこでTLSのServer Name Indication拡張のフィールドを見ることによって、どのホスト名(FQDN)に接続しようとしていたのかを知ることができます。TLSはその上に乗るHTTPのデータなどは完全に暗号化していますが、クライアント・サーバ同士のやりとりでは平文で最初のハンドシェイクなどをしており、その中にあるServer Name Indication拡張ヘッダの中に接続しようとしているホスト名が記述されています。
ちなみに、監視している通信のサーバに管理権限がある場合、TLSのサーバ証明書、秘密鍵・公開鍵を使って無理やりTLSの暗号化部分を解読することも技術的には可能です。Wiresharkにもその機能が実装されているので、詳しくは以下のページを参照してください。