IIJmioひかりでVPN（DS-Lite回線にラズパイでPPPoE接続を追加してPiVPNでWireguard）

※更新版もどうぞ

https://qiita.com/exthnet/items/e9fa487b1882d4b6d197

# はじめに
長らく（？）スマホにIIJmio回線を使っているのだが、引っ越しにより自分でインターネット回線を契約する必要が生じ（それまでは無料でケーブルTV回線が使える物件に住んでいた）、ケーブルテレビ回線を使うよりもmioひかりを使った方がお得っぽいことに気がついた。せっかくだから無料で使えるIPoEオプションもつけて、DS-Lite接続してみた。ここまでは良かったのだが、せっかくケーブルTV回線と異なりグローバルIPもふられる環境なのに（普通にIPv4 PPPoE接続すればグローバルIPがふられてVPNも自宅サーバも問題なくできる）、DS-Lite接続にすると手元でポート制御できないためVPNやサーバ遊びができないことに気がついた。
DS-Lite接続なんてするから悪いのであって、普通にIPv4接続すりゃいいじゃん、という話ではあるのだが、せっかくだから新しいのを試してみたいじゃん？という悪い癖？が発動したので、ちょっと調べて試してみたという話である。

（作業メモ的なものでもあるので、細かいところには間違いがあるかも。）

- 参考文献
  - https://denor.jp/v6%E3%83%97%E3%83%A9%E3%82%B9%E7%92%B0%E5%A2%83%E3%81%8B%E3%82%89raspberry-pi-4%E3%81%A7ipv4-pppoe%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF
  - https://shikiblog.link/index.php/2022/09/23/raspi-pppoe-and-dslite/
  - https://raspida.com/pivpn


# ネットワーク構成
世の中にはDS-Lite接続とIPv4 PPPoE接続を同時にできるルータがあるようで、そういうものを使っていれば何も困ることはない。しかし残念ながら手持ちのTP-Link Archer AX10はそうではなかった。（おそらく家庭用の安価なルータの多くは対応していない。）
世の中にはDS-Lite接続の下流のクライアントからIPv4 PPPoE接続ができる（パススルーできる）ルータもあるようだが、残念ながら以下略。（おそらく以下略。）
そこで、回線終端装置とルータの間に手持ちの（ごく普通のGbEの）スイッチングハブを置き、DS-Lite接続とIPv4 PPPoE接続を分け、外部からのVPN接続等は後者で担当することにした。後者については~~どこのご家庭にも1台は転がっている~~ 余っていたRaspberry Pi 3Bを使うことにした。

全体的な物理構成はおおよそこんな感じ。
（Raspberry Piのeth1はUSB接続のLANアダプタ。別にデフォルトで使えるwlanを使っても良いと思うのだが、有線の方が確実だよねということで。AX10のグローバル側にIPが書かれていないのはDS-Lite接続のため。192.168.0.1を使っていないのはAX10のグローバル側で使っていたものであり何かの際にすぐ戻せるようにしておくため。）

![おうちネットワーク構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199517/b489dc5c-c941-ff28-000b-c23a38dfb01d.png)

とりあえずデフォルトルートをeth1側の192.168.1.1に設定すれば`191.168.1.*`側を通ってAX10を経由してインターネット接続が可能。

```bash:dhcpcd.conf 抜粋
interface eth0
static ip_address=192.168.0.2/24

interface eth1
static ip_address=192.168.1.16/24
static routers=192.168.1.1
static domain_name_servers=8.8.8.8
```

- （あとから考えたらそもそもeth0にIPを振る必要はなかったか。）

# 設定
RasPiのOSはRaspbianのbullseye。Debian 11ベース。ここが変わると色々変わる可能性が高いと思うのでメモしておく。

PPPoEでネットワークに繋ぐことと、PiVPNを設定すること、これらができればよく、両方ともWeb上にたくさん資料があるのだが、両方まとめて説明している情報が見つからずに苦労した。

## PPPoE
PPPoEの設定は最初に参考文献に挙げた[こちら](https://denor.jp/v6%E3%83%97%E3%83%A9%E3%82%B9%E7%92%B0%E5%A2%83%E3%81%8B%E3%82%89raspberry-pi-4%E3%81%A7ipv4-pppoe%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF)などが詳しい。`apt`で`pppoe`と`pppoeconf`をインストールして、ちょっと設定すればつながる。

PPPoEを有効化した際（pon dsl-provider）にはppp0をgwに、無効化した際（poff）にはeth1側をgwにするには以下のファイルを作成して実行権限を与えておくと良さそう。なおこのあたりの設定はあまり詳しくないため、これが本当に適切なのかは自信がない。少なくとも現状ではうまく動いている。


```bash:/etc/ppp/ip-up.d/10dsl-provider
#!/bin/sh
sudo route del default dev eth1
sudo route add default dev ppp0
```

```bash:/etc/ppp/ip-down.d/10dsl-provider
#!/bin/sh
sudo route del default dev ppp0
route add default gw 192.168.1.1
```

## PiVPN
PiVPNの基本的な初期設定等は他の解説サイトを参照すれば良いとして、主な注意点は、ppp0で通信を受け付けるようにすることと、eth1へのNAT(masquerade)が機能するようにすること。
具体的な注意点は以下。

- `setupVars.conf`設定ファイル内にppp0関係の設定を書く。
```bash:/etc/pivpn/wireguard/setupVars.conf 抜粋
IPv4dev=ppp0
IPv4addr=(ppp0のIPアドレス)/32
IPv4gw=（ppp0のデフォルトゲートウェイ）
```
ppp0のIPアドレスとデフォルトゲートウェイを最新情報にしておかないと問題が起きるので、先のdsl-provider内でスクリプトを走らせて更新しておくのが良い？例えばこんな感じだろうか？
```bash:/etc/ppp/ip-up.d/10dsl-provider
#!/bin/sh
sudo route del default dev eth1
sudo route add default dev ppp0
sudo /etc/pivpn/wireguard/update.sh
sudo wg-quick down wg0
sudo wg-quick up wg0
```

```bash:/etc/pivpn/wireguard/update.sh
#!/bin/bash
inet=`ip addr show ppp0|grep inet|awk '{print $2}'`
gw=`ip route|grep ppp0|grep kernel|awk '{print $1}'`

cat <<EOF > /etc/pivpn/wireguard/setupVars.conf
PLAT=Raspbian
OSCN=bullseye
USING_UFW=0
pivpnforceipv6route=0
IPv4dev=ppp0
IPv4addr=${inet}/32
IPv4gw=${gw}
以下省略（本来setupVars.confに書かれている内容そのまま）
EOF
```

さらに`/etc/wireguard/wg0.conf`の中でNAT設定が必要。今回はiptablesを生で叩いているため、PostUpとPostDownの行にeth1に対する処理を記述。
```bash:/etc/wireguard/wg0.conf
[Interface]
PrivateKey = mPYnsQamhA+sm4YNzx+g+hCDajxWSu/16tN0eoPQ3HQ=
Address = 10.118.237.1/24
MTU = 1420
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth1 -j MASQUERADE
（このあとにpivpn -addで追加したクライアントの情報が足されていく）
```

参考までに、iptablesでは以下のような設定を記述している。natの部分に上記のPostUp情報が足される形になる。（これだとwg0からのINPUTがDROPされちゃってVPN経由192.168.1.xへのアクセスができないかな？）
```bash:iptables
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -i wg0 -j ACCEPT
-A FORWARD -o wg0 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
必要なポートACCEPT情報を追加
-A INPUT -i ppp0 -p udp --dport 51820 -j ACCEPT
-A INPUT -i ppp0 -j DROP
COMMIT
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth1 -j MASQUERADE
-A POSTROUTING -o ppp0 -j MASQUERADE
COMMIT
```


# その他の注意点など
- poff/ponを繰り返していたらIPが変わって名前引きが失敗してつながらなくなってた。意外な落とし穴なので忘れてはいけない。
- OSが古いうえに32bitなためか、apt installとかがエラーする例がしばしば見受けられる。更新するか……。