마을 변두리를 지나면 통화가 끊기고, 같은 순간에 VPN 아이콘이 사라진다. 이것을 “기지국 교체가 터널을 죽였다”고 기록하고 싶어진다. 실제로는 두 가지 다른 일이 일어났고, 기지국과 관련된 것은 그중 하나뿐이다. 무선 핸드오버는 IP 주소, 기본 경로, 세션을 완전히 그대로 둘 수 있지만, 진짜 주소 변경은 그것을 따라갈 수 없는 모든 터널을 끊는다. 클라이언트가 두 번째 경우를 어떻게 다루는지 비교하는 것이 유용한 훈련인데, 설계된 동작인지 결함인지 알려 주기 때문이다.

기지국 교체가 반드시 주소 변경은 아니다

이동통신망은 사업자의 이동성 앵커가 같은 동안 핸드오버를 넘어 패킷 세션을 유지한다. 무선 링크는 바뀌지만 터널은 알아차리지 못하고, 어떤 로그에도 재연결이 나타나서는 안 된다. 도시 안에서의 이동에서는 이것이 보통의 경우다.

주소를 바꾸는 것은 앵커 사이의 이동, Wi-Fi에서 셀룰러로의 전환, 긴 공백 뒤 사업자 측의 터널 재수립이다. 그런 이벤트는 패킷이 지니는 출발지 주소를 바꾸고, VPN 피어는 이동한 피어를 보게 된다.

실무적 결론은 이동이 증거가 아니라는 것이다. 사십 킬로미터를 달린 기기가 내내 하나의 주소를 지켰을 수 있고, 멈춰 있던 기기가 네트워크의 결정으로 주소를 두 번 바꿨을 수도 있다. 이벤트를 기록하는 것만이 둘을 구별한다.

두 가지 설계: 터널을 옮기거나 다시 만들기

클라이언트는 바깥 출발지가 바뀐 것을 얼마나 중요하게 여기는지에서 갈린다. 어떤 것은 터널을 만들어진 주소에 묶고 완전한 재수립을 요구한다. 다른 것은 각 패킷을 독립적으로 인증하고 응답을 보낼 곳만 갱신한다.

MechanismBehaviour after the source changesWhat the user notices
WireGuardEndpoint updated on the next authenticated packetUsually nothing; the tunnel continues
IKEv2 with MOBIKESecurity association moves to the new addressShort pause, no re-authentication
OpenVPN over UDP with floatPeer address may change without a restartMight survive, depending on timing
Client bound to one addressSession dies and is rebuiltA visible reconnect and a new authentication

맨 위 줄은 많은 혼란스러운 보고를 설명한다. WireGuard에는 끊을 세션이 없어서, 각 패킷은 피어의 색인을 지니고 인증되므로 새 주소에서 도착한 유효한 패킷은 정의상 그 피어의 것으로 기록된 엔드포인트가 그것을 따라간다. 주행 내내 “연결됨”을 계속 표시하는 클라이언트는 사실을 말하고 있다.

아래 줄도 결함이 아니다. 세션을 다시 만들면 현재 주소에 대해 인증을 다시 수행하며, 옛 주소가 다른 사람의 것이 되었을 수 있을 때 바로 그것을 원한다.

이동이 아니라 이벤트를 관찰하라

Android에서 연결 하위 시스템은 네트워크 변화를 이벤트로 보고하며, 클라이언트의 동작과 연관 지어야 하는 것이 바로 그것이다. 덤프는 길지만 관련 부분은 기본 네트워크와 그 주소다:

adb shell dumpsys connectivity | grep -E 'NetworkAgentInfo|Default network'
adb shell ip -br addr show
adb logcat -b main -s Vpn:* | head -n 40

서버 쪽에는 로밍 상황에 대한 직접 측정이 있다. WireGuard는 피어마다 마지막으로 인증된 엔드포인트를 저장하므로, 주소 변경은 재연결이 아니라 변경된 값으로 나타난다:

sudo wg show wg0 endpoints
sudo wg show wg0 latest-handshakes

주행 전후의 엔드포인트를 비교한다. 주소와 포트가 바뀌지 않았다면 터널은 아무것도 할 필요가 없었고 재연결은 다른 곳, 보통 애플리케이션에서 왔다. 엔드포인트가 바뀌었는데 핸드셰이크 시각이 정상 키 갱신 간격에 가까웠다면, 터널은 재시작이 아니라 이동한 것이다.

재시작은 다르게 보이는데, 핸드셰이크 시각이 재연결 순간으로 초기화되고 클라이언트는 조용한 지속이 아니라 초기화 순서를 기록한다.

재연결이 올바른 동작일 때

모든 재연결을 고장으로 보면 죽은 세션을 살려 두는 설정에 이르게 된다. 네트워크가 다시 할당해서 주소가 바뀐 피어는 옛 매핑의 트래픽을 계속 받아서는 안 되고, 조용히 계속하는 클라이언트는 아이콘이 초록인 채로 블랙홀에 보낼 수 있다.

사용자 관점에서 두 실패를 비교한다. 재연결의 값은 몇 초와 새 인증이다. 낡은 터널의 값은 오류도 없이 멈추는 애플리케이션이며, 설명하기 훨씬 어렵고 “인터넷이 망가졌다”고 보고될 가능성이 훨씬 높다.

그 밑에는 정책 질문도 숨어 있다. 한 경로를 잃고 다른 경로를 세우는 사이에 일부 클라이언트는 트래픽을 직접 보내는 쪽으로 돌아간다. 그것을 막는 것은 자동 복구와는 별개의 제어이며, 클라이언트는 한쪽에 강하고 다른 쪽에 약할 수 있다. 둘 중 하나를 조정하기 전에 무엇이 필요한지 정하라.

관찰한 순서를 적어 두라

유용한 보고는 이벤트의 출처, 즉 새 주소를 동반한 기본 네트워크 변화, Wi-Fi에서 셀룰러로의 전환, 또는 주소 변화가 전혀 없는 핸드오버를 밝힌다. 그다음 클라이언트가 무엇을 했는지 기억이 아니라 서버 쪽 시각으로 적는다.

터널이 이동했다면 그렇게 말하고 새 엔드포인트 계열을 적는다. 재수립되었다면 인증이 첫 시도에 성공했는지와 공백이 얼마나 지속되었는지를 적는다. 이 세 사실이 건전한 모바일 설계와 네트워크 사이를 오가는 클라이언트를 가른다.

그리고 기기 로그가 실제로 뒷받침하지 않는 한 “기지국 교체”라는 표현을 피하라. Android 연결 문서는 가용성과 기본 네트워크 변화를 구별하는 콜백을 설명하며, 보고에 필요한 것이 바로 그 구별이다. 나머지는 모두 운전에 관한 이야기다.

관련 글