何か月も安定して接続していた自動化が、クライアント更新後に動かなくなり、同じプロファイルは手動では今も接続できる。このパターンが指すのは VPN サーバーではなく制御の契約だ。アプリが受け付けるアクション、あるいは期待する識別子を誰かが変えたのに、タスクは古いものを送り続けている。結び付けを組み直すほうが、サーバーを再確認するより短時間で済む。

契約は 一つのアプリと一つのバージョン範囲に属する

OpenVPN Connect と OpenVPN for Android は別のアプリであり、一方のパッケージを名指す intent はもう一方では何もしない。タスクに触る前に、どちらのクライアントが入っているのか、比較している挙動をどのバージョンが生んだのかを確認する。Android 3.3.2 以降の Connect では、文書化された Tasker 連携がプロファイル ID を期待する。表示名の前に AS や PC を付ける古い手順は以前の契約を説明したもので、それを現在のタスクに写すのが、何も起きない最もよくある理由だ。

このバージョンの境界が「以前は動いていた」という報告の大半を説明する。アプリが機能を壊したのではなく、機能が受け取るものを変えたのだ。バージョン範囲は、これから書く契約の一部として扱う。

識別子はどこから来るか

Connect の中で目的のプロファイルを開き、そのプロファイル自身の詳細からプロファイル ID をコピーする。一覧で見覚えのある名前ではなくその値を使うのは、名前がラベルにすぎず、アプリが照合するのは識別子だからだ。Tasker の Send Intent アクションの接続フィールドは下のブロックのとおりで、識別子だけを差し替える。個人用プロファイルと仕事用プロファイルのアプリの実体も揃えておく。

Action: net.openvpn.openvpn.CONNECT
Extra: net.openvpn.openvpn.AUTOSTART_PROFILE_ID:'PROFILE_ID'
Extra: net.openvpn.openvpn.AUTOCONNECT:true
Package: net.openvpn.openvpn
Class: net.openvpn.unified.MainActivity
Target: Activity

仕事用プロファイル側の複製が、同じパッケージ名で別の保存プロファイルを持つと、intent は受け付けるが一致するプロファイルが見つからず、壊れたタスクに見えるが範囲の取り違えだ。プロファイルを再インポートしたり差し替えたりしたら、識別子は疑わしいものとして再確認する。再インポートでは表示名が変わらなくても新しいプロファイル項目ができることが多い。ほかを変える前に識別子を確認する。

無関係なフィールドは文書どおり空のままにする。ガイドが求めていないカテゴリ、MIME タイプ、データのフィールドは Android の intent 解決に影響しうるし、解決のされ方が違えば、プロファイルを開始せずにアプリだけが開くことがある。

このアクションがすること、あなたに残すこと

接続の intent を送るのは、アプリにプロファイルの開始を頼むだけだ。そのプロファイルが要求する認可を飛ばすわけではない。Connect がプロンプトを出すことはあり、だからこそ文書化された自律動作の条件は、追加の認可も保存済みの接続資格情報もないことを前提にしている。この境界を外したくなる誘惑は、パスワードや秘密鍵の機密を共有の Tasker エクスポートに埋め込む形で現れる。

そうしてはいけない。タスクのエクスポートはテキストファイルで人がチャットに貼り付けるもので、機密をそこに置けば共有した瞬間に開示される。プロファイルが資格情報を必要とするなら、アプリ自身が保存した接続資格情報を使い、MFA のプロンプトはプロンプトのままにしておく。答えを保存してプロンプトを避けるやり方は、問題を解いたのではなく、機密の置き場所を移しただけだ。

切断側にはそれ専用の文書化されたアクションがあり、クライアントを騙す小細工ではない:

Action: net.openvpn.openvpn.DISCONNECT
Extra: net.openvpn.openvpn.STOP:true
Package: net.openvpn.openvpn
Class: net.openvpn.unified.MainActivity
Target: Activity

存在しないプロファイルへわざと接続して切断を強制するのは、古いスレッドに見られる回避策で、更新後に黙って失敗する。明示的なアクションを使う。

次の手順が走る前に状態を確認する

intent の起動に成功したのは要求が届いた証拠であって、トンネルがある証拠ではない。タスクがそのあと社内アプリを開くなら、その手順には上限付きのタイムアウトを伴う準備条件が要る。送信直後のアクションは、いずれプロンプトに当たる。

$ adb shell cmd package resolve-activity --brief net.openvpn.openvpn
net.openvpn.openvpn/net.openvpn.unified.MainActivity
$ adb shell dumpsys activity activities | grep -i openvpn

resolve クエリは、狙っているパッケージとアクティビティがその端末にあることを確認するので、クラス欄の打ち間違いはこれで排除できる。アクティビティのダンプは、タスクを走らせたあと実際に前面にあるものを示し、アプリが接続ではなくプロンプトを開いたのかを見るのに一番安い方法だ。失敗したタスクのあとで両方を実行し、どのフィールドが悪いかを推測しない。クラス名の不一致は即座にエラーになるが、プロファイルが無い場合は目に見えるエラーがまったく出ない。

タスクを配る前に、切断の持ち主を決めておく。別の業務タスクが依存しているトンネルを落とすショートカットは、原因とまったく似ていないサポートチケットを生む。同じクライアントを操作する自動化を二つ抱えるとログから追えない競合が起きるので、新しいものが動いたら古いアクションは消す。

関連記事