naoki86star

インターネットの片隅でなにかしら書いてみる

OpenConnect on Raspberry Pi3

きっかけ

 まだ、いくらか使っているインターネット上のVPSと自宅piをOpenVPNというVPNソフトでつないでいたりする。が、それとは別に、つい先日OpenConnectというLinuxで動かせるVPNクライアントがあるのを知った。

 元々はCISCOのアプライアンスが設置するVPNのクライアント側のオープン実装と見受けたが、現時点ではCISCO以外のいくらか複数のプロトコルに対応しているようである。つまり、このコマンドでいくつかのアプライアンス経由のVPNを張ることができそうということ。パッケージとかにはなっておらず、githubからソースを引っ張て来てビルドするかHPにはダウンロード用のtarアーカイブがあるのでそれを引っ張ってきてビルドするようである。

 さらにリンクをたどると、VPNサーバ側のオープン実装も存在するようである。こちらのほうはいくつかのシステムでのパッケージも用意してもらっている。


 バッチとかスクリプトでVPNサーバにつないでなにかやらせてから切る、みたいな処理を書きたいことあり、それでOpenVPN以外のコマンド側の実装に興味を持ち検索していた。今回は特に、クライアント側をRaspberry PiとかもしくはノートPCのような軽量環境にして使えるかどうかの見方で試してみていく。

ocserv(サーバ側)インストールと起動

 ocservはaptインストール可能なのでそれで入れてみる。pi3(buster)/ubuntu20.04どちらもさっくり入る。
 sudo apt install ocservすると、最終的にはsystemctl を通じて起動してくれたみたい。/etc/ocserv/ocserv.confが設定ファイルで、まずは供給するネットワークアドレスはチェックしておく。デフォルトは普通に使いそうで衝突しそうな192.168.1.0になっていた。

openconnect をraspberry pi3でビルドしてみる
  • Requirementsはそろっている(と思う)でもGnuTLS はgettextってパッケージ要求していたみたいなのでこれもいれる。
  • vpnc-scriptあるいは同等の動きをするものを用意しろとある。とりあえずリンク先のをそのまま引っ張ってくる。
  • GNU TLSのバージョンが安全でないやつだから、それでいいなら--without-gnutls-version-checkをつけろとconfigureに言われた。のでこのオプションつけて入っているパッケージのままでビルドすることにした。
動かしてみる

インターネット側のあるVPSで、ocservをインストール・起動する。FWの443/tcp,udpは開けて、それから自宅側ネットワークアドレスとかぶるので/etc/ocserv/ocserv.confでipv4-network = 172.31.1.0にしておく。

 openconnectコマンド、接続先を指定して打ってみる。まずはこんな警告がでてきたけども、自分のものなのでいまのところよし。

SSL negotiation with ********
Server certificate verify failed: self signed certificate

Certificate from VPN server "********" failed verification.
Reason: self signed certificate

ユーザーパスワード認証でサーバ側のユーザアカウントをつかい肯定応答。とりあえずVPN接続できたように思う。クライアント側にtun0インタフェースができて、171.31.1.114のアドレスが振られた。ping -s 1500したら通っている。
接続コマンドの出力には、処理経緯のログとともに

Too few arguments.

とか

DTLS handshake failed: Resource temporarily unavailable, try again.
DTLS handshake failed: The operation timed out

とかでてくる。実用上問題ないのかもう少し調べるべし。

vpnc-scriptについて

 OpenConnect、使えそうだと分かってきたが、vpnc-scriptの動作を理解することで、より適切な設定が可能になるのだろう。vpnc-scriptの動きについて、このスクリプトを読み、実際の動きとくらべながら理解してみる。

 このスクリプトの主な役割は、1)tun0デバイスを作成し*1、2)降ってきたGWアドレスを与えて、3)ルーティングテーブルを追加する、というところのようである。(接続解除時はそれの逆)tun0のアドレスやルーティングアドレスは環境変数でvpnc-scriptに渡されてくる。その環境変数の一覧はvpnc-scriptファイルに記述されている。

 認証が成功してトンネルが設定されたのち、このスクリプトが環境変数+引数とともに呼び出されている。引数にはpre-init、connect、disconnectがあって、接続時には引数pre-init、connectで順に呼ばれていた。それぞれの引数pre-init、connect呼び出し時には本スクリプトで定義されているdo_pre_init(),do_connect()関数が呼ばれるようになっている。それの前後でさらに自分で定義したスクリプトを呼び出すことができる仕掛けになっている。自分で定義したスクリプトは/etc/vpnc/にディレクトリ作成して配置する。vpnc-scriptスクリプト内ではrun_hooks関数が定義してあり、これがそれぞれの引数時の前後で/etc/vpnc/{pre_init.d,connec.d,post-connect.d}に配置されたスクリプト呼び出すようになっている。

 pi3クライアント接続時にでてきたToo few arguments.の出力は、do_connect()の中で/etc/resolv.confが更新されていて、そのときに出力されていたようだ。比較で、ubuntu20.04でOpenConnectを動かしてみたらToo few arguments.はでてこないが/etc/resolv.confの更新は行われている。VPN有効時のnameserverどうする?な設定にあたると思っている。自分の用途だと、DNSドメイン配下問い合わせみたいなのはない。ケースと使うNW環境によってはまるっと/sbin/resolvconf呼び出さないほうがいいかもしれない。そんなときにrun_hooks使ってうまく制御できるように環境変数をunsetするなりすればいいのだろう、そう理解した。

 do_connect関数読んでみて、Linuxルーティングテーブルの設定に関して実はよく知らなかったことがでてきた。

ip route flush cache

って構文は使ったことがなく、cacheという領域があってそれが参照できることを初めて知った。
 VPNサーバ側で供給するルーティングエントリが送られてきて、クライアント側での事情を考慮しながら追加する・しないをスクリプトで処理していく。その時にもとにあるエントリと重複する場合はいったん保存していて接続解除時には復元するとか細かいことも設計・設定できるポテンシャルがこのスクリプトにはある、というように理解した。

自分のまとめ
  • OpenConnect個人ユースで使えそう*2
  • 元の自分のNWのルーティングエントリの保全に気を付けるべし
  • Windows版(OpenConnectGUI)はコマンドになってない

*1:OSに応じた処理を呼んでいる

*2:アプライアンスにつなぐときに正規クライアントでないというリスクはある。単に接続できないという以上のなにか悪い状況とかあるかも。