WSL上のDebianからWireGuardを使いたい

投稿者: | 2024年9月21日

WireGuardはLinuxカーネルモジュールとして動作するが、少なくとも2024/9/21現在においてWSL純正のカーネルは必要なオプションが有効になっていないらしく、なんやかんやで以下のようなエラーが発生し詰まることになる。

/dev/fd/63:6:65-80: Error: Could not process rule: No such file or directory

カスタムカーネルを使ったりオプションを有効化して自分でビルドし直したりする方法もあるようだが、ユーザー空間で実行させる方法が非常に手っ取り早い。

WireGuardはインストール済みであるとする。
またWireGuard自体の細かいセットアップもここでは割愛する。


今回鍵となるのはwireguard-goで、GitHubにはgit cloneしてmakeと書いてあるものの少なくともDebainはaptでインストール出来たため手早い。

# apt install wireguard-go

続いて通常通り /etc/wireguard/wg0.conf を作成するが、[Interface] 部に記載するのは PrivateKey のみで Address や DNS は記載しない。というのもこのファイルでは設定が出来ないためで、後で別途設定する必要がある。
また、 AllowedIPs = 0.0.0.0/0 としているもののこれによって勝手にルーティングはしてくれないため、こちらも後で別途設定する。

[Interface]
PrivateKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#Addressは不要

[Peer]
PublicKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
PresharedKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Endpoint = <接続先のIP>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

次に wireguard-go でwg0インターフェースを立ち上げる。
これでwg0が出来るものの、以下のようにIPアドレス等がまだ何も設定されていない。

# wireguard-go wg0
┌──────────────────────────────────────────────────────┐
│                                                      │
│   Running wireguard-go is not required because this  │
│   kernel has first class support for WireGuard. For  │
│   information on installing the kernel module,       │
│   please visit:                                      │
│         https://www.wireguard.com/install/           │
│                                                      │
└──────────────────────────────────────────────────────┘

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
~省略~
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
~省略~
3: wg0: <POINTOPOINT,MULTICAST,NOARP> mtu 1420 qdisc noop state DOWN group default qlen 500
    link/none

そこで次のようにしてwg0を設定する。IPはCIDR表記で入力する。
ここでは仮に192.168.10.2/24で割り当てたとする。

# ip address add dev wg0 192.168.10.2/24
# wg setconf wg0 /etc/wireguard/wg0.conf

この時点でWireGuardが接続され wg show コマンドから状態が見えるようになるが、まだインターフェースが上がっていないため繋がらない。

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
~省略~
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
~省略~
3: wg0: <POINTOPOINT,MULTICAST,NOARP> mtu 1420 qdisc noop state DOWN group default qlen 500
    link/none
    inet 192.168.10.2/24 scope global wg0
       valid_lft forever preferred_lft forever

# wg show
interface: wg0
  public key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  private key: (hidden)
  listening port: XXXXX

peer: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  preshared key: (hidden)
  endpoint: <接続先のIP>
  allowed ips: 0.0.0.0/0
  latest handshake: 7 seconds ago
  transfer: 92 B received, 244 B sent
  persistent keepalive: every 25 seconds

最後にインターフェースを上げたら完了……と思いきやルーティングが設定されていない。
WireGuardに流したい通信を設定してやることでやっと繋がるようになる。例えば192.168.0.0/16宛をWireGuard経由で流すなら次のようにすればいい。

# ip link set up dev wg0
# ip route add 192.168.0.0/16 dev wg0

これで繋がる。やったぜ。

接続を終了するにはwg0インターフェースを飛ばす。

# ip link del wg0

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
~省略~
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
~省略~

とはいえ毎回この工程をするのもダルいので、適当にスクリプトを書いておくと楽。
8行目のsleepは気分で入れているだけなので特に必要ない。

#!/bin/sh

wireguard-go wg0
ip address add dev wg0 192.168.10.2/24
wg setconf wg0 /etc/wireguard/wg0.conf
ip link set up dev wg0
ip route add 192.168.0.0/16 dev wg0
sleep 1
wg show

そしてこのスクリプトをいい感じにするとこう。改変などご自由に……
wg_confwgX.conf のパスを指定したらいい感じに読み込んで、あとはwgXがあるかどうかを判断してコマンド一発でup/downを切り替える。パス通しておくと完璧だ。
なお wgX.conf にはコメントアウトで Address を書いておくこと。

#!/bin/sh

wg_conf="/etc/wireguard/wg0.conf"

wg_dev=$(echo "$wg_conf" | awk -F/ '{f=$NF; sub(/\.[^.]*$/, "", f); print f}')
wg_domain=$(awk -F= '/^Endpoint[ \t]*=/{gsub(/^[ \t]+|[ \t]+$/,"",$2); split($2,a,":"); print a[1]}' "$wg_conf")
wg_peer_ip=$(dig +short $wg_domain A)

wg_check () {
        command=$(ip a | grep $wg_dev:)
        if [ "$command" != "" ]; then
                return 0 #wgX is Active
        else
                return 1 #wgX is NOT Active
        fi
}

wg_up () {
        gateway_ip=$(ip route | awk '/^default/ {print $3}')
        gateway_dev=$(ip route | awk '/^default/ {print $5}')
        wg_ip=$(awk -F= '/Address/ {gsub(/ /,"",$2); print $2}' "$wg_conf")
        allowed_ips=$(awk -F= '/AllowedIPs/ {gsub(/ /,"",$2); print $2}' "$wg_conf")

        echo "[wgctl] $wg_dev up\n"
        wireguard-go $wg_dev
        ip address add dev $wg_dev $wg_ip
        wg setconf $wg_dev $wg_conf
        ip link set up dev $wg_dev
        ip route add $wg_peer_ip via $gateway_ip dev $gateway_dev

        set -- $(echo "$allowed_ips" | tr ',' ' ')
        for allowed_cidr in "$@"
        do
            ip route add $allowed_cidr dev $wg_dev
        done

        sleep 1
        wg show
}

wg_down () {
        echo "[wgctl] $wg_dev down"
        ip link del $wg_dev
        ip route del $wg_peer_ip
}

if [ $(id -u) != 0 ] && [ "$1" != "?" ]; then
        echo "[wgctl] ERROR: Please run as root"
        exit 1
fi

if [ "$1" = "" ]; then
        wg_check
        if [ $? = 0 ]; then
                wg_down
        elif [ $? = 1 ]; then
                wg_up
        else
                echo "[wgctl] ERROR: what?"
        fi
elif [ "$1" = "up" ]; then
        wg_check
        if [ $? = 1 ]; then
                wg_up
        else
                echo "[wgctl] $wg_dev is currently up\n"
                wg show
        fi

elif [ "$1" = "down" ]; then
        wg_check
        if [ $? = 0 ]; then
                wg_down
        else
                echo "[wgctl] $wg_dev is currently down"
        fi

elif [ "$1" = "?" ]; then
        echo "Usage:"
        echo "  wgctl [options]\n"
        echo "If no options are specified, wgctl switches connections automatically!\n"
        echo "Options:"
        echo "  up          Enable WireGuard connections"
        echo "  down        Remove WireGuard connections"
        echo "  ?           Show this help"

else
        echo "[wgctl] Invalid argument"
        echo "        Use \"wgctl ?\" for help"
fi

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です