mirror of
https://github.com/amnezia-vpn/amneziawg-android.git
synced 2026-10-13 21:34:07 +00:00
[PR #104] feat: JNI bridge for the split tunneling UID filter #101
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
amnezia-vpn/amneziawg-android#101
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/amnezia-vpn/amneziawg-android/pull/104
Author: @Fast-and-Pythonic
Created: 9/22/2026
Status: 🔄 Open
Base:
master← Head:pr/strict-split-tunneling📝 Commits (2)
15c9ea1feat: JNI bridge for the split tunneling UID filter94c30d7fix(libwg-go): do not hold the UID filter lock across the Java call📊 Changes
3 files changed (+165 additions, -0 deletions)
View changed files
📝
tunnel/src/main/java/org/amnezia/awg/GoBackend.java(+15 -0)📝
tunnel/tools/libwg-go/api-android.go(+28 -0)📝
tunnel/tools/libwg-go/jni.c(+122 -0)📄 Description
The second of three PRs fixing amnezia-vpn/amnezia-client#2457 on Android: an app excluded from the VPN can bind a socket to
tun0and reach the VPN server, which reveals the server's address.amnezia-vpn/amneziawg-go#199 adds a
uidfilterpackage. It drops outbound packets whose owning app the split-tunnel policy does not allow. The policy has to live on the Java side, because only the app that owns the activeVpnServicecan askConnectivityManager.getConnectionOwnerUidwho owns a connection. This PR connects the two.What this adds
GoBackend.awgSetUidFilter(UidFilter)installs a filter, andawgSetUidFilter(null)removes it. It returns 0 on success.UidFilteris one method:boolean allow(String network, String srcIp, int srcPort, String dstIp, int dstPort).api-android.go, a GoPacketFilterthat calls into C. Injni.c, the upcall into Java.The call is an upcall from one of
uidfilter's worker threads, which the JVM does not know, andjni.chandles that as follows:FindClassfrom the Go thread;pthread_keydestructor when it exits;PushLocalFrame/PopLocalFrame, so no local references accumulate;With no filter installed, nothing crosses the bridge: the Go side does not call into C at all.
Dependency
The bridge imports
github.com/amnezia-vpn/amneziawg-go/v3/uidfilter, which does not exist until amnezia-vpn/amneziawg-go#199 is merged and released. Until then this branch does not build. Once it is released, this PR gets ago.modbump to that version, and I will push it here. For review, it builds with-Werroragainst the amneziawg-go PR branch through a temporaryreplace, and both entry points are exported fromlibwg-go.so.Testing
Built into the client with the rest of the series and run on a Poco F7 (Android 16) against an AmneziaWG server (protocol 3.1). With the filter on, 0 of 6 bypass attempts from an app outside the VPN reached the server, and ICMP echo through
tun0timed out. With it off, 6 of 6 did and ping answered, as before. There were no JNI errors or native crashes in logcat across several sessions with reconnects and mode switches. Re-tested on 2026-09-25 with the current amneziawg-go#199, where 4 worker threads call the filter concurrently. The logs showed denials from all four threads, no JNI errors, and connect latency under 5000 new flows/s matched the filter being off (numbers in amneziawg-go#199).Notes and probes: https://github.com/amnezia-tun0-fix/strict-split-tunneling-notes
Series and merge order
awg-androidonce this is released🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.