Skip to content

Add VPN mode support without requiring root permissions#32

Open
madeye wants to merge 15 commits into
masterfrom
claude/vpn-service-no-root-VjBUy
Open

Add VPN mode support without requiring root permissions#32
madeye wants to merge 15 commits into
masterfrom
claude/vpn-service-no-root-VjBUy

Conversation

@madeye

@madeye madeye commented Jan 25, 2026

Copy link
Copy Markdown
Owner

Summary

This PR adds a VPN-based proxy mode to ProxyDroid that doesn't require root permissions. Users can now choose between the traditional root-based service and a new VPN-based service that uses tun2socks to redirect traffic through a SOCKS proxy.

Key Changes

  • VPN Service Implementation: Added ProxyDroidVpnService that extends Android's VpnService to provide system-wide proxy functionality without root
  • tun2socks JNI Wrapper: Implemented native C++ code (tun2socks_jni.cpp) that handles TUN interface management and SOCKS proxy redirection for TCP/UDP traffic
  • VPN Mode Toggle: Added isVpnMode preference to allow users to switch between VPN and root-based modes
  • Minimum SDK Update: Increased minSdkVersion from 16 to 21 to support VPN Service APIs
  • Version Bump: Updated to version 3.3.0 (versionCode 73)
  • Per-App Proxy Support: Extended ProxyedApp class with package name tracking for per-app VPN filtering
  • Local Proxy Server: Added support for HTTP/HTTPS proxy conversion to SOCKS for VPN mode
  • VPN Permission Handling: Implemented proper VPN permission request flow with onActivityResult callback
  • Conditional Root Checks: Modified root requirement checks to only apply when VPN mode is disabled

Implementation Details

  • The VPN service establishes a TUN interface and uses tun2socks to intercept and redirect traffic
  • Supports SOCKS5 authentication (username/password)
  • Handles both TCP and UDP traffic with connection tracking
  • Includes DNS proxy support with configurable DNS servers
  • Per-app proxy filtering works with both "proxy these apps" and "bypass these apps" modes
  • Graceful fallback to root-based service when VPN mode is disabled
  • Proper cleanup and resource management on service stop/revoke

Testing Recommendations

  • Test VPN mode activation and permission flow
  • Verify traffic routing through SOCKS proxy
  • Test per-app proxy filtering in VPN mode
  • Confirm backward compatibility with root-based mode
  • Test switching between VPN and root modes

claude and others added 15 commits January 24, 2026 23:28
This commit adds a new VPN-based proxy mode that allows ProxyDroid to work
without root permissions by using Android's VpnService API and tun2socks.

Key changes:
- Add ProxyDroidVpnService class implementing VpnService
- Add tun2socks native JNI library for TUN-to-SOCKS conversion
- Add Tun2SocksHelper for managing the tun2socks process
- Add LocalProxyServer for HTTP-to-SOCKS proxy conversion
- Update AndroidManifest.xml with VPN permission and service declaration
- Modify ProxyDroid.java to support both VPN and root modes
- Add isVpnMode preference toggle (enabled by default)
- Update minSdkVersion to 21 for per-app VPN filtering support
- Bump version to 3.3.0

The VPN mode routes all traffic through a TUN interface which is then
forwarded through the configured proxy server via tun2socks. For HTTP
proxies, a local SOCKS server converts the traffic appropriately.
This commit adds a full tun2socks implementation with:
- Core TCP/IP packet processing (tun2socks.c/h)
- SOCKS5 client with authentication support
- TCP connection tracking and state machine
- UDP packet forwarding (DNS support)
- Proper IP/TCP/UDP checksum calculation
- Connection timeout handling

The implementation reads packets from the TUN device, parses IP/TCP/UDP
headers, establishes SOCKS5 connections to the proxy server, and relays
data bidirectionally between the TUN interface and SOCKS proxy.

Key features:
- Full TCP state machine (SYN, ACK, FIN, RST handling)
- SOCKS5 CONNECT command for TCP connections
- DNS query forwarding via UDP
- Per-connection send/receive buffers
- Non-blocking I/O with poll()
- Connection idle timeout cleanup
This adds a CI workflow that:
- Builds the debug APK on every push and pull request
- Sets up JDK 11 and Android SDK with NDK
- Caches Gradle dependencies for faster builds
- Creates dummy google-services.json for CI builds
- Uploads the built APK as an artifact
- Runs Android Lint checks in a separate job

The workflow triggers on:
- Pushes to master, main, and claude/* branches
- Pull requests to master and main branches
- Replace deprecated jcenter() with mavenCentral()
- Remove deprecated Fabric.io maven repository
- Update from deprecated io.fabric plugin to com.google.firebase.crashlytics
- Update google-services plugin to 4.3.15
- Replace deprecated com.crashlytics.sdk.android:crashlytics with
  com.google.firebase:firebase-crashlytics:18.4.3
- Fix IPPROTO_* redefinition warnings in tun2socks.h by using #ifndef guards
- Upgrade Gradle from 5.4.1 to 7.6.3
- Upgrade Android Gradle Plugin from 3.5.3 to 7.4.2
- Update app/build.gradle for AGP 7.x syntax:
  - compileSdkVersion → compileSdk
  - minSdkVersion → minSdk
  - targetSdkVersion → targetSdk
  - Remove buildToolsVersion (optional in AGP 7+)
  - Add namespace for AGP 7+ requirement
  - Update configurations to use implementation instead of compile
- Remove specific CMake version requirement from app/build.gradle
  (let AGP use default CMake version)
- Install CMake 3.22.1 in GitHub Actions workflow alongside NDK
- Remove package attribute (using namespace in build.gradle)
- Add android:exported to activities with intent-filters (required for API 31+)
- Add android:exported to receivers with intent-filters
- Add POST_NOTIFICATIONS permission for Android 13
- Add FOREGROUND_SERVICE_SPECIAL_USE permission
- Add foregroundServiceType="specialUse" to services
- Add PROPERTY_SPECIAL_USE_FGS_SUBTYPE property to services
- Limit WRITE_EXTERNAL_STORAGE to maxSdkVersion 28
- Remove foregroundServiceType="specialUse" (only available in API 34+)
- Remove FOREGROUND_SERVICE_SPECIAL_USE permission
- Remove PROPERTY_SPECIAL_USE_FGS_SUBTYPE properties
- Keep services without foregroundServiceType for API 33 compatibility
Convert switch statements using R.id.* values to if-else statements
because resource IDs are no longer compile-time constants in AGP 7.x.
- Update Gradle wrapper from 7.6.3 to 8.13
- Update Android Gradle Plugin from 7.4.2 to 8.13.2
- Update Google Services plugin from 4.3.15 to 4.4.1
- Convert app/build.gradle to plugins block syntax (required by AGP 8+)
- Replace switch on R.id with if-else chain in BypassListActivity (R.id
  fields are no longer compile-time constants in AGP 8+)
- Fix arc4random_addrandom compilation error in evutil_rand.c

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add JUnit and Mockito test dependencies to build.gradle
- Create LocalHttpProxyTest with comprehensive tests:
  - SOCKS5 handshake protocol
  - IPv4 and domain name connection handling
  - HTTP proxy authentication
  - Proxy connection failure handling
  - Data relay functionality
  - Server start/stop lifecycle
  - Concurrent connection handling
- Add test job to GitHub Actions workflow with:
  - Unit test execution with stacktrace and info output
  - Test result artifact upload
  - Test summary output for debugging
- Add NDK and CMake installation to test job (required for native code compilation)
- Add ndk.dir to local.properties for test job
- Update compileOptions to Java 11 (required for Mockito 4.x)
- Use explicit testDebugUnitTest task instead of generic test
- Improve test summary output with better XML result parsing
AGP 8.x requires NDK 25.x or later. Updated from NDK 21.4.7075529 to
25.1.8937393 (the default for AGP 8.x) in both the GitHub Actions
workflow and app/build.gradle.
madeye pushed a commit that referenced this pull request Feb 1, 2026
This implements PR #32 features:
- Add ProxyDroidVpnService extending Android's VpnService API
- Add native tun2socks library for TUN to SOCKS5 conversion
- Add LocalProxyServer for HTTP-to-SOCKS protocol conversion
- Add Tun2SocksHelper JNI wrapper for native library
- Update build.gradle to SDK 33, Gradle 8.x, NDK 25.1
- Add VPN mode toggle in preferences (enabled by default)
- Update AndroidManifest with VPN service declaration and permissions

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL
madeye added a commit that referenced this pull request Feb 1, 2026
* Add VPN mode support without requiring root permissions

This implements PR #32 features:
- Add ProxyDroidVpnService extending Android's VpnService API
- Add native tun2socks library for TUN to SOCKS5 conversion
- Add LocalProxyServer for HTTP-to-SOCKS protocol conversion
- Add Tun2SocksHelper JNI wrapper for native library
- Update build.gradle to SDK 33, Gradle 8.x, NDK 25.1
- Add VPN mode toggle in preferences (enabled by default)
- Update AndroidManifest with VPN service declaration and permissions

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Add GitHub Actions CI workflow and unit tests

- Add android-build.yml workflow for CI/CD with:
  - JDK 17 and Android SDK setup
  - Gradle build, unit tests, and lint
  - APK and test results artifact upload
- Add LocalHttpProxyTest with comprehensive unit tests for:
  - SOCKS5 handshake (auth and no-auth)
  - SOCKS5 connect requests (IPv4, domain, IPv6)
  - HTTP CONNECT proxy requests
  - Protocol parsing and encoding

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Add local HTTP proxy tests with Android emulator integration

- Add emulator-test job to GitHub Actions workflow that:
  - Starts an HTTP CONNECT proxy server on the host
  - Installs the app on Android emulator
  - Configures proxy settings via adb
  - Verifies VPN service declaration and native libraries
  - Tests app startup and configuration handling

- Add test_http_proxy.py: Python HTTP CONNECT proxy for testing
  - Supports authentication
  - Logs all CONNECT requests
  - Relays data between client and target

- Add run_integration_tests.sh: Integration test script
  - Automates emulator testing workflow
  - Configures preferences via adb
  - Runs connectivity verification tests

- Update app/build.gradle with additional androidTest dependencies

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Remove unused imports and constants from unit tests

Clean up test file to remove unused imports (ServerSocket, Socket,
InputStream, OutputStream, etc.) and unused port constants that
were left over from the previous socket-based test implementation.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix CI lint job by adding NDK/CMake installation

The lint job was failing because it couldn't compile native code
without NDK and CMake installed. Also removed unnecessary dummy
google-services.json from lint job since Firebase is not used.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix build error: remove API 34+ foregroundServiceType

The 'specialUse' foregroundServiceType and FOREGROUND_SERVICE_SPECIAL_USE
permission were added in Android 14 (API 34), but the app targets API 33.
VPN services don't need a specific foregroundServiceType since VpnService
has special handling built-in.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Make gradlew executable

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix JUnit exclusion to not affect test configurations

The previous configuration excluded JUnit from all configurations which
broke unit tests. Now JUnit is only excluded from implementation scope
to prevent json-simple's transitive JUnit dependency from being included
in the APK, while still allowing testImplementation to use JUnit.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Remove Firebase/AdMob dependencies and fix R.id switch statements

- Remove Firebase Analytics from ProxyDroidApplication
- Remove AdMob (AdView, AdSize, AdRequest) from ProxyDroid
- Convert switch statement with R.id.* to if-else in BypassListActivity
  (R.id fields are not constant expressions with Android Gradle Plugin)
- Remove unused getLayout method, ViewParent and LinearLayout imports

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Remove remaining Firebase Analytics references

Remove firebaseAnalytics calls from:
- AppManager.java
- FileChooser.java
- ProxyDroidService.java (onDestroy and onStart)

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix configurations syntax in build.gradle

Use configurations.implementation instead of configurations { implementation { } }
to properly exclude JUnit from implementation configuration.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix JUnit exclusion: exclude only from json-simple dependency

The previous configuration excluded JUnit from all implementation
configurations which was also blocking it from test configurations.
Now JUnit is only excluded from the json-simple dependency which
incorrectly pulls it in as a compile dependency.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix shell quoting in emulator test script

Use heredoc (cat << 'PREFS_EOF') instead of variable assignment
to avoid shell parsing issues with XML special characters.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix emulator test: create prefs.xml in separate step

The android-emulator-runner action executes script lines individually,
so heredocs don't work within the script block. Move the prefs.xml
creation to a separate step that runs before the emulator.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Add Python cache to .gitignore

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Move emulator test script to separate file

Extract inline emulator test script from workflow YAML into
scripts/run_emulator_tests.sh for easier maintenance and testing.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Enable emulator snapshots in CI

Remove -no-snapshot-save flag to allow emulator snapshots,
which can speed up boot times on subsequent runs.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix emulator test script execution

Use 'bash scripts/run_emulator_tests.sh' instead of './scripts/...'
to ensure the script is found and executed correctly.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

* Fix line endings in emulator test script

Convert CRLF to LF line endings to fix bash syntax error.

https://claude.ai/code/session_01XDv7Fhpou2mSbpsV56cWxL

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants