hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

tcpdumpの使い方(基本編)



1 tcpdumpとは?

パケットをキャプチャするためのコマンドです。

以下の記事も作成しました。 tcpdumpの使い方(パケットファイルの切り替え方法) - hana_shinのLinux技術ブログ

2 検証環境

2.1 ネットワーク構成

サーバとクライアントの2台構成です。図中のens33はNICの名前です。

                          192.168.2.0/24
client(ens33) -------------------------------------(ens33) server
        .105                                       .100

2.2 版数

サーバ、クライアントともに下記版数です。

[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

カーネル版数は以下のとおりです。

[root@server ~]# uname  -r
3.10.0-1160.el7.x86_64

3 インストール方法

[root@server ~]# yum -y install tcpdump

tcpdumpの版数を確認します。版数は4.9.2です。

[root@server ~]# tcpdump -h
tcpdump version 4.9.2
-snip-

4 オプション一覧

[root@server ~]# tcpdump -h
tcpdump version 4.9.2
libpcap version 1.5.3
OpenSSL 1.0.2k-fips  26 Jan 2017
Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ]
                [ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]
                [ -i interface ] [ -j tstamptype ] [ -M secret ] [ --number ]
                [ -Q|-P in|out|inout ]
                [ -r file ] [ -s snaplen ] [ --time-stamp-precision precision ]
                [ --immediate-mode ] [ -T type ] [ --version ] [ -V file ]
                [ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]
                [ -Z user ] [ expression ]

5 パケットキャプチャに使用できるインタフェースを調べる方法(-D)

tcpdumpを実行するさい、パケットをキャプチャするインタフェースを指定します。 -Dオプションを指定すると、キャプチャに使用できるインタフェース一覧を表示することができます。 本記事では、インタフェースとしてens33を使います。

[root@server ~]# tcpdump -D
1.virbr0
2.bluetooth0 (Bluetooth adapter number 0)
3.nflog (Linux netfilter log (NFLOG) interface)
4.nfqueue (Linux netfilter queue (NFQUEUE) interface)
5.usbmon1 (USB bus number 1)
6.usbmon2 (USB bus number 2)
7.ens33
8.any (Pseudo-device that captures on all interfaces)
9.lo [Loopback]

6 プロミスキャス・モードへの移行を抑止する方法(-p)

tcpdumpを実行すると、tcpdumpNICをプロミスキャス・モードにします。 プロミスキャス・モードは、自分宛だけではなく、ネットワーク上を流れるすべてのパケットを取り込むという動作になります。 自分宛以外のパケットを取り込むというのは、Ethernetフレームの宛先MACアドレスが、自身のNICMACアドレスとは異なっていても、Ethernetフレームを取り込むことを意味しています。

-pを指定することで、NICがプロミスキャス・モードになるのを抑止します。

[root@server ~]# tcpdump -p -i ens33 src host 192.168.2.105

なお、-pオプションを指定しないと、/var/log/messagesに下記メッセージが記録されます。

Dec 25 19:03:49 server kernel: device ens33 entered promiscuous mode

また、tcpdumpを終了すると、/var/log/messagesに下記メッセージが記録されます。

Dec 25 19:06:04 server kernel: device ens33 left promiscuous mode

6 送信元IPアドレス/宛先IPアドレスを指定する方法(src ip/dst ip)

ここでは、送信元IPアドレスが、192.168.2.105(クライアント)のパケットをキャプチャしてみます。

[root@server ~]# tcpdump -i ens33 src host 192.168.2.105

次に、クライアントでサーバ宛てのpingを実行します。 このとき、クライアントでping -c 1 192.168.2.100と入力すると、サーバ側の画面にキャプチャしたパケットが 表示されるのがわかります。これは、先に説明したNICがプロミスキャス・モードになっているからです。 プロミスキャス・モードだと、関係のないパケットを受信して解析がやりにくいので、以下のように-pを指定してサーバの NICをプロミスキャス・モードになるのを抑止します。

[root@server ~]# tcpdump -p -i ens33 src host 192.168.2.105

次にクライアントでpingを1回だけ実行します。 なお、pingの使い方は、pingコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@client ~]# ping -c 1 192.168.2.100

サーバ側のtcpdump実行結果を確認します。 送信元IPが192.168.2.105のパケットが表示されていることがわかります。

[root@server ~]# tcpdump -p -i ens33 src host 192.168.2.105
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
17:48:36.675851 IP 192.168.2.105 > server: ICMP echo request, id 2725, seq 1, length 64

7 送信元ネットワークアドレス/宛先ネットワークアドレスを指定方法(src net/dst net)

送信元ネットワークアドレスを指定する場合は、以下のように指定します。

[root@server ~]# tcpdump -p -i ens33 src net 192.168.3.0/24
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
-snip-

8 送信元ポート番号/宛先ポート番号を指定する方法(src port/dst port)

8.1 事前準備

ncコマンドを実行します。TCPの11111番ポートでncプロセスがListenするようにします。 なお、ncコマンドの使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# nc -kl 11111

lsofコマンドを実行します。 ncプロセスがTCPの11111番ポートでListenしていることがわかります。 なお、lsofコマンドの使い方は、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# lsof -i4:11111 -P
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      3747 root    4u  IPv4  46971      0t0  TCP *:11111 (LISTEN)

TCPの11111番ポートを開放します。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ポート番号を確認します。11111番ポートが開放されていることがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

8.2 実行結果

ここでは、宛先ポート番号が11111のパケットをキャプチャしてみます。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -nn

クライアントでncコマンドを実行します。 宛先IPアドレスにサーバのIP、ポート番号に11111番ポートを指定します。

[root@client ~]# nc 192.168.2.100 11111

tcpdumpの実行結果を確認します。 クライアントからTCPの11111番ポートへのパケットが出力されていることがわかります。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:57:33.430921 IP 192.168.2.105.60632 > 192.168.2.100.11111: Flags [S], seq 3811849999, win 29200, options [mss 1460,sackOK,TS val 13081167 ecr 0,nop,wscale 7], length 0
19:57:33.431708 IP 192.168.2.105.60632 > 192.168.2.100.11111: Flags [.], ack 2737242265, win 229, options [nop,nop,TS val 13081182 ecr 13213087], length 0

なお、上記tcpdumpの実行結果は、以下の①、③のパケット(宛先ポート番号が11111)がキャプチャされています。

client                                          server
  |                                               |
  |                                               |
  |-------------------- SYN --------------------->| ①
  |                                               |
  |<------------------- SYN + ACK --------------->| ②
  |                                               |
  |-------------------- ACK --------------------->| ③
  |                                               |

9 ARPパケットをキャプチャする方法(arp)

ARPパケットをキャプチャするため、以下のように実行します。

[root@server ~]# tcpdump -p -i ens33 arp

次に、クライアントでarpingコマンドを実行します。 arpingコマンドを実行すると、クライアントからサーバにARPリクエストパケットが1つ送信されます。 ARPリクエストパケットを送信すると、サーバのIPアドレスからサーバのNICMACアドレスを求めることができます。 以下の実行結果より、サーバのNIC(192.168.2.100)のMACアドレスはxx:xx:xx:yy:yy:yyであることがわかります。

[root@client ~]# arping -c 1 -I ens33 192.168.2.100
ARPING 192.168.2.100 from 192.168.2.105 ens33
Unicast reply from 192.168.2.100 [xx:xx:xx:yy:yy:yy]  1.674ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)

tcpdumpの実行結果は以下のようになります。 ARPリクエストを受信したあと、ARPリプライを返信していることがわかります。 またARPリプライで、サーバのNIC(192.168.2.105)のMACアドレスがxx:xx:xx:yy:yy:yyであることを返信しています。

[root@server ~]# tcpdump -p -i ens33 arp
20:56:00.575290 ARP, Request who-has server (Broadcast) tell 192.168.2.105, length 46
20:56:00.575315 ARP, Reply server is-at xx:xx:xx:yy:yy:yy (oui Unknown), length 28

10 ICMPパケットをキャプチャする方法(icmp)

ICMPパケットをキャプチャするため、以下のように実行します。

[root@server ~]# tcpdump -p -i ens33 icmp

次に、クライアントでpingコマンドを実行します。pingの宛先はサーバを指定します。

[root@client ~]# ping -c 1 192.168.2.100

サーバでtcpdumpの実行結果を確認します。 ICMP echo requestを受信して、その応答としてICMP echo replyをクライアントに返信していることがわかります。

[root@server ~]# tcpdump -p -i ens33 icmp
21:22:45.156777 IP 192.168.2.105 > server: ICMP echo request, id 4741, seq 1, length 64
21:22:45.156856 IP server > 192.168.2.105: ICMP echo reply, id 4741, seq 1, length 64

11 IPv6パケットをキャプチャする方法(ip6)

IPv6パケットをキャプチャするため、以下のように実行します。

[root@server ~]# tcpdump -p -i ens33 ip6

次に、クライアントでpingコマンドを実行します。pingの宛先はサーバを指定します。 pingの宛先はIPv6のリンクローカルアドレスを指定します。 なお、pingの使い方は、pingコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@client ~]# ping -6 -c 1 -I ens33 fe80::174:936a:8876:8055

サーバでtcpdumpの実行結果を確認します。 ICMP echo requestを受信して、その応答としてICMP echo replyをクライアントに返信していることがわかります。

[root@server ~]# tcpdump -p -i ens33 ip6
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
21:31:29.365316 IP6 fe80::3e2:a9c0:9fa6:a8ad > server: ICMP6, echo request, seq 1, length 64
21:31:29.365391 IP6 server > fe80::3e2:a9c0:9fa6:a8ad: ICMP6, echo reply, seq 1, length 64

12 簡潔な出力をする方法(-q)

-qオプションを指定すると、出力が簡潔になります。 TCPの場合、TCPヘッダの一部の情報だけを表示します。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -n -q
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:08:07.494545 IP 192.168.2.105.43018 > 192.168.2.100.vce: tcp 2

13 時刻に関するパラメータの使い方

13.1 直前にキャプチャした時刻からの経過時刻表示(-ttt)

tcpdumpを実行します。

[root@server ~]# tcpdump -ttt -i ens33 icmp

クライアントからサーバにpingを実行します。

[root@client ~]# ping -c 3 192.168.2.100

tcpdumpの実行結果を確認します。 ICMP echo replyを送信してから、1秒に ICMP echo requestを受信していることがわかります。

[root@server ~]# tcpdump -ttt -i ens33 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 00:00:00.000000 IP 192.168.2.105 > server: ICMP echo request, id 1814, seq 1, length 64
 00:00:00.000113 IP server > 192.168.2.105: ICMP echo reply, id 1814, seq 1, length 64
 00:00:01.001217 IP 192.168.2.105 > server: ICMP echo request, id 1814, seq 2, length 64
 00:00:00.000084 IP server > 192.168.2.105: ICMP echo reply, id 1814, seq 2, length 64
 00:00:01.003023 IP 192.168.2.105 > server: ICMP echo request, id 1814, seq 3, length 64
 00:00:00.000080 IP server > 192.168.2.105: ICMP echo reply, id 1814, seq 3, length 64

13.2 時刻を西暦、時分秒で表示する表示する(-tttt)

tcpdumpを実行します。

[root@server ~]# tcpdump -tttt -i ens33 icmp

クライアントからサーバにpingを実行します。

[root@client ~]# ping -c 3 192.168.2.100

tcpdumpの実行結果を確認します。時刻が西暦、時分秒で表示されていることがわかります。

[root@server ~]# tcpdump -tttt -i ens33 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
2021-12-26 12:27:51.509024 IP 192.168.2.105 > server: ICMP echo request, id 1839, seq 1, length 64
2021-12-26 12:27:51.509150 IP server > 192.168.2.105: ICMP echo reply, id 1839, seq 1, length 64
2021-12-26 12:27:52.515449 IP 192.168.2.105 > server: ICMP echo request, id 1839, seq 2, length 64
2021-12-26 12:27:52.515535 IP server > 192.168.2.105: ICMP echo reply, id 1839, seq 2, length 64
2021-12-26 12:27:53.531047 IP 192.168.2.105 > server: ICMP echo request, id 1839, seq 3, length 64
2021-12-26 12:27:53.531129 IP server > 192.168.2.105: ICMP echo reply, id 1839, seq 3, length 64

13.3 最初にキャプチャしたパケットからの相対時刻を表示する方法(-ttttt)

tcpdumpを実行します。

[root@server ~]# tcpdump -ttttt -i ens33 icmp

クライアントからサーバにpingを実行します。

[root@client ~]# ping -c 3 192.168.2.100

tcpdumpの実行結果を確認します。 最初にキャプチャしたパケットから1秒後、2秒後の時刻が表示されていることがわかります。

[root@server ~]# tcpdump -ttttt -i ens33 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
 00:00:00.000000 IP 192.168.2.105 > server: ICMP echo request, id 1889, seq 1, length 64
 00:00:00.000221 IP server > 192.168.2.105: ICMP echo reply, id 1889, seq 1, length 64
 00:00:01.003282 IP 192.168.2.105 > server: ICMP echo request, id 1889, seq 2, length 64
 00:00:01.003370 IP server > 192.168.2.105: ICMP echo reply, id 1889, seq 2, length 64
 00:00:02.004585 IP 192.168.2.105 > server: ICMP echo request, id 1889, seq 3, length 64
 00:00:02.004670 IP server > 192.168.2.105: ICMP echo reply, id 1889, seq 3, length 64

14 ホスト名やサービス名を数値に変更する方法

14. 1 事前準備

サーバでhostsファイルを編集します。 サーバとクライアントのホスト名とIPアドレスを登録します。

[root@server ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.2.100 server
192.168.2.105 client

テスト用のポート番号を開放します。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ncコマンドを実行します。

[root@server ~]# nc -kl 11111

14. 2 ホスト名をIPアドレスで表示する方法(-n)

まず-nオプションを使わない場合について確認してみます。

[root@server ~]# tcpdump -p -i ens33 port 11111

クライアントでncコマンドを実行します。

[root@client ~]# nc 192.168.2.100 11111

tcpdumpの実行結果を確認します。IPアドレスではなくホスト名が表示されていることがわかります。

[root@server ~]# tcpdump -p -i ens33 port 11111
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
17:59:30.015908 IP client.43014 > server.vce: Flags [S], seq 2375339819, win 29200, options [mss 1460,sackOK,TS val 705644 ecr 0,nop,wscale 7], length 0
17:59:30.015996 IP server.vce > client.43014: Flags [S.], seq 2426277720, ack 2375339820, win 28960, options [mss 1460,sackOK,TS val 785656 ecr 705644,nop,wscale 7], length 0
17:59:30.016493 IP client.43014 > server.vce: Flags [.], ack 1, win 229, options [nop,nop,TS val 705644 ecr 785656], length 0

なお上記のvceはサービス名です。サービス名は/etc/servicesファイルで定義されています。 /etc/servicesでサービス名とポート番号の対応関係が定義されています。

[root@server ~]# cat /etc/services |grep 11111
vce             11111/tcp               # Viral Computing Environment (VCE)
vce             11111/udp               # Viral Computing Environment (VCE)

次に、-nオプションを指定してみます。

[root@server ~]# tcpdump -p -i ens33 port 11111 -n

続けて、クライアントからサーバにデータを送信します。

[root@client ~]# nc 192.168.2.100 11111
12345

今度は、ホスト名ではなくIPアドレスが表示されたことがわかります。

[root@server ~]# tcpdump -p -i ens33 port 11111 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:01:29.037076 IP 192.168.2.105.43014 > 192.168.2.100.vce: Flags [P.], seq 2375339820:2375339826, ack 2426277721, win 229, options [nop,nop,TS val 824666 ecr 785656], length 6
18:01:29.037146 IP 192.168.2.100.vce > 192.168.2.105.43014: Flags [.], ack 6, win 227, options [nop,nop,TS val 904677 ecr 824666], length 0

14. 3 ホスト名とサービス名を数値で表示する方法(-nn)

次は、-nnオプションを指定して、サービス名をポート番号で表示してみます。

[root@server ~]# tcpdump -p -i ens33 port 11111 -nn

続けて、クライアントからサーバにデータを送信します。

[root@client ~]# nc 192.168.2.100 11111
12345
11111

tcpdumpの実行結果を確認します。サービス名も数値で表示されていることがわかります。

[root@server ~]# tcpdump -p -i ens33 port 11111 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:06:51.357431 IP 192.168.2.105.43014 > 192.168.2.100.11111: Flags [P.], seq 2375339826:2375339832, ack 2426277721, win 229, options [nop,nop,TS val 1146986 ecr 904677], length 6
18:06:51.357486 IP 192.168.2.100.11111 > 192.168.2.105.43014: Flags [.], ack 6, win 227, options [nop,nop,TS val 1226997 ecr 1146986], length 0

15 パケットの中身を表示する方法

15.1 パケットの中身を16進数で表示する方法(-x)

サーバでncコマンドを実行します。

[root@server ~]# nc -kl 11111

tcpdumpを実行します。このとき、-xオプションを指定してパケットの中身を16進表示してみます。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -nn -x

クライアントでncコマンドを実行します。 TCPコネクションを確立した後、クライアントからサーバに文字列(12345)を送信します。

[root@client ~]# nc 192.168.2.100 11111
12345

tcpdumpの実行結果を確認します。 パケット末尾のほうに、3132 3334 35と表示されているのがわかります。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -nn -x
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

18:53:24.056781 IP 192.168.2.105.43018 > 192.168.2.100.11111: Flags [P.], seq 976391533:976391539, ack 1612350400, win 229, options [nop,nop,TS val 3939685 ecr 3745633], length 6
        0x0000:  4500 003a 8dcc 4000 4006 26d4 c0a8 0269
        0x0010:  c0a8 0264 a80a 2b67 3a32 8d6d 601a 83c0
        0x0020:  8018 00e5 9214 0000 0101 080a 003c 1d65
        0x0030:  0039 2761 3132 3334 350a

15.2 パケットの中身を16進数とASCII文字で表示する方法(-X)

15.1と同じ手順で実行します。 このとき、tcpdumpのオプションには -Xを指定します。 -Xを指定を指定することで、パケットの中身を16進数とASCII文字で表示することができます。 以下に実行結果を示します。

[root@server ~]# tcpdump -p -i ens33 dst port 11111 -nn -X
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:05:30.989783 IP 192.168.2.105.43018 > 192.168.2.100.11111: Flags [P.], seq 976391539:976391545, ack 1612350400, win 229, options [nop,nop,TS val 4666618 ecr 4019697], length 6
        0x0000:  4500 003a 8dcd 4000 4006 26d3 c0a8 0269  E..:..@.@.&....i
        0x0010:  c0a8 0264 a80a 2b67 3a32 8d73 601a 83c0  ...d..+g:2.s`...
        0x0020:  8018 00e5 4bda 0000 0101 080a 0047 34fa  ....K........G4.
        0x0030:  003d 55f1 3132 3334 350a                 .=U.12345.

16 Netlinkを流れるパケットをキャプチャする方法

nlmonモジュールをローディングします。

[root@server ~]# modprobe nlmon
[root@server ~]# lsmod |grep nlmon
nlmon                  16384  0

nlmonタイプのデバイス(nlmon0)を追加します。

[root@server ~]# ip link add nlmon0 type nlmon
[root@server ~]# ip link set nlmon0 up
[root@server ~]# ip link show dev nlmon0
6: nlmon0: <NOARP,UP,LOWER_UP> mtu 3776 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/netlink

tcpdumpを実行します。なお、NETLINKタイプの場合、標準出力へのデータ出力はサポートされていないため、-wオプションを使ってファイルにデータを保存する必要があります。

[root@server ~]# tcpdump -i nlmon0 -s0 -w test.pcap
dropped privs to tcpdump
tcpdump: listening on nlmon0, link-type NETLINK (Linux netlink), snapshot length 262144 bytes

別のターミナルを開いて、ipコマンドを実行してみます。ipコマンドでなくても、Netlinkを使用するコマンドなら何でも構いません。

[root@server ~]# ip l

Ctrl+Cを押下してtcpdumpを終了します。保存したtest.pcapは、Wiresharkで確認してください。ipコマンド実行時にNetlinkを介してやりとりしたパケットを確認することができます。

[root@server ~]# tcpdump -i nlmon0 -s0 -w test.pcap
dropped privs to tcpdump
tcpdump: listening on nlmon0, link-type NETLINK (Linux netlink), snapshot length 262144 bytes
^C9 packets captured
9 packets received by filter
0 packets dropped by kernel

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。 Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ