小規模LANの構築ノウハウ（１）：小型PCでL3ルータの基礎を作る

#TL;DR

* LANポートを2つ以上持つ小型PCを使って，L3ルータを作ります
    * 一般的にはONUなどの終端装置がルータの機能を持っていることが多いですが，VPNを張ったりプロキシしたりなど，多様な機能を使いたいので，ルータを設置して運用します
* PCを介して2つのネットワークを片側からもう一方の側へNAPT(IPマスカレード)し，ゲートウェイの機能を実現します
    * iptablesを使用します

# ルータマシン

* 2つ以上のLANポートを持ち，Linuxが稼働するPCを代替物として使用することができます
    * この記事では[OpenBlockS AX3](https://openblocks.plathome.co.jp/products/obs_a/ax3/)を使用していますが，販売終了がアナウンスされてしまいました(2019年1月29日)
    * 初期セットアップは[小規模LANの構築ノウハウ（０） OpenBlockS AX3(LAN2ポート版)をセットアップする](https://qiita.com/myoshimi/items/880c0354809968ce6da9)を参照してください
    * OpenBlockSを使用した理由は，手元にあったこと，比較的省電力で，長期間運用に向きそうなことなどが理由です
    * とは言え，Linuxマシンであれば作業は変わらないので，基本的には同じ作業でルータを作ることができます
        * **Debian9**の環境を使っていますので，ubuntuなどでも同様の手順で構築ができると思います
    * [ECS Liva Zシリーズ](https://www.links.co.jp/item/liva-z-n3350/)などがリーズナブルでよいです
        * [ECS LIVA ZにDebian stretchをインストール](https://qiita.com/mktlab/items/e33e7421a53a879ca78d)などの記事が，インストールの参考になります
    * 通常のデスクトップPCにNICを増設して使用しても良いです
    * ノートPCにUSB-NICを追加しても良いですが，若干安定性に不安があります

# 家庭内ネットワーク概要

* 下図のようなネットワーク構成を作ることを考えます

![nw.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/3653a9e6-99b0-7c4f-0f52-4d031f422b2b.jpeg)

* OpenBlockS AX3がルータとなるPC(ルータPC，ホスト名：gw)です．最もシンプルな構成を考え，以下の機能を持ちます．この記事では，以下の3つの機能の設定を行います．
    1. **Gateway**：外部のネットワーク(internet)に接続します
        * PPPで接続したり，終端装置が一部の機能を担う場合もありますが，この記事では，より上位のネットワークからDHCPでプライベートIPアドレスが振られる状況（マンションなどでときどきある形式）を想定します
    1. **NAPT**：配下のネットワーク（internal）から外部（internet）へのルーティングを行います．この記事で解説します．
    1. **DHCP**：internalに接続したマシンがDHCPクライアントを動かしていた場合，プライベートIP(レンジは192.168.100.101-200)を割り当てます
* internalネットワークには，いくつかのマシンが接続されています．この記事ではそれぞれの設定方法は解説していません．
    * 無線ルータ：無線LANを提供します．DHCPで192.168.100.0/24のプライベートIPを設定します．ブリッジモードで，gwのDHCPサーバから得られるプライベートIPを無線LANの接続クライアントに提供します
    * NAS：ネットワークストレージです．DHCPで192.168.100.0/24のプライベートIPを設定します
    * TV：録画サーバです．DHCPで192.168.100.0/24のプライベートIPを設定します
    * PC：計算用のサーバです．固定のプライベートIPを設定します．

# 1. インターネットへの接続

* 今回の環境の場合，インターネットへの接続は，eth0がDHCPで受け取ったプライベートIPで接続することができます
    * そのため，[小規模LANの構築ノウハウ（０） OpenBlockS AX3(LAN2ポート版)をセットアップする](https://qiita.com/myoshimi/items/880c0354809968ce6da9)で行ったeth0の設定のままでインターネットへ接続できます

# 2. DHCPdでinternalネットワークにプライベートIPを配布する

* DHCPサーバをインストールし，eth1に対してDHCPリクエストが来たときに，192.168.100.101-200のIPアドレスを配布する設定を行います
    * 2つの設定ファイルをいじります
        * /etc/dhcp/dhcpd.conf
        * /etc/default/isc-dhcp-server
* 下記の手順でインストールと設定を行います
    * 設定ファイルは，変更点だけ記載しています

```bash
# DHCPdのインストール
aptitude install -y isc-dhcp-server

cp /etc/default/isc-dhcp-server /etc/default/isc-dhcp-server.orig
vi /etc/default/isc-dhcp-server

# 設定ファイルの位置をコメントアウト
DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
# リクエストを受け付けるNICの指定
INTERFACESv4="eth1"

cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.orig
vi /etc/dhcp/dhcpd.conf

# クライアントに渡すDNSの設定
option domain-name-servers 1.1.1.1, 8.8.8.8;
# DHCPサーバはinternalネットワークで1つだけなので，authoritativeをコメントアウトする
authoritative;
# 配布するプライベートIPのレンジを設定ファイルに追記
# 192.168.100.101-200とする
subnet 192.168.100.0 netmask 255.255.255.0 {
    option routers 192.168.100.1;
    option subnet-mask 255.255.255.0;
    range dynamic-bootp 192.168.100.101 192.168.100.200;
}

# DHCPdを再起動
/etc/init.d/isc-dhcp-server restart
```

* 動作確認は，以下のように行います
    * gw-eth1と別のマシンAを，スイッチングハブを介して接続します
        * internalネットワークです
    * マシンAのDHCPクライアントで，IP（192.168.100.101-200の範囲のいずれかのIP）が得られることを確認します
* この時点では，internalネットワーク内のマシンAからgwを経由してインターネットへ接続することはできません
    * 次章のルーティングを行って，internalとインターネットの接続を行います

# 3. ルータPCの設定

* ルータPCの2つのNIC間のルーティングを行います
    * eth0: インターネット側に接続されるNIC
    * eth1: internalネットワーク側に接続されるNIC
* internalネットワークにあるマシン（無線ルータやNASなど）が，インターネットに接続できるように，ルータPCにNAPTの機能を持たせます
* 手順は以下のとおりです．すべてgwにログインして作業を行います
    1. パケット転送の有効化
    1. NAPT(IPマスカレード)の設定
    1. 設定の恒久化

## 3.1. パケット転送の有効化

* ```/etc/sysctl.conf```を編集して，パケット転送を有効化します
    * 変更点のみ記載します．コメントアウトを解除した上で，```net.ipv4.ip_forward```の値を1にします

```bash
vi /etc/sysctl.conf

net.ipv4.ip_forward=1
```

## 3.2. NAPTの設定

### 最もシンプルな転送設定

* internalネットワークをインターネットにフォワードするためには，```iptables```コマンドで以下のようにIPマスカレードの設定を行うと実現できます．
    * このコマンドを実行した際に，internalネットワーク内のマシンがインターネットに接続できることで，動作を確認できます
    * ただし，この設定だけだとセキュリティ上の不安があるので，次項で複数の転送設定を行います

```bash
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```

### 実用的な転送設定

* ルーティングのみではセキュリティ上の不安があるので，以下のようなスクリプト```/usr/local/bin/fw.sh```を作ります
    * gwへの入力は，SSH，pingのみ許可，それ以外のポートは閉じておく
    * 転送とgwからの出力は許可する
    * 極めて単純な設定です．今後，発展的修正が行われます

```bash
vi /usr/local/bin/fw.sh

#!/bin/bash

# 転送設定（念のため）
echo 1 >/proc/sys/net/ipv4/ip_forward

IPTABLES=/sbin/iptables
# インターネットに接続されたNIC
WAN=eth0

# すべての設定をいったんクリア
${IPTABLES} -F
# gwへの入力は，基本的には拒否します（許可するサービス，ポートは後半で設定します）
${IPTABLES} -P INPUT   DROP
# 転送と出力は許可します
${IPTABLES} -P FORWARD ACCEPT
${IPTABLES} -P OUTPUT  ACCEPT

# 既に確立済みのセッションは入力を許可します
${IPTABLES} -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# icmp(ping)は入力を許可します
${IPTABLES} -A INPUT -p icmp -j ACCEPT
# 自分自身(gw)からのローカル入力を許可します
${IPTABLES} -A INPUT -i lo -j ACCEPT
# ssh接続を許可します
${IPTABLES} -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
# NAPT転送を行います
${IPTABLES} -t nat -A POSTROUTING -o ${WAN} -j MASQUERADE
```

* 作成した```/usr/local/bin/fw.sh```を実行して，ルーティングができること，22/TCP以外の接続ができないことを確認します

```bash
sudo su
chmod 700 /usr/local/bin/fw.sh
sh /usr/local/bin/fw.sh
```

# 3.3. 再起動時のルーティング自動設定

* マシンの起動時に，転送用のスクリプトを実行する設定を行います
    * ```/etc/rc.local```にスクリプトの実行コマンドを記載します

```bash
vi /etc/rc.local

# fw.sh実行コマンドを記載
sh /usr/local/bin/fw.sh
exit 0
```

* gwを再起動してもinternalネットワーク内部のマシンからインターネット接続できるようになっていれば，ただしく動作しています

# 参考

* [小規模LANの構築ノウハウ（０） OpenBlockS AX3(LAN2ポート版)をセットアップする](https://qiita.com/myoshimi/items/880c0354809968ce6da9)
* [ECS LIVA ZにDebian stretchをインストール](https://qiita.com/mktlab/items/e33e7421a53a879ca78d)