LoginSignup
23
32

More than 1 year has passed since last update.

Dockerネットワークで遊ぶ_その6_WEBアクセス編

Last updated at Posted at 2023-05-07

はじめに

前回までで、ルーター自作でわかるパケットの流れをDocker内のネットワークで試すことを一通り終えた

今回はPINGだけではなく、アプリレベルでの疎通確認を行う

具体的には、2つあるネットワークの片方にWEBサーバを立てて
他方のネットワークからルーターマシンを介してブラウジング(実態はcurl)できることを確認する

連載情報

連載 内容
その1 〈実践〉同じセグメント内のPING疎通確認
その2 〈コード〉イーサネットヘッダの中身をみてみる
その3 〈コード〉ARP,IP,ICMPの中身をみてみる
その4 〈実践〉IP,TCPをキャプチャする
その5 〈実践)ルーターを準備する
その6 〈実践〉別セグメントのWEBへアクセスをする

Webサーバーとの通信

Dockerのhttpdイメージを使ってWEBサーバを立てる
httpdは下記の通り中身はApacheであり、コンテナ起動してローカルホストへアクセスすれば簡単にページが見れる

What is httpd?
The Apache HTTP Server, colloquially called Apache, is a Web server application notable for playing a key role in the initial growth of the World Wide Web.

コンテナ起動後にlocalhost:8080へアクセスして見える実際のページ

image.png

Webサーバをたてる

  • ポートは8080
  • ホスト名はWebServer
  • 静的ルーティングを変更するために特権--privilegedを与える
docker pull httpd
docker container run -itd --privileged --mount type=bind,source=/d/200_Study/2304_Router_Jisaku,target=/app -p 8080:80 --net testnw --hostname WebServer --name web httpd:latest
docker container exec -u root -it web /bin/bash

静的ルートを変更する

デフォルトルートがx.x.x.1を向いているので
172.19.0.0/16宛てのパケットをルーターマシン 172.18.0.2 へ流すよう変更する

apt update
apt install iproute2

# ルート変更
ip route add 172.19.0.0/16 via 172.18.0.2 dev eth0

同じネットワークからWEBサーバへ疎通確認

まずは本題へ入る前に、同じネットワーク内でWEBサーバへアクセスできるか確認する

curl WebServer
<html><body><h1>It works!</h1></body></html>

サーバ側からはどう見えるか?

クライアントから nc -v -w 1 172.18.0.5 80 をした後で
WEBサーバでnetstat -tanをすると、最終行にクライアントからのアクセスが確認できる

netstat -tan
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.11:44109        0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 172.18.0.5:80           172.18.0.3:45656        SYN_RECV
パケットキャプチャ結果
Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=61199
frag_off=2,0,ttl=64,protocol=6(TCP),check=7ff3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum
Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:05
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=0
frag_off=2,0,ttl=64,protocol=6(TCP),check=8fe2
saddr=172.18.0.5,daddr=172.18.0.3
bad tcp checksum
Packet[66bytes]

ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=61200
frag_off=2,0,ttl=64,protocol=6(TCP),check=86f3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum
Packet[140bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=126,id=61201
frag_off=2,0,ttl=64,protocol=6(TCP),check=3bf3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum
Packet[66bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:05
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=23601
frag_off=2,0,ttl=64,protocol=6(TCP),check=6686
saddr=172.18.0.5,daddr=172.18.0.3
bad tcp checksum
Packet[336bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:05
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=322,id=23602
frag_off=2,0,ttl=64,protocol=6(TCP),check=5785
saddr=172.18.0.5,daddr=172.18.0.3
bad tcp checksum
Packet[66bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=61202
frag_off=2,0,ttl=64,protocol=6(TCP),check=84f3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum
Packet[66bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=61203
frag_off=2,0,ttl=64,protocol=6(TCP),check=83f3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum
Packet[66bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:03
ether_shost=02:42:ac:12:00:05
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=23603
frag_off=2,0,ttl=64,protocol=6(TCP),check=6486
saddr=172.18.0.5,daddr=172.18.0.3
bad tcp checksum
Packet[66bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=52,id=61204
frag_off=2,0,ttl=64,protocol=6(TCP),check=82f3
saddr=172.18.0.3,daddr=172.18.0.5
bad tcp checksum

【本題】別ネットワークからWEBサーバへ疎通確認

上記と同じ方法で別ネットワークからWebServerにアクセスしようとしても応答なし

nc -zv 172.18.0.5 80
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: TIMEOUT.

ここから1日以上かけて長い長い原因究明をした・・・

サーバ側でnc受信

  • サーバ: nc -vul 172.18.0.5 8888
  • クライアント: nc -u 172.18.0.5 8888
結果
  • 同一ネットワークからは受信可
  • 他ネットワークからは不可
  • なお他ネットワークからも、サーバのNICまでは届いている

traceroute -I (ICMP)

ICMPは通る

traceroute -I 172.18.0.5
traceroute to 172.18.0.5 (172.18.0.5), 30 hops max, 60 byte packets
 1  myrouter.testnw2 (172.19.0.2)  0.264 ms  0.234 ms  0.311 ms
 2  172.18.0.5 (172.18.0.5)  0.696 ms  0.876 ms  1.023 ms

TCP Traceroute

tcptracerouteも通る

tcptraceroute 172.18.0.5 80
Running:
        traceroute -T -O info -p 80 172.18.0.5
traceroute to 172.18.0.5 (172.18.0.5), 30 hops max, 60 byte packets
 1  myrouter.testnw2 (172.19.0.2)  0.258 ms  0.146 ms  0.298 ms
 2  172.18.0.5 (172.18.0.5) <syn,ack>  0.558 ms  0.639 ms  0.916 ms

これは traceroute に -T オプションを付けたものと同等

※(前回確認済だった)

tracerouteのオプション

traceroute --helpより一部抜粋

-I --icmp Use ICMP ECHO for tracerouting
-T --tcp Use TCP SYN for tracerouting (default port is 80)
-U --udp Use UDP to particular port for tracerouting

traceroute -U と traceroute (無印) が通らない

章題のとおり。
ICMPは通るが、TCP,UDPが通らない

サーバーのインターフェイス監視

サーバーに対するパケットしか見当たらない(=戻りのパケットが無い!)
saddr=172.19.0.3,daddr=172.18.0.5

つまり
ルーターが悪さをしているわけではなく
サーバマシン自体がパケットを送出していないということ・・・!?

パケットキャプチャ結果
Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46342
frag_off=2,0,ttl=63,protocol=6(TCP),check=882e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum

Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46343
frag_off=2,0,ttl=63,protocol=6(TCP),check=872e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum

Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46344
frag_off=2,0,ttl=63,protocol=6(TCP),check=862e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum

Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46345
frag_off=2,0,ttl=63,protocol=6(TCP),check=852e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum

Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46346
frag_off=2,0,ttl=63,protocol=6(TCP),check=842e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum

Packet[74bytes]
ether_header----------------------------
ether_dhost=02:42:ac:12:00:05
ether_shost=02:42:ac:12:00:02
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=60,id=46347
frag_off=2,0,ttl=63,protocol=6(TCP),check=832e
saddr=172.19.0.3,daddr=172.18.0.5
bad tcp checksum
TCP Dump

sudo tcpdump -w sample.pcap

pcapファイルはWireSharkで読める

(寄り道)WEBサーバのアクセスログを確認する

/usr/local/apache2の階層で、vi conf/httpd.conf
もともと # でコメントアウトされている行の # を外して、logs以下にファイルが生成されるようにする

CustomLog "logs/access_log" combined

apachectl -k stop でサーバをいったん停止して、再度コンテナに入りなおす
アクセスログにアクセスされた形跡はなかった

Dockerデスクトップがあれば、コンソールにログが流れるので、上記操作をしなくてもログを監視することは可能

WireSharkで詳細確認

WireSharkでチェックサムの検証を有効化する

ip_forward有効|別ネットワークからcurl

立ち戻って、Linux標準機能のIPフォワード機能を使ったらWEBサーバまでたどり着くか検証した

チェックサムはすべて誤り
だけど通信はうまくいっている
これは本書にも書いてあるとおり、TCPオフロード機能によってNICでチェックサムが挿入されるから、、(なのか?)

いずれにせよ、IPフォワード機能を使えば通信はできている
チェックサムは誤っているが・・(二度目)

image.png

ip_forward無効|自作ルーターで別ネットワークからcurl

何度もSYNパケットの再送がされており、サーバーからのSYNACKが返ってこない
サーバーでパケットが処理されていない
これは本当にチェックサムが誤っている?

image.png

TCPオフロードを無効化した。うまくいった。

こちらの記事を参考にサーバ・クライアント双方のNICのTCPオフロードを無効化した

通信がうまくいった!!

サーバとクライアントの両方で設定変更が必要
ethtool -K eth0 rx off
ethtool -K eth0 tx off
ethtool -K eth0 tso off
ethtool -K eth0 gro off
curl成功時のターミナル

このときはIPアドレスが振り替わって、クライアントが172.19.0.3でWEBサーバが172.18.0.2

root@Client2:/app/Src/Pcap# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth0
       valid_lft forever preferred_lft forever

root@Client2:/app/Src/Pcap# curl -v 172.18.0.2
*   Trying 172.18.0.2:80...
* Connected to 172.18.0.2 (172.18.0.2) port 80 (#0)
> GET / HTTP/1.1
> Host: 172.18.0.2
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sun, 07 May 2023 13:22:53 GMT
< Server: Apache/2.4.57 (Unix)
< Last-Modified: Mon, 11 Jun 2007 18:53:14 GMT
< ETag: "2d-432a5e4a73a80"
< Accept-Ranges: bytes
< Content-Length: 45
< Content-Type: text/html
<
<html><body><h1>It works!</h1></body></html>
* Connection #0 to host 172.18.0.2 left intact

WireSharkにもTCP CHECKSUM INCORRECTが表示されなくなった

image.png

まとめ

Dockerネットワークを2つ構築して、AネットワークのクライアントからBネットワークのWebサーバへ接続しようとした

全然つながらないまま
その結果、nctracerouteの使い方がよく分かっていった

最終的にはTCPオフロードが邪魔をしていたようで
WEBサーバがACKを返してこなかったことが原因(たぶん)と分かった

本書の題名の通り、まさにルータ自作でパケットの気持ちになれた気がする

余談~Linux標準のIPフォワードはすごい

TCPオフロードをOFFにした状態で、Linuxの標準IPフォワード機能を有効にしてみた
(自作ルーターは無効化)

ちゃんとcurlでWEBページがとってこれた
当たり前かもしれないけど、すごい

参考

糸冬了!!

23
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
32