WSL2上のUbuntuから外部ネットワークに接続したり，固定IPを振るまでの備忘録

やっとこさWSL2上のUbuntu 20.04で外部ネットワークに繋いだり，固定IPを振ったりできるようになったのでその備忘録
ただ，公式にはリリースされていない(公式ドキュメントにない)機能を使っていたりするし，WSLまわりはコロコロ状況が変わるので参考程度にしてください．

# 動作環境
||内容|
|:-:|:-:|
プロセッサ | 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz   2.80 GHz
RAM | 16.0 GB
OS | Windows 11 Pro
OSバージョン | 22H2
ビルド | 22621.1265
WSL バージョン | 1.1.3.0
カーネル バージョン | 5.15.90.1
WSLg バージョン | 1.0.49
MSRDC バージョン | 1.2.3770
Direct3D バージョン | 1.608.2-61064218
DXCore バージョン | 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windowsバージョン | 10.0.22621.1265

## 前提条件
- Hyper-Vの仮想スイッチマネージャーが使えること
- [windows terminal](https://apps.microsoft.com/store/detail/9N0DX20HK701?hl=ja-jp&gl=JP)が使えること
- WSL2の基本的なセットアップが完了し，Ubuntuがインストールされていること

## 注意事項
- DHCPかつIPv4に関しては有線・無線ともに快適．しかし，固定IPを割り当てるには有線推奨[^1]．
- IPv6を利用するときも有線推奨[^1]

# WSL2のUbuntu 20.04から外部ネットワークに接続する

WSLネットワークのブリッジモードを使う．

## 手順

### ホスト側で`.wslconfig`を編集する．
ホスト側のホームディレクトリ(大抵の場合`C:\Users\<ユーザー名>`)に`.wslconfig`を作成し，以下のように編集する．
```yaml:.wslconfig
[wsl2]
networkingMode=bridged
vmSwitch=<任意の仮想スイッチ名>
dhcp=true
localhostForwarding=True
```

- `networkingMode` 
  WSLのネットワークモードを設定する部分．今回はブリッジモードで接続するので`bridged`　　
- `vmSwitch`
  Hyper-Vの仮想スイッチマネージャーに設定されている仮想スイッチの名前．
- `dhcp`
  DHCPの有効/無効設定．ここではひとまず有効．
- `localhostForwarding`
  `True`にするとホストからWSLにアクセスする際，`localhost`が使えるようになる．必須ではない．

### WSL2を起動(再起動)する．
- 既にWSL2が起動されているなら，以下のコマンドでシャットダウンした後再起動する．
```powershell:win11(ホスト)
wsl --shutdown
```

- ホスト側で仮想スイッチに割り当てられているIPアドレスを確認する

```bash:ipconfigの出力結果
イーサネット アダプター vEthernet (Vwi-fi):
<中略>
   IPv4 アドレス . . . . . . . . . . . .: 192.168.179.40
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: fe80::6859:cfff:fe61:229a%9
                                          192.168.179.1
```

- WSL側でDHCPサーバーからIPが割り当てられている事を確認する．

```bash:Ubuntu(WSL2)
$ ip a
<中略>
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 5c:bb:f6:9e:ee:fa brd ff:ff:ff:ff:ff:ff
    inet 192.168.179.20/24 brd 192.168.179.255 scope global eth0
       valid_lft forever preferred_lft forever
```
IPが振られていれば成功．外部ネットワークにアクセスできるので`apt update`も`apt install`も自由にできる．

# WSL上のUbuntuに固定IPを割り当てる
Ubuntuの`ip`コマンドを利用する．

## 手順
### `.wslconfig`を以下のように編集する
```yaml:.wslconfig
[wsl2]
networkingMode=bridged
vmSwitch=<任意の仮想スイッチ名(有線推奨)>
dhcp=False
localhostForwarding=True
```
変更したのは`dhcp=False`のみ

### WSL2を再起動してIPが振られなくなった事を確認する．
```bash:Ubuntu(WSL2)
$ ip a
<中略>
6: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 5c:bb:f6:9e:ee:fa brd ff:ff:ff:ff:ff:ff
```

### 接続する仮想スイッチのIPを確認する
```bash:win11(ホスト)
イーサネット アダプター vEthernet (VethNet):

   接続固有の DNS サフィックス . . . . .:
   リンクローカル IPv6 アドレス. . . . .: fe80::1a2c:52eb:517:872%18
   IPv4 アドレス . . . . . . . . . . . .: 192.168.128.56
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 192.168.128.1
```

### Ubuntuの`ip`コマンドを利用して固定IPを割り当てる
WSL2ではsystemdなどが正常に動作しないので，よく使われる`netplan`は利用できない．
そこで，`ip`コマンドを利用して固定IPを割り当てる．

```bash:Ubuntu(WSL2)
$ sudo ip l set eth0 up
$ sudo ip address add 192.168.128.100/24 broadcast 192.168.128.1 dev eth0
$ sudo ip route add default via 192.168.128.56
```
- `192.168.128.100/24` : 割り当てたいIPアドレスとネットマスク
- `192.168.128.1` : デフォルトゲートウェイ
- `192.168.128.56` : 接続する仮想スイッチのホスト側でのIPアドレス

これで，外部から固定IPによってアクセスすることができる．
Hyper-Vの仮想スイッチを利用しているので，ポートフォワードなどの設定も必要ない．

## この方法の弱点
この方法で固定IPアドレスを振っても，WSL2を再起動したときには設定が消えてしまう．
毎回やるには面倒なので，スクリプトを書いて`.bashrc`に追記しておくなどの工夫が必要．

(追記)
IPアドレスとか色々入力するの面倒だったのでpowershellスクリプトにしてみました．
何故bashじゃないかというと，仮想スイッチのIPアドレスを取得するのにwin側からやった方が楽だったからです．
起動前にこのスクリプトを走らせれば自動でIP設定します．

```powershell
# オプション及びパラメータ．""の内が既定値なのでよく使うものに書き換えておくと楽
Param(
    [switch]$help,
    [switch]$dhcp,
    $V_switch = "VethNet",
    $ubuntu_ip = "192.168.128.101",
    $netmask = "255.255.255.0",
    $default_gateway = "192.168.128.1"
)

# .wslconfigの共通部分を出力
Set-Content -Path ~/.wslconfig -Encoding utf8 "[wsl2]"
add-Content -Path ~/.wslconfig -Encoding utf8 "networkingMode=bridged"
add-Content -Path ~/.wslconfig -Encoding utf8 "localhostForwarding=True"

#ヘルプ表示
if($help){
    Write-Host @"
使い方: wslconfig.ps1 [OPTIONS]
    
    OPTIONS:
    -help                         このヘルプを表示
    -dhcp                         HCPを利用するかどうか．このオプションを付けるとDHCPが有効になる．
    -V_switch [スイッチ名]        接続する仮想スイッチ名を指定．ex) VethNet
    -ubuntu_ip [IPアドレス]       Ubuntuに割り当てる固定IPアドレス． ex) 192.168.128.100
    -netmask [サブネットマスク]   Ubuntuに割り当てるサブネットマスク. ex) 255.255.255.0 または 24
    -defalt_gateway [IPアドレス]  接続するネットワークのデフォルトゲートウェイ． ex) 192.168.128.1 
"@
    add-Content -Path ~/.wslconfig -Encoding utf8 "dhcp=true"
    add-Content -Path ~/.wslconfig -Encoding utf8 "vmSwitch=$V_switch"
    exit
}

if ($dhcp){
    add-Content -Path ~/.wslconfig -Encoding utf8 "dhcp=true"
}
else{
    add-Content -Path ~/.wslconfig -Encoding utf8 "dhcp=false"
    $wsl_ip=get-NetIPConfiguration -InterfaceAlias "vEthernet ($V_switch)" | Select-Object -ExpandProperty IPv4Address | Select-Object -ExpandProperty IPAddress
    wsl -e sudo ip l set eth0 up
    wsl -e sudo ip address add ${ubuntu_ip}/${netmask} broadcast ${default_gateway} dev eth0 # 固定IP設定
    wsl -e sudo ip route add default via ${wsl_ip} # 接続する仮想スイッチの設定
}

add-Content -Path ~/.wslconfig -Encoding utf8 "vmSwitch=$V_switch"
```


# 参考にしたサイト
- [WSL2ブリッジモード備忘録(おそらく誰の役に立たないメモ)](https://qiita.com/shigeokamoto/items/6a79cd47a65bf2ab7b1e)
- [WSL2 で外部からアクセス可能にするために bridge mode を有効にする](https://zenn.dev/euxn23/articles/7b83df39720ccb)
- [wsl2上のLinux　からインターネットにアクセスできない場合の暫定解決策](https://cpoint-lab.co.jp/article/202105/19922/)

[^1]: [WSL2ブリッジモード備忘録(おそらく誰の役に立たないメモ)](https://qiita.com/shigeokamoto/items/6a79cd47a65bf2ab7b1e)より
[^2]: [WSL2 で外部からアクセス可能にするために bridge mode を有効にする](https://zenn.dev/euxn23/articles/7b83df39720ccb)
[^3]: [wsl2上のLinux　からインターネットにアクセスできない場合の暫定解決策](https://cpoint-lab.co.jp/article/202105/19922/)