Linux上のMultipassの仮想マシンへ外部ネットワークから接続する

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. multipass使ってますか？

multipassは、仮想マシン管理ツールです。
Linuxでqemuを使いやすくしてくれる仮想化ツールです。
(WindowsだとHyper-V、Macだとhyperkitを使います)

コマンド一つ(multipass launch)で仮想マシンを簡単に動かすことができます。
簡単にLinuxの仮想マシンを使うことができるので、テストしたり練習したりCIに使ったりするのに便利です。

今はDockerなどのコンテナもあるし、いまさら仮想マシンという意見もあると思いますが、k3sを動かす時に使ったり、microk8sを動かしたり、なかなか便利なんです。

途中経過を見ないで結論に飛ぶには、`7. まとめ`を見てください

# 1. しかし、困ったことが....

multipass launch した仮想マシンに接続できるのはmultipassのホストからしか接続できなくて困っていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/3b62fa1c-aa09-e574-417e-103db8940892.png)

`198.51.100.89`は、multipass内だけで利用できる内部ネットワークです。

# 2. んな訳ないはず

Ubuntu OSのNICからMultipass仮想マシン(QEMU)へ接続できるんだから、以下のようにルーティングを追加すれば外からのパケットだって通るはず！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/ff30b2a8-1606-614f-d5cc-35fc6cb8507c.png)

(正確には外部のNICとMultipassのネットワークをOSが知っていればルーティング可能)

# 3. Googleで調べた

しかし、つながらないので調べてみました。

Googleで検索したら、いくつかの記事が見つかりました。

multipassでOSX上にmicro-k8sを立てる。 - nがひとつ多い。
https://nnao45.hatenadiary.com/entry/2018/12/20/085706

multipassでつくるmacOS向けのDockerd & K8s環境 - Qiita
https://qiita.com/mumoshu/items/6ff56badcfabe5ab1f49

これらによると、multipassで起動した仮想マシン内で`FORWARD ACCEPT`すれば良いようですが、

```shell:multipass-client
sudo iptables -P FORWARD ACCEPT
```

残念ながらこれでは外部から接続することができませんでした。

# 4. Ubuntu OS内でパケットをルーティング出来るようにする

そもそも、Ubuntu OS内でルーティングできるようにしてないとよくありません。
/etc/sysctl.d/99-sysctl.confファイルに以下を追記しました。

```shell:multipass-host:/etc/sysctl.d/99-sysctl.conf
net.ipv4.ip_forward=1
```

それでも接続できませんでした。

# 5. iptableを確認する

wiresharkでパケットの流れをチェックしてみるとパケットは転送されているようですが、途中でパケットがどこかに落っこちているようです。そこでmultipassのホスト側のiptablesのフィルタールールを見てみます。


```shell:multipass-host
$ sudo iptables -nvL
Chain INPUT (policy ACCEPT 5310 packets, 1486K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  mpqemubr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53 /* generated for Multipass network mpqemubr0 */
    2   144 ACCEPT     udp  --  mpqemubr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 /* generated for Multipass network mpqemubr0 */
    0     0 ACCEPT     udp  --  mpqemubr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67 /* generated for Multipass network mpqemubr0 */

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  mpqemubr0 mpqemubr0  0.0.0.0/0            0.0.0.0/0            /* generated for Multipass network mpqemubr0 */
   35  3186 ACCEPT     all  --  mpqemubr0 *       198.51.100.0/24       0.0.0.0/0            /* generated for Multipass network mpqemubr0 */
   31  6005 ACCEPT     all  --  *      mpqemubr0  0.0.0.0/0            198.51.100.0/24       ctstate RELATED,ESTABLISHED /* generated for Multipass network mpqemubr0 */
    0     0 REJECT     all  --  mpqemubr0 *       0.0.0.0/0            0.0.0.0/0            /* generated for Multipass network mpqemubr0 */ reject-with icmp-port-unreachable
   90  4680 REJECT     all  --  *      mpqemubr0  0.0.0.0/0            0.0.0.0/0            /* generated for Multipass network mpqemubr0 */ reject-with icmp-port-unreachable

Chain OUTPUT (policy ACCEPT 2655 packets, 210K bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      mpqemubr0  0.0.0.0/0            0.0.0.0/0            tcp spt:53 /* generated for Multipass network mpqemubr0 */
    2   232 ACCEPT     udp  --  *      mpqemubr0  0.0.0.0/0            0.0.0.0/0            udp spt:53 /* generated for Multipass network mpqemubr0 */
    0     0 ACCEPT     udp  --  *      mpqemubr0  0.0.0.0/0            0.0.0.0/0            udp spt:67 /* generated for Multipass network mpqemubr0 */
```

一見正しく転送されているように見えますが、以下の行がREJECTされていて仮想マシンのIPアドレスに接続しようとするとREJECTの数値が上がります。

```shell:multipass-host
    0     0 REJECT     all  --  mpqemubr0 *       0.0.0.0/0            0.0.0.0/0            /* generated for Multipass network mpqemubr0 */ reject-with icmp-port-unreachable
   90  4680 REJECT     all  --  *      mpqemubr0  0.0.0.0/0            0.0.0.0/0            /* generated for Multipass network mpqemubr0 */ reject-with icmp-port-unreachable
```

どうも、このルールがパケットを落っことしているようです。

# 6. iptablesのルールを削除する

```shell:multipass-host
sudo iptables -D FORWARD -o mpqemubr0 -m comment --comment "generated for Multipass network mpqemubr0" -j REJECT --reject-with icmp-port-unreachable
```

これで繋がるようになりました。

このままだとマシンを再起動するとiptablesが元に戻ってしまいます。
以下のコマンドでiptablesを保存しておきましょう。

```shell:multipass-host
sudo apt install iptables-persistent
sudo netfilter-persistent save
```

# 7．まとめ

## 7-1. iptablesのルールを削除する

```shell:multipass-host
sudo iptables -D FORWARD -o mpqemubr0 -m comment --comment "generated for Multipass network mpqemubr0" -j REJECT --reject-with icmp-port-unreachable
```

## 7-2. OS内でルーティングを有効化
(最近のUbuntuではデフォルトで有効になっているかも)

```shell:multipass-host:/etc/sysctl.d/99-sysctl.conf
net.ipv4.ip_forward=1
```

## 7-3. Multipassの仮想マシン内でFORWARD ACCEPTする
(仮想マシンによる、不要なものもある)

```shell:multipass-client
sudo iptables -P FORWARD ACCEPT
```

# 8. 注意事項

このiptablesのルールを削除しても問題ないと思いますが、何か理由があってルールが存在する可能性もあるので変更には注意してください。