ホームラボを支える技術（おうちのネットワークについて）

## はじめに
はじめまして。私はドワンゴで niconico の検索システムとプレミアム課金システムの開発をしています。

niconico の検索システムについては、先日 ken57 さんが発表されたのでこちらの資料をご覧ください。
https://speakerdeck.com/ken57/niconicofalsejian-suo-sisutemu-2019nian-ban

プレミアム課金システムについては、今後（出せるところについては）発表していきたいと思います。

さて、今日は本当はとある本番システムのネットワーク移設の話を書こうと思っていたのですが、進捗が全然ダメなので代わりに自宅のネットワークの話を書きます。私はネットワークが専門ではありません。自宅だからある程度は自由にできるねって話でもあります。

この記事の内容はもちろん株式会社ドワンゴとは何の関係もありません。しかしながら、この自宅ネットワークを使ってリモートワークをすることはあります。リモートワークに興味がある人は「ドワンゴ 採用」でググってください。

## 自宅のネットワークについて
### 背景
私の契約している ISP は、標準で 2 つのグローバルIPを取得することができます。本来は必要ないのですが、もらえるものならもらっておこうということで、書斎にもルーターを置くことにしました。

......というのがおよそ 2 年ほど前のことで、今では嫁から「いい加減ネットワーク図書いて貰えないと、家のネットが壊れたときどうしようもないんだけど！」と怒られています。アドベントカレンダーのネタとしてもちょうど良いかなということで、今回ちゃんと書くことにしました。

### 論理構成図
既存のネットワークを論理構成図に起こした形が以下となります。

![スライド3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99980/a142298a-7532-2412-896c-2df73b415625.png)

このネットワーク構成で、2 つのグローバル IP を扱うことができます（家庭用ルーターに付与されるグローバル IP と、書斎 L3 スイッチに付与されるグローバル IP）。

一般的な家庭のネットワークと異なるのは、コアネットワークと呼ばれるネットワーク（vlan100）が挟まっているところ、このコアネットワークから書斎用ネットワークが生えているところでしょうか。ネットワークの大きさについては、意図的に `/25` としましたが、家庭内でブロードキャストが問題になるケースはおそらくほぼないかと思いますので、デフォルト（`/24`）でも問題ないかと思います。

家庭内デバイスと呼ばれているのは MacBook Pro や Apple TV、Nintendo Switch、Google Home などです。家庭用ネットワークのプライベート IP アドレスについては、基本的に DHCP で割り当てています。IP アドレスが固定されていた方が扱いやすい一部のデバイス（スイッチ、プリンターなど）については、手動で固定 IP アドレスを設定しています。このため、家庭内ルーターから DHCP で配布されるアドレスは `192.168.11.24` から 96 個（`192.168.11.120` まで）としています。


### 物理構成図
上記の論理構成を実現するための物理構成図は、壁内配線の関係でやや複雑なものになります。

![スライド1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99980/f45d08a4-a4d7-c725-5908-845226f38ded.png)

VLAN ID が 1 つのポートは untag で流しています。なおトランクポートにおける Native VLAN ID（NETGEAR 用語でいう PVID）はすべてデフォルト（`VLAN 1`）です。アクセスポートについてはその VLAN ID を設定しています。

まず、クローゼットの壁面に設置された穴から出てきた光ファイバーが ONU に入ります。
（図には書いていませんが、壁面から出てきた光ファイバーは一度 4 本にブレイクアウトされています。このうち 1 本がインターネット用で、ONU に入ります。ほかの1本が TV アンテナ用で、こちらは同軸に変換されて各居室内に配線されています。残りの 2 本は予備で、他の ISP と契約することができるようです。）

続いて ONU から Core L2 と呼んでいるスイッチに引き込みます。このスイッチから、ホームセキュリティ（電子錠等のシステム）や家庭用ルーター、各居室へ配線しています。家庭用ルーターとは WAN 側と LAN 側で 1 本ずつ、計 2 本配線しています。WAN 側が vlan100、LAN 側が vlan200 となります。また、このルーターに直接 Philips HUE Bridge が接続されています。

元々はこのスイッチはアンマネージスイッチだったのですが、書斎までインターネット側の回線を引くために VLAN を使う必要があったため、自分で交換しています。ホームセキュリティが vlan100 で繋がっているのは、その時の構成を引き継ぐためです。

リビング(R) の対向にもスイッチが配置されており、Apple TV や Nintendo Switch などが接続されています。

書斎には trunk(tagged) で vlan100, vlan200 を流しています。書斎にある L2 スイッチから L3 スイッチと記載している Cisco 841M （統合型サービスルーター）で NAT を行い、この内側のネットワークが vlan300 となっています（本当はルーターと呼ぶのが適切なんですが、L3 スイッチって書くとかっこいいですよね）。

NUC に入っている vlan200 は、ESXi の Management Network です。WebClient を家庭内ネットワークから利用できるようにこのような構成となっています。Management Network は VM からは直接利用できないようにしています。

## 困っていること
この構成だと、手元の MacBook Pro から NUC Server 上にある仮想マシン（VM）に SSH するとき、MacBook Pro にアダプタを使って LAN ケーブルを繋ぐ必要があります。これは手間ですから、インターネット越しで SSH できるように設定するわけですが、VM 数が 10 を超えたあたりからこれも面倒になってきました。

## 解決方法の検討
このような場合に、どのような解決策があるでしょうか。

まず 1 つ思いつくのは、クライアント（たとえば MacBook Pro）からインターネットを通してトンネルを掘ってしまうという方法です。PPPoE や PPTP といった技術が考えられます。この方法の良い点は、

- クライアントからの操作で、利用するときだけ繋ぐことができる（常に繋いでおかなくてよい）
- （設定によっては）自宅以外からもアクセスできる

逆に悪いところは、

- 利用するたびに接続する必要がありやや面倒
- （自宅以外の場合）クライアントと書斎ネットワークが L2 で繋がってしまうため、接続元のプライベートネットワークの構成によっては、ほかの通信に支障が出る

他の方法として、何とかしてコアネットワークを通す方法も考えられるかと思います。グローバル IP アドレスを割り当てているのは ISP が管理する DHCP サーバーですが、ここは何とかすれば何とかなるかもしれません。しかしながら、万が一設定をミスったときにご近所さまと IP アドレスが競合するリスクがあること、DHCP で割り当てられる 2 つの IP が必ず同一のネットワークであるとは限らないため、検討から外します。
（これは逆にいうと L2 で繋がった 2 つの IP が割り当てられる可能性もあるということ･･････。ただし、この 2 つの IP が直接通信できるかは未検証です。）

また別の方法として、2 つのネットワークの間に L3 スイッチを追加することも考えられます。この方法の利点は、

- クライアントからの接続が不要
- 自分が管理するネットワークで完結するため、通信が安定して高速になる（スイッチの性能に依存）

逆に悪い点としては、

- インターネットから利用できない
- ルーティングループが起こる可能性が高まる
- クライアントのルーティングテーブルを変更する必要がある
- どちらかのネットワークに侵入されるともう片方にも侵入されるリスクが高まる

といったことが考えられます。とはいえ、インターネットから利用できないことは受け入れられること、ルーティングループについては設計で回避できるため、クライアントからの接続が不要なこと、安定して高速であるメリットを享受するために、この方法を選択します。
また、ルーティングについては、ルーターで静的ルーティングの設定を行うことで一応通信はできる（はず）かなと思っています（実験もかねてやってみよう、というアドベントカレンダー的なやつ）

### 機材について
Hubot として動いている Raspberry Pi を転用します。

- Raspberry Pi Model 3 B+
  - Ubuntu Server 18.04.3 LTS (Bionic Beaver)
- Kingston 32GB microSDHC card

### 論理設計
vlan200 と vlan300 をまたぐ L3 スイッチとして追加することで、家庭内 Wi-Fi に接続した MacBook Pro から VM へ通信できるようにします。追加する L3 スイッチの IP アドレスは、vlan200 と vlan300 それぞれのネットワークの最後のアドレス（`192.168.x.126`）とします。

また、家庭用ルーターおよび書斎 L3 スイッチで、相手側のネットワークにへの静的ルーティング（static route）の設定を行います。こうすることで、MacBook Pro 側でルーティングの設定をしなくても、デフォルトゲートウェイに設定されている家庭用ルーターを通って、VM と通信ができるようになります。

このとき、論理構成図は以下の通りとなります（変更点はオレンジ色）。

![スライド4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99980/3f857160-9693-07b2-0626-8762f420b9af.png)

ここでもう一度経路について検討しておきます。家庭内デバイスのひとつである MacBook Pro から出たパケットは家庭内ルーターを通り Raspberry Pi へ到達します。一方で、戻りのパケットはルーターを通らずに直接 MacBook Pro へ帰ってきます。

なんだかまずい気がしてきましたが、気にせず進みます。

### 物理設計
物理的には、書斎 L2 スイッチの `#7` に tagged vlan を付けたポートを新しく設定し、Raspberry Pi のオンボード NIC とを LAN ケーブルで接続します。

![スライド2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99980/9940bcf8-f2f8-8045-cb6f-91b2aea406a2.png)

### STEP1: Raspberry Pi に 2 つの IP アドレスを設定する
#### netplan の設定変更
オンボード NIC `eth0` を使って、VLAN ID 200 のとき IP アドレス `192.168.11.126` を、VLAN ID 300 のとき `192.168.21.126` を設定します。手順は以下の通りです。

```
network:
    version: 2
    ethernets:
        eth0:
            addresses: []
            dhcp4: false
    vlans:
      vlan.200:
        id: 200
        link: eth0
        addresses:
          - 192.168.11.126/25
        gateway4: 192.168.11.1
        nameservers:
          addresses:
            - 192.168.11.1
      vlan.300:
        id: 300
        link: eth0
        addresses:
          - 192.168.21.126/25
        routes:
          - to: 192.168.21.0/25
            via: 192.168.21.1
```

なお、デフォルトゲートウェイ（`gateway4` という設定）は `192.168.11.1` としていますが、今回の用途では `192.168.21.1` に設定しても大丈夫です。

#### 設定確認

```
$ sudo netplan --debug generate
DEBUG:command generate: running ['/lib/netplan/generate']
** (generate:1605): DEBUG: 18:03:47.133: Processing input file /etc/netplan/50-cloud-init.yaml..
** (generate:1605): DEBUG: 18:03:47.133: starting new processing pass
** (generate:1605): DEBUG: 18:03:47.134: vlan.300: setting default backend to 1
** (generate:1605): DEBUG: 18:03:47.134: Configuration is valid
** (generate:1605): DEBUG: 18:03:47.134: vlan.200: setting default backend to 1
** (generate:1605): DEBUG: 18:03:47.134: Configuration is valid
** (generate:1605): DEBUG: 18:03:47.134: eth0: setting default backend to 1
** (generate:1605): DEBUG: 18:03:47.134: Configuration is valid
** (generate:1605): DEBUG: 18:03:47.135: Generating output files..
** (generate:1605): DEBUG: 18:03:47.135: NetworkManager: definition eth0 is not for us (backend 1)
** (generate:1605): DEBUG: 18:03:47.135: NetworkManager: definition vlan.200 is not for us (backend 1)
** (generate:1605): DEBUG: 18:03:47.136: NetworkManager: definition vlan.300 is not for us (backend 1)
```

#### 設定反映
```
$ sudo netplan apply
# このタイミングでネットワークは一度切断されます
```

#### スイッチの設定変更
書斎 L2 スイッチで、Raspberry Pi にタグ付きで vlan200 と vlan300 を流すように設定します。

#### IPアドレスが正しく設定されていることを確認
再度 Raspberry Pi にログインし、IPアドレスが正しく設定されていることを確認します。

```
$ ip a
（省略）
4: vlan.200@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:bb:43:25 brd ff:ff:ff:ff:ff:ff
    inet 192.168.11.126/25 brd 192.168.11.127 scope global vlan.200
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:febb:4325/64 scope link
       valid_lft forever preferred_lft forever
5: vlan.300@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:bb:43:25 brd ff:ff:ff:ff:ff:ff
    inet 192.168.21.126/25 brd 192.168.21.127 scope global vlan.300
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:febb:4325/64 scope link
       valid_lft forever preferred_lft forever
```

### STEP2: IP フォワードの設定
#### Ubuntu Firewall を無効化
```
$ sudo ufw disable
ファイアウォールを無効にし、システム起動時にも無効にします
```

#### ip_forward の設定

```
# net.ipv4.ip_forward=1 に変更
$ sudo vim /etc/sysctl.conf

# 設定反映
$ sudo sysctl -p
net.ipv4.ip_forward = 1
```

#### 静的ルーティングの設定
家庭用ルーターおよび書斎用ルーターの設定を変更し、静的ルーティングの設定を行います。

家庭用ルーターには、以下のような設定を行います。

- 宛先アドレス: `192.168.21.0/25`
- ゲートウェイ: `192.168.21.126`
- メトリック: 15（デフォルト）

<img width="941" alt="スクリーンショット 2019-12-08 18.11.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99980/1395627e-f67a-d1d8-052d-29567ce6c0da.png">

また、書斎の L3 スイッチにも同様に静的ルーティングの設定を入れます。

### 確認
#### Raspberry Pi（ゲートウェイ）への通信
手元の MacBook Pro から Raspberry Pi へ ping を飛ばしてみます。

```
$ ifconfig
（省略）
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=400<CHANNEL_IO>
	ether a4:83:e7:c7:2c:a3
	inet6 fe80::45:cc3b:a06:3dc6%en0 prefixlen 64 secured scopeid 0x6
	inet 192.168.11.25 netmask 0xffffff80 broadcast 192.168.11.127
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active
（省略）

$ ping 192.168.21.126
PING 192.168.21.126 (192.168.21.126): 56 data bytes
64 bytes from 192.168.21.126: icmp_seq=0 ttl=64 time=20.160 ms
64 bytes from 192.168.21.126: icmp_seq=1 ttl=64 time=21.179 ms
64 bytes from 192.168.21.126: icmp_seq=2 ttl=64 time=14.353 ms
```

#### vlan300 にある VM への通信
まず、手元の MacBook Pro に静的ルーティングの設定が入っていないことを確認します。

```
$ route -n get 192.168.21.2
   route to: 192.168.21.2
destination: 192.168.21.2
    gateway: 192.168.11.1
  interface: en0
（省略）
```

次に、vlan300 に作った VM `192.168.21.2` へ ping を飛ばしてみます。

```
$ ping 192.168.21.2
PING 192.168.21.2 (192.168.21.2): 56 data bytes
Request timeout for icmp_seq 0
92 bytes from buffalo.setup (192.168.11.1): Redirect Host(New addr: 192.168.11.126)
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 0054 690b   0 0000  3f  01 7132 192.168.11.25  192.168.21.2

Request timeout for icmp_seq 1
92 bytes from buffalo.setup (192.168.11.1): Redirect Host(New addr: 192.168.11.126)
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 0054 bb1f   0 0000  3f  01 1f1e 192.168.11.25  192.168.21.2

（省略）

64 bytes from 192.168.21.2: icmp_seq=7 ttl=63 time=9.962 ms
64 bytes from 192.168.21.2: icmp_seq=8 ttl=63 time=5.761 ms
64 bytes from 192.168.21.2: icmp_seq=9 ttl=63 time=3.551 ms
```

何度か ICMP リダイレクトが起こっていますが、一応 ping は通っています。ICMP リダイレクトが起こっているということは、行きと帰りの経路が異なるということなので、ネットワーク的にはミスコンフィギュレーションといっても良い状態かと思います（詳しい方コメントください）。しかしながら、クライアントのルーティングテーブルはいじりたくないので、何となく繋がってるからいいかー！ということにしておきます。

### こまったこと
#### エンバグした話
手元の Linux kernel バージョンが古いようで、以下のバグを引きました。
https://github.com/raspberrypi/linux/issues/2659

```
$ uname -a
Linux rasp-v3bp 4.15.0-1052-raspi2 #56-Ubuntu SMP PREEMPT Tue Nov 26 15:34:44 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux
```

ちなみに `apt upgrade` しても新しいカーネルは降ってこないので Ubuntu の対応待ち。動作には特に問題がないように思えますが、ログが出るごとに microSD カードの寿命がゴリゴリ削られていきます。

#### IP 設定を間違えた話
Raspberry Pi の IP アドレス設定でうっかり `192.168.11.127`（これは `192.168.11.0/25` におけるブロードキャストアドレスです）を設定してしまいました。画面に繋いで再設定しましたが、ネットワーク周りで設定ミスると面倒なことになるので気をつけて作業していきたい気持ちがあります。

#### 往復で経路を合わせる方法

通信できるからいいじゃんという気もするのですが、ICMP リダイレクトに頼らない方法も一応書いておきます。

手元の MacBook Pro で静的ルーティングの設定を追加します。

```
$ sudo route add -net 192.168.21.0/25 192.168.11.126
add net 192.168.21.0: gateway 192.168.11.126
```

次に、ping で ICMP リダイレクトが起こらないことを確認します。

```
$ ping 192.168.21.2
PING 192.168.21.2 (192.168.21.2): 56 data bytes
64 bytes from 192.168.21.2: icmp_seq=0 ttl=63 time=3.067 ms
64 bytes from 192.168.21.2: icmp_seq=1 ttl=63 time=2.967 ms
64 bytes from 192.168.21.2: icmp_seq=2 ttl=63 time=9.308 ms
64 bytes from 192.168.21.2: icmp_seq=3 ttl=63 time=9.292 ms
64 bytes from 192.168.21.2: icmp_seq=4 ttl=63 time=9.435 ms
```

## まとめ
このネットワーク図があれば何かあったとき何とかできるでしょうか(?)。

うちの ISP はあまり評判は良くないのですが、[fast.com](https://fast.com/) で測定すると日曜日の 22:00、Wi-Fi 経由でも 400-500Mbps 出ています。マンションのバックボーンがちょっと特殊なせいもあるかと思うんですが、月 900 円で 500Mbps って控え目に言っても最高！ あと IPv6 も対応してください！

書いていて気づいたんですが、ホームセキュリティは中身はかなり謎です。Fast Ethernet(100Mbps) でリンクアップしていることはスイッチ側から確認できています。通信が途絶えると警備員が家に来るという未確認情報もあるため詳しい調査を躊躇しています。

あと実は書斎には 1820J とか 2960 とかがいたりしますが、本筋には関係ないので省略しています。このへんの機材はちゃんと使いこなせていないので勉強していきたいと思っています。

皆様もよいクリスマスをお過ごしください。