-
Notifications
You must be signed in to change notification settings - Fork 25
iOS Loopback VPN Local MITM proxy
Antonio Cheong edited this page Sep 19, 2025
·
2 revisions
To do a user study on system or app services, MITM is required to record traffic, especially on a platform as restrictive as iOS. However, most existing MITM methods require sending data off device, both a privacy concern and inconvenience due to slower speed. There are also developer tools, such as Charles Proxy, Fiddler, and Proxyman. However, all of them are commercial with no way to fork & adapt for user studies.
Therefore, I decided to investigate how these local MITM apps worked and write up something similar for completely local data collection.
Referenced material:
- VPN Profiles and Network Extensions
- iOS Packet Tunnel Provider with Local On-Device Server
- Swift NIO HTTPS Proxying
- NEPacketTunnelProvider Sniffer iOS
None of the solutions found were complete, but they paint a clear architecture.
graph TD
A[iOS App Traffic] -->|HTTPS/HTTP Requests| B[iOS Network Stack]
B --> C[PacketTunnelProvider<br/>Network Extension]
C -->|Proxy Configuration<br/>127.0.0.1:8080| D[GoMITMProxy.swift<br/>Swift Wrapper]
D -->|CGO Bridge<br/>gomitm_* functions| E[Go MITM Library<br/>main.go]
E --> F[Proxy Server<br/>proxy.go]
F --> G[HTTP/HTTPS Handler<br/>goproxy library]
G -->|CONNECT for HTTPS| H{Host Regex Match?}
H -->|Yes - Match| I[MITM Mode<br/>TLS Termination]
H -->|No - No Match| J[Transparent Proxy<br/>Pass Through]
I --> K[Certificate Generation<br/>cert.go]
K --> L[Dynamic TLS Certificate<br/>Per Target Host]
L --> M[Decrypt & Inspect Traffic]
M --> N[Request Logger<br/>database.go]
N --> O[SQLite Database<br/>Captured Requests]
M -->|Re-encrypt & Forward| P[Target Server]
J -->|Direct Forward| P
P -->|Response| Q[Response Handler]
Q -->|Log Response| N
Q -->|Back to App| A
subgraph "Network Extension Process"
C
D
end
subgraph "Go Library (C Archive)"
E
F
G
K
N
end
subgraph "MITM Decision Logic"
H
I
J
end
subgraph "Certificate Management"
K
L
R[CA Certificate Storage<br/>UserDefaults]
end
K --> R
R --> K
subgraph "Data Persistence"
N
O
end
style A fill:#e1f5fe
style C fill:#f3e5f5
style E fill:#e8f5e8
style I fill:#fff3e0
style N fill:#fce4ec
style O fill:#fce4ec
Some things to note:
- All apps on iOS are required to be proxy aware, hence the ability to use
NEProxyServerrather than TCP/UDP packet tunnels. - Do not write the proxy server in Swift. There is a distinct lack of libraries & you'll be forced to handle a lot of parsing, certificate generation, and SNI sniffing yourself
- Network extensions are not allowed to spawn subprocesses, so embedding mitmproxy itself is not viable. Instead use something like Rust or Golang and compile to a C archive
- You must use App Groups to share preferences and data between the main app and network extension