diff --git a/README.md b/README.md index adcf90b9..89f2d1d2 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 26) `Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V,unsupported` * (prior to API 26) `Landroid/net/wifi/WifiManager;->setWifiApEnabled(Landroid/net/wifi/WifiConfiguration;Z)Z` * `Landroid/net/wifi/p2p/WifiP2pConfig$Builder;->MAC_ANY_ADDRESS:Landroid/net/MacAddress;,blocked` +* (since API 29) `Landroid/net/wifi/p2p/WifiP2pConfig$Builder;->mNetworkName:Ljava/lang/String;,blocked` * `Landroid/net/wifi/p2p/WifiP2pManager;->startWps(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/WpsInfo;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V,max-target-r` * (since API 28, prior to API 30) `Landroid/provider/Settings$Global;->SOFT_AP_TIMEOUT_ENABLED:Ljava/lang/String;,lo-prio,max-target-o` * (prior to API 30) `Lcom/android/internal/R$array;->config_tether_bluetooth_regexs:I,max-target-q` @@ -300,10 +301,7 @@ Nonexported system resources: * (since API 30) `@com.android.networkstack.tethering:array/config_tether_wigig_regexs` * (since API 30) `@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownTimeoutMilliseconds` -Other: - -* (since API 29) `android.net.wifi.p2p.WifiP2pConfig` needs to be parcelized in a very specific order, except for possible extra fields at the end. (used only for safe mode) -* Activity `com.android.settings/.Settings$TetherSettingsActivity` is assumed to be exported. +Other: Activity `com.android.settings/.Settings$TetherSettingsActivity` is assumed to be exported. For `ip rule` priorities, `RULE_PRIORITY_SECURE_VPN` and `RULE_PRIORITY_TETHERING` is assumed to be 12000 and 18000 respectively; (prior to API 24) `RULE_PRIORITY_DEFAULT_NETWORK` is assumed to be 22000 (or at least > 18000). diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index 21fed36f..56b20c56 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -13,7 +13,6 @@ import android.os.Looper import android.provider.Settings import androidx.annotation.StringRes import androidx.core.content.edit -import be.mygod.librootkotlinx.useParcel import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.net.MacAddressCompat import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor @@ -48,10 +47,6 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene private const val KEY_AUTO_SHUTDOWN = "service.repeater.autoShutdown" private const val KEY_SHUTDOWN_TIMEOUT = "service.repeater.shutdownTimeout" private const val KEY_DEVICE_ADDRESS = "service.repeater.mac" - /** - * Placeholder for bypassing networkName check. - */ - private const val PLACEHOLDER_NETWORK_NAME = "DIRECT-00-VPNHotspot" var persistentSupported = false @@ -65,6 +60,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene val safeModeConfigurable get() = Build.VERSION.SDK_INT >= 29 && hasP2pValidateName val safeMode get() = Build.VERSION.SDK_INT >= 29 && (!hasP2pValidateName || app.pref.getBoolean(KEY_SAFE_MODE, true)) + private val mNetworkName by lazy { UnblockCentral.WifiP2pConfig_Builder_mNetworkName } var networkName: String? get() = app.pref.getString(KEY_NETWORK_NAME, null) @@ -372,7 +368,12 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene p2pManager.createGroup(channel, listener) } else @TargetApi(29) { p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply { - setNetworkName(PLACEHOLDER_NETWORK_NAME) + try { + mNetworkName.set(this, networkName) // bypass networkName check + } catch (e: ReflectiveOperationException) { + Timber.w(e) + setNetworkName(networkName) + } setPassphrase(passphrase) when (val oc = operatingChannel) { 0 -> setGroupOperatingBand(when (val band = operatingBand) { @@ -386,37 +387,9 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene } } setDeviceAddress(deviceAddress?.toPlatform()) - }.build().run { - useParcel { p -> - p.writeParcelable(this, 0) - val end = p.dataPosition() - p.setDataPosition(0) - val creator = p.readString() - val deviceAddress = p.readString() - val wps = p.readParcelable(javaClass.classLoader) - val long = p.readLong() - check(p.readString() == PLACEHOLDER_NETWORK_NAME) - check(p.readString() == passphrase) - val extrasLength = end - p.dataPosition() - check(extrasLength and 3 == 0) // parcel should be padded - if (extrasLength != 4) app.logEvent("p2p_config_extras_unexpected_length") { - param("length", extrasLength.toLong()) - } - val extras = (0 until extrasLength / 4).map { p.readInt() } - p.setDataPosition(0) - p.writeString(creator) - p.writeString(deviceAddress) - p.writeParcelable(wps, 0) - p.writeLong(long) - p.writeString(networkName) - p.writeString(passphrase) - extras.forEach(p::writeInt) - p.setDataPosition(0) - p.readParcelable(javaClass.classLoader) - } - }, listener) + }.build(), listener) } - } catch (e: SecurityException) { + } catch (e: RuntimeException) { Timber.w(e) startFailure(e.readableMessage) } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt index a61d802d..2813221b 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt @@ -1,13 +1,16 @@ package be.mygod.vpnhotspot.util import android.annotation.SuppressLint +import android.net.wifi.p2p.WifiP2pConfig import androidx.annotation.RequiresApi import timber.log.Timber /** * The central object for accessing all the useful blocked APIs. Thanks Google! + * + * Lazy cannot be used directly as it will create inner classes. */ -@SuppressLint("DiscouragedPrivateApi") +@SuppressLint("BlockedPrivateApi", "DiscouragedPrivateApi") @Suppress("FunctionName") object UnblockCentral { /** @@ -27,4 +30,9 @@ object UnblockCentral { @RequiresApi(31) fun getApInstanceIdentifier(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("getApInstanceIdentifier") } + + @get:RequiresApi(29) + val WifiP2pConfig_Builder_mNetworkName get() = init.let { + WifiP2pConfig.Builder::class.java.getDeclaredField("mNetworkName").apply { isAccessible = true } + } }