TL-WR902ACにOpenWrtとOpenVPNを入れて旅先VPNサーバを作る

# はじめに
　TP-LINK TL-WR902ACというトラベルルーターにOpenWrtとOpenVPNをいれて旅先VPNサーバをつくってみました。大学時代に流行った某RTSゲームを温泉旅館で合宿という名目で年一ぐらいで開催してたんですが、さすがにこのご時世、何人か参加できないとのことで、リモートから乗り込める環境を構築してみました。（ちなみに今年は、富山の宇奈月温泉で開催しました。）

# お断り
OpenWrt化は**自己責任**でお願いします。

# 準備したもの
- TP-LINK TL-WR902AC（3000円ぐらい）
- Google Pixel 3a（買ったけど使ってなかったスマホ）
- NifMoのSIM (3GBで900円。グローバルIPもらえる！）

# 構成
![Untitled Diagram(4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172186/7b546a22-d7f0-9f2e-f2fa-2417550e6c6b.png)
※Pixel 3aとTL-WR902AC間はUSB接続でテザリングします。

# 準備
公式サイトの[手順](https://openwrt.org/toh/tp-link/tl-wr902ac_v3)通りに進めますが、まずTFTPサーバが必要だったので、Windows10上のWSL上にUbuntu20.04をインストールして、そこにtftpd-hpaをいれて作業します。

## WSL(Ubuntu)上で準備
1. tftpサーバをいれる。（WSL上での操作）

```
sudo apt install tftpd-hpa
```

2. ファームを/srv/tftp/にダウンロードし、tp_recovery.binにリネーム（WSL上での操作）

```
cd /srv/tftp
sudo wget http://downloads.openwrt.org/releases/19.07.5/targets/ramips/mt76x8/openwrt-19.07.5-ramips-mt76x8-tplink_tl-wr902ac-v3-squashfs-tftp-recovery.bin
sudo mv openwrt-19.07.5-ramips-mt76x8-tplink_tl-wr902ac-v3-squashfs-tftp-recovery.bin tp_recovery.bin
```

3. TFTPサーバのIPは、「192.168.0.66」にする必要があるのでWindows上でTL-WR902ACと接続するネットワークアダプタのIPアドレスを変更。（Windows上での操作）
4. WSL2でtftpdを起動する。WSLの場合、systemctlから起動できないので、コマンドラインで直起動。（WSL上での操作）

```
sudo /usr/sbin/in.tftpd --listen --user tftp --address :69 --secure /srv/tftp
```
5. tftpのポートを開くとファイアウォール設定の画面が表示されるので許可する。（Windows上での操作）
6. PCとTL-WR902ACを直結

## OpenWrt化
1. TL-WR902ACのリセットボタンをSIMピンとか爪楊枝とかの細い棒で押しっぱなしにした状態で電源ON（USBケーブルを刺す）
2. 20秒ほど押しっぱなしにすると電源LED下のLEDがチカチカしだすのでリセットボタンから離す。OpenWrtファームに書き換わる。
3. しばらくすると自動で再起動
4. ブラウザで[http://192.168.1.1/](http://192.168.1.1/)　にアクセス。OpenWrtのログイン画面が出れば成功。

## OpenWrtの設定
### IPアドレスの変更とDHCPサーバの無効化
初期設定でDHCPサーバが有効なので無効化とIPアドレスを変更します。WebUIから変更するとうまく変更出来なかったのでsshログインして、uciコマンドで以下を打つ。
（ここではまた有線側からインターネットへ接続できるIPアドレス(192.168.249.220)を設定しています。）

```
uci del dhcp.lan.start
uci del dhcp.lan.limit
uci del dhcp.lan.leasetime
uci set dhcp.lan.ra_management='1'
uci set dhcp.lan.ignore='1'
uci set network.lan.ipaddr='192.168.249.220'
uci set network.lan.gateway='192.168.249.1'
uci add_list network.lan.dns='192.168.249.1'
uci commit
/etc/init.d/network restart
```

### OpenVPNのインストール
ここも基本は、公式サイトの[手順](https://openwrt.org/docs/guide-user/services/vpn/openvpn/server)を元に進めます。
sshログインして以下を実行

```
opkg update
opkg install openvpn-openssl openvpn-easy-rsa
```

### OpenVPNの設定
#### 証明書の作成
秘密鍵のパスワードはなしです。sshログインして以下を実行

```
cd /etc/openpvn/
easyrsa init-pki
easyrsa gen-dh #結構時間かかる。。
easyrsa build-ca nopass #「Common Name」聞かれたら適当に入力
easyrsa build-server-full server nopass
easyrsa build-client-full client nopass
openvpn --genkey --secret ta.key
```

「easyrsa gen-dh」は、1時間13分ぐらいかかったので、気長に待ちましょう。。
> root@OpenWrt:/etc/openvpn# time easyrsa gen-dh
> 
> Note: using Easy-RSA configuration from: /etc/easy-rsa/vars
> Generating DH parameters, 2048 bit long safe prime, generator 2
> This is going to take a long time
> ....................................................+...........................
> （略）
> ..................................................................++*++*++*++*
> 
> DH parameters of size 2048 created at /etc/openvpn/pki/dh.pem
> 
> real    1h 13m 42s
> user    1h 13m 28s
> sys     0m 2.86s

#### サーバ設定ファイル作成
内容は以下で、/etc/openvpn/server.confとして保存。tcpの1194ポート、tunデバイスで起動。クライアントには、「10.8.0.0/24」を割り当てます。今回は、クライアント証明書の重複を許す設定をしているのでクライアントに配布する証明書は一つだけです。セキュリティ気にするなら、個々にクライアント証明書を作りましょう。

```
cat << EOF > /etc/openvpn/server.conf
port 1194
proto tcp
dev tun
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/server.crt
key /etc/openvpn/pki/private/server.key
dh /etc/openvpn/pki/dh.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn-ipp.txt
push "route 192.168.249.0 255.255.255.0"
client-to-client
duplicate-cn #クライアント証明書の重複を許す設定
keepalive 10 120
tls-auth ta.key 0
cipher AES-256-CBC
persist-key
persist-tun
status /var/log/openvpn-status.log
log-append  /var/log/openvpn.log
verb 3
EOF
```

#### クライアント設定ファイル作成

クライアントに配布する証明書（秘密鍵、公開鍵）を「/tmp/openvpn-client-key/config」に集めます。

```
mkdir -p /tmp/openvpn-client-key/config
cp /etc/openvpn/pki/ca.crt /tmp/openvpn-client-key/config
cp /etc/openvpn/pki/issued/client.crt /tmp/openvpn-client-key/config
cp /etc/openvpn/pki/private/client.key /tmp/openvpn-client-key/config
cp /etc/openvpn/ta.key /tmp/openvpn-client-key/config
```

また、クライアント側の設定ファイルは、内容は以下で、client.ovpnとして保存。クライアント側の設定ファイルをリモート参加者が書き換えしなくてもよいように、サーバの指定は、ホスト名にしました。NifmoはグローバルIPもらえるので、[No-IP](https://www.noip.com/)という無料のDynamic DNSで登録しました。

```
cat << EOF > /tmp/openvpn-client-key/config/client.ovpn
client
dev tun
proto tcp
remote 合宿地のホスト名.ddns.net 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
tls-auth ta.key 1
cipher AES-256-CBC
verb 3
EOF
```

「/tmp/openvpn-client-key/」に集めたファイル群をzipとかで固めてリモート参加者に渡します。（お約束の文言ですが、、安全な経路で渡しましょう。渡したファイルは適切に管理してもらいましょう。）

#### ルーティング設定

VPNはtunデバイスなので、L3ルーティング設定が必要。iptablesでVPN側とLAN側を相互にルーティングさせます。OpenWrtの場合、/etc/firewall.userにiptablesのコマンドを記述しておけば読み込んでくれるみたいです。

```
cat << EOF > /etc/firewall.user
iptables -I FORWARD -i br-lan -o tun0 -s 192.168.249.0/24 -d 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -i tun0 -o br-lan -s 10.8.0.0/24 -d 192.168.249.0/24 -m conntrack --ctstate NEW -j ACCEPT
EOF
/etc/init.d/firewall restart
```

## AndroidでUSBテザリング

### OpenWrt側のドライバのインストール。

公式サイトの[手順](https://openwrt.org/docs/guide-user/network/wan/smartphone.usb.tethering)。ドライバいれて、usb0デバイスをDHCPクライアントに設定にする。

```
opkg update
opkg install kmod-usb-net-rndis
uci set network.usb0=interface
uci set network.usb0.ifname='usb0'
uci set network.usb0.proto='dhcp'
uci commit
/etc/init.d/network restart
```

### Android側の設定

[設定]→「ネットワークとインターネット」→「アクセスポイントとテザリング」→「USBテザリング」をON
OpenWrt側で「usb0」デバイスが生えていれば成功。IPアドレスはランダムに決まる模様。




OpenWrt側に割り当たったIPアドレスはあとでAndroidのポートフォワードアプリで使うので記録しておく。下記の例では、「192.168.182.10」。テザリングのON/OFFで毎回IPアドレスが変わってしまうので若干面倒だが、起動後に一度確認するだけなので、ここは我慢・・・。

```
root@OpenWrt:~# ip a
(略）
11: usb0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN qlen 1000
    link/ether f6:b4:61:10:16:d9 brd ff:ff:ff:ff:ff:ff
    inet 192.168.182.10/24 brd 192.168.182.255 scope global usb0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4b4:61ff:fe10:16d9/64 scope link
       valid_lft forever preferred_lft forever
```

### Androidでポートフォワードアプリをインストールと設定
今回は、AndroidでUSBテザリングして、OpenVPNの1194ポートをOpenWrt側にポートフォワードする構成にしますので、Androidでポートフォワードアプリをインストールします。

Fwdというアプリです。[リンク](https://play.google.com/store/apps/details?id=com.elixsr.portforwarder&hl=ja&gl=US)

アプリ起動して、「＋」ボタンで設定追加。設定内容は、以下にする。
![Screenshot_20201220-112728s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172186/4341e629-caec-704b-173b-2d0cad597d4e.png)

名前は適当、Protocolは、tcp、fromは、rmnet_data2、ポートは、1194targetには、OpenWrt側のusb0のアドレス（192.168.182.10）を入れて、右上の「SAVE」を押して、「START」で開始

### LTE側のIPアドレス確認とDynamic DNSの書き換え
今回、AndroidのLTE側に割り当たったのIPアドレスを確認する必要があったので、「PingTools Network Utilities」というアプリを使いました。[リンク](https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools&hl=ja&gl=US)
Wi-FiをOFFにして起動すれば、LTE側のIPアドレスを確認できます。
![Screenshot_20201220-115648s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172186/3b9770a0-da7b-048c-9f4d-97e83a7d28cb.png)

確認したIPアドレスをNo-IPにログインして、Dynamic DNSの書き換え

## 合宿地側のPCにリモート側のルート設定追加
リモート側のセグメント(10.8.0.0/24)へのルート設定が必要なので。コマンドプロンプト開いて、

```
route -p add 10.8.0.0/24 mask 255.255.255.0 192.168.249.220
```

（上記の手順でもいいですが、今回は、別のWi-Fiルータもあり、そいつがDHCPサーバにもなっていたので、DHCPの設定でデフォルトゲートウェイを「192.168.249.220」に向けてしまいました。）

# クライアント側の準備

1. OpenVPNクライアントを[ダウンロード（OpenVPN-2.5.0-I601-amd64.msi）](https://www.openvpn.jp/download/)してインストール
2. リモート参加者に配布した「openvpn-client-key.zip」を展開し、「c:\users\[ログインユーザ名]\OpenVPN\config」にコピー
   下記のフォルダ構造にする。

```
C:\USERS\[ログインユーザ名]\OPENVPN
├─config\
│      ca.crt
│      client.crt
│      client.key
│      client.ovpn
│      ta.key
│
└─log
```
3. 合宿地側から準備OKの連絡がきたら、OpenVPN GUIを起動し、タスクトレイのOpenVPN GUIアイコンを
   右クリックし「接続」をクリック。緑色のアイコンになったら接続完了
   ＃最初の起動で「No readable connection・・・・」とメッセージがでてもそのまま「OK」を押す
4. pingで合宿地側のIPから応答があって、ゲームにログインできたらOK！

# まとめ
TL-WR902ACで旅先VPNサーバをつくりました。旅先なのでAndroid端末でテザリングしましたが、家庭のルータでも同じことできそう。以上。

# おまけ
## 元のファームに戻す手順
1. 元ファームをTP-LINKからダウンロード。[ここから](https://www.tp-link.com/jp/support/download/tl-wr902ac/#Firmware)
2. ダウンロードしたzipファイルを展開
3. [ここ](https://forum.openwrt.org/t/tp-link-tl-wr902ac-bad-flash-recovery/25950/8)の情報より。先頭の257バイト分を削ったファイルを作成

```
dd if="TL-WR902ACv3_JP_0.9.1_0.2_up_boot[191209-rel55646].bin" of=tp_recovery.bin skip=257 bs=512
```
4. tp_recovery.binをscpでTL-WR902ACに転送。転送先は、RAMDISKの/tmpへ。

```
scp tp_recovery.bin root@192.168.1.1:/tmp
```

5. 「mtd」コマンドで元ファームを書き込み。完了すると自動で再起動します。

```
mtd -r write /tmp/tp_recovery.bin firmware
Unlocking firmware ...

Writing from /tmp/tp_recovery.bin to firmware ...
Rebooting ...
```