はじめに
前回までで、ルーター自作でわかるパケットの流れを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
へアクセスして見える実際のページ
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サーバへアクセスできるか確認する
<html><body><h1>It works!</h1></body></html>
サーバ側からはどう見えるか?
クライアントから nc -v -w 1 172.18.0.5 80
をした後で
WEBサーバで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で詳細確認
ip_forward有効|別ネットワークからcurl
立ち戻って、Linux標準機能のIPフォワード機能を使ったらWEBサーバまでたどり着くか検証した
チェックサムはすべて誤り
だけど通信はうまくいっている
これは本書にも書いてあるとおり、TCPオフロード機能によってNICでチェックサムが挿入されるから、、(なのか?)
いずれにせよ、IPフォワード機能を使えば通信はできている
チェックサムは誤っているが・・(二度目)
ip_forward無効|自作ルーターで別ネットワークからcurl
何度もSYNパケットの再送がされており、サーバーからのSYNACKが返ってこない
サーバーでパケットが処理されていない
これは本当にチェックサムが誤っている?
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
が表示されなくなった
まとめ
Dockerネットワークを2つ構築して、AネットワークのクライアントからBネットワークのWebサーバへ接続しようとした
全然つながらないまま
その結果、nc
やtraceroute
の使い方がよく分かっていった
最終的にはTCPオフロードが邪魔をしていたようで
WEBサーバがACKを返してこなかったことが原因(たぶん)と分かった
本書の題名の通り、まさにルータ自作でパケットの気持ちになれた気がする
余談~Linux標準のIPフォワードはすごい
TCPオフロードをOFFにした状態で、Linuxの標準IPフォワード機能を有効にしてみた
(自作ルーターは無効化)
ちゃんとcurl
でWEBページがとってこれた
当たり前かもしれないけど、すごい
参考