diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bb289c7..d750e5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,9 @@ + = Build.VERSION_CODES.TIRAMISU) { + excludeLocalRoutes(builder); + } + disallowApp(builder, "com.google.android.projection.gearhead"); disallowApp(builder, "com.google.android.apps.chromecast.app"); disallowApp(builder, "com.google.android.apps.messaging"); @@ -95,6 +109,56 @@ private int createTun(String ip, int prefixLength, int mtu, String dns, String[] } } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + private void excludeLocalRoutes(VpnService.Builder builder) { + Log.i(LOGTAG, "excludeLocalRoutes: checking local routes for exclusion (API 33+)"); + + ConnectivityManager cm = vpnService.getSystemService(ConnectivityManager.class); + if (cm == null) { + Log.w(LOGTAG, "excludeLocalRoutes: ConnectivityManager is null, skipping"); + return; + } + + Network activeNetwork = cm.getActiveNetwork(); + if (activeNetwork == null) { + Log.w(LOGTAG, "excludeLocalRoutes: no active network found, skipping"); + return; + } + + LinkProperties lp = cm.getLinkProperties(activeNetwork); + if (lp == null) { + Log.w(LOGTAG, "excludeLocalRoutes: no link properties for active network, skipping"); + return; + } + + Log.i(LOGTAG, "excludeLocalRoutes: active network interface=" + lp.getInterfaceName() + " routes=" + lp.getRoutes().size()); + + List excluded = new ArrayList<>(); + for (RouteInfo routeInfo : lp.getRoutes()) { + IpPrefix dest = routeInfo.getDestination(); + if (dest.getPrefixLength() == 0) { + Log.d(LOGTAG, "excludeLocalRoutes: skipping default route " + dest); + continue; + } + + try { + builder.excludeRoute(dest); + excluded.add(dest.toString()); + Log.i(LOGTAG, "excludeLocalRoutes: excluded " + dest + " (iface=" + routeInfo.getInterface() + ")"); + } catch (Exception e) { + Log.e(LOGTAG, "excludeLocalRoutes: failed to exclude " + dest + ": " + e.getMessage()); + } + } + + Log.i(LOGTAG, "excludeLocalRoutes: total excluded=" + excluded.size() + " routes=" + excluded); + if (!excluded.isEmpty()) { + String msg = "Excluding " + excluded.size() + " local routes: " + String.join(", ", excluded); + new Handler(Looper.getMainLooper()).post(() -> + Toast.makeText(vpnService, msg, Toast.LENGTH_LONG).show() + ); + } + } + private void prepareDnsSetting(VpnService.Builder builder, String dns) { if(dns == null) { return;