🧪

WSL で手を動かして覚える TCP/IP 入門

に公開

Windows の WSL2 上で Docker Compose を使い、ping と HTTP の裏側で動く ARP / ICMP / TCP を、実際のパケットを“見ながら”確認します。所要 10〜15 分、初学者向けです。


このハンズオンでやること(ゴールと流れ)

  • 同一サブネット上に client / server / sniffer の3コンテナを立ち上げ、Docker のブリッジ labnet を作る
  • client → server の通信で、まず ARP(IP→MAC 解決)が起き、その後 ICMP(ping) が流れる様子を観察する
  • client から server:8000HTTP でアクセスし、裏側の TCP 3ウェイハンドシェイク を観察する
  • 使い終わったら docker compose down で後片付けして元の状態に戻す

対象と前提

  • Windows 11 + WSL2 + Ubuntu で動作検証をしています。
  • Docker Desktop for Windows をインストールし、Settings → Resources → WSL IntegrationUbuntu を ON にします。

  • 事前チェック:

PowerShell

PS> wsl -l -v 
  NAME                   STATE           VERSION
* docker-desktop-data    Running         2
  docker-desktop         Running         2
  Ubuntu                 Running         2

WSL(Ubuntu)ターミナル

$ docker -v
Docker version 24.0.6, build ed223bc
$ docker compose version
Docker Compose version v2.23.0-desktop.1

いずれもバージョンが表示されれば準備完了です。


作るもの(最小の“私設 LAN”)

  • clientserver は、同じユーザー定義ブリッジ labnet に接続されます(同一サブネット上)。
  • 同一サブネット間の通信はルータを経由せず、直接イーサネットフレームを投げます。そのため最初に ARP で相手の MAC を解決します。
  • snifferserver のネットワーク名前空間をそのまま共有し(同じ eth0 を見る)、tcpdumpserver 側を流れるパケットを観察します。

用語解説:

  • サブネット: 同じネットワークに属する IP のまとまり。サブネット内どうしはルータなしで直接通信できる。
  • MAC アドレス: ネットワーク機器(NIC)の個体識別番号。L2(データリンク層)の「住所」。
  • IP アドレス: コンピュータに割り当てられた L3(ネットワーク層)の「住所」。
  • ARP: IP アドレスから対応する MAC アドレスを問い合わせる仕組み(IP→MAC の対応表を作る)。
  • ネットワーク名前空間: 1 台の OS の中で、仮想的に独立したネットワーク空間を作る仕組み(コンテナごとに分かれる)。

1) ひな形(2ファイル)の用意

本記事で使用する lab 用の内容は、sfx-t/tcpip-labで公開しています。

ホーム直下などに作業用ディレクトリを作ります。

tcpip-lab/
├─ docker-compose.yml
└─ site/
   └─ index.html

docker-compose.yml

services:
  # 簡単な HTTP サーバー(Python の標準機能)
  server:
    image: python:3.12-alpine
    working_dir: /site
    command: sh -c "python -m http.server 8000"
    volumes:
      - ./site:/site:ro
    networks:
      - labnet

  # ツールが一通り入ったクライアント
  client:
    image: nicolaka/netshoot:latest
    command: ["sh", "-c", "sleep infinity"]
    networks:
      - labnet

  # server と同じネット名前空間で動くスニファ
  sniffer:
    image: nicolaka/netshoot:latest
    network_mode: "service:server"   # server の eth0 を共有
    cap_add:
      - NET_ADMIN
      - NET_RAW
    command: ["sh", "-c", "sleep infinity"]
    depends_on:
      - server

networks:
  labnet:
    driver: bridge

ここでしていること(ざっくり):

  • server: Python の簡易 HTTP サーバを 8000 番で起動。volumes でホスト側 site/ を読み取り専用で見せています。
  • client: 診断ツールが多数入った netshoot を常駐(ping, curl, ip, tcpdump などが使えます)。
  • sniffer: network_mode: "service:server" により server と同じネットワーク名前空間(同じ eth0)を共有。cap_add によりパケットのキャプチャが可能です。
  • labnet: Docker のブリッジネットワーク。コンテナ間は同一サブネット上に配置されます。

site/index.html

<!doctype html>
<meta charset="utf-8">
<title>Hello TCP/IP</title>
<h1>Hello TCP/IP</h1>
<p>WSL 上の Docker から配信しています。</p>

ブラウザで見える最小の静的ページです(後で curl で取得します)。


2) 起動と疎通確認

作業フォルダへ移動して起動します。

$ cd tcpip-lab
$ docker compose up -d
[+] Running 3/3
 ✔ Network tcpip-lab_labnet  Created
 ✔ Container tcpip-lab-server-1   Started
 ✔ Container tcpip-lab-client-1   Started

clientserverlabnet 上で起動します。

$ docker compose ps
NAME                    IMAGE                         COMMAND                  SERVICE   CREATED          STATUS          PORTS
...

2-1) ARP と ICMP(ping)を観察

client から serverping を打ち、その様子を sniffer で観察します。

# 1) client シェルへ
$ docker compose exec client sh

# 2) server の IP を調べる
/ # getent hosts server
172.21.0.2      server

# 3) 別タブで sniffer 側の tcpdump を開始(server が受けるパケットを観測)
$ docker compose exec sniffer sh
/ # tcpdump -n -i eth0 icmp

別のタブで client のシェルから ping を実行します。

/ # ping -c 3 server
...
  • 最初に ARP が発生し、server の MAC を解決します。
  • 続いて ICMP が往復します。

2-2) HTTP と TCP ハンドシェイクを観察

sniffer で TCP を観察しながら、client から server:8000 にアクセスします。

# sniffer タブ(server 側通信を観測)
/ # tcpdump -n -i eth0 tcp port 8000

# client タブ
/ # curl -sS http://server:8000/
<html>...
  • SYN → SYN/ACK → ACK の 3 ウェイハンドシェイクが流れ、HTTP のデータが続きます。
  • FIN による接続終了も見られます。

3) 後片付け

$ docker compose down
[+] Running 3/3
 ✔ Container tcpip-lab-client-1   Removed
 ✔ Container tcpip-lab-server-1   Removed
 ✔ Network tcpip-lab_labnet      Removed

以上で、最小構成での ARP / ICMP / TCP の“見て理解する”ハンズオンは完了です。

Discussion