RT2600ACでWireGuardを使用する

RT2600acのVPNではOpenVPNは対応していますが、最近流行のwireguardは対応していません。これを動作させるまでの備忘録を載せます。

こちらのサイトでwireguardをRT2600acで使用する方法を載せています。しかし、コンパイル済みのバイナリをroot権限で実行するなどセキュリティ的に怖い部分があります。中身を読んだ感じこのスクリプトの作者というよりこのスクリプトが依存するEntwareにやや疑問が湧いたくらいで実際には問題ないと思いますが、どうせなら自分でバイナリをコンパイルして自分で設定してみます。

https://qiita.com/bellx2/items/68d0b444c2bf372ea33c

Wslでwireguardとwireguard-toolsをコンパイルします。 wsl標準のGOコンパイラでは古いようなのでコンパイラは自分で落とします。以下コマンド

#依存ファイルインストール
sudo apt update
sudo apt install -y \
  git build-essential \
  gcc-arm-linux-gnueabihf
#goは自分でダウンロード
cd /tmp
wget https://go.dev/dl/go1.22.1.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.1.linux-amd64.tar.gz
export PATH=/usr/local/go/bin:$PATH
export GOTOOLCHAIN=local
#wireguardビルド
git clone https://git.zx2c4.com/wireguard-go
cd wireguard-go
export GO111MODULE=on
export GOOS=linux
export GOARCH=arm
export GOARM=7
export CGO_ENABLED=1
export CC=arm-linux-gnueabihf-gcc
make
arm-linux-gnueabihf-strip wireguard-go #サイズ削減
cd ..
#wgビルド
git clone https://git.zx2c4.com/wireguard-tools
cd wireguard-tools/src
make \
  CC=arm-linux-gnueabihf-gcc \
  STRIP=arm-linux-gnueabihf-strip
cd ..
#wireguard-goとwgを一度/tmpフォルダーに移動後、sshでログインし、/volume1/wgに配置します。
#/volume1フォルダは更新時に削除されないため、独自ファイル配置するのによいようです。
cd wireguard-go
scp wireguard-go <acount>@<router ip>:/tmp/
cd ../wireguard-tools/src
scp wg <acount>@<router ip>:/tmp/
ssh <acount>@<router ip> -p <port>
sudo -i
mkdir /volume1/wg
mv /tmp/wireguard-go /volume1/wg
mv /tmp/wg /volume1/wg
#ファイルに実験権限付与
chmod +x /volume1/wg/wg
chmod +x /volume1/wg/wireguard-go

サーバー、クライアントそれぞれに秘密鍵、公開鍵、事前共有鍵を作成します。ここは他でいくらでも解説されているので跳ばします(WireGuardの場合、自分がインターフェース、相手がピアとなり、サーバークライアントの関係は実際にはないようです)。

設定ファイル wg0.confも/volume1/wgに保存します。内容は以下です。よくサンプルに表示されているAddressやup, downはwg-quick用の設定なので、wgのみで設定している場合は使えません。

[Interface]
PrivateKey = <ルーター側秘密鍵>
#Address = <A.A.A.A/24 #wan側IP>  wg-quickを使用しないのでここの設定は使用しません
ListenPort = <ポート番号>

[Peer]
PublicKey = <クライアント側公開鍵>
AllowedIPs = <A.A.A.B/32 #このピアに割り振るローカルip>

TUNデバイスの有無を確認して、なければ作ります(VPN plusをインストールしていればSRM側で作成されているようです)

#tunの有無を確認
ls -l /dev/net/tun
#なければ作成
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
chmod 666 /dev/net/tun
#以下でwireguardを設定します。
/volume1/wg/wireguard-go wg0
/volume1/wg/wg setconf wg0 /volume1/wg/wg0.conf
ip addr add <A.A.A.A/24 #WAN側ip> dev wg0
ip link set wg0 up
ifconfig wg0 mtu 1432 txqueuelen 1000

上記を再起動後自動で行うためスクリプトを設定します。RT2600acでは/usr/local/etc/rc.d/に保存したスクリプトは自動実行してくれるようです。ただしここもアップデート時に消える可能性があるので直接実行せず/volume1に保存したスクリプトを実行させます。
/usr/local/etc/rc.d/wireguard.shを作成し、実行権限付与

chmod +x /usr/local/etc/rc.d/wireguard.sh

内容は以下の通りです。rc.dに保存したスクリプトはstart, stopの引数を処理しないと実行されないようです。

#!/bin/sh

case "$1" in
start)
	/volume1/wg/wireguard.sh start
        ;;
stop)
	/volume1/wg/wireguard.sh stop
	;;
esac
                
exit 0

/volume1/wg/wireguard.shを作成し、実行権限付与

chmod +x /volume1/wg/wireguard.sh

内容は以下の通りです。

#!/bin/sh

WG_IF=wg0
WG_DIR=/volume1/wg
CONF=/volume1/wg/wg0.conf

case "$1" in
start)

sleep 20

ip link del $WG_IF 2>/dev/null

$WG_DIR/wireguard-go $WG_IF &
sleep 2

$WG_DIR/wg setconf $WG_IF $CONF
ip addr add <A.A.A.A/24 #wan側IP> dev $WG_IF
ip link set $WG_IF up
ifconfig $WG_IF mtu 1432 txqueuelen 1000
;;

stop)

ip link del $WG_IF 2>/dev/null

;;

esac

exit 0

これで再起動時にRT2600acでwireguardが待機状態になります。

クライアント向けに以下のように設定ファイルを書きます。

[Interface]
PrivateKey = <クライアント秘密鍵>
Address = <B.B.B.B/32 #上記で設定したクライアント側ローカルip>
DNS = 1.1.1.1 #VPN越しでは標準のNTTのDNSが動作しない模様
MTU = 1432

[Peer]
PublicKey = <ルーターの公開鍵>
AllowedIPs = 0.0.0.0/0 #すべての通信をVPNに通す場合
Endpoint = <ルーターグローバルip>:<ポート>

後はrt2600acのファイアーフォールを開けば、動作確認できました。接続が確立するまでの速さはOpenVPNよりずっと早かったですが、回線速度はスマホでは差が出なかったです。

ここで問題点としてWireguardで接続した場合SRMのログには表示されず、接続されても分かりません。色々怖いので、接続時にメールを送るようにします。先ほどと同様に/usr/local/etc/rc.d/wg-watch.shを作成し、実行権限付与を付与します。内容は以下です。

#!/bin/sh

case "$1" in
	start)
		/bin/sh /volume1/wg/watch.sh &
	        ;;
        stop)
		pkill -f /volume1/wg/watch.sh
                ;;
esac
            
exit 

/volume1/wg/watch.shを作成し、実行権限付与を付与します。内容は以下です。

#!/bin/sh

IF=wg0
STATE_FILE=/tmp/wg_state
THRESHOLD=300   # 300秒以内を接続中とみなす
WG_DIR=/volume1/wg
CONNECT_SH=$WG_DIR/on_connect.sh #新規接続時に実行するスクリプト
CONNECT_SH=$WG_DIR/on_disconnect.sh

touch $STATE_FILE

while true
do
    NOW=$(date +%s)

    $WG_DIR/wg show $IF latest-handshakes | while read PUBKEY TS
    do
        if [ "$TS" = "0" ]; then
            CURRENT=0
        else
            AGE=$((NOW - TS))
            [ $AGE -lt $THRESHOLD ] && CURRENT=1 || CURRENT=0
        fi

        PREV=$(grep "^$PUBKEY " $STATE_FILE 2>/dev/null | awk '{print $2}')

        [ -z "$PREV" ] && PREV=0

        # 未接続→接続 に変わった瞬間のみ実行
        if [ "$PREV" = "0" ] && [ "$CURRENT" = "1" ]; then
            $CONNECT_SH "$PUBKEY"
        fi
        # 未接続→接続 に変わった瞬間のみ実行
        if [ "$PREV" = "1" ] && [ "$CURRENT" = "0" ]; then
            $DISCONNECT_SH "$PUBKEY"
        fi

        # 状態更新
	grep -v "^$PUBKEY " $STATE_FILE > ${STATE_FILE}.tmp
	echo "$PUBKEY $CURRENT" >> ${STATE_FILE}.tmp
	mv ${STATE_FILE}.tmp $STATE_FILE
    done

    sleep 5
done

これで接続時に/volume1/wg/on_connect.sh切断時に/volume1/wg/on_disconnect.shが実行されます。同様に作成して実行権限を付与します内容はそれ以下です。捨てGoogleアカウントでアプリパスワードを設定してcurlで普段使いのメールに送信します。

#on_connect.sh
#!/bin/sh
curl    --url 'smtps://smtp.gmail.com:465' --mail-rcpt  '<To@gmail.com>' --mail-from  '<from@gmail.com>' --user '<from@gmail.com>:<password>' --ssl-reqd -T - <<EOS
To: <To@gmail.com>
From: <from@gmail.com>
Subject: VPN connected

VPN is used.
EOS
#on_disconnect.sh
#!/bin/sh
curl    --url 'smtps://smtp.gmail.com:465' --mail-rcpt  '<To@gmail.com>' --mail-from  '<from@gmail.com>' --user '<from@gmail.com>:<password>' --ssl-reqd -T - <<EOS
To: <To@gmail.com>
From: <from@gmail.com>
Subject: VPN disconnected

VPN is disconnected
EOS

これでRT2600acでもWireGuardが動作するようになりました。多分素直にOpenWrtに移行した方が楽だと思います。

Pocket

コメントを残す

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