はじめに
ここまで(その1、その4)、同一ネットワークに属するサーバクライアント間の通信を試してきた
※ネットワークはDockerネットワーク
今回は新たにネットワークを1つ追加作成し
2つのネットワークに接続するルーターと
新規ネットワークにだけ属する孤独なクライアントを作成する
そして2つのネットワーク間での通信を実現する
結構長くなったので、IPフォワード無効化や静的ルーティングなどの事前準備と
PINGの応答確認まで行う
連載情報
連載 | 内容 |
---|---|
その1 | 〈実践〉同じセグメント内のPING疎通確認 |
その2 | 〈コード〉イーサネットヘッダの中身をみてみる |
その3 | 〈コード〉ARP,IP,ICMPの中身をみてみる |
その4 | 〈実践〉IP,TCPをキャプチャする |
その5 | 〈実践)ルーターを準備する |
その6 | 〈実践〉別セグメントのWEBへアクセスをする |
状況整理
- testnw
172.18.0.0/16
- Server1
- Client1
- Router1 new!!
- testnw2
172.19.0.0/16
new!!- Router1 new!!
- Client2 new!!
いずれもubuntu:latest
イメージを使用
各マシンに固定IPを振っていない。コンテナを起動する順番ごとにIPアドレスの若番が振られる。
環境構築
ネットワーク新規追加
新規ネットワークを作成する。ネットワークの名前はtestnw2
とする。
docker network create --driver bridge testnw2
docker network ls
Linuxマシン2台追加
- ルーターマシンとクライアントを1台ずつ立ち上げる
- ルーティングテーブルを変更するので、特権
--privileged
オプションを付ける
docker container run -itd --privileged --mount type=bind,source=/d/200_Study/2304_Router_Jisaku,target=/app --net testnw2 --hostname Router1 --name myrouter ubuntu:latest
docker container run -itd --privileged --mount type=bind,source=/d/200_Study/2304_Router_Jisaku,target=/app --net testnw2 --hostname Client2 --name myclient2 ubuntu:latest
docker container ls
ルーターマシンを2つのネットワークに所属させる
ルーターマシンは既存のネットワークtestnw
にも所属させる
NICが2つある想定
docker network connect testnw myrouter
ネットワークと所属するマシンの確認
testnw
には既存のサーバ・クライアントと、新規のルーターがある
作った順番にIPアドレスの若い番号が振られている
[
{
"Name": "testnw",
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
"Containers": {
"Name": "myserver",
"IPv4Address": "172.18.0.2/16",
"Name": "myrouter",
"IPv4Address": "172.18.0.4/16",
"Name": "myclient",
"IPv4Address": "172.18.0.3/16",
}
}
]
新たに作成したtestnw2
にはルーターマシンとクライアント2号機が所属している
[
{
"Name": "testnw2",
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
"Containers": {
"Name": "myclient2",
"IPv4Address": "172.19.0.3/16",
"Name": "myrouter",
"IPv4Address": "172.19.0.2/16",
}
}
]
疎通確認
別ネットワークに所属するクライアント同士で PINGを送る
まずはネットワーク系の必要なパッケージをインストールする
このあたりは、その1と同じ
docker container exec -it myclient2 /bin/bash
apt update
apt install -y iputils-ping net-tools traceroute ncat
プログラミング用のパッケージもインストールする
ルーターでは/proc/sys/net/ipv4/ip_forward
も書き換えるので、sudo
を追加する
apt install -y sudo
apt install -y vim make build-essential
PING結果
-
ping Client1
も逆のping Client2
も不通- 別ネットワークに所属するクライアントなので通信できない
-
ping Router1
はクライアント1号2号どちらからも応答あり- ルーターは両方のネットワークに所属するので、どのクライアントからも通信可能
ルーターから各クライアントにPINGを送った結果
testnw
内、ルーターマシンからクライアント1号機へ
root@Router1: ping Client1
PING Client1 (172.18.0.3) 56(84) bytes of data.
64 bytes from myclient.testnw (172.18.0.3): icmp_seq=1 ttl=64 time=7.29 ms
testnw2
内、ルーターマシンからクライアント2号機へ
root@Router1: ping Client2
PING Client2 (172.19.0.3) 56(84) bytes of data.
64 bytes from myclient2.testnw2 (172.19.0.3): icmp_seq=1 ttl=64 time=0.810 ms
Linux標準のIPフォワード機能
ip_forward
が 1 の場合は、ルーターマシンに2つ備わるNIC間でパケット転送をしてしまう
今回の検証では、ルータープログラムを使ってその転送機能を実現することが目的なので
Linux標準のIPフォワード機能を無効にする必要がある
そのために(検証の妨げにならないために)、ip_forward
を 0 にする必要がある(本書より)
IPフォワード設定を変更する(標準機能の無効化)
ルーターマシンでデフォルトの設定を確認する
デフォルトの設定は 1 になっている
1
sudo vi /proc/sys/net/ipv4/ip_forward
で0に書き換えようとしてもできないLinux初心者
こちらのサイトによると、/etc/sysctl.conf
のnet.ipv4.ip_forward = $value
を変更するらしい
sysctlコンフィグを変更する
変更前は #
でコメントアウトされている
#net.ipv4.ip_forward=1
vi /etc/sysctl.conf
で該当行の行頭のコメント用 # を外し、右辺を0にする
net.ipv4.ip_forward=0
最後に sysctl -p
で変更を反映し、cat
で確認する
0
IPフォワードが有効になっていると
ltest
でパケットキャプチャすると、eth0->eth1へデータが流れていることがわかる
本来、ルーターとしての機能をまだ有効化していないので、片方のNICから流れてきたデータについては、もう片方のNICは関与しないはず
静的ルーティングを変更する
クライアント2号 ⇒ ルーター ⇒ クライアント1号へPINGを通すために
クライアントのゲートウェイを変更する
具体的には、172.18.0.0/16宛てのパケットは、ルーターマシンに渡す
(dockerではデフルトゲートウェイをの初期値がそのネットワークの x.x.x.1
になっている?)
Destination Gateway Genmask Flags MSS Window irtt Iface
default 172.19.0.1 0.0.0.0 UG 0 0 0 eth0
172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
下記コマンドで 172.18.0.0/16 ネットワークへの通信をルーターマシンに向ける
sudo route add -net 172.18.0.0 gw 172.19.0.2 netmask 255.255.0.0 eth0
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 172.19.0.1 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 myrouter.testnw 255.255.0.0 UG 0 0 0 eth0
172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
別ネットワークのクライアントへのルート確認
ルーターマシン(172.19.0.2)を経由しようとしていることがわかる
traceroute to 172.18.0.2 (172.18.0.2), 30 hops max, 60 byte packets
1 myrouter.testnw2 (172.19.0.2) 0.534 ms 0.032 ms 0.018 ms
2 * * *
が、クライアントまでは到着しない。。。
ICMP応答(設定が足りていないケース)
受信側のパケットをキャプチャしたところ、ICMPの応答がデフォルトゲートウェイ172.18.0.1
を向いている
(arp -a
の結果、「172.18.0.1 at 02:42:2c:99:3a:c2 [ether] on eth0」とのこと)
ether_header----------------------------
ether_dhost=02:42:2c:99:3a:c2 !!!!!!!!!!!
ether_shost=02:42:ac:12:00:03
ether_type=800(IP)
ip--------------------------------------
version=4,ihl=5,tos=0,tot_len=84,id=921
frag_off=0,0,ttl=64,protocol=1(ICMP),check=e51e
saddr=172.18.0.3,daddr=172.19.0.3
icmp------------------------------------
icmp_type=0(Echo Reply),icmp_code=0,icmp_cksum=51281
icmp_id=27,icmp_seq=1
「!!!!」の行のとおり、ICMP応答の宛先dhost
がルーターマシンを向いていないので
送信側クライアントと同様に、受信側のクライアントにもスタティックルートを設定する
ICMPを応答する側のマシンにもルーティング情報を追加
dockerデフォルトのままでは、x.x.x.1
がゲートウェイになっているので
sudo route add -net 172.19.0.0 gw 172.18.0.2 netmask 255.255.0.0 eth0
で設定を追加する
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 172.18.0.1 0.0.0.0 UG 0 0 0 eth0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
172.19.0.0 myrouter.testnw 255.255.0.0 UG 0 0 0 eth0
172.19.0.0
宛はルーターマシンに送られるようになった
ICMP応答(OK)
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=84,id=50845
frag_off=0,0,ttl=64,protocol=1(ICMP),check=e05b
saddr=172.18.0.3,daddr=172.19.0.3
icmp------------------------------------
icmp_type=0(Echo Reply),icmp_code=0,icmp_cksum=58385
icmp_id=32,icmp_seq=1
実際に動いている様子
一番右の窓から左の窓へPINGを打つ
真ん中のルーターマシンが .Src/Router/router
を実行していないとPINGが相手に届かない
次回、WEBアクセス編
PINGが通れば、その上のレイヤも難なくいけるだろう
と思っていたが、なかなか苦戦したWEBアクセス
参考
- 複数のDockerネットワークを使った基本的な構成例を3つご紹介
- Linux IP forwarding – How to Disable/Enable using net.ipv4.ip_forward