Android Proxy Manager is a single APK that acts as both an Android app and an LSPosed module. It uses Magisk for root access and iptables for transparent proxying.
┌─────────────────────────────────────────────────────────────────┐
│ Android App (APK) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ Compose UI │ │ ViewModel │ │ IntentReceiver │ │
│ │ (Screens) │◄──│ (Hilt) │ │ (CLI/ADB API) │ │
│ └──────────────┘ └──────┬───────┘ └────────┬───────────┘ │
│ │ │ │
│ ┌───────▼────────────────────▼──────────┐ │
│ │ ProxyRepository │ │
│ │ (Room DB + DataStore + config writer) │ │
│ └───────────────────┬───────────────────┘ │
│ │ │
│ ┌───────────────────▼───────────────────┐ │
│ │ IptablesManager │ │
│ │ (root commands via RootCommand/su) │ │
│ └───────────────────┬───────────────────┘ │
└────────────────────────────────────────┼────────────────────────┘
│ su + named pipe
┌────────────────────────────────────────▼────────────────────────┐
│ Magisk Module (service.sh) │
│ │
│ • Runs as root after boot │
│ • Listens on /data/local/proxy-manager/cmd.pipe │
│ • Manages iptables TPROXY + MARK rules │
│ • Reads /data/local/proxy-manager/config.json on RELOAD │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ LSPosed Module (XposedInit) │
│ │
│ • Loaded into target app processes by LSPosed framework │
│ • Reads /data/local/proxy-manager/config.json │
│ • Hooks: ProxySelector.getDefault(), OkHttpClient.Builder.build()│
│ • Sets system properties for WebView proxy │
└───────────────────────────────────────────────────────────────────┘
| Mode | Mechanism | Scope |
|---|---|---|
SYSTEM |
settings put global http_proxy |
Apps that respect system proxy |
TPROXY |
iptables PREROUTING TPROXY + ip rule/route | All TCP traffic (transparent) |
PER_APP |
iptables OUTPUT MARK per UID + PREROUTING TPROXY | Selected apps by UID |
DISABLED |
Teardown all rules | — |
TPROXY is only valid in the PREROUTING chain. For locally-generated traffic (OUTPUT), we use MARK to reroute packets back through loopback where the PREROUTING TPROXY rule intercepts them:
# Routing: marked packets → loopback
ip rule add fwmark 0x01 table 100
ip route add local default dev lo table 100
# PREROUTING: intercept marked TCP → tproxy listener
iptables -t mangle -A PREROUTING -p tcp -j TPROXY \
--tproxy-mark 0x01 --on-port 8118
# OUTPUT (per-app): mark packets from UID
iptables -t mangle -A OUTPUT -m owner --uid-owner $uid -j MARK --set-mark 0x01
The transparent proxy listener must bind with IP_TRANSPARENT socket option.
/data/local/proxy-manager/config.json (chmod 600, root-owned) bridges all three layers:
{
"enabled": true,
"mode": "per_app",
"global_proxy": "1.2.3.4:8080",
"tproxy_port": 8118,
"app_proxies": {
"com.example.app": {
"host": "1.2.3.4",
"port": 8080,
"type": "HTTP",
"uid": 10123,
"enabled": true
}
}
}Commands are sent via named pipe /data/local/proxy-manager/cmd.pipe (chmod 600):
SET_GLOBAL host:port
CLEAR_GLOBAL
SET_APP uid:host:port
CLEAR_APP uid
STATUS
RELOAD
Response is written to /data/local/proxy-manager/cmd.response.
android-proxy-rooted/
├── magisk-module/
│ ├── module.prop # Magisk module metadata
│ ├── customize.sh # Install-time setup
│ ├── post-fs-data.sh # Early boot
│ └── service.sh # Root daemon (iptables + IPC)
└── app/
└── app/src/main/
├── AndroidManifest.xml
├── assets/xposed_init # LSPosed entry point
└── java/com/proxymanager/
├── data/
│ ├── ProxyDatabase.kt # Room DB
│ └── ProxyRepository.kt # Data layer
├── root/
│ ├── RootCommand.kt # su exec
│ ├── IptablesManager.kt # iptables rules
│ ├── ProxyTester.kt # Connectivity test
│ └── IpChecker.kt # IP verification
├── service/
│ ├── ProxyService.kt # Foreground service
│ ├── IntentReceiver.kt # CLI/ADB API
│ └── BootReceiver.kt
├── viewmodel/
│ └── ProxyViewModel.kt
├── ui/ # Compose screens
└── xposed/
└── XposedInit.kt # LSPosed hooks