Skip to content

네트워크 제어 ​

툴바의 네트워크 제어 버튼을 누르면 시뮬레이터·에뮬레이터의 네트워크가 오프라인이 되고, 다시 누르면 온라인이 됩니다. 오프라인 배너나 재시도 처리처럼 네트워크가 끊겼을 때만 나오는 동작을 브라우저에서 확인할 수 있습니다.

버튼은 시뮬레이터·에뮬레이터 단위로 동작합니다. 동일한 에이전트 맥에서 실행되는 다른 기기나 에이전트 맥 자체의 네트워크는 영향을 받지 않습니다.

끊을 수 없을 때는 요청을 거절합니다. 트래픽을 실제로 막지 못하는 상태에서 앱에만 오프라인이라고 알리면, 요청은 전부 성공하는데 화면은 오프라인으로 보입니다. 그 상태로 확인한 오프라인 동작은 확인한 것이 아니므로, tapflow는 절반만 적용하는 대신 버튼에 이유를 표시합니다.

무엇이 끊기고 무엇이 남는가 ​

오프라인으로 바꾸면 그 기기가 새로 여는 연결은 에이전트 맥의 루프백을 빼고 전부 막힙니다. 이미 열려 있던 연결은 tapflow로 실행한 앱 안에서만 함께 끊깁니다.

맥의 네트워크 필터는 새 연결만 판단합니다. 한 번 통과시킨 연결은 되돌릴 수 없습니다. 그래서 이미 열려 있던 소켓은 앱 안에서 따로 끊는데, 이 방식은 tapflow가 실행한 앱에서만 동작합니다. 그 밖에서 도는 것은 열어 둔 연결을 그대로 씁니다. 시뮬레이터의 브라우저나 tapflow로 실행하지 않은 다른 앱이 여기 해당합니다.

실제로는 이렇게 보입니다. 오프라인으로 바꾼 순간 이미 내려받고 있던 화면은 잠시 더 진행되고, 같은 순간 새로 연 화면은 바로 실패합니다. 둘 다 정상입니다.

확인은 새 요청으로 합니다. 화면을 새로 열거나 당겨서 새로고침해 앱이 새 요청을 보내게 하세요. 이미 진행 중이던 요청이 끝나는 것으로 판단하면 오프라인이 걸리지 않은 것처럼 보입니다.

로컬호스트는 끊기지 않습니다 ​

Metro 같은 개발 서버는 에이전트 맥의 루프백으로 연결되기 때문에 기기를 오프라인으로 둬도 계속 붙어 있습니다. 디버그 빌드를 연결한 채로 오프라인 동작을 확인할 수 있습니다.

iOS는 네트워크 확장이 필요합니다 ​

iOS 시뮬레이터에서 네트워크 제어를 하려면 tapflow 네트워크 확장이 에이전트 맥에 한 번 설치돼 있어야 합니다. 시뮬레이터가 아니라 맥에 설치합니다. 시뮬레이터에는 끌 수 있는 무선 장치가 없고 맥의 네트워크를 함께 쓰기 때문입니다.

확장은 tapflow와 함께 옵니다. 설치와 승인 절차는 iOS 네트워크 확장에 있고, 모두 에이전트 맥에서 합니다. 승인 단계에는 관리자 암호가 필요합니다.

버튼이 이유를 말할 때 ​

기기를 끊을 수 없는 상태에서는 버튼이 실패 색으로 바뀌고 무엇을 하면 되는지 함께 표시합니다.

버튼이 말하는 것다음에 할 일
앱을 실행해 달라tapflow로 앱을 실행하세요. 트래픽은 이미 끊을 수 있지만, 앱에 알리려면 앱이 tapflow 아래에서 실행돼야 합니다
기기를 재시작해 달라기기를 재시작하세요. 이번 부팅에서 준비가 되지 않았습니다
확인하지 못했으니 다시 시도해 달라다시 누르세요. 기기가 부팅 중이거나 연결이 잠깐 끊겼을 때 나옵니다
요청했는데 기기가 바뀌지 않았다다시 누르세요. 계속 같으면 그 기기가 설정을 받지 않는 것이니 다른 기기를 쓰세요
이 앱에 네트워크가 끊겼다고 알릴 수 없다다시 눌러도 같은 답이 나옵니다. 다른 앱을 실행해 보고 에이전트 맥에서 tapflow doctor ios의 Network hook 항목을 확인하세요
이 맥이 준비되지 않았다아래 iOS는 네트워크 확장이 필요합니다를 보세요. 에이전트 맥에서 하는 설치 작업입니다

다시 시도하라고 표시될 때만 다시 누를 만합니다. 나머지는 눌러도 같은 답이 돌아옵니다.

오프라인으로 확인하던 중에 기기가 스스로 온라인으로 돌아왔다는 알림이 뜬다면, 그때까지 확인한 오프라인 동작은 다시 확인해야 합니다. 원인과 대처는 문제 해결에 있습니다.

무엇을 신뢰하게 되는가 ​

이 확장은 시뮬레이터가 여는 모든 연결을 트래픽이 맥을 떠나기 전에 넘겨받아 통과 여부를 정합니다. tapflow가 요구하는 신뢰 중 가장 큰 것이므로 그대로 적습니다.

  • 무엇을 보는가 — 시뮬레이터로 귀속된 연결의 존재와 목적지를 봅니다. 내용은 읽지 않습니다.
  • 무엇이 맥을 떠나는가 — 아무것도 떠나지 않습니다. 판단은 전부 맥 안에서 이뤄지고, 확장이 남기는 상태 파일도 로컬입니다.
  • 누가 서명하는가 — tapflow의 Developer ID입니다. Apple 공증을 거칩니다.

서명이 증명하는 것과 증명하지 않는 것은 다릅니다. 아래 두 명령은 이 앱이 tapflow가 만든 것이고 이후 변조되지 않았음을 확인합니다.

sh
codesign -dv --verbose=4 /Applications/TapflowNetFilter.app
spctl -a -vv /Applications/TapflowNetFilter.app

증명하지 않는 것은 이 바이너리가 저장소에 커밋된 Swift 소스에서 나왔다는 사실입니다. 앱은 메인테이너의 맥에서 빌드돼 저장소에 커밋되며, 서명 키는 CI에 두지 않습니다 — 태그를 밀 수 있는 사람이 네트워크 필터에 서명할 수 있게 되기 때문입니다. 그 대가로 빌드는 재현 불가능합니다. 소스와 바이너리의 연결까지 직접 확인하려면 소스를 읽고 직접 빌드해야 하며, 여기에는 유료 Apple 개발자 계정이 필요합니다.

끄는 것과 제거하는 것은 다릅니다. 시스템 설정 → 일반 → 로그인 항목 및 확장 프로그램 → 네트워크 확장에서 끄면 설치된 채로 동작만 멈춥니다. 완전히 제거하려면 먼저 이 맥에서 도는 tapflow(tapflow start, tapflow agent start)를 멈추세요. iOS 에이전트가 돌고 있으면 필터를 다시 켭니다. 그다음 필터를 끄고 앱을 지웁니다.

sh
/Applications/TapflowNetFilter.app/Contents/MacOS/TapflowNetFilter --off
rm -rf /Applications/TapflowNetFilter.app

마지막으로 같은 화면에서 TapflowNetFilter 옆 ⋯ 버튼을 눌러 확장 프로그램 삭제를 고르고 맥을 재시동합니다. 앱을 지운 뒤에도 목록에 남아 있어서 삭제할 수 있습니다. 제거는 재시동할 때 끝납니다. 그 전까지 systemextensionsctl list에는 terminated waiting to uninstall on reboot로 남습니다. 필터를 먼저 끄는 이유는 켜진 필터를 지우면 맥의 새 연결이 막힐 수 있기 때문입니다.

systemextensionsctl uninstall은 쓸 수 없습니다. 시스템 무결성 보호(SIP)가 켜진 맥에서는 macOS가 이 명령을 거부합니다.

/Applications/TapflowNetFilter.app만 지우는 것으로는 제거되지 않습니다. macOS는 컨테이너 앱이 사라진 확장도 계속 실행하며, tapflow doctor ios가 바로 그 상태를 따로 알려줍니다.

하이브리드 앱의 WebView는 오프라인 배너를 그리지 않습니다

WebView 안에서 도는 화면에는 오프라인 통지가 닿지 않아 배너가 뜨지 않습니다. 알려진 제약입니다.

이미 열려 있던 연결도 WebView에서는 끊기지 않습니다. 소켓을 끊는 처리는 tapflow가 실행한 앱 안에서만 동작하는데, WebView의 네트워크는 별도 프로세스에서 돌아 거기에 닿지 않습니다. WebView가 새로 여는 연결은 다른 요청과 똑같이 실패합니다.

그 화면의 오프라인 동작은 배너가 아니라 새 요청의 실패로 확인하세요.

오류 코드가 실기기와 다릅니다

iOS 시뮬레이터에서는 NSURLErrorNetworkConnectionLost(-1005)가 납니다. 실기기를 기내 모드로 두었을 때 나오는 NSURLErrorNotConnectedToInternet(-1009)와 다른 값이므로 오류 코드로 분기하는 앱이라면 두 값을 모두 처리하는지 확인하세요.

Released under the MIT License.