9
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dockerネットワークで遊ぶ_その5_ルーター準備編

Last updated at Posted at 2023-05-07

はじめに

ここまで(その1その4)、同一ネットワークに属するサーバクライアント間の通信を試してきた
※ネットワークはDockerネットワーク

今回は新たにネットワークを1つ追加作成し
2つのネットワークに接続するルーター
新規ネットワークにだけ属する孤独なクライアントを作成する

そして2つのネットワーク間での通信を実現する

image1.png

結構長くなったので、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アドレスの若い番号が振られている

docker network inspect testnw(一部抜粋)
[
    {
        "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号機が所属している

docker network inspect testnw2(一部抜粋)
[
    {
        "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_forward1 の場合は、ルーターマシンに2つ備わるNIC間でパケット転送をしてしまう

今回の検証では、ルータープログラムを使ってその転送機能を実現することが目的なので
Linux標準のIPフォワード機能を無効にする必要がある

そのために(検証の妨げにならないために)、ip_forwardを 0 にする必要がある(本書より)

IPフォワード設定を変更する(標準機能の無効化)

ルーターマシンでデフォルトの設定を確認する
デフォルトの設定は 1 になっている

cat /proc/sys/net/ipv4/ip_forward
1

sudo vi /proc/sys/net/ipv4/ip_forwardで0に書き換えようとしてもできないLinux初心者

こちらのサイトによると、/etc/sysctl.confnet.ipv4.ip_forward = $valueを変更するらしい

sysctlコンフィグを変更する

変更前は # でコメントアウトされている

cat /etc/sysctl.conf | grep ip_forward
#net.ipv4.ip_forward=1

vi /etc/sysctl.confで該当行の行頭のコメント用 # を外し、右辺を0にする

cat /etc/sysctl.conf | grep ip_forward
net.ipv4.ip_forward=0

最後に sysctl -p で変更を反映し、catで確認する

cat /proc/sys/net/ipv4/ip_forward
0

IPフォワードが有効になっていると

ltestでパケットキャプチャすると、eth0->eth1へデータが流れていることがわかる
本来、ルーターとしての機能をまだ有効化していないので、片方のNICから流れてきたデータについては、もう片方のNICは関与しないはず

静的ルーティングを変更する

クライアント2号 ⇒ ルーター ⇒ クライアント1号へPINGを通すために
クライアントのゲートウェイを変更する

具体的には、172.18.0.0/16宛てのパケットは、ルーターマシンに渡す
(dockerではデフルトゲートウェイをの初期値がそのネットワークの x.x.x.1 になっている?)

netstat -r
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 -I 172.18.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
で設定を追加する

netstat -r
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が相手に届かない

Animation1.gif

次回、WEBアクセス編

PINGが通れば、その上のレイヤも難なくいけるだろう
と思っていたが、なかなか苦戦したWEBアクセス

参考

糸冬了!!

9
17
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
9
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?