labunix's blog

labunixのラボUnix

ping(ICMPv4)で出力されたパケットキャプチャデータを読んでみる。

■ping(ICMPv4)で出力されたパケットキャプチャデータを読んでみる。
 以下の続き。

 ラウンドトリップ時間をpingのワンライナーで計測してみる。
 http://labunix.hateblo.jp/entry/20150804/1438641097

$ ping -c 1 -s $((1500-28)) 172.31.31.252
PING 172.31.31.252 (172.31.31.252) 1472(1500) bytes of data.
1480 bytes from 172.31.31.252: icmp_seq=1 ttl=254 time=1.41 ms

--- 172.31.31.252 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.417/1.417/1.417/0.000 ms

■RTT(ラウンドトリップ時間)なので、往復のパケット。

$ sudo tcpdump -i eth0 -n icmp -vvv > icmp.log
$ cat icmp.log 
05:15:33.901362 IP (tos 0x0, ttl 64, id 32943, offset 0, flags [DF], proto ICMP (1), length 1500)
    172.16.16.90 > 172.31.31.252: ICMP echo request, id 3717, seq 1, length 1480
05:15:33.902697 IP (tos 0x0, ttl 254, id 60839, offset 0, flags [none], proto ICMP (1), length 1500)
    172.31.31.252 > 172.16.16.90: ICMP echo reply, id 3717, seq 1, length 1480

■DFフラグはフラグメント化禁止フラグ

$ man tcpdump 2>&1 | grep DF
       フラグメント化禁止フラグ の設定されたパケットの場合、行末に (DF)と表示する。

■tsharkを導入、icmpをキャプチャ

$ sudo apt-get install -y tshark
$ sudo tshark -D 2>&1 | grep eth0
1. eth0

$ sudo tshark -V -i 1 -f "icmp" | grep -v ^0 > icmp.log
Capturing on 'eth0'

■pingのデータを「1」で埋めて

$ man ping | grep -A 3 "\-p pattern\$"
     -p pattern
             送出するパケットを埋めるための 16 個までの ``pad'' バイトを指定で
             きる。 これはネットワークでの、データに依存した問題の診断に有用で
             ある。 たとえば “-p ff” は全て 1 で埋められたパケットを送る。

$ ping -c 1 -s $((1500-28)) -p ff 172.31.31.252
PATTERN: 0xff
PING 172.31.31.252 (172.31.31.252) 1472(1500) bytes of data.
1480 bytes from 172.31.31.252: icmp_seq=1 ttl=254 time=1.41 ms

--- 172.31.31.252 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.413/1.413/1.413/0.000 ms

■tsharkのtcpdumpと関連する箇所のみ確認

$ sed 's/[0-9a-f][0-9a-f]:[0-9a-f][0-9a-f]/XX:XX/g' icmp.log | grep -A 35 "^Internet Protocol"
Internet Protocol Version 4, Src: 172.16.16.90 (172.16.16.90), Dst: 172.31.31.252 (172.31.31.252)
    Version: 4
    Header Length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
        0000 00.. = Differentiated Services Codepoint: Default (0x00)
        .... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
    Total Length: 1500
    Identification: 0xc223 (49699)
    Flags: 0x02 (Don't Fragment)
        0... .... = Reserved bit: Not set
        .1.. .... = Don't fragment: Set
        ..0. .... = More fragments: Not set
    Fragment offset: 0
    Time to live: 64
    Protocol: ICMP (1)
    Header checksum: 0xea77 [validation disabled]
        [Good: False]
        [Bad: False]
    Source: 172.16.16.90 (172.16.16.90)
    Destination: 172.31.31.252 (172.31.31.252)
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
Internet Control Message Protocol
    Type: 8 (Echo (ping) request)
    Code: 0
    Checksum: 0xfc72 [correct]
    Identifier (BE): 5837 (0x16cd)
    Identifier (LE): 52502 (0xcd16)
    Sequence number (BE): 1 (0x0001)
    Sequence number (LE): 256 (0x0100)
    Timestamp from icmp data: Aug  5, 2015 XX:XX:48.000000000 JST
    [Timestamp from icmp data (relative): 0.798956000 seconds]
    Data (1464 bytes)

        Data: af300c0000000000ffffffffffffffffffffffffffffffff...
        [Length: 1464]
■tcpdumpも再度出力してみる。

$ sudo tcpdump -i eth0 -n icmp -vvv -x > icmp.log
$ grep ^0 -A 4 icmp.log 
07:30:49.975264 IP (tos 0x0, ttl 64, id 58904, offset 0, flags [DF], proto ICMP (1), length 1500)
    172.16.16.90 > 172.31.31.252: ICMP echo request, id 5914, seq 1, length 1480
	0x0000:  4500 05dc e618 4000 4001 c682 ac10 105a
	0x0010:  ac1f 1ffc 0800 8c70 171a 0001 193d c155
	0x0020:  0000 0000 6be1 0e00 0000 0000 ffff ffff
--
07:30:49.976687 IP (tos 0x0, ttl 254, id 43062, offset 0, flags [none], proto ICMP (1), length 1500)
    172.31.31.252 > 172.16.16.90: ICMP echo reply, id 5914, seq 1, length 1480
	0x0000:  4500 05dc a836 0000 fe01 8664 ac1f 1ffc
	0x0010:  ac10 105a 0000 9470 171a 0001 193d c155
	0x0020:  0000 0000 6be1 0e00 0000 0000 ffff ffff

■「4500」について、「5」はヘッダ長、ToSはフラグ無し。

$ echo "$((0x5*4)) bytes"
20 bytes

4bit  Version
4bit  Header Length / 4(オクテット)
8bit  Differentiated Services Field(Tos)

■「05dc」はパケット長。

$ echo "$((0x05dc))"
1500

16 Total Length

■識別子はフラグメント時の復元用。

$ echo "$((0xa836))"
43062

16 Identification

■フラグの先頭ビット(3桁目)(Reserved)で予約済みの未使用なので実質2ビット。
 2桁目はDF(Do not Fragment)ビット
 1桁目はMF(More Fragments)ビット。
 それぞれ別のフラグだし、「パケットのフラグメントを許可しない,分割されたパケットの途中のフラグメント」は、
 矛盾しているので起こらないとは思うが、DF,MFの両フラグが立ったパケットの扱いについては分からない。

$ seq 0 3  | awk '{print "ibase=10;obase=2 ;"$1}' | bc | \
    awk '{printf "%03d\n",$1}' | awk '{printf $0" "}; \
      {if($1>="010"){printf "パケットのフラグメントを許可しない,"} \
                else{printf "パケットのフラグメントを 許可する,"}} \
      {if($1%2=="1"){print "分割されたパケットの途中のフラグメント"} \
  else{if($1%2=="0"){print "分割されたパケットの最後のフラグメント"}}}'
000 パケットのフラグメントを許可する,分割されたパケットの最後のフラグメント
001 パケットのフラグメントを許可する,分割されたパケットの途中のフラグメント
010 パケットのフラグメントを許可しない,分割されたパケットの最後のフラグメント
011 パケットのフラグメントを許可しない,分割されたパケットの途中のフラグメント

3  Flags

■最大8191のフラグメント(断片化)した場合の位置を8オクテット単位で示す。

$ echo $((0x1fff))
8191

13 Fragment offset

■TTL

$ echo $((0xfe))
254

8  Time to live

■0から255までのプロトコル番号のうち、ICMPv4は1。

$ w3m -cols 1000 -dump http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml | \
    grep "^  *[0-9]" | cut -c -20 | grep ICMP
   1    ICMP        
  58    IPv6-ICMP   

8  Protocol

■「1の補数和の1の補数」で計算されたチェックサム

16 Header checksum

■送信元IP

$ echo "ac 1f 1f fc" | tr ' ' '\n' | awk '{print "echo $((0x"$1"))"}' | bash | xargs echo -n | sed -e 's/ /./g';echo
172.31.31.252

32 Source

■宛先IP

$ echo "ac 10 10 5a" | tr ' ' '\n' | awk '{print "echo $((0x"$1"))"}' | bash | xargs echo -n | sed -e 's/ /./g';echo
172.16.16.90

32 Destination

■オプション
 32bit単位で無い場合、桁揃えのためにパディングで32bitまで0埋めされる。
 オプション(32-n bit)、パディング(n bit)の構成。
 pingのデータ部分は「0xff」で埋めたので、宛先IPとの間に
 32bit区切りでタイムスタンプ等の付加情報や拡張情報が入る。

 IP Packet Structure
 http://www.freesoft.org/CIE/Course/Section3/7.htm