Ubuntu 22.04にて L2TP/IPsec でVPNに接続するとbad control packetと言われる
Microsoft系のVPNで使われている L2TP/IPsec、Ubuntu 22.04 にアプデすると接続できなくなる問題。
「Ubuntu 22.04 bad control packet」とかで調べると色々と出てくるが、良い対処記事が無かったので自身の奮闘を記事にした。
私はネットワークの専門家ではないので、詳細は他の人に託したい...
前提
以下のリンクからダウンロードした Ubuntu Desktop 22.04.1 LTS
といっても他ディストリビューションでも同様。
昔は接続できていたのに......という人が対象。
L2TP VPN の設定
デフォルトだとL2TPには対応していないのでパッケージを入れる。
$ sudo apt install network-manager-l2tp network-manager-l2tp-gnome
生えてくるので、普通に設定する。(ここは割愛)
デバッグモードを起動して、VPNのスイッチを入れる。
$ sudo /usr/lib/NetworkManager/nm-l2tp-service --debug
xl2tpd[xxxx]: message_type_avp: message type 6 (Hello)
xl2tpd[xxxx]: control_finish: message type is Hello(6). Tunnel is xxxxx, call is 0.
xl2tpd[xxxx]: check_control: Received out of order control packet on tunnel xxxxx (got 2, expected 3)
xl2tpd[xxxx]: handle_control: bad control packet!
xl2tpd[xxxx]: network_thread: bad packet
🤔🤔🤔
Hello はできているが、 bad control packet
と言われてしまう。🤔
3が来る予定が2が来たとも言っている。🤔
ブラウザでページは開けず、しばらく経つと VPN から切断されてしまう。
ネットワークに接続していない状態と同義。
困った。(もしや誰も困ってないのかな...?)
対処法
Q.神はいると思う? A.インターネットで見た
この神様曰く、spurious IP (偽のIP)があると言っている。
確認する。
$ ip addr
...
0: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1400 qdisc fq_codel state UNKNOWN group default qlen 0
link/ppp
inet xxx.xxx.xxx.xxx peer yyy.yyy.yyy.yyy/yy scope global ppp0
valid_lft forever preferred_lft forever
inet xxx.xxx.xxx.xxx/xx scope global noprefixroute ppp0
valid_lft forever preferred_lft forever
inet6 zz::zz:zz:zz:zz peer zz::zz:zz:zz:zz/zz scope link
valid_lft forever preferred_lft forever
※ IPは漏らせないため、黒塗りです。
ubuntu の VPN の接続は ppp
という名前で作られる。
確認すると、以前の Ubuntu では存在しなかった inet ip が確かに存在する。(1つ目)
これを消してあげる。
$ sudo ip a del xxx.xxx.xxx.xxx peer yyy.yyy.yyy.yyy dev ppp0
(1つ目の inet のIPのみを記載、pppは対応する番号にする)
もう一度 $ ip addr
で確認して、対象の inet が削除されていればOK。
すると VPN が落ちることも無くなるはず。🙌🙌🙌
永続化
しかしこの設定、接続のたびに初期化されてしまう。
毎回確認してコマンド実行なんて面倒なことはできない!!
ということで調べたところ、VPN接続設立時に dispatcher がスクリプトを実行してくれるらしい。
(Arch はようまとまっておる)
ディスパッチファイルは /etc/NetworkManager/dispatcher.d/
に存在する。
私の環境では /etc/NetworkManager/dispatcher.d/01-ifupdown
の中に別のスクリプトを読み出すコードが存在した。
# Run the right scripts
case "$2" in
up|vpn-up)
export MODE="start"
export PHASE="post-up"
run-parts /etc/network/if-up.d
;;
down|vpn-down)
export MODE="stop"
export PHASE="post-down"
run-parts /etc/network/if-post-down.d
;;
VPN 接続確立時に先程のコマンドを実行したいので、 /etc/network/if-up.d
のディレクトリにスクリプトファイルを作成する。
スクリプトは、対象ディレクトリの名前順?先頭から実行してくれるらしいので、任意の名前でOK。
実行スクリプトのデバッグは、 echo
を使って以下のコマンドで拾える。
$ sudo cat /var/log/syslog | grep nm-dispatcher
#!/bin/bash
if [[ "$IFACE" =~ ^ppp[0-9] ]]; then
PPP=`ip addr show dev $IFACE | grep 'scope global'`
IP1=`echo $PPP | awk '{ print $2 }'`
IP2=`echo $PPP | sed -e 's@/@ @g' | awk '{ print $4 }'`
sudo ip addr del $IP1 peer $IP2 dev $IFACE
fi
$IFACE
ってのに ppp0 のような文字が送られるので、これで判別する。
$ ip addr
コマンドで状況を確認して、削除コマンドを構築、実行する簡単なもの。
(私のshell能力じゃこれが限界...😭)
本当は元IPの確認や存在確認入れたほうが良いと思うが、とりあえず動くのでええやろ。
一ヶ月は問題なく動いてる。
終わりに
神様直して😭ロールバックでもいいの😭
xl2tpd[xxxx]: check_control: Received out of order control packet on tunnel xxxxx (got 2, expected 3)
って言われてたのは、不明な重複するIPが割り当てられて、それぞれに適当にパケット届いちゃった結果なんじゃないですかねぇ。
Discussion
まとめありがとうございます!
一箇所だけ修正が必要でした。シェルスクリプトの名前は
/etc/network/if-up.d/vpn-fixed.sh
ではなく/etc/network/if-up.d/vpn-bad-control-packet-patch
などのようにピリオドを含まないファイル名にする必要がありました。