海外に置いたAppleTVで日本のNetflixを見る - RaspberryPiで作るVPN切り替え機

## やりたいこと
- USの家に置いてあるAppleTVで、日本のIPからしか使えないサービスを使いたい。
    - AbemaTV
    - Netflix（日本版）
- 常時日本経由のインターネットだと速度面、レイテンシ面で不利なので任意に切り替えられるようにしたい。

## 実装の方針

![](https://i.imgur.com/He6daKn.png)

1. RaspberryPiで日本の実家においてあるサーバへVPNを張り、日本側の出口とする。
2. RaspberryPiの`wlan0`を家庭内LAN、`eth0`を切り替え用LANにして、`eth0`の先にAppleTVをぶら下げる。
3. RaspberryPiにて
    - `eth0` にDHCPサーバ立てて、IP配るようにする
    - `eth0` → `wlan0`の転送設定を入れる
    - デフォルトゲートウェイ(DGW)をJP側とUS側の間で切り替えることで、出口を制御する
    - DGWの切り替えはコマンド入力だと家族が使えないので、Homebridgeを使ってiPhoneから制御できるようにする


## 実際の構築
### VPNを張る

SoftEther VPN Serverを使った拠点間VPN。これはまぁ色んな所に参考情報が記載されているので簡単に。

- 実家側はNIC2枚刺しのCentOSに`SoftEther VPN Server`のVPNサーバを用意
    - 仮想HUBを作成し、2枚めのethにブリッジするようにする
    - これでこの仮想HUBへアクセスすると、実家のLANにL2接続できるようになる
- USのRaspberryPiに`SoftEther VPN Bridge`をインストール
    - 仮想HUBを作成して実家の仮想ハブにカスケード接続を設定する。
    - `tap`デバイスにローカルブリッジするように設定する。(ここでは`tap_jikka`とした) ![](https://i.imgur.com/Vd4ifHF.png)

- この時点でうまくローカルブリッジが動いていれば、数百msec遅延のping、すなわち日本経由でのpingが返ってくるはず。

```
$ ping -I tap_jikka 8.8.8.8
```

### ラズパイのネットワークの設定
#### IPアドレスを固定

`/etc/dhcpcd.conf` で、下記行を追加して、`eth0`と`wlan0`のIPアドレスを固定する。

```
interface eth0
static ip_address=10.0.0.1/8

interface wlan0
static ip_address=192.168.50.111/24
```

#### udhcpd設定
DHCPサーバをインストールしてセットアップ。

1. `udhcpd`をインストール。
2. `/etc/udhcpd.conf` をデフォルトの設定を参考にしながら編集。

```
start           10.0.0.2        #default: 192.168.0.20
end             10.0.0.254      #default: 192.168.0.254
option  subnet  255.0.0.0
interface       eth0            #default: eth0
opt     dns     8.8.8.8
opt     router  10.0.0.1
option  domain  local
option  lease   864000          # 10 days of seconds
```
3. 自動起動とかを設定

```
# systemctl enable udhcpd
# systemctl restart udhcpd
```

#### ルーティングやNATの設定
`/etc/rc.local`の`exit 0`より前に下記記載を追加する。
これにより起動時にこれらのコマンドが実行され、再起動後も有効になる。

```
# パケット転送を許可
echo 1 > /proc/sys/net/ipv4/ip_forward

# 実家サーバへのアクセスは、常にUS側のゲートウェイを通るようにスタティックルートを設定
jikka_ip=$(ping <実家サーバドメイン> | head -n1 | awk 'BEGIN{FS="\\(|\\)"}{print $2}')
route add -host ${jikka_ip} gw 192.168.50.1 wlan0

# iptablesで転送の許可と、10.0.0.0/8 ネットワークへのIPマスカレード設定
iptables -I FORWARD -j ACCEPT
iptables -t nat -I POSTROUTING -s 10.0.0.0/8 -j MASQUERADE
```

ここまでで、`eth0`に繋がっている装置からインターネットに出ていこうとすると、`10.0.0.1`を経由して、`192.168.50.1`のルータ経由での通信となる。　

ここでデフォルトゲートウェイを下記コマンドで変更すると、日本のルータ`192.168.0.1`からインターネットに出ていくようになる。

```
# route add default gw 192.168.0.1 tap_jikka
# route del default gw 192.168.50.1 wlan0
```

#### Homebridgeで切り替えできるようにする
HomebridgeはApple HomeKitの装置を模倣するオープンソースプロダクト。
これを使って電球と同じような感じでiPhoneから切り替えられるようにする。

Homebridgeは導入済みとする。

1. [cmdswitch2](https://www.npmjs.com/package/homebridge-cmdswitch2)プラグインを導入する。
```
# npm -g install homebridge-cmdswitch2
```
2. config.json を編集する。

- `on_cmd`には日本ルータをデフォルトゲートウェイにする設定を入れる。
- `off_cmd`にはUSルータをデフォルトゲートウェイにする設定を入れる。また、VPNサーバへのスタティックルートが落ちる事があるので、ここで改めて追加するようにする。
- `state_cmd`には、日本ルータを向いているときに終了コード0を返すようなコマンドを設定する。

```
    {
      "platform": "cmdSwitch2",
      "name": "JP-US switch",
      "switches": [
        {
          "name": "JP net",
          "on_cmd": "sudo sh -c 'route add default gw 192.168.0.1 tap_jikka; route del default gw 192.168.50.1 wlan0; true'",
          "off_cmd": "sudo sh -c 'route add default gw 192.168.50.1 wlan0; route del default gw 192.168.0.1 tap_jikka; true'",
          "state_cmd": "ip route | grep default | grep jikka",
          "polling": true,
          "interval": 5
        }
      ]
    }
```

これでHomebridgeをrestartするとこんな感じにiPhoneに表示されるようになり、切り替えられるようになる。

![](https://i.imgur.com/UUHrUtH.jpg)



#### Apple TVリモートを使えるようにする

この構成だとApple TVは`10.0.0.0/8`のネットワークにあり、iPhoneは`192.168.0.50/24`のネットワークにあるので、Apple TVからのBonjourのマルチキャストDNS配信がiPhoneから見えないことになる。iOSにはAppleTVのリモコンとして動く機能があるが、この機能はBonjourに依存しているため、このままでは使えないことになる。

Bonjourの実装のひとつであるAvahi-daemonがRaspbianにはプリインストールされており、これのreflector機能を使って、プロキシとして機能して他のネットワークに伝播させることができる。

設定は、`/etc/avahi/avachi-daemon.conf`の`enable-refrector`を`yes`にして有効にすればOK。

```
enable-reflector=yes
```

ただしこれだけでは`10.0.0.0/8`への経路がiOSからは分からないので、家のルータにLAN側のスタティックルートを設定してやる必要がある。うちのASUSのルータだとこんな感じ。

![](https://i.imgur.com/tCiLigB.png)