ラズパイをLTE回線でWiFiルータ化、通信エラー時のMTU、MSS設定など

Raspberry Pi 4をWi-Fiルーター化してLTE回線でインターネットに接続させてみました。
LTE回線の通信はメカトラックス社様からお借りしたラズパイ用の4G通信モジュール「[4GPi](https://mechatrax.com/products/4gpi/)」を使用しています。

##構成
　　<img width="800" alt="gaiyou02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/7ae0cc94-3fa5-7ede-821c-da2f3d6020da.png">

##環境
・Raspberry Pi 4 Model B
　※OS は Raspbian (Buster) をインストール済み
・4GPi
・SIMカード※1
・SIMカードアダプター（Nano-SIMを標準SIMに変換するアダプター）
・作業PC（Tera Termインストール済み）
・Wi-Fi環境※2

（※1）個人のスマホから抜いたNano-SIMを使用しました。
（※2）ラズパイに4GPiモジュールをインストールするまで使用します。

##構築の流れ
1. 4GPiのインストール
2. IPアドレスの固定化
3. DHCPサービス設定
4. Wi-Fi アクセスポイント設定
5. IPフォワードの有効化
6. iptablesによるルーティング設定
7. MTU、MSS値のチューニング

##1. 4GPiのインストール
こちらの[記事の#1](https://qiita.com/sirius246/items/26e64b0df2fdd27d5c4f#1-4gpi%E3%81%AE%E8%A3%85%E7%9D%80)、[#4](https://qiita.com/sirius246/items/26e64b0df2fdd27d5c4f#4-4gpi%E3%81%AE%E8%A8%AD%E5%AE%9A)を参考に、ラズパイに4GPiをインストールします。
ラズパイからLTE通信でインターネットに接続できたら、ラズパイのWi-Fi接続を切断します。

##2. IPアドレスの固定化
ラズパイのwlan0（Wi-Fiアクセスポイント側）のIPアドレスを固定化します。

* /etc/dhcpcd.confを編集します。nohook wpa_supplicantでWi-Fiクライアントのサービスを無効化してます。

```
interface wlan0
static ip_address=192.168.110.7/24
nohook wpa_supplicant
static routers=
static domain_name_servers=
static domain_search=
```

* ワイヤレスデバイスのブロックを解除します。  
Wireless LANのSoft blockedが「no」になっていればOKです。

```
$ rfkill unblock wifi
$ 
$ sudo rfkill list
0: phy0: Wireless LAN
        Soft blocked: no
        Hard blocked: no
1: hci0: Bluetooth
        Soft blocked: no
        Hard blocked: no
```

* dhcpcd を再起動してエラーが出力されないことを確認します。

```
$ sudo systemctl restart dhcpcd
$ 
```

##3. DHCPサービス設定
* Raspbianにdnsmasqをインストールします。

```
$ sudo apt-get install dnsmasq
```

* /etc/dnsmasq.confを編集してDHCPのレンジを決定します。ここでは192.168.110.10～192.168.110.20を指定しました。

```
interface=wlan0
dhcp-range=192.168.110.10,192.168.110.20,255.255.255.0,24h
```

* dnsmasqサービスを起動してエラーが出力されないことを確認します。

```
$ sudo systemctl start dnsmasq
$ sudo systemctl enable dnsmasq
```

##4. Wi-Fi アクセスポイント設定
* Raspbianにhostapd をインストールします。

```
$ sudo apt-get install hostapd
```

* /etc/hostapd/hostapd.confを編集してWi-FiのSSID（ssid）とパスワード（wpa_passphrase）を設定します。

```
interface=wlan0
driver=nl80211
ssid=testssid01　　　← ここを編集
hw_mode=g
channel=6
wmm_enabled=0
macaddr_acl=0
auth_algs=1
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=testpassword01　　　← ここを編集
```

* /etc/default/hostapdを編集して、サービス起動時にhostapd.confを読み込ませます。

```
DAEMON_CONF="/etc/hostapd/hostapd.conf"
```

* hostapdをunmaskしてサービスを起動します。

```
$ sudo systemctl unmask hostapd
$ sudo systemctl enable hostapd
$ sudo systemctl start hostapd
```

##5. IPフォワードの有効化
* /etc/sysctl.confを編集してIPフォワードを有効化します。

```
net.ipv4.ip_forward=1
```

##6. iptablesによるルーティング設定
Rasbianのファイアウォールを設定します。

* iptablesを設定します。  
・1～3行目はiptables設定のリセット  
・4行目は作業端末からwlan0へのSSH接続を許可するための定義  
・5行目はwlan0に入力された通信をwwan0に出力するための定義  
・6行目は接続が確立（ESTABLISHED）している通信を許可するための定義  
・7行目はwwan0に対するIPマスカレードの定義  

```
$ sudo iptables -t nat -F
$ sudo iptables -t filter -F
$ sudo iptables -t mangle -F
$ sudo iptables -A INPUT -i wlan0 -p tcp -m state --state NEW,ESTABLISHED,RELATED --dport 22 -j ACCEPT
$ sudo iptables -A FORWARD -i wlan0 -o wwan0 -j ACCEPT
$ sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$ sudo  iptables -t nat -A POSTROUTING -o wwan0 -j MASQUERADE
```
* iptablesの設定を/etc/iptables.ipv4.natに保存します。

```
$ sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
```

* /etc/rc.localに下記の行を追記して、OS再起動時にiptablesの定義ファイルが読み込まれるようにします。

```
iptables-restore < /etc/iptables.ipv4.nat
```
* Raspbianを再起動します。

```
$ sudo reboot
```
* 再起動後に作業端末から#4で作成したアクセスポイントに無事接続でき、www.yahoo.co.jpにpingで疎通できるようになりました。
<img width="250" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/d6e1bc1f-d3b2-953d-8f16-dcb95f48179c.png">
<img width="500" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/a137ece9-44a6-23aa-55de-9c3dc13b7a06.png">

* 但し、ブラウザからYahooページを表示できないため次項#7の設定を実施します。
<img width="400" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/2f6b3e76-f47e-4623-379d-4c415d579b8b.png">


## 7. MTU、MSS値のチューニング
ブラウザや特定アプリのインターネット接続に失敗する場合はWi-Fiルーターの下記の何れかを設定することで改善する可能性があります。

・RaspbianのMTU（Maximum Transmission Unit）値を変更する
・iptablesのTCP MSS（Maximum Segment Size）値を定義する

#### 7.1 RaspbianのMTU値を変更する
MTUは隣接したネットワークに一度に送信できるパケットの最大サイズです。Wi-FiルーターのMTU値が経路上のNW機器群のMTU値より大きいとWi-Fiルーターから送信されたパケットが送信先に到達しない可能性があります。

* 作業端末のコマンドプロンプトを起動し、www.yahoo.co.jpにpingを実行します。下記の例ではpingで一度に送信できるパケットサイズの最大値が1392バイトのため、MTU値の最適値は1392バイトにヘッダの28バイトを加えた1420バイトです。この場合、1421バイト以上のパケットは通過できない可能性があります。詳細はこちらの[サイト](https://www.atmarkit.co.jp/ait/articles/0512/17/news017.html)を参照してください。
<img width="500" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/4cf9ef45-c9e7-cded-a815-de09626c2cc3.png">

* 現在のwlan0のMTU値は1500なので、1420バイト以下になるように設定します。
<img width="500" alt="8-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/4df00e78-9253-8f23-0c92-719a25eef7c0.png">

* 試しに、/etc/rc.localに下記の行を追記してwlan0のMTU値が1200になるように定義します。

```
ifconfig wlan0 mtu 1200
```

* Raspbianを再起動します。

```
$ sudo reboot
```

* wlan0のMTU値が1200になっています。
<img width="500" alt="9-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/54a1771a-4b7f-85a7-be99-cf2b21ac9fb8.png">

* Yahooのページが問題なく表示されました。
<img width="350" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/60c5a55c-2707-b669-b27e-77dbb25d5a6b.png">


#### 7.2 iptablesのTCP MSS値を定義する
作業PCのブラウザからYahooページへのアクセス時に、作業PCとYahooサーバー間のTCP 3ウェイハンドシェイクでMSS（Maximum Segment Size）値を調整します。MSSはTCPレイヤーで格納するデータの最大サイズです。MSS値の調整が完了すると、作業PCは調整したMSS値のサイズのパケットをYahooサーバーに送信します。このTCP 3ウェイハンドシェイクで調整されるMSS値は、中継するWi-Fiルーター側で書き換えることが可能です。

* iptablesにTCP 3ウェイハンドシェイクで使用するMSS値を定義します。  
具体的な数値を定義できますが、ここではMSS値を自動調整するオプション（--clamp-mss-to-pmtu）を入れます。

```
$ sudo iptables -t mangle -A FORWARD -o wlan0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
$ sudo sh -c "iptables-save > /etc/iptables.ipv4.nat"
$ sudo cat /etc/iptables.ipv4.nat
```

* Yahooページが問題なく表示されました。
<img width="350" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/60c5a55c-2707-b669-b27e-77dbb25d5a6b.png">

* Wiresharkのパケットの中身を確認してみます。
【自動調整オプション定義前】インターネット接続NGの時は、作業PCからYahooサーバーへの通知は「MSS=1460」、Yahooサーバーから作業PCへの通知は「MSS=1394」です。
<img width="900" alt="13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/3039bc24-9a7f-6ee1-4848-e4026008baeb.png">

【自動調整オプション定義後】インターネット接続OKの時は、Yahooサーバーから作業PCへの通知が「MSS=1380」となっているので、自動調整オプションによりMSS値が調整されていることが分かります。なお、Len=1380はパケットが1380バイトに分割されていることを示します。
<img width="900" alt="12-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599959/de4515fa-1c5b-a1ad-3391-0e83c74dc1e7.png">

#### 7.3 【補足】ルーターのパケット受信時の挙動

* 「MTU値がルーターA＞ルーターB」且つ「パケットのDF（Don't Fragment）ビットが1」の場合、ルーターAから送信されたパケットはルーターBを通過できない。
* ルーターは自身のMTU値より大きなパケットを分割して送信する機能を有するが、スループットが低下するので分割禁止（DF=1）にされていることが多い。
* 「DF＝1」のルーターはPath MTU Discovery機能によりパケットサイズを自動調整する。Path MTU Discoveryは、ルーターが自身のMTU値より大きなサイズのパケットを受信すると、当該パケットを破棄し、送信元に対して「サイズを調整したパケットの再送要求」を送信する。  
* Path MTU Discoveryの再送要求はICMP（Type 3 Code 4）を送信元ホストへ送信することで成立するが、経路上の中継ルータがICMPをブロックしているとパケットサイズが調整できない（ブラックホール問題）。
* 「DFビット＝1」且つ「Path MTU Discovery機能が利用不可」の場合は、下記①②の何れか方法で問題を回避できる。  
①外側のルーターほどMTU値を小さくする。例えば、データの流れが「送信元⇒A⇒B⇒C⇒D⇒E⇒送信先」の場合、MTU値は「A＜B＜C＞D＞E」とする。（#7-1参照）  
②送信元と送信先のTCP 3ウェイハンドシェイクでネゴされるMSS値を中継ルーター側で調整する。（#7-2参照）

## 最後に
Raspberry Pi 4をWi-Fiルーター化して4GPiのLTE回線で通信させる場合は、Wi-FiルーターのNWインタフェース（wlan0）のMTU値の調整が必要となりますのでご注意ください。