몇 달 동안 안정적으로 연결되던 자동화가 클라이언트 업데이트 뒤에 동작을 멈추는데, 같은 프로필은 손으로는 여전히 연결된다. 이 패턴이 가리키는 것은 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는 프로필을 시작하지 않은 채 앱만 열 수 있다.

이 동작이 하는 일과 당신에게 남기는 일

연결 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 조회는 노리는 패키지와 액티비티가 그 기기에 있음을 확인하므로, 클래스 필드의 오타는 이로써 배제된다. 액티비티 덤프는 작업이 돈 뒤 실제로 전면에 무엇이 있는지 보여 주며, 앱이 연결 대신 프롬프트를 열었는지 보는 가장 싼 방법이다. 실패한 작업 뒤에 둘 다 실행하고, 어느 필드가 틀렸는지 짐작하지 마라. 클래스 이름이 어긋나면 곧바로 오류가 나지만, 프로필이 없으면 눈에 보이는 오류가 전혀 나지 않는다.

작업을 내보내기 전에 연결 끊기의 소유자를 정하라. 다른 업무 작업이 의존하는 터널을 끊는 지름길은 원인과 전혀 닮지 않은 지원 티켓을 만든다. 같은 클라이언트를 조작하는 자동화 두 개를 두면 로그로 추적할 수 없는 경쟁이 생기니, 새것이 동작하면 옛 동작은 지워라.

관련 글