README.md
Connecting things to your VPN made simple. Share your VPN connection over hotspot or repeater. (root required)
This app is useful for:
P.S. You can also do the similar on Windows, Mac, and iOS.
The following features in the app requires it to be installed under /system/priv-app since some restricted permissions are required.
One way to do this is to use App systemizer for Magisk.
android.permission.OVERRIDE_WIFI_CONFIG: Read/write system Wi-Fi hotspot configuration. (#117)Installing as system app also has the side benefit of launching root daemon less frequently due to having privileged permissions listed below.
android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKSandroid.permission.LOCAL_MAC_ADDRESSandroid.permission.MANAGE_USBandroid.permission.OVERRIDE_WIFI_CONFIGandroid.permission.READ_WIFI_CREDENTIALandroid.permission.TETHER_PRIVILEGEDandroid.permission.WRITE_SECURE_SETTINGSWhenever you install an app update, if there was a new protected permission addition (last updated in v2.17.1), you should update the app installed in system as well to make the system grant the privileged permission.
Search the issue tracker for more.
/data/misc/wifi/p2p_supplicant.conf or /data/vendor/wifi/wpa/p2p_supplicant.conf.
If things stopped working after you use this feature, simply delete this file and everything should start working again.tether_offload_disabled setting will persist.
Toggle it back in this app or the matching Developer options setting to revert it.Routing, firewall, addresses, and daemon/service state managed by this app are cleaned up when stopped, by Clean, or upon reboot.
This could caused by the Wi-Fi channel you selected is no longer available, due to:
For maximum stability, you need to set channel = 0 so that your device will pick a channel automatically. You can also use WPS to connect your 2.4GHz-only device to force the repeater to switch from 5GHz to 2.4GHz for this time.
a.k.a. things that can go wrong if this app doesn't work.
This is a list of stuff that might impact this app's functionality if unavailable.
This is only meant to be an index.
You can read more in the source code.
API restrictions are updated up to SHA-256 checksum 9102af02fe6ab68b92464bdff5e5b09f3bd62c65d1130aaf85d3296f17d38074.
Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded or implicitly used)
Landroid/net/ConnectivityManager;->getLastTetherError(Ljava/lang/String;)I,max-target-rLandroid/net/ConnectivityManager;->EXTRA_ACTIVE_LOCAL_ONLY:Ljava/lang/String;,lo-prio,max-target-oLandroid/net/ConnectivityManager;->EXTRA_ACTIVE_TETHER:Ljava/lang/String;,max-target-rLandroid/net/ConnectivityManager;->EXTRA_AVAILABLE_TETHER:Ljava/lang/String;,max-target-rLandroid/net/ConnectivityManager;->ACTION_TETHER_STATE_CHANGED:Ljava/lang/String;,max-target-rLandroid/net/ConnectivityManager;->EXTRA_ERRORED_TETHER:Ljava/lang/String;,max-target-rLandroid/net/ConnectivityModuleConnector;->IN_PROCESS_SUFFIX:Ljava/lang/String;Landroid/net/INetd$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetd;Landroid/net/INetd;->ipSecUpdateSecurityPolicy(IIILjava/lang/String;Ljava/lang/String;IIII)VLandroid/net/IIntResultListener$Stub;-><init>()V,blockedLandroid/net/IIntResultListener;->onResult(I)V,blockedLandroid/net/ITetheringConnector;->stopTethering(ILjava/lang/String;Landroid/net/IIntResultListener;)V,blockedLandroid/net/ITetheringConnector;->stopTethering(ILjava/lang/String;Ljava/lang/String;Landroid/net/IIntResultListener;)V,blockedLandroid/net/TetheringManager$ConnectorConsumer;->onConnectorAvailable(Landroid/net/ITetheringConnector;)V,blockedLandroid/net/TetheringManager$TetheringEventCallback;->onTetherableInterfaceRegexpsChanged(Landroid/net/TetheringManager$TetheringInterfaceRegexps;)V,blockedLandroid/net/TetheringManager$TetheringEventCallback;->onSupportedTetheringTypes(Ljava/util/Set;)V,blockedLandroid/net/TetheringManager;->getConnector(Landroid/net/TetheringManager$ConnectorConsumer;)V,blockedLandroid/net/TetheringManager;->TETHER_ERROR_*:I,blockedLandroid/net/TetheringManager;->TETHERING_VIRTUAL:I,blockedLandroid/net/IpSecManager;->DIRECTION_FWD:I,blockedLandroid/net/IpSecManager;->INVALID_SECURITY_PARAMETER_INDEX:I,blockedLandroid/net/wifi/SoftApCapability;->getCountryCode()Ljava/lang/String;,blockedLandroid/net/wifi/SoftApConfiguration$Builder;->setRandomizedMacAddress(Landroid/net/MacAddress;)Landroid/net/wifi/SoftApConfiguration$Builder;,blockedLandroid/net/wifi/SoftApConfiguration;->BAND_TYPES:[I,blockedLandroid/net/wifi/SoftApInfo;->getApInstanceIdentifier()Ljava/lang/String;,blockedLandroid/net/wifi/WifiClient;->getApInstanceIdentifier()Ljava/lang/String;,blockedLandroid/net/wifi/WifiConfiguration$KeyMgmt;->FT_PSK:I,lo-prio,max-target-oLandroid/net/wifi/WifiConfiguration$KeyMgmt;->WPA_PSK_SHA256:I,blockedLandroid/net/wifi/WifiConfiguration;->AP_BAND_2GHZ:I,lo-prio,max-target-oLandroid/net/wifi/WifiConfiguration;->AP_BAND_5GHZ:I,lo-prio,max-target-oLandroid/net/wifi/WifiConfiguration;->AP_BAND_ANY:I,lo-prio,max-target-oLandroid/net/wifi/WifiConfiguration;->apBand:I,unsupportedLandroid/net/wifi/WifiConfiguration;->apChannel:I,unsupportedLandroid/net/wifi/WifiContext;->ACTION_RESOURCES_APK:Ljava/lang/String;,blockedLandroid/net/wifi/WifiManager$SoftApCallback;->onNumClientsChanged(I)V,greylist-max-oLandroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V,unsupportedLandroid/net/wifi/p2p/WifiP2pConfig$Builder;->MAC_ANY_ADDRESS:Landroid/net/MacAddress;,blockedLandroid/net/wifi/p2p/WifiP2pConfig$Builder;->mNetworkName:Ljava/lang/String;,blockedLandroid/net/wifi/p2p/WifiP2pGroup;->interfaceAddress:[B,unsupportedLandroid/net/wifi/p2p/WifiP2pManager;->startWps(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/WpsInfo;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V,unsupportedLandroid/provider/Settings$Global;->SOFT_AP_TIMEOUT_ENABLED:Ljava/lang/String;,lo-prio,max-target-oLandroid/service/quicksettings/TileService;->mToken:Landroid/os/IBinder;,lo-prio,max-target-oLcom/android/internal/R$array;->config_tether_bluetooth_regexs:I,max-target-qLcom/android/internal/R$array;->config_tether_usb_regexs:I,max-target-qLcom/android/internal/R$array;->config_tether_wifi_regexs:I,max-target-qLcom/android/internal/R$bool;->config_wifi_p2p_mac_randomization_supported:I,blacklistLcom/android/internal/R$integer;->config_wifi_framework_soft_ap_timeout_delay:I,greylist-max-oLcom/android/internal/R$string;->config_ethernet_iface_regex:I,lo-prio,max-target-oLcom/android/server/wifi/p2p/WifiP2pServiceImpl;->ANONYMIZED_DEVICE_ADDRESS:Ljava/lang/String;Lcom/android/server/SystemServer;->TETHERING_CONNECTOR_CLASS:Ljava/lang/String;Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;,unsupportedLdalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;,unsupportedLjava/lang/invoke/MethodHandles$Lookup;-><init>(Ljava/lang/Class;I)V,unsupportedLjava/lang/invoke/MethodHandles$Lookup;->ALL_MODES:I,lo-prio,max-target-oSee mobile/src/hiddenApiStubs for hidden whitelisted/system APIs as well as partial SDK-class stubs.
Nonexported system resources:
@com.android.networkstack.tethering:array/config_tether_bluetooth_regexs@com.android.networkstack.tethering:array/config_tether_ncm_regexs@com.android.networkstack.tethering:array/config_tether_usb_regexs@com.android.networkstack.tethering:array/config_tether_wifi_p2p_regexs@com.android.networkstack.tethering:array/config_tether_wifi_regexs@com.android.networkstack.tethering:array/config_tether_wigig_regexs@com.android.wifi.resources:bool/config_wifi_p2p_mac_randomization_supported@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownTimeoutMillisecondsOther:
com.android.settings/.Settings$TetherSettingsActivity is assumed to be exported.IPv6 NAT mode depends on the iptables TPROXY and NFQUEUE targets and
transparent sockets. ICMPv6 Echo interception uses app-owned queue 30000
and assumes queued downstream packets expose six-byte source hardware-address
metadata through NFQA_HWADDR.android.net.ITetheringConnector,
may be jarjar-relocated under the optional prefixes
android.net.connectivity or com.android.connectivity.android.net.INetd*,
may be jarjar-relocated under the optional prefixes
android.net.connectivity or com.android.connectivity.TetheringEventCallback.onLocalOnlyInterfacesChanged is present, AOSP dispatches
startup tether-state callbacks from one executor.execute { ... } block in onCallbackStarted,
and later tether-state updates from one executor.execute { ... } block in
onTetherStatesChanged.android_res_nsend/android_res_nresult.
To keep daemon tasks nonblocking while still using android_res_nresult as the public result
reader/closer, it waits for dnsproxyd to close the one-shot resnsend client socket before
reading the result. This assumes resnsend writes the complete resolver result before returning
and the socket receive buffer can hold that result until the framework socket listener closes the
client socket.ip rule priorities, AOSP local-network/tethering priorities are assumed to be 17000/18000
on API 29..30 and 20000/21000 on API 31+. VPNHotspot uses the 17500..17900 or 20500..20900
gap between them.IPv6 NAT
TPROXY uses table 900 to stay below that range and away from AOSP fixed tables 97..99 and kernel built-ins.IPv6 NAT also adds its
deterministic ULA /64 route to Android's shared local_network table; Clean never flushes that table
and only deletes VPNHotspot prefixes reconstructed from current interface names.IPv6 NAT fwmark fallback for TPROXY uses masked high reserved bits 0x10000000/0x10000000.
That fallback is expected on only kernels without effective FRA_IP_PROTO policy-rule support, which upstream Linux added in 4.17.0x00030063, which assumes
LOCAL_NET_ID = 99 plus the explicitlySelected and protectedFromVpn fwmark bits.System/root command assumptions:
The following Android system binaries are assumed to be bundled and executable:
/system/bin/dumpsys (ipsec);/system/bin/iptables-restore, /system/bin/ip6tables-restore (-w --noflush, restore input
commands including -I, -D, -N, -nvx -L <chain>);/system/bin/ndc (ipfwd, nat);/system/bin/settings (put global);/system/bin/linker, /system/bin/linker64 (path.zip!/program).Wi-Fi driver wpa_supplicant:
/data/vendor/wifi/wpa/p2p_supplicant.conf or /data/misc/wifi/p2p_supplicant.conf and have reasonable format;wpa_supplicant after it terminates.