TCPとUDPのパケットを初歩的でも読めるようにする
検証環境
proxmox
ubuntuLXC
tcpudp-dev1
10.0.0.1/30
tcpudp-dev2
10.0.0.2/30
環境変数に設定しておく
#dev1
echo 'export PEER_IP="10.0.0.2"' >> ~/.bashrc && source ~/.bashrc
#dev2
echo 'export PEER_IP="10.0.0.1"' >> ~/.bashrc && source ~/.bashrc
通信の振る舞いを可視化
port8080を監視
dev1から送信
#dev1からてTCP接続を試みる
nc ${PEER_IP} 8080
#dev1からUDP接続を試みる
#下のコマンドではなにもとばない
#nc -u ${PEER_IP} 8080
#パケットを発生させる
echo "hello" | nc -u -w1 ${PEER_IP} 8080
dev2からパケットをキャプチャする
# TCP
root@tcpudp-dev2:/# tcpdump -i any port 8080 -nn -v
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
07:58:48.529211 eth0 In IP (tos 0x0, ttl 64, id 60979, offset 0, flags [DF], proto TCP (6), length 60)
10.0.0.1.57916 > 10.0.0.2.8080: Flags [S], cksum 0x1431 (incorrect -> 0x11e1), seq 4243373352, win 64240, options [mss 1460,sackOK,TS val 4222971792 ecr 0,nop,wscale 10], length 0
07:58:48.529230 eth0 Out IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
10.0.0.2.8080 > 10.0.0.1.57916: Flags [R.], cksum 0xdfea (correct), seq 0, ack 4243373353, win 0, length 0
^C
2 packets captured
2 packets received by filter
0 packets dropped by kernel
#UDP
root@tcpudp-dev2:/# tcpdump -i any port 8080 -nn -v
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
#パケットがカーネルを通過した時刻 > 07:53:48.174598
#どのNICを通ったか > eth0
07:53:48.174598 eth0 In IP (tos 0x0, ttl 64, id 41108, offset 0, flags [DF], proto UDP (17), length 34)
10.0.0.1.47924 > 10.0.0.2.8080: UDP, length 6
UDP
IP層ヘッダー
#UDP
IP (tos 0x0, ttl 64, id 41108, offset 0, flags [DF], proto UDP (17), length 34)
tos(Type of Service) 0x0パケットの優先度#通常は0
ttl(Time To Live) ルーターを通過するたびに1減り、0になると破棄される
ループ防止のため
id 41108 パケットを識別する番号ここでは41108
flags [DF]
DFとはDon't Fragment このパケットは途中で分割(フラグメント)しないでという指示
proto UDP (17)中身がUDPプロトコルであることを示す。TCPは6
length 34 IPパケット全体の長さ(ヘッダー+データ)が34バイトである
送信元と宛先
46924は一時ポート
#どこから > どこへ
10.0.0.1.47924 > 10.0.0.2.8080
UDPのデータ部分
送信したデータ(ペイロード)が6バイトである
UDP, length 6
MTUを小さくしてみる
dev1とdev2で実行
ip link set eth0 mtu 500
dev1から大きなデータを流してみる
ping -s 1000 -c 1 {PEER_IP}
dev2からキャプチャ
#id 34801 (Request) と id 35858 (Reply) が異なるIDになっている
root@tcpudp-dev2:/# sudo tcpdump -ni any icmp -v
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
#flags [+]はまだ続きがある合図
08:14:05.075031 eth0 In IP (tos 0x0, ttl 64, id 34801, offset 0, flags [+], proto ICMP (1), length 500)
#1つ目のパケットにはICMPヘッダー(プロトコル番号1の先頭部分)が含まれている
#ICMP echo request
10.0.0.1 > 10.0.0.2: ICMP echo request, id 685, seq 1, length 480
08:14:05.075079 eth0 In IP (tos 0x0, ttl 64, id 34801, offset 480, flags [+], proto ICMP (1), length 500)
#二つめ以降はIPの分割データしか入っていないた何のプロトコルかわからずにip-proto-1となっている
10.0.0.1 > 10.0.0.2: ip-proto-1
#flags [none]はこれでおしまい
08:14:05.075081 eth0 In IP (tos 0x0, ttl 64, id 34801, offset 960, flags [none], proto ICMP (1), length 68)
10.0.0.1 > 10.0.0.2: ip-proto-1
08:14:05.075099 eth0 Out IP (tos 0x0, ttl 64, id 35858, offset 0, flags [+], proto ICMP (1), length 500)
10.0.0.2 > 10.0.0.1: ICMP echo reply, id 685, seq 1, length 480
08:14:05.075101 eth0 Out IP (tos 0x0, ttl 64, id 35858, offset 480, flags [+], proto ICMP (1), length 500)
10.0.0.2 > 10.0.0.1: ip-proto-1
08:14:05.075103 eth0 Out IP (tos 0x0, ttl 64, id 35858, offset 960, flags [none], proto ICMP (1), length 68)
10.0.0.2 > 10.0.0.1: ip-proto-1
^C
6 packets captured
6 packets received by filter
0 packets dropped by kernel
#ip link set eth0 mtu 1500
TCPのipヘッダー
MSS (Maximum Segment Size): 一度に送れる最大データサイズ
sackOK: パケットが抜けた際に効率的に再送するための機能
TS (Timestamp): 通信の遅延計測用
wscale (Window Scale): 通信速度を上げるための設定
#TCP
(tos 0x0, ttl 64, id 60979, offset 0, flags [DF], proto TCP (6), length 60)
10.0.0.1.57916 > 10.0.0.2.8080: Flags [S], cksum 0x1431 (incorrect -> 0x11e1), seq 4243373352, win 64240, options [mss 1460,sackOK,TS val 4222971792 ecr 0,nop,wscale 10], length 0
07:58:48.529230 eth0 Out IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)