Dockerネットワークで遊ぶ_その4_IP,TCPキャプチャ編

## はじめに

ルーター自作本を読みながら、Dockerネットワーク内でC言語を眺めている

今回は同一ネットワーク内において、PINGとTCPのキャプチャを試す

### 本の紹介

ネットワークプログラミングの世界へ

https://gihyo.jp/book/2011/978-4-7741-4745-1

### 連載情報

連載|内容
---|---
[その１](https://qiita.com/t13801206/items/0fd95e85377098f996b3)|〈実践〉同じセグメント内のPING疎通確認
[その2](https://qiita.com/t13801206/items/0858f2af9c57a9db65aa)|〈コード〉イーサネットヘッダの中身をみてみる
[その3](https://qiita.com/t13801206/items/81459f9374bffcd293ec)|〈コード〉ARP,IP,ICMPの中身をみてみる
[その4](https://qiita.com/t13801206/items/478493c1527cbcf0511c)|〈実践〉IP,TCPをキャプチャする
[その5](https://qiita.com/t13801206/items/7fa2f7bf75021899e05e)|〈実践）ルーターを準備する
[その6](https://qiita.com/t13801206/items/0aa1d0f2b762d013e9f8)|〈実践〉別セグメントのWEBへアクセスをする

## 関数

- [socket() - ソケットの作成](https://www.ibm.com/docs/ja/zos/2.3.0?topic=functions-socket-create-socket)
- [perror() — エラー・メッセージの出力](https://www.ibm.com/docs/ja/i/7.3?topic=functions-perror-print-error-message)
- [memset() — 値へのバイトの設定](https://www.ibm.com/docs/ja/i/7.2?topic=functions-memset-set-bytes-value)
- [ioctl() - 装置の制御](https://www.ibm.com/docs/ja/zos/2.3.0?topic=functions-ioctl-control-device)
- [htons() - ネットワーク・バイト・オーダーへの符号なし短整数の変換](https://www.ibm.com/docs/ja/zos/2.3.0?topic=lf-htons-translate-unsigned-short-integer-into-network-byte-order)
- [ntohs() - ホスト・バイト・オーダーへの符号なし短整数の変換](https://www.ibm.com/docs/ja/zos/2.2.0?topic=lf-ntohs-translate-unsigned-short-integer-into-host-byte-order)

## Ethernetタイプ

IP, ARP, SNMP・・など2byte

[Ethernetタイプ番号 ( Ethernet Type Number )](https://www.infraexpert.com/study/tea13.htm)

### ether_header構造体

```c:cat /usr/include/net/ethernet.h
struct ether_header
{
  uint8_t  ether_dhost[ETH_ALEN];       /* destination eth addr */
  uint8_t  ether_shost[ETH_ALEN];       /* source ether addr    */
  uint16_t ether_type;                  /* packet type ID field */
} __attribute__ ((__packed__));
```

### sockaddr_ll構造体

```c:cat /usr/include/netpacket/packet.h
struct sockaddr_ll
  {
    unsigned short int sll_family;
    unsigned short int sll_protocol;
    int sll_ifindex;
    unsigned short int sll_hatype;
    unsigned char sll_pkttype;
    unsigned char sll_halen;
    unsigned char sll_addr[8];
  };

  /* Packet types.  */

#define PACKET_HOST             0               /* To us.  */
#define PACKET_BROADCAST        1               /* To all.  */
#define PACKET_MULTICAST        2               /* To group.  */
#define PACKET_OTHERHOST        3               /* To someone else.  */
#define PACKET_OUTGOING         4               /* Originated by us . */
```

## 本書IPキャプチャを試す

`Src/Link/ltest`をroot権限で実行すると、レイヤ3レベルでパケットの中身を監視できる

### Pingを打つ

[その1](https://qiita.com/t13801206/items/0fd95e85377098f996b3)で作ったサーバーから、クライアントに対してPINGを打つ
`-c 1`で１回だけ打つ

**`ping -n -I eth0 -c 1 Client1`**

PINGをクライアントが受けたあとに、クライアント側からARPが続けて送られている
5秒後にARPが実行されるらしい、詳しくは[参考の記事](https://zenn.dev/hinoshiba/articles/linux-ping-rearp-5sec)へ。

```bash
sll_family=17
sll_protocol=8
sll_ifindex=78
sll_hatype=1
sll_pkttype=0
sll_halen=6
sll_addr=02:42:AC:12:00:02
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
sll_family=17
sll_protocol=8
sll_ifindex=78
sll_hatype=1
sll_pkttype=4
sll_halen=6
sll_addr=02:42:AC:12:00:03
ether_header----------------------------
ether_dhost=02:42:ac:12:00:02
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)

sll_family=17
sll_protocol=1544
sll_ifindex=78
sll_hatype=1
sll_pkttype=4
sll_halen=6
sll_addr=02:42:AC:12:00:03
ether_header----------------------------
ether_dhost=02:42:ac:12:00:02
ether_shost=02:42:ac:12:00:03
ether_type=806(ARP)
sll_family=17
sll_protocol=1544
sll_ifindex=78
sll_hatype=1
sll_pkttype=0
sll_halen=6
sll_addr=02:42:AC:12:00:02
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:02
ether_type=806(ARP)
```

`socket`[関数](https://www.ibm.com/docs/ja/zos/2.3.0?topic=functions-socket-create-socket)の第3引数を`ETH_P_ALL`から`ETH_P_IP`に変更すると、冒頭の受信だけが表示される

```bash
sll_family=17
sll_protocol=8
sll_ifindex=78
sll_hatype=1
sll_pkttype=0
sll_halen=6
sll_addr=02:42:AC:12:00:02
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
```

## 本書TCPキャプチャを試す

`Src/Pcap/pcap eth0`をroot権限で実行すると、レイヤ4レベルでパケットの中身を監視できる

### TCPのチェックサム

[TCPオフロード](https://www.i-highway.com/business/toe/)

TCPのチェックサムの計算をNICが代行する場合がある
送出されるパケットについて
リンクレイヤでキャプチャすると、それはまだNICを出る前のデータであるため
チェックサムが異常であることがある

次章キャプチャ結果にも **bad tcp checksum** と書かれている

## TCP通信テスト

ポート80番へTCP通信テストは`nc`コマンドで。

```bash:nc Client1 80
Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=28592
frag_off=2,0,ttl=64,protocol=6(TCP),check=e272
saddr=172.18.0.2,daddr=172.18.0.3
bad tcp checksum
Packet[54bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:02
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=40,id=0
frag_off=2,0,ttl=64,protocol=6(TCP),check=a6e2
saddr=172.18.0.3,daddr=172.18.0.2
tcp-------------------------------------
source=80,dest=35800
seq=0
ack_seq=2265763664
doff=5,urg=0,ack=1,psh=0,rst=1,syn=0,fin=0,th_win=0
th_sum=29985,th_urp=0
Packet[42bytes]

ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:02
ether_type=806(ARP)
arp-------------------------------------
arp_hrd=1(Ethernet 10/100Mbps.),arp_pro=2048(IP)
arp_hln=6,arp_pln=4,arp_op=2(ARP reply.)
arp_sha=02:42:ac:12:00:02
arp_spa=172.18.0.2
arp_tha=02:42:ac:12:00:03
arp_tpa=172.18.0.2
```

## 参考

https://zenn.dev/hinoshiba/articles/linux-ping-rearp-5sec

## 糸冬了！！