ルータを介したIPルーティングの設定

# はじめに
　一般に、異なるサブネットのネットワークに属するサーバ同士が通信するには、ルーターを介する必要があります(下図)。
![network1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/230b478f-06a8-d67a-e7a4-eb0070a1532e.png)

　しかし、とあるネットワーク構築において、サーバ2がサーバ1と同一のLAN-1にも属するケースの構築を担当することになりました。
![network2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/9a55c484-ff95-c216-225e-57bcf340586e.png)

　実現したい構成はシンプルに、以下の通りとなります。
*  サーバ1は、eth0からサーバ2のeth0ともeth1とも通信できる。
*  サーバ2は、eth0はサーバ1のeth0と通信でき、eth1はルータを介してサーバ1のeth0と通信できる。

　サーバ1については、LAN-2のサブネットに通信するときのgateway設定を施せばほぼ問題ありません。しかし、サーバ2は単純にLAN-1へのgatewayを設定してしまうと、ルータを介さずLAN-1通信する場合がうまく行かないと考えられます（たぶん）。
そのため、主にサーバ2のルーティング設定でどのような設定をすればいいか、検証する必要があるため、このたび検証用の環境を用意して検検証することにしました。

# 検証環境
　自分が持っているサーバ（というかPC）がUbuntuマシン1台しかないので、Linux KVMを用いて以下のような検証用環境を構成します。ルーターはLinuxをルータ化して代用することにします。
その他の構成としては、
*  ゲストOSはCentOS 7.2（version lock済）を使用する。
*  LAN-1 : 192.168.1.0/24, LAN-2 : 192.168.2.0/24 とする。
*  それぞれのサーバに設定するネットワークアドレスは図の通りとする。
としています。
![Kenshou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624259/3bb752e3-dde7-7b98-a564-755591b2c770.png)

# 検証環境の構築
　検証環境の構築にあたり、LinuxKVMを用いたCentOS7仮想マシンの構築は、本議題から外れるため割愛します。ここでは、仮想マシンは構築した状態から各ethポートに対して実施するIPアドレス設定について記述します。

## サーバ1の静的なIPアドレス設定
　root権限のユーザにて以下の設定を実施します。
1.  nmcliコマンドを用いて、eth0にIPアドレスを設定する。
2.  ネットワークを再起動する。

```shell-session

#  nmcli con add type ethernet ifname eth0
#  nmcli con mod ethernet-eth0 ipv6.method ignore ipv4.method manual ipv4.address 192.168.1.10/24
#  systemctl restart network
```
## サーバ2の静的なIPアドレス設定
　サーバ1と同様、root権限のユーザにて以下の設定を実施します。
1.  nmcliコマンドを用いて、eth0、eth1にIPアドレスを設定する。
2.  ネットワークを再起動する。

```shell-session
#  nmcli con add type ethernet ifname eth0
#  nmcli con mod ethernet-eth0 ipv6.method ignore ipv4.method manual ipv4.address 192.168.1.20/24
#  nmcli con add type ethernet ifname eth1
#  nmcli con mod ethernet-eth1 ipv6.method ignore ipv4.method manual ipv4.address 192.168.2.20/24
#  systemctl restart network
```
## ルーターの設定
### その１：静的なIPアドレス設定
　サーバ1と同様、root権限のユーザにて以下の設定を実施します。
1.  nmcliコマンドを用いて、eth0、eth1にIPアドレスを設定する。
2.  ネットワークを再起動する。

```shell-session
#  nmcli con add type ethernet ifname eth0
#  nmcli con mod ethernet-eth0 ipv6.method ignore ipv4.method manual ipv4.address 192.168.1.254/24
#  nmcli con add type ethernet ifname eth1
#  nmcli con mod ethernet-eth1 ipv6.method ignore ipv4.method manual ipv4.address 192.168.2.254/24
#  systemctl restart network
```

### その2：IPフォワーディング設定
LAN1<->LAN2間のファワーディングを有効にするため、/etc/sysctl.confにカーネルパラメータの設定変更を記述します。編集終了後、ルータを再起動します。

```shell-session
#  vi /etc/sysctl.conf
```
```vim
# System default settings live in /usr/lib/sysctl.d/00-system.conf.
# To override those settings, enter new settings here, or in an /etc/sysctl.d/<name>.conf file
#
# For more information, see sysctl.conf(5) and sysctl.d(5).

net.ipv4.ip_forward=1
```

# 導通検証のやり方
　基本的にはpingとtcpdumpを用いて経路ごとにecho requestとecho replyのやりとりを確認します。
（例）経路：サーバ2 eth1 -> サーバ1 eth0へのping
1. サーバ1にて、`tcpdump -i eth0 icmp`でeth0のパケット送受信をウォッチする。
2. サーバ2にて、`tcpdump -i eth1 icmp`でeth1のパケット送受信をウォッチする。
3. サーバ2にて、`ping -I eth1 192.168.1.10`とデバイス指定pingを実行する。
4. tcpdumpのICMPのやり取りとping応答の状況を確認する（下のサンプル参照）。

```shell-session
(サーバ1 tcpdump)
#  tcpdump -i eth0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
01:19:20.110270 IP 192.168.2.20 > centos1: ICMP echo request, id 1038, seq 1, length 64
01:19:20.110311 IP centos1 > 192.168.2.20: ICMP echo reply, id 1038, seq 1, length 64
01:19:21.111793 IP 192.168.2.20 > centos1: ICMP echo request, id 1038, seq 2, length 64
01:19:21.111829 IP centos1 > 192.168.2.20: ICMP echo reply, id 1038, seq 2, length 64
                                  (以下略)

(サーバ2 tcpdump)
#  tcpdump -i eth1 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
01:19:19.788623 IP 192.168.2.20 > 192.168.1.10: ICMP echo request, id 1038, seq 1, length 64
01:19:19.789339 IP 192.168.1.10 > 192.168.2.20: ICMP echo reply, id 1038, seq 1, length 64
01:19:20.789920 IP 192.168.2.20 > 192.168.1.10: ICMP echo request, id 1038, seq 2, length 64
01:19:20.790528 IP 192.168.1.10 > 192.168.2.20: ICMP echo reply, id 1038, seq 2, length 64
                                  (以下略)

(サーバ2 ping)
#  ping -I eth1 192.168.1.10
PING 192.168.1.10 (192.168.1.10) from 192.168.2.20 eth1: 56(84) bytes of data.
64 bytes from 192.168.1.10: icmp_seq=1 ttl=63 time=0.905 ms
64 bytes from 192.168.1.10: icmp_seq=2 ttl=63 time=1.13 ms
                                  (以下略)
```

# 検証結果：各経路でping導通するために必要なルーティング設定
　各経路でのping導通確認を実施し、以下の設定が必要であるとわかりました。なお、ここで導出した設定はipコマンド等の揮発な設定のため、静的に実施したい場合はnmcliによる設定やsysctl.confへの追記、もしくは導出したコマンドをシェルスクリプトにまとめsystemdのサービス登録して起動時にONESHOT実行するなどが必要です。

## サーバ1の設定
　LAN-2へのルーティング設定を追加します。

```shell-session
#  ip route add 192.168.2.0/24 via 192.168.1.254 dev eth0
```

## サーバ2の設定
### その１：ルーティング設定
#### その1-1：eth1のデフォルトゲートウェイ設定
　eth1から出力する通信はルータをdefault gatewayに設定します。

```shell-session
# ip route add default via 192.168.2.254 dev eth1  proto static  metric 100
```

#### その1-2：eth1から入力されたパケットは、eth1から返却する設定
　サブネットごとのルーティング優先度により変わりますが、以下のようにroute優先度がLAN1＞LAN2の場合、eth1に入力されたパケットの返却先サブネットがLAN1の場合、返却パケットがeth0から出力されてしまいます。

```shell-session
#  ip route show table main
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.20  metric 100 
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.20  metric 100 
```
　これを回避するため、eth1に入力されたパケットに適用するルーティングルールを追加する必要があります。
(設定)
*  /etc/iproute2/rt_tablesにsubroute-eth1を定義する。
*  ip route コマンドでsubroute-eth1にルーティングルールを追加する。
*  ip rule コマンドでsubroute-eth1を有効にする。

```shell-session
#  echo "100     subroute-eth1" >> /etc/iproute2/rt_tables
#  ip route add table subroute-eth1 192.168.2.0/24 dev eth1 scope link proto kernel
#  ip route add table subroute-eth1 192.168.1.0/24 via 192.168.2.254 dev eth1
#  ip rule add from 192.168.2.20 table subroute-eth1 prio 100
#  ip rule show
0:	from all lookup local 
100:	from 192.168.2.20 lookup subroute-eth1 
32766:	from all lookup main 
32767:	from all lookup default
#  ip route show table subroute-eth1
192.168.1.0/24 via 192.168.2.254 dev eth1 
192.168.2.0/24 dev eth1  proto kernel  scope link 
```


### その2：rp_filter設定（非常に重要）
（参考）[CentOS 7 の rp_filter でハマった件 ( https://mano.xyz/2008/ )](https://mano.xyz/2008/)
　　　＊参考にさせていただきました。誠にありがとうございます。
　`CentOS7は標準設定では入力インターフェイスと出力インターフェイスが異なるトラフィックを破棄する`のでカーネルパラメータを変更します。

```shell-session
#  echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter 
```

## 設定後の導通確認結果
以下の4経路でのping導通を確認できました。
*  経路：サーバ1 eth0 -> サーバ2 eth0へのping　：　OK
*  経路：サーバ1 eth0 -> サーバ2 eth1へのping　：　OK
*  経路：サーバ2 eth0 -> サーバ1 eth0へのping　：　OK
*  経路：サーバ2 eth1 -> サーバ1 eth0へのping　：　OK

検証は、以上です。