diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 9033f0785..cf32e1800 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( netguard src/main/jni/netguard/netguard.c src/main/jni/netguard/session.c src/main/jni/netguard/ip.c + src/main/jni/netguard/route.c src/main/jni/netguard/tls.c src/main/jni/netguard/tcp.c src/main/jni/netguard/udp.c diff --git a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java index e2b3fbc2f..b680e6c39 100644 --- a/app/src/main/java/eu/faircode/netguard/ActivitySettings.java +++ b/app/src/main/java/eu/faircode/netguard/ActivitySettings.java @@ -896,6 +896,12 @@ else if ("socks5_addr".equals(name)) { } else if ("wg_keepalive_when_screen_off".equals(name)) { ServiceSinkhole.reload("changed " + name, this, false); + } else if (Rule.PREF_WG_ROUTE_MODE.equals(name)) { + // The reload restarts the tunnel thread, which is what picks up the + // matching fwd53 change — that flag is only read at jni_run. + Rule.clearCache(this); + ServiceSinkhole.reload("changed " + name, this, false); + } else if ("wg_config".equals(name)) { String wg_config = prefs.getString(name, null); boolean valid = true; @@ -1257,6 +1263,10 @@ private void xmlExport(OutputStream _out) throws IOException { xmlExport(getSharedPreferences("tracker_protect", Context.MODE_PRIVATE), serializer); serializer.endTag(null, "tracker_protect"); + serializer.startTag(null, Rule.PREF_WG_ROUTE); + xmlExport(getSharedPreferences(Rule.PREF_WG_ROUTE, Context.MODE_PRIVATE), serializer); + serializer.endTag(null, Rule.PREF_WG_ROUTE); + serializer.startTag(null, "notify"); xmlExport(getSharedPreferences("notify", Context.MODE_PRIVATE), serializer); serializer.endTag(null, "notify"); @@ -1435,6 +1445,7 @@ private void xmlImport(InputStream in) throws IOException, SAXException, ParserC xmlImport(handler.application, prefs); xmlImport(handler.apply, getSharedPreferences("apply", Context.MODE_PRIVATE)); xmlImport(handler.tracker_protect, getSharedPreferences("tracker_protect", Context.MODE_PRIVATE)); + xmlImport(handler.wg_route, getSharedPreferences(Rule.PREF_WG_ROUTE, Context.MODE_PRIVATE)); xmlImport(handler.notify, getSharedPreferences("notify", Context.MODE_PRIVATE)); xmlImport(handler.blocklist, getSharedPreferences(PREF_BLOCKLIST, Context.MODE_PRIVATE)); @@ -1489,6 +1500,7 @@ private class XmlImportHandler extends DefaultHandler { public Map roaming = new HashMap<>(); public Map apply = new HashMap<>(); public Map tracker_protect = new HashMap<>(); + public Map wg_route = new HashMap<>(); public Map notify = new HashMap<>(); public Map blocklist = new HashMap<>(); private Map current = null; @@ -1528,6 +1540,8 @@ else if (qName.equals("apply")) else if (qName.equals("tracker_protect")) current = tracker_protect; + else if (qName.equals(Rule.PREF_WG_ROUTE)) + current = wg_route; else if (qName.equals("notify")) current = notify; diff --git a/app/src/main/java/eu/faircode/netguard/Rule.java b/app/src/main/java/eu/faircode/netguard/Rule.java index 91adf4bf0..a157b09a0 100644 --- a/app/src/main/java/eu/faircode/netguard/Rule.java +++ b/app/src/main/java/eu/faircode/netguard/Rule.java @@ -42,6 +42,7 @@ import net.kollnig.missioncontrol.R; import net.kollnig.missioncontrol.data.Pair; import net.kollnig.missioncontrol.data.BlockingMode; +import net.kollnig.missioncontrol.data.RemoteRoutingLogic; import net.kollnig.missioncontrol.data.TrackerBlocklist; import net.kollnig.missioncontrol.data.TrackerList; @@ -59,6 +60,10 @@ public class Rule { private static final String TAG = "TrackerControl.Rule"; + /** Per-package remote-routing overrides, mirroring "apply"/"tracker_protect". */ + public static final String PREF_WG_ROUTE = "wg_route"; + /** Global remote-routing mode, in the default shared preferences. */ + public static final String PREF_WG_ROUTE_MODE = "wg_route_mode"; public int uid; public String packageName; @@ -84,6 +89,11 @@ public class Rule { public boolean apply = true; // If false, completely exclude from VPN (no DNS, no routing) public boolean tracker_protect = true; // If false, don't block trackers (but still route through VPN) + // Whether this app's traffic is forwarded through the remote VPN. Filtering + // and remote routing are independent choices (#723): an app can be fully + // monitored and blocked while still connecting from the device's own + // network. Resolved from the global mode plus an optional per-app override. + public boolean wg_route = true; public boolean notify = true; public boolean relateduids = false; @@ -301,7 +311,10 @@ public static List getRules(final boolean all, boolean self, Context conte SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences apply = context.getSharedPreferences("apply", Context.MODE_PRIVATE); SharedPreferences tracker_protect = context.getSharedPreferences("tracker_protect", Context.MODE_PRIVATE); + SharedPreferences wg_route = context.getSharedPreferences(PREF_WG_ROUTE, Context.MODE_PRIVATE); SharedPreferences notify = context.getSharedPreferences("notify", Context.MODE_PRIVATE); + String wgRouteMode = RemoteRoutingLogic.normalizeMode( + prefs.getString(PREF_WG_ROUTE_MODE, RemoteRoutingLogic.getDefaultMode())); // Get settings boolean manage_system = prefs.getBoolean("manage_system", false); @@ -417,6 +430,12 @@ public static List getRules(final boolean all, boolean self, Context conte rule.apply = apply.getBoolean(info.packageName, true); rule.tracker_protect = BlockingMode.isTrackerProtectionEnabled( context, tracker_protect, info.packageName); + rule.wg_route = RemoteRoutingLogic.routesThroughTunnel( + wgRouteMode, + wg_route.contains(info.packageName) + ? wg_route.getBoolean(info.packageName, true) + : null, + rule.apply); rule.notify = notify.getBoolean(info.packageName, true); // Related packages @@ -557,7 +576,11 @@ public static List getSearchStubs(Context context) { SharedPreferences apply = context.getSharedPreferences("apply", Context.MODE_PRIVATE); SharedPreferences tracker_protect = context.getSharedPreferences("tracker_protect", Context.MODE_PRIVATE); + SharedPreferences wg_route = context.getSharedPreferences(PREF_WG_ROUTE, Context.MODE_PRIVATE); SharedPreferences notify = context.getSharedPreferences("notify", Context.MODE_PRIVATE); + String wgRouteMode = RemoteRoutingLogic.normalizeMode( + PreferenceManager.getDefaultSharedPreferences(context) + .getString(PREF_WG_ROUTE_MODE, RemoteRoutingLogic.getDefaultMode())); DatabaseHelper dh = DatabaseHelper.getInstance(context); for (PackageInfo info : getPackages(context)) @@ -570,6 +593,12 @@ public static List getSearchStubs(Context context) { rule.apply = apply.getBoolean(info.packageName, true); rule.tracker_protect = BlockingMode.isTrackerProtectionEnabled( context, tracker_protect, info.packageName); + rule.wg_route = RemoteRoutingLogic.routesThroughTunnel( + wgRouteMode, + wg_route.contains(info.packageName) + ? wg_route.getBoolean(info.packageName, true) + : null, + rule.apply); rule.notify = notify.getBoolean(info.packageName, true); rule.updateChanged(); listStub.add(rule); diff --git a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java index d2d2b2789..4294ef960 100644 --- a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java +++ b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java @@ -87,6 +87,7 @@ import net.kollnig.missioncontrol.data.BlockingMode; import net.kollnig.missioncontrol.data.BlockingModeLogic; import net.kollnig.missioncontrol.data.InternetBlocklist; +import net.kollnig.missioncontrol.data.RemoteRoutingLogic; import net.kollnig.missioncontrol.data.Tracker; import net.kollnig.missioncontrol.data.TrackerBlocklist; import net.kollnig.missioncontrol.data.TrackerList; @@ -111,10 +112,12 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; @@ -186,6 +189,16 @@ public class ServiceSinkhole extends VpnService { private static final Map mapValidated = new ConcurrentHashMap<>(); private Map mapUidAllowed = new HashMap<>(); private Map mapUidKnown = new HashMap<>(); + // UIDs whose routing differs from the global default. Pushed down to the + // packet path as a sorted array; unlisted UIDs follow the global default. + private Set mapUidRouteOverride = new HashSet<>(); + private boolean defaultTunnel = true; + // Resolver used by apps routed around the remote tunnel. Null when the + // system offers none, in which case their DNS stays in the tunnel. + private String directDnsTarget = null; + // Whether any app is routed around the tunnel, which is what makes the + // extra per-query DNS cost worth paying. + private boolean anyDirectRouting = false; private final Map> mapUidIPFilters = new HashMap<>(); private Map mapForward = new HashMap<>(); public static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); @@ -297,6 +310,16 @@ public enum Command { * dropped instead of forwarded directly, so restarts never leak. */ private native void jni_wireguard_required(boolean required); + /** + * Pushes the set of UIDs whose routing differs from the global default down + * to the packet path, plus that default (applied to every UID not in the + * set — unknown UIDs and system traffic included) and whether direct apps' + * DNS is redirected to the system resolver rather than always taking the + * tunnel. Java writes this while the tunnel thread reads it, so the native + * side guards it with its own lock. + */ + private native void jni_wireguard_route(int[] overrideUids, boolean defaultTunnel, boolean dnsDirect); + private native void jni_done(long context); public static void setPcap(boolean enabled, Context context) { @@ -1851,6 +1874,17 @@ private boolean startNative(final ParcelFileDescriptor vpn, List listAllow int prio = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.WARN))); final int rcode = Integer.parseInt(prefs.getString("rcode", "3")); + // Port 53 is the only UDP traffic that skips the UID lookup entirely + // today, so turning fwd53 on costs a lookup, a JNI upcall and a real + // UDP session per query. Only pay that when some app is routed around + // the tunnel and a non-null underlying resolver target is available — + // which are both properties of the resolved rules, not of the mode: a + // per-app override sends an app direct in either mode, and gating on + // the mode alone left such an app tunnelling its DNS while its traffic + // went direct, exactly the split the redirect exists to avoid. + final boolean fwd53 = mapForward.containsKey(53) + || RemoteRoutingLogic.redirectDirectDns(anyDirectRouting, + directDnsTarget != null); if (prefs.getBoolean("socks5_enabled", false)) jni_socks5( prefs.getString("socks5_addr", ""), @@ -1861,6 +1895,7 @@ private boolean startNative(final ParcelFileDescriptor vpn, List listAllow jni_socks5("", 0, "", ""); jni_sni(prefs.getBoolean("sni_enabled", false)); + pushRoutingToNative(); updateUnderlyingNetworks(); // WireGuard egress. startOrUpdate is idempotent: same config + @@ -1898,7 +1933,7 @@ private boolean startNative(final ParcelFileDescriptor vpn, List listAllow @Override public void run() { Log.i(TAG, "Running tunnel context=" + jni_context); - jni_run(jni_context, vpn.getFd(), mapForward.containsKey(53), rcode); + jni_run(jni_context, vpn.getFd(), fwd53, rcode); Log.i(TAG, "Tunnel exited"); tunnelThread = null; } @@ -1982,9 +2017,100 @@ private void prepareUidAllowed(List listAllowed, List listRule) { for (Rule rule : listRule) mapUidKnown.put(rule.uid, rule.uid); + defaultTunnel = RemoteRoutingLogic.defaultTunnel( + RemoteRoutingLogic.normalizeMode( + PreferenceManager.getDefaultSharedPreferences(this) + .getString(Rule.PREF_WG_ROUTE_MODE, + RemoteRoutingLogic.getDefaultMode()))); + mapUidRouteOverride = mapUidRouteOverride(listRule, defaultTunnel); + anyDirectRouting = anyDirectRouting(listRule); + // Util.getDefaultDNS does binder calls, so resolve it once per reload + // rather than on the DNS path. + directDnsTarget = resolveDirectDnsTarget(); + lock.writeLock().unlock(); } + /** + * The UIDs whose routing differs from the global default. + *

+ * A shared UID is tunnelled if any of its packages is: the packet path only + * ever sees the UID, so the finer per-package answer cannot be honoured and + * the more private of the two is the right way to round. + *

+ * Bypassed apps are skipped rather than counted as direct. They are handed + * to {@code addDisallowedApplication}, so no packet of theirs ever reaches + * the tun — listing them would put an entry in the override set for every + * bypassed app and defeat the empty-set fast path for no benefit. + */ + private static Set mapUidRouteOverride(List listRule, boolean defaultTunnel) { + Map tunnelByUid = new HashMap<>(); + for (Rule rule : listRule) { + if (!rule.apply) + continue; + Boolean current = tunnelByUid.get(rule.uid); + tunnelByUid.put(rule.uid, (current != null && current) || rule.wg_route); + } + + Set overrides = new HashSet<>(); + for (Map.Entry entry : tunnelByUid.entrySet()) + if (RemoteRoutingLogic.isRouteOverride(entry.getValue(), defaultTunnel)) + overrides.add(entry.getKey()); + return overrides; + } + + /** + * The system resolver for apps routed around the remote tunnel. + *

+ * With the tunnel up, the tun advertises the tunnel's own resolvers, which + * a direct app may not be able to reach at all. Redirecting its queries to + * the underlying network's resolver is what makes direct routing work when + * the tunnel drops — at the cost, stated in the UI, of that app's DNS being + * visible to its local network rather than to the VPN provider. + */ + private String resolveDirectDnsTarget() { + List sysDns = Util.getDefaultDNS(ServiceSinkhole.this); + for (String dns : sysDns) + if (!TextUtils.isEmpty(dns)) + return dns; + + Log.w(TAG, "No system DNS for direct apps; keeping their DNS in the tunnel"); + return null; + } + + private static boolean anyDirectRouting(List listRule) { + for (Rule rule : listRule) + if (rule.apply && !rule.wg_route) + return true; + return false; + } + + /** + * Whether this UID is routed around the remote tunnel. Mirrors the native + * is_tunnel_uid: a UID absent from the override set follows the global + * default rather than counting as "not tunnelled", which a bare + * mapUidRouteOverride lookup would wrongly report. + */ + private boolean routesDirect(int uid) { + return RemoteRoutingLogic.routesDirect( + mapUidRouteOverride.contains(uid), defaultTunnel); + } + + /** Hands the current routing decision to the packet path. */ + private void pushRoutingToNative() { + lock.readLock().lock(); + int[] uids = new int[mapUidRouteOverride.size()]; + int i = 0; + for (Integer uid : mapUidRouteOverride) + uids[i++] = uid; + boolean defaults = defaultTunnel; + boolean dnsDirect = RemoteRoutingLogic.redirectDirectDns(anyDirectRouting, + directDnsTarget != null); + lock.readLock().unlock(); + + jni_wireguard_route(uids, defaults, dnsDirect); + } + public static void prepareHostsBlocked(Context c) { BufferedReader br = null; InputStreamReader is = null; @@ -2393,6 +2519,13 @@ private Allowed isAddressAllowed(Packet packet) { allowed = new Allowed(fwd.raddr, fwd.rport); packet.data = "> " + fwd.raddr + "/" + fwd.rport; } + } else if (packet.dport == 53 && directDnsTarget != null + && routesDirect(packet.uid)) { + // An app routed around the remote tunnel resolves against the + // underlying network instead of the tunnel's resolver. The + // redirect is transparent: replies are rebuilt from the + // session's original addresses, so the app never sees it. + allowed = new Allowed(directDnsTarget, 53); } else allowed = new Allowed(); @@ -2919,6 +3052,7 @@ private void handlePackageChanged(Context context, Intent intent) { context.getSharedPreferences("apply", Context.MODE_PRIVATE).edit().remove(packageName).apply(); BlockingMode.clearAutoExcludedApp(context, packageName); context.getSharedPreferences("tracker_protect", Context.MODE_PRIVATE).edit().remove(packageName).apply(); + context.getSharedPreferences(Rule.PREF_WG_ROUTE, Context.MODE_PRIVATE).edit().remove(packageName).apply(); context.getSharedPreferences("notify", Context.MODE_PRIVATE).edit().remove(packageName).apply(); int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); diff --git a/app/src/main/java/net/kollnig/missioncontrol/data/RemoteRoutingLogic.java b/app/src/main/java/net/kollnig/missioncontrol/data/RemoteRoutingLogic.java new file mode 100644 index 000000000..92f4e6c22 --- /dev/null +++ b/app/src/main/java/net/kollnig/missioncontrol/data/RemoteRoutingLogic.java @@ -0,0 +1,184 @@ +/* + * TrackerControl is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TrackerControl is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright © 2026 + */ + +package net.kollnig.missioncontrol.data; + +/** + * Decides which apps are forwarded through the remote WireGuard tunnel. + *

+ * Whether an app is filtered by TrackerControl and whether it is + * forwarded through the remote VPN are independent choices. Before + * this existed the only way to keep an app off the remote tunnel was to + * exclude it from the VPN altogether, which also dropped local monitoring and + * blocking (#723). + *

+ * Pure helpers mirroring the native routing decision, no Android dependencies, + * kept JVM-testable so the decision table is covered by unit tests. + */ +public final class RemoteRoutingLogic { + /** Every app goes through the remote tunnel. The shipped default. */ + public static final String MODE_ALL = "all"; + /** Only apps with an explicit per-app override go through the tunnel. */ + public static final String MODE_SELECTED = "selected"; + + private RemoteRoutingLogic() { + } + + public static String getDefaultMode() { + return MODE_ALL; + } + + public static String normalizeMode(String mode) { + return MODE_SELECTED.equals(mode) ? MODE_SELECTED : MODE_ALL; + } + + /** + * Whether unknown-UID and system traffic takes the tunnel. In + * {@link #MODE_ALL} this is true, which makes the whole feature a no-op + * against the behaviour that shipped before it. + */ + public static boolean defaultTunnel(String mode) { + return !MODE_SELECTED.equals(normalizeMode(mode)); + } + + /** + * Whether one app is routed through the remote tunnel. + * + * @param mode the global routing mode + * @param override the per-app override, or {@code null} when unset + * @param apply the app's "apply" preference; a bypassed app is outside + * the tun entirely, so it has no routing to decide + */ + public static boolean routesThroughTunnel(String mode, Boolean override, boolean apply) { + if (!apply) + return false; + + if (override != null) + return override; + + return defaultTunnel(mode); + } + + /** + * Whether the per-app routing control should be offered at all. + *

+ * Routes come from the tunnel's AllowedIPs, and they are a property of the + * one tun every app shares — narrowing them to route some apps around the + * tunnel would shrink them for the tunnelled apps too. v1 therefore only + * offers the control for a default-route tunnel. gotatun silently drops + * packets whose destination matches no peer's AllowedIPs, so a narrower + * tunnel would blackhole traffic rather than fail visibly. + * + * @param wgEnabled whether remote egress is configured and on + * @param defaultRoutes whether AllowedIPs covers 0.0.0.0/0 (and ::/0 when + * IPv6 is enabled) + * @param apply the app's "apply" preference + */ + public static boolean isControlAvailable(boolean wgEnabled, boolean defaultRoutes, boolean apply) { + return wgEnabled && defaultRoutes && apply; + } + + /** + * Why the control is unavailable, for the explanation shown in its place. + */ + public static Unavailable getUnavailableReason(boolean wgEnabled, boolean defaultRoutes, + boolean apply) { + if (!wgEnabled) + return Unavailable.NO_REMOTE_VPN; + if (!apply) + return Unavailable.BYPASSED; + if (!defaultRoutes) + return Unavailable.PARTIAL_ROUTES; + return null; + } + + /** + * Whether direct apps' DNS is redirected to the system resolver. + *

+ * Turning this on makes every DNS query cost a UID lookup, an + * isAddressAllowed upcall and a real UDP session — today port 53 skips all + * three. It is therefore only enabled once some app is routed around the + * tunnel and a non-null underlying resolver target is available, so + * everyone else keeps the existing zero-cost DNS path. Note this is a + * property of the resolved rules, not of the mode: a per-app override + * sends an app direct in either mode. + */ + public static boolean redirectDirectDns(boolean anyAppRoutedDirect, + boolean resolverTargetAvailable) { + return anyAppRoutedDirect && resolverTargetAvailable; + } + + /** + * Whether a UID whose routing differs from the global default should be + * pushed to the packet path. + *

+ * Only the exceptions are pushed, never the whole tunnelled set: with no + * per-app override the set is then empty, which is what lets the packet + * path skip the UID lookup entirely. Pushing every tunnelled UID instead + * made the default mode — where every applied app is tunnelled — look + * indistinguishable from a heavily-overridden one. + */ + public static boolean isRouteOverride(boolean tunnelled, boolean defaultTunnel) { + return tunnelled != defaultTunnel; + } + + /** + * Whether one UID's traffic leaves outside the tunnel, mirroring the native + * is_tunnel_uid. + *

+ * A UID absent from the override set follows the global default, whatever + * it is. That includes system traffic and UIDs belonging to no installed + * app, which is what makes the default mode identical to the behaviour + * before per-app routing existed. + * + * @param inOverrideSet whether the UID's routing differs from the default + * @param defaultTunnel the global default + */ + public static boolean routesDirect(boolean inOverrideSet, boolean defaultTunnel) { + return !(defaultTunnel != inOverrideSet); + } + + /** + * Whether the tunnel's AllowedIPs is a default route. + *

+ * Routes are a property of the single tun every app shares, so a narrower + * AllowedIPs shrinks them for directly-routed apps too. v1 therefore only + * offers per-app routing for a full-tunnel config. + * + * @param allowedIps the union of every peer's AllowedIPs + * @param ip6 whether IPv6 is enabled, in which case ::/0 is required too + */ + public static boolean hasDefaultRoutes(java.util.List allowedIps, boolean ip6) { + boolean v4 = false; + boolean v6 = false; + for (String allowedIp : allowedIps) { + String trimmed = allowedIp == null ? "" : allowedIp.trim(); + if ("0.0.0.0/0".equals(trimmed)) + v4 = true; + else if ("::/0".equals(trimmed)) + v6 = true; + } + + return v4 && (!ip6 || v6); + } + + public enum Unavailable { + /** No remote VPN is configured or enabled. */ + NO_REMOTE_VPN, + /** The app bypasses TrackerControl, so it is outside the tun. */ + BYPASSED, + /** The tunnel's AllowedIPs is not a default route. */ + PARTIAL_ROUTES + } +} diff --git a/app/src/main/java/net/kollnig/missioncontrol/details/TrackersListAdapter.java b/app/src/main/java/net/kollnig/missioncontrol/details/TrackersListAdapter.java index 52b4d6ff4..44c9ef101 100644 --- a/app/src/main/java/net/kollnig/missioncontrol/details/TrackersListAdapter.java +++ b/app/src/main/java/net/kollnig/missioncontrol/details/TrackersListAdapter.java @@ -25,6 +25,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; +import android.util.Log; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -43,6 +44,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; import androidx.work.Data; @@ -54,6 +56,7 @@ import net.kollnig.missioncontrol.analysis.TrackerAnalysisWorker; import net.kollnig.missioncontrol.data.AppProtectionState; import net.kollnig.missioncontrol.data.BlockingMode; +import net.kollnig.missioncontrol.data.RemoteRoutingLogic; import net.kollnig.missioncontrol.data.InternetBlocklist; import net.kollnig.missioncontrol.data.Tracker; import net.kollnig.missioncontrol.data.TrackerBlocklist; @@ -475,6 +478,88 @@ private void updateText(TextView tv, Tracker t) { applyState(selected, w); notifyDataSetChanged(); }); + + bindRemoteRouting(holder); + } + } + + /** + * The remote-routing control, which is deliberately independent of the + * protection state above: whether an app is filtered and whether it is + * forwarded through the remote VPN are separate choices (#723). + */ + private void bindRemoteRouting(VHHeader holder) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + boolean wgEnabled = prefs.getBoolean("wg_enabled", false) + && !TextUtils.isEmpty(prefs.getString("wg_config", "")); + boolean applyApp = apply.getBoolean(mAppId, true); + boolean defaultRoutes = wgEnabled && hasDefaultRoutes(prefs); + + RemoteRoutingLogic.Unavailable unavailable = + RemoteRoutingLogic.getUnavailableReason(wgEnabled, defaultRoutes, applyApp); + if (unavailable != null) { + holder.mAppRoute.setVisibility(View.GONE); + holder.mAppRouteUnavailable.setVisibility(View.VISIBLE); + holder.mAppRouteUnavailable.setText(explainUnavailable(unavailable)); + return; + } + + holder.mAppRouteUnavailable.setVisibility(View.GONE); + holder.mAppRoute.setVisibility(View.VISIBLE); + + String mode = RemoteRoutingLogic.normalizeMode( + prefs.getString(Rule.PREF_WG_ROUTE_MODE, RemoteRoutingLogic.getDefaultMode())); + boolean tunnelled = RemoteRoutingLogic.routesThroughTunnel(mode, getRouteOverride(), true); + + holder.mAppRoute.setOnCheckedChangeListener(null); + holder.mAppRoute.check(tunnelled ? R.id.rbRouteTunnel : R.id.rbRouteDirect); + holder.mAppRoute.setOnCheckedChangeListener((group, checkedId) -> { + boolean wantsTunnel = (checkedId == R.id.rbRouteTunnel); + if (wantsTunnel == RemoteRoutingLogic.routesThroughTunnel(mode, getRouteOverride(), true)) + return; + + mContext.getSharedPreferences(Rule.PREF_WG_ROUTE, Context.MODE_PRIVATE) + .edit().putBoolean(mAppId, wantsTunnel).apply(); + + AsyncTask.execute(() -> { + Rule.clearCache(mContext); + ServiceSinkhole.reload("app routing changed", mContext, false); + }); + }); + } + + @Nullable + private Boolean getRouteOverride() { + SharedPreferences wgRoute = mContext.getSharedPreferences(Rule.PREF_WG_ROUTE, + Context.MODE_PRIVATE); + return wgRoute.contains(mAppId) ? wgRoute.getBoolean(mAppId, true) : null; + } + + private boolean hasDefaultRoutes(SharedPreferences prefs) { + try { + net.kollnig.missioncontrol.wg.WgConfig config = + net.kollnig.missioncontrol.wg.WgConfigParser.INSTANCE + .parse(prefs.getString("wg_config", "")); + List allowedIps = new ArrayList<>(); + for (net.kollnig.missioncontrol.wg.WgPeer peer : config.getPeers()) + allowedIps.addAll(peer.getAllowedIPs()); + return RemoteRoutingLogic.hasDefaultRoutes(allowedIps, + prefs.getBoolean("ip6", true)); + } catch (Throwable ex) { + Log.w(TAG, "Cannot read AllowedIPs, hiding per-app routing: " + ex); + return false; + } + } + + private String explainUnavailable(RemoteRoutingLogic.Unavailable unavailable) { + switch (unavailable) { + case BYPASSED: + return mContext.getString(R.string.app_route_unavailable_bypassed); + case PARTIAL_ROUTES: + return mContext.getString(R.string.app_route_unavailable_partial_routes); + case NO_REMOTE_VPN: + default: + return mContext.getString(R.string.app_route_unavailable_no_vpn); } } @@ -615,6 +700,9 @@ static class VHHeader extends RecyclerView.ViewHolder { final TextView mLibraryDisclaimer; final RadioGroup mAppState; final TextView mNoInternetExplanation; + final View mAppRouteCard; + final RadioGroup mAppRoute; + final TextView mAppRouteUnavailable; VHHeader(View view) { super(view); @@ -622,6 +710,9 @@ static class VHHeader extends RecyclerView.ViewHolder { mLibraryDisclaimer = view.findViewById(R.id.tvLibraryDisclaimer); mAppState = view.findViewById(R.id.rgAppState); mNoInternetExplanation = view.findViewById(R.id.tvStateNoInternetDesc); + mAppRouteCard = view.findViewById(R.id.cardAppRoute); + mAppRoute = view.findViewById(R.id.rgAppRoute); + mAppRouteUnavailable = view.findViewById(R.id.tvAppRouteUnavailable); } } } diff --git a/app/src/main/jni/netguard/ip.c b/app/src/main/jni/netguard/ip.c index 3deb7336c..f361f991c 100644 --- a/app/src/main/jni/netguard/ip.c +++ b/app/src/main/jni/netguard/ip.c @@ -53,6 +53,76 @@ static int is_local_dest(int version, const void *daddr) { } } +// The UID of an established flow, for packets that arrive without one. +// +// Packet 2+ of a direct flow reaches the routing fork with uid == -1: the +// expensive lookup above is deliberately skipped for existing UDP sessions and +// non-SYN TCP. The uid cache usually answers, but it expires and is evicted, +// and defaulting on a miss would send the rest of an established, already-NATted +// flow into the tunnel mid-stream. The session table is the authoritative and +// free source, so consult it before giving up. +// +// This runs only behind a route_flow_lookup miss, so it is the second fallback +// rather than the per-packet cost it once was. The UDP arm repeats the 5-tuple +// match in udp.c's has_udp_session; keep the two in step. +static jint get_session_uid(const struct arguments *args, int version, int protocol, + const uint8_t *pkt, const uint8_t *payload) { + const struct iphdr *ip4 = (struct iphdr *) pkt; + const struct ip6_hdr *ip6 = (struct ip6_hdr *) pkt; + + for (struct ng_session *cur = args->ctx->ng_session; cur != NULL; cur = cur->next) { + if (cur->protocol != protocol) + continue; + + if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6) { + const struct icmp *icmp = (struct icmp *) payload; + if (cur->icmp.version == version && cur->icmp.id == icmp->icmp_id && + (version == 4 + ? cur->icmp.saddr.ip4 == ip4->saddr && cur->icmp.daddr.ip4 == ip4->daddr + : memcmp(&cur->icmp.saddr.ip6, &ip6->ip6_src, 16) == 0 && + memcmp(&cur->icmp.daddr.ip6, &ip6->ip6_dst, 16) == 0)) + return cur->icmp.uid; + continue; + } + + if (protocol == IPPROTO_UDP) { + const struct udphdr *udphdr = (struct udphdr *) payload; + if (cur->udp.version == version && + cur->udp.source == udphdr->source && cur->udp.dest == udphdr->dest && + (version == 4 + ? cur->udp.saddr.ip4 == ip4->saddr && cur->udp.daddr.ip4 == ip4->daddr + : memcmp(&cur->udp.saddr.ip6, &ip6->ip6_src, 16) == 0 && + memcmp(&cur->udp.daddr.ip6, &ip6->ip6_dst, 16) == 0)) + return cur->udp.uid; + } else if (protocol == IPPROTO_TCP) { + const struct tcphdr *tcphdr = (struct tcphdr *) payload; + if (cur->tcp.version == version && + cur->tcp.source == tcphdr->source && cur->tcp.dest == tcphdr->dest && + (version == 4 + ? cur->tcp.saddr.ip4 == ip4->saddr && cur->tcp.daddr.ip4 == ip4->daddr + : memcmp(&cur->tcp.saddr.ip6, &ip6->ip6_src, 16) == 0 && + memcmp(&cur->tcp.daddr.ip6, &ip6->ip6_dst, 16) == 0)) + return cur->tcp.uid; + } + } + + return -1; +} + +// Re-run the authoritative UID lookup only after both the flow cache and the +// native session table miss. This is deliberately off the hot path: established +// UDP/TCP packets normally hit the flow cache, while a miss can be caused by a +// cache expiry or hash collision. Keep the Android <=28 procfs path identical +// to the initial lookup and use ConnectivityManager on newer releases. +static jint get_route_uid(const struct arguments *args, int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, + const char *source, const char *dest) { + if (args->ctx->sdk <= 28) + return get_uid(version, protocol, saddr, sport, daddr, dport); + return get_uid_q(args, version, protocol, source, sport, dest, dport); +} + uint16_t get_mtu() { return 10000; } @@ -330,7 +400,13 @@ void handle_ip(const struct arguments *args, jint uid = -1; if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6 || (protocol == IPPROTO_UDP && !has_udp_session(args, pkt, payload)) || - (protocol == IPPROTO_TCP && syn && (dport != 443 || !is_play))) { + // SNI research mode lets a 443 SYN through without a UID so the + // ClientHello can be reassembled first. That is fine for the block + // decision, but the routing fork needs the UID now: with no UID and no + // session, the SYN falls to the global default and every later packet + // of that flow inherits the answer from it. + (protocol == IPPROTO_TCP && syn && + (dport != 443 || !is_play || route_uid_relevant()))) { if (args->ctx->sdk <= 28) // Android 9 Pie uid = get_uid(version, protocol, saddr, sport, daddr, dport); else @@ -484,7 +560,66 @@ void handle_ip(const struct arguments *args, int is_dns = (dport == 53 && (protocol == IPPROTO_UDP || protocol == IPPROTO_TCP)); int wg_is_required = atomic_load_explicit(&wg_required, memory_order_acquire); - int wg_dest = !is_local_dest(version, daddr) || is_dns; + + // Which app this packet belongs to — but only when that can change the + // answer. With no per-app override configured every UID routes the same + // way, and this is the per-packet path: resolving a UID there would + // cost a lock and, for the established flows that arrive with uid == -1 + // (existing UDP sessions, non-SYN TCP, i.e. most packets), a walk of the + // whole session table, which grows with load. That is pure waste for + // everyone who has not opted in. + int tunnel_uid; + if (route_uid_relevant()) { + // A flow keeps the verdict its first packet was given. A fresh UID + // is authoritative even when a previous flow happened to reuse the + // same 5-tuple, so do not consult the flow cache in that case. + jint route_uid = uid; + if (route_uid >= 0) { + tunnel_uid = is_tunnel_uid(route_uid); + route_flow_store(version, protocol, saddr, sport, daddr, dport, + tunnel_uid); + } else if (route_flow_lookup(version, protocol, saddr, sport, daddr, dport, + &tunnel_uid)) { + // Established tunnelled flows never create an ng_session — the + // WireGuard write below returns first — so the cache preserves + // their first-packet answer without a per-packet UID lookup. + } else { + // A cache expiry or collision is rare, but falling back to the + // selected-mode default would divert an already-established + // tunnelled flow direct and can make TCP reset. Recover the UID + // from the native session table first, then from the + // authoritative Android/procfs lookup. + route_uid = get_session_uid(args, version, protocol, pkt, payload); + if (route_uid < 0) + route_uid = get_route_uid(args, version, protocol, + saddr, sport, daddr, dport, + source, dest); + + if (route_uid >= 0) { + tunnel_uid = is_tunnel_uid(route_uid); + route_flow_store(version, protocol, saddr, sport, daddr, dport, + tunnel_uid); + } else { + // Unknown ownership is privacy-sensitive: keep the packet + // in the remote tunnel rather than fail-open to direct + // routing in selected mode. Cache that explicit fail-closed + // verdict so the rest of this flow does not repeat a Binder + // or procfs lookup on every packet. A later flow with the + // same tuple still wins because a freshly resolved UID is + // handled before the cache above. + tunnel_uid = 1; + route_flow_store(version, protocol, saddr, sport, daddr, dport, + tunnel_uid); + log_android(ANDROID_LOG_WARN, + "Route UID unavailable for v%d p%d %s/%u > %s/%u; tunnelling", + version, protocol, source, sport, dest, dport); + } + } + } else + tunnel_uid = route_default_is_tunnel(); + + int wg_dest = route_wants_tunnel(is_local_dest(version, daddr), is_dns, + tunnel_uid, route_dns_direct()); if (wg_dest) { ssize_t w; diff --git a/app/src/main/jni/netguard/netguard.c b/app/src/main/jni/netguard/netguard.c index 1f2c246b2..e0f2969d3 100644 --- a/app/src/main/jni/netguard/netguard.c +++ b/app/src/main/jni/netguard/netguard.c @@ -453,6 +453,34 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1wireguard_1required(JNIEnv *env, atomic_store_explicit(&wg_required, required ? 1 : 0, memory_order_release); } +JNIEXPORT void JNICALL +Java_eu_faircode_netguard_ServiceSinkhole_jni_1wireguard_1route(JNIEnv *env, jobject instance, + jintArray uids_, + jboolean default_tunnel, + jboolean dns_direct) { + jint count = 0; + jint *uids = NULL; + if (uids_ != NULL) { + count = (*env)->GetArrayLength(env, uids_); + if (count > 0) { + uids = (*env)->GetIntArrayElements(env, uids_, NULL); + if (uids == NULL) { + log_android(ANDROID_LOG_ERROR, "wg route uids unavailable, keeping previous"); + return; + } + } + } + + set_route_uids(uids, count, default_tunnel ? 1 : 0, dns_direct ? 1 : 0); + + if (uids != NULL) + (*env)->ReleaseIntArrayElements(env, uids_, uids, JNI_ABORT); + + log_android(ANDROID_LOG_WARN, + "WireGuard routing: default %s, %d uid overrides, direct DNS %s", + default_tunnel ? "tunnel" : "direct", count, dns_direct ? "on" : "off"); +} + JNIEXPORT void JNICALL Java_eu_faircode_netguard_ServiceSinkhole_jni_1wireguard_1stop(JNIEnv *env, jobject instance) { if (pthread_mutex_lock(&wg_outbound_lock)) { @@ -490,6 +518,8 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1done( uid_cache_size = 0; uid_cache = NULL; + clear_route_uids(); + ng_free(ctx, __FILE__, __LINE__); } diff --git a/app/src/main/jni/netguard/netguard.h b/app/src/main/jni/netguard/netguard.h index 7ec615db1..ae25a1c8f 100644 --- a/app/src/main/jni/netguard/netguard.h +++ b/app/src/main/jni/netguard/netguard.h @@ -116,6 +116,7 @@ struct allowed { int write_wireguard_packet(const void *packet, size_t length, ssize_t *written, int *write_errno); + struct segment { uint32_t seq; uint16_t len; @@ -536,6 +537,38 @@ void dns_resolved(const struct arguments *args, jboolean is_domain_blocked(const struct arguments *args, const char *name); +// Per-app remote routing (route.c). Java pushes down only the UIDs whose +// routing differs from the global default; the packet path only reads them. +void set_route_uids(const jint *uids, int count, int default_tunnel, int dns_direct); + +void clear_route_uids(); + +int is_tunnel_uid(jint uid); + +// Lock-free fast path: whether a UID lookup can change the answer at all, the +// answer everything gets when it cannot, and whether DNS follows that answer. +int route_uid_relevant(); + +int route_default_is_tunnel(); + +int route_dns_direct(); + +int route_wants_tunnel(int local_dest, int is_dns, int tunnel_uid, int dns_direct); + +// Per-flow verdict cache, so a flow that has already been routed keeps its +// answer once its packets stop carrying a UID. Tunnel-thread only. +int route_flow_lookup(int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, + int *tunnel); + +void route_flow_store(int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, + int tunnel); + +void route_flow_invalidate(); + jint get_uid_q(const struct arguments *args, jint version, jint protocol, diff --git a/app/src/main/jni/netguard/route.c b/app/src/main/jni/netguard/route.c new file mode 100644 index 000000000..3bedda1b1 --- /dev/null +++ b/app/src/main/jni/netguard/route.c @@ -0,0 +1,295 @@ +/* + * TrackerControl is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * TrackerControl is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright © 2026 + */ + +#include "netguard.h" + +#include +#include + +// Sorted array of the UIDs whose routing *differs* from the global default, +// plus that default. Written from the Java thread during a reload and read by +// the tunnel thread on the packet path, so both sides take route_lock. The +// packet path is otherwise single-threaded (one tunnelThread runs jni_run), +// which is why nothing else here needs a lock. +// +// Only the exceptions are pushed, never the whole tunnelled set. In the default +// mode every applied app is tunnelled, so a "tunnelled UIDs" array held every +// installed app and was indistinguishable from a heavily-overridden one — which +// made route_uid_relevant() below always true and cost every user, WireGuard or +// not, a per-packet lock and session-table walk. +static pthread_mutex_t route_lock = PTHREAD_MUTEX_INITIALIZER; +static jint *route_uids = NULL; +static int route_uid_count = 0; +static int route_default_tunnel = 1; + +// Fast-path mirrors of the facts the packet path needs before it knows whether +// resolving a UID is worth anything. All are read per packet, so they are +// atomics rather than lock-protected: with no per-app override configured — +// the shipped default — every UID gets the same answer, and the packet path +// must not pay a mutex or a session-table walk to rediscover that. +static _Atomic int route_has_overrides = 0; +static _Atomic int route_default_tunnel_fast = 1; + +// Whether direct apps' DNS is redirected to the system resolver. Its own flag +// rather than a reuse of args->fwd53: that one is also set by an unrelated +// port-53 forward (Secure DNS runs one whenever WireGuard carries no DNS line +// of its own), and borrowing it silently switched off the rule that every +// resolver query takes the tunnel. +static _Atomic int route_dns_direct_fast = 0; + +static int compare_uid(const void *a, const void *b) { + jint ua = *(const jint *) a; + jint ub = *(const jint *) b; + return (ua > ub) - (ua < ub); +} + +void set_route_uids(const jint *uids, int count, int default_tunnel, int dns_direct) { + jint *copy = NULL; + if (count > 0) { + copy = ng_malloc(sizeof(jint) * (size_t) count, "route uids"); + if (copy == NULL) { + log_android(ANDROID_LOG_ERROR, "route uids alloc failed, keeping previous routing"); + return; + } + memcpy(copy, uids, sizeof(jint) * (size_t) count); + qsort(copy, (size_t) count, sizeof(jint), compare_uid); + } + + if (pthread_mutex_lock(&route_lock)) { + log_android(ANDROID_LOG_ERROR, "route lock failed, keeping previous routing"); + if (copy != NULL) + ng_free(copy, __FILE__, __LINE__); + return; + } + + jint *previous = route_uids; + route_uids = copy; + route_uid_count = count; + route_default_tunnel = default_tunnel; + + atomic_store_explicit(&route_has_overrides, count > 0 ? 1 : 0, memory_order_release); + atomic_store_explicit(&route_default_tunnel_fast, default_tunnel, memory_order_release); + atomic_store_explicit(&route_dns_direct_fast, dns_direct, memory_order_release); + + if (pthread_mutex_unlock(&route_lock)) + log_android(ANDROID_LOG_ERROR, "route unlock failed"); + + // Verdicts cached against the previous rules must not survive them. + route_flow_invalidate(); + + if (previous != NULL) + ng_free(previous, __FILE__, __LINE__); +} + +void clear_route_uids() { + set_route_uids(NULL, 0, 1, 0); +} + +int is_tunnel_uid(jint uid) { + if (pthread_mutex_lock(&route_lock)) { + // Fall back to the safest answer: keep the app in the tunnel. + log_android(ANDROID_LOG_ERROR, "route lock failed, tunnelling uid %d", uid); + return 1; + } + + int tunnel; + // Only UIDs the user gave an explicit, differing answer for are listed. + // Everything else — an unresolved UID, system traffic, an app installed + // since the last reload — follows the global default, which is what makes + // the default mode identical to the behaviour before per-app routing + // existed. + if (uid < 0 || route_uids == NULL) + tunnel = route_default_tunnel; + else if (bsearch(&uid, route_uids, (size_t) route_uid_count, sizeof(jint), compare_uid) + != NULL) + tunnel = !route_default_tunnel; + else + tunnel = route_default_tunnel; + + if (pthread_mutex_unlock(&route_lock)) + log_android(ANDROID_LOG_ERROR, "route unlock failed"); + + return tunnel; +} + +/** + * Whether resolving this packet's UID can change the routing answer. + * + * With no per-app override configured, every UID resolves to the same global + * default, so the packet path can skip both the UID lookup and the lock. This + * is the shipped default, and keeping it free is what holds the per-packet cost + * at what it was before per-app routing existed. + */ +int route_uid_relevant() { + return atomic_load_explicit(&route_has_overrides, memory_order_acquire); +} + +/** The answer every UID gets when no override is configured. */ +int route_default_is_tunnel() { + return atomic_load_explicit(&route_default_tunnel_fast, memory_order_acquire); +} + +/** Whether direct apps' DNS is redirected, in which case DNS follows the UID. */ +int route_dns_direct() { + return atomic_load_explicit(&route_dns_direct_fast, memory_order_acquire); +} + +/** + * Whether this packet belongs in the tunnel. Pure, so the rule can be read + * straight through — the caller still decides what to do when the tunnel is + * down, because only the write attempt can say whether it is. + * + * @param local_dest loopback / link-local / multicast destination + * @param is_dns port 53, over UDP or TCP + * @param tunnel_uid whether this packet's UID is routed through the tunnel + * @param dns_direct whether direct apps' DNS is redirected to the system + * resolver; while false, DNS always takes the tunnel + */ +int route_wants_tunnel(int local_dest, int is_dns, int tunnel_uid, int dns_direct) { + // Destinations WireGuard cannot meaningfully forward never take the tunnel, + // whichever app sent them. + if (local_dest && !is_dns) + return 0; + + // Unless a direct app's DNS is being redirected, every resolver query takes + // the tunnel: sending it out directly would expose the user's physical + // network to the resolver. + if (is_dns && !dns_direct) + return 1; + + return tunnel_uid; +} + +// --- Per-flow verdict cache ------------------------------------------------- +// +// A tunnelled packet is handed to WireGuard and returns before handle_tcp / +// handle_udp run, so no ng_session is ever created for it. Meanwhile the UID +// lookup upstream is skipped for non-SYN TCP and existing UDP, so packet 2+ of +// a tunnelled flow arrives with uid == -1 and nothing left to resolve it from. +// Falling back to the global default there is wrong in exactly the mode the +// feature exists for: in "selected" mode the default is direct, so the rest of +// a tunnelled TCP flow was routed direct and handle_tcp, finding no session for +// a non-SYN segment, answered it with an RST. +// +// So remember the verdict per flow, keyed on the 5-tuple, and consult it before +// giving up. Written and read only by the tunnel thread, which is why nothing +// here takes a lock; a reload bumps route_flow_gen instead of clearing the +// table, so entries decided under superseded rules simply stop matching. + +#define ROUTE_FLOW_SIZE 1024 // power of two; ~40 KB resident +#define ROUTE_FLOW_MAX_AGE 300 // seconds idle before an entry is reusable + +struct route_flow_entry { + uint32_t gen; // 0 = free + uint8_t version; + uint8_t protocol; + uint8_t tunnel; + uint16_t sport; + uint16_t dport; + uint8_t saddr[16]; + uint8_t daddr[16]; + time_t time; +}; + +static struct route_flow_entry route_flows[ROUTE_FLOW_SIZE]; +static _Atomic uint32_t route_flow_gen = 1; + +void route_flow_invalidate() { + // Wrapping past 0 would resurrect free slots, so skip it. + uint32_t next = atomic_fetch_add_explicit(&route_flow_gen, 1, memory_order_release) + 1; + if (next == 0) + atomic_store_explicit(&route_flow_gen, 1, memory_order_release); +} + +static size_t route_flow_slot(int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport) { + size_t alen = (version == 4 ? 4u : 16u); + // FNV-1a + uint32_t h = 2166136261u; + const uint8_t *s = saddr; + const uint8_t *d = daddr; + for (size_t i = 0; i < alen; i++) { + h = (h ^ s[i]) * 16777619u; + h = (h ^ d[i]) * 16777619u; + } + h = (h ^ (uint8_t) version) * 16777619u; + h = (h ^ (uint8_t) protocol) * 16777619u; + h = (h ^ (uint8_t) (sport & 0xff)) * 16777619u; + h = (h ^ (uint8_t) (sport >> 8)) * 16777619u; + h = (h ^ (uint8_t) (dport & 0xff)) * 16777619u; + h = (h ^ (uint8_t) (dport >> 8)) * 16777619u; + return (size_t) (h & (ROUTE_FLOW_SIZE - 1)); +} + +static int route_flow_matches(const struct route_flow_entry *e, uint32_t gen, + int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, time_t now) { + size_t alen = (version == 4 ? 4u : 16u); + return e->gen == gen && + e->version == (uint8_t) version && e->protocol == (uint8_t) protocol && + e->sport == sport && e->dport == dport && + memcmp(e->saddr, saddr, alen) == 0 && memcmp(e->daddr, daddr, alen) == 0 && + now - e->time <= ROUTE_FLOW_MAX_AGE; +} + +/** + * The remembered verdict for this flow, if any. + * + * @return 1 when *tunnel was filled in, 0 on a miss. + */ +int route_flow_lookup(int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, + int *tunnel) { + uint32_t gen = atomic_load_explicit(&route_flow_gen, memory_order_acquire); + struct route_flow_entry *e = &route_flows[route_flow_slot( + version, protocol, saddr, sport, daddr, dport)]; + + time_t now = time(NULL); + if (!route_flow_matches(e, gen, version, protocol, saddr, sport, daddr, dport, now)) + return 0; + + e->time = now; + *tunnel = e->tunnel; + return 1; +} + +/** + * Remember this flow's verdict. One slot per hash, overwritten on collision — + * it is a cache, and a miss only costs the fallback path that ran before it + * existed. Never called for a packet whose UID was unknown: pinning a guessed + * default for the life of a flow is the failure this exists to prevent. + */ +void route_flow_store(int version, int protocol, + const void *saddr, uint16_t sport, + const void *daddr, uint16_t dport, + int tunnel) { + size_t alen = (version == 4 ? 4u : 16u); + struct route_flow_entry *e = &route_flows[route_flow_slot( + version, protocol, saddr, sport, daddr, dport)]; + + e->gen = atomic_load_explicit(&route_flow_gen, memory_order_acquire); + e->version = (uint8_t) version; + e->protocol = (uint8_t) protocol; + e->tunnel = (uint8_t) (tunnel ? 1 : 0); + e->sport = sport; + e->dport = dport; + memset(e->saddr, 0, sizeof(e->saddr)); + memset(e->daddr, 0, sizeof(e->daddr)); + memcpy(e->saddr, saddr, alen); + memcpy(e->daddr, daddr, alen); + e->time = time(NULL); +} diff --git a/app/src/main/res/layout/list_item_trackers_header.xml b/app/src/main/res/layout/list_item_trackers_header.xml index 02b82a72d..194b82e4f 100644 --- a/app/src/main/res/layout/list_item_trackers_header.xml +++ b/app/src/main/res/layout/list_item_trackers_header.xml @@ -289,4 +289,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 7e0d2115f..2de33128e 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -388,4 +388,18 @@ ينطبق أيضًا على %1$s، الذي يشارك هذا التطبيق مُعرِّف مستخدم أندرويد. تجاوز TrackerControl يتصل التطبيق مباشرةً، خارج TrackerControl. لا تتم مراقبة أو حظر أي شيء له. استخدم هذا كملاذ أخير إذا كان التطبيق لا يزال لا يعمل.\n\nملاحظة: يجب تعطيل \"حظر الاتصالات بدون VPN\" في إعدادات VPN بنظام أندرويد حتى يعمل هذا. + + + التوجيه عبر VPN البعيد + أي التطبيقات تُمرَّر عبر VPN البعيد. التطبيقات التي لا تُمرَّر تبقى مراقَبة ومُرشَّحة بالكامل — لكنها تتصل من شبكة هذا الجهاز. + كل التطبيقات + التطبيقات المحددة فقط + VPN البعيد + عبر VPN البعيد + يتصل هذا التطبيق عبر VPN البعيد الخاص بك، الذي يرى حركته بدلاً من شبكتك. + مباشرةً من هذا الجهاز + يتصل هذا التطبيق من شبكتك. تظل مراقبة أدوات التتبع وحظرها سارية. تذهب استعلامات DNS الخاصة به إلى محلل شبكتك بدلاً من محلل VPN، ويرى العنوان الحقيقي لهذا الجهاز — بعض التطبيقات تحتاج ذلك، مثلاً للوصول إلى الأجهزة المحلية أو فحص بوابة الاتصال. + لا يوجد VPN بعيد مُعد، لذا فإن كل الحركة تغادر هذا الجهاز مباشرةً بالفعل. + يتجاوز هذا التطبيق TrackerControl تمامًا، لذا لا توجد حركة لتوجيهها. + لا ينقل VPN البعيد كل الحركة (قيمة AllowedIPs لديه ليست نفقًا كاملاً). يتطلب التوجيه لكل تطبيق نفقًا كاملاً، لأن المسارات مشتركة بين كل التطبيقات. diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn-rBD/strings.xml index 89b6f1267..ed4b606a4 100644 --- a/app/src/main/res/values-bn-rBD/strings.xml +++ b/app/src/main/res/values-bn-rBD/strings.xml @@ -71,4 +71,18 @@ %1$s-এর ক্ষেত্রেও প্রযোজ্য, যেটি এই অ্যাপের সঙ্গে একই Android ব্যবহারকারী আইডি ভাগ করে। TrackerControl এড়িয়ে যান অ্যাপটি TrackerControl-এর বাইরে সরাসরি সংযোগ করে। এর জন্য কিছুই পর্যবেক্ষণ বা ব্লক করা হয় না। অ্যাপ তবুও কাজ না করলে শেষ উপায় হিসেবে এটি ব্যবহার করুন।\n\nদ্রষ্টব্য: এটি কাজ করতে হলে Android-এর VPN সেটিংসে \"VPN ছাড়া সংযোগ ব্লক করুন\" বন্ধ থাকতে হবে। + + + দূরবর্তী VPN দিয়ে পাঠান + কোন অ্যাপগুলি দূরবর্তী VPN দিয়ে যাবে। যেগুলি যায় না সেগুলিতেও ট্র্যাকার পর্যবেক্ষণ ও ব্লকিং পুরোপুরি চলে — সেগুলি কেবল এই ডিভাইসের নিজের নেটওয়ার্ক থেকে সংযোগ করে। + সব অ্যাপ + শুধু নির্বাচিত অ্যাপ + দূরবর্তী VPN + দূরবর্তী VPN দিয়ে + এই অ্যাপটি আপনার দূরবর্তী VPN দিয়ে সংযোগ করে, যা আপনার নেটওয়ার্কের বদলে এর ট্রাফিক দেখে। + সরাসরি এই ডিভাইস থেকে + এই অ্যাপটি আপনার নিজের নেটওয়ার্ক থেকে সংযোগ করে। ট্র্যাকার পর্যবেক্ষণ ও ব্লকিং তবুও প্রযোজ্য। এর DNS অনুরোধ VPN-এর বদলে আপনার নেটওয়ার্কের রিজলভারে যায় এবং এটি এই ডিভাইসের প্রকৃত ঠিকানা দেখে — কিছু অ্যাপের এটি দরকার, যেমন স্থানীয় ডিভাইসে পৌঁছাতে বা ক্যাপটিভ পোর্টাল যাচাই করতে। + কোনও দূরবর্তী VPN সেট করা নেই, তাই সব ট্রাফিক ইতিমধ্যেই সরাসরি এই ডিভাইস থেকে যাচ্ছে। + এই অ্যাপটি TrackerControl সম্পূর্ণ এড়িয়ে যায়, তাই পাঠানোর মতো কোনও ট্রাফিক নেই। + আপনার দূরবর্তী VPN সব ট্রাফিক বহন করে না (এর AllowedIPs পূর্ণ টানেল নয়)। অ্যাপভিত্তিক রাউটিংয়ের জন্য পূর্ণ টানেল দরকার, কারণ রুটগুলি সব অ্যাপ ভাগ করে নেয়। diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 0b58c2613..c40fe4bf1 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -404,4 +404,18 @@ Privátní DNS musí být vypnutá. Platí i pro %1$s, která s touto aplikací sdílí uživatelské ID systému Android. Obejít TrackerControl Aplikace se připojuje přímo, mimo TrackerControl. Nic se pro ni nesleduje ani neblokuje. Použijte jako poslední možnost, pokud aplikace stále nefunguje.\n\nPoznámka: Aby to fungovalo, musí být volba \"Blokovat připojení bez VPN\" v nastavení VPN systému Android VYPNUTA. + + + Směrovat přes vzdálenou VPN + Které aplikace se přeposílají přes vzdálenou VPN. Ostatní zůstávají plně sledované a filtrované — jen se připojují ze sítě tohoto zařízení. + Všechny aplikace + Jen vybrané aplikace + Vzdálená VPN + Přes vzdálenou VPN + Tato aplikace se připojuje přes vaši vzdálenou VPN, která místo vaší sítě vidí její provoz. + Přímo z tohoto zařízení + Tato aplikace se připojuje z vaší vlastní sítě. Sledování a blokování trackerů dál platí. Její DNS dotazy míří na resolver vaší sítě místo na VPN a aplikace vidí skutečnou adresu tohoto zařízení — některé aplikace to potřebují, třeba k dosažení místních zařízení nebo kontrole captive portálu. + Není nastavena žádná vzdálená VPN, takže veškerý provoz už z tohoto zařízení odchází přímo. + Tato aplikace TrackerControl zcela obchází, takže není co směrovat. + Vaše vzdálená VPN nepřenáší veškerý provoz (její AllowedIPs netvoří úplný tunel). Směrování po aplikacích vyžaduje úplný tunel, protože trasy sdílejí všechny aplikace. diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index 897627458..dedca0f6f 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -126,4 +126,18 @@ Gælder også %1$s, som deler et Android-bruger-id med denne app. Omgå TrackerControl Appen forbinder direkte, uden om TrackerControl. Intet overvåges eller blokeres for den. Brug dette som sidste udvej, hvis appen stadig ikke virker.\n\nBemærk: \"Bloker forbindelser uden VPN\" i Androids VPN-indstillinger skal være DEAKTIVERET, for at dette virker. + + + Send gennem fjern-VPN + Hvilke apps der sendes gennem fjern-VPN\'et. De øvrige overvåges og filtreres fortsat fuldt ud — de forbinder blot fra enhedens eget netværk. + Alle apps + Kun valgte apps + Fjern-VPN + Gennem fjern-VPN\'et + Denne app forbinder gennem dit fjern-VPN, som ser dens trafik i stedet for dit netværk. + Direkte fra denne enhed + Denne app forbinder fra dit eget netværk. Sporingsovervågning og -blokering gælder stadig. Dens DNS-forespørgsler går til dit netværks resolver i stedet for VPN\'ets, og appen ser enhedens rigtige adresse — nogle apps har brug for det, for eksempel for at nå lokale enheder eller tjekke en captive portal. + Der er ikke opsat noget fjern-VPN, så al trafik forlader allerede enheden direkte. + Denne app omgår TrackerControl helt, så der er ingen trafik at sende. + Dit fjern-VPN bærer ikke al trafik (dets AllowedIPs er ikke en fuld tunnel). Routing pr. app kræver en fuld tunnel, fordi ruter deles af alle apps. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c1669f1a1..f6c18fb06 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -353,4 +353,18 @@ Gilt auch für %1$s, da diese App sich eine Android-Benutzer-ID mit dieser App teilt. TrackerControl umgehen Die App verbindet sich direkt, außerhalb von TrackerControl. Nichts wird für sie überwacht oder blockiert. Nutze dies als letzten Ausweg, wenn die App weiterhin nicht funktioniert.\n\nHinweis: \"Verbindungen ohne VPN blockieren\" in den Android-VPN-Einstellungen muss DEAKTIVIERT sein, damit dies funktioniert. + + + Über Remote-VPN leiten + Welche Apps über das Remote-VPN geleitet werden. Apps, die es nicht sind, werden weiterhin vollständig auf Tracker überwacht und gefiltert — sie verbinden sich nur über das eigene Netzwerk dieses Geräts. + Alle Apps + Nur ausgewählte Apps + Remote-VPN + Über das Remote-VPN + Diese App verbindet sich über dein Remote-VPN, das ihren Datenverkehr anstelle deines Netzwerks sieht. + Direkt von diesem Gerät + Diese App verbindet sich über dein eigenes Netzwerk. Tracker-Überwachung und -Blockierung gelten weiterhin. Ihre DNS-Anfragen gehen an den Resolver deines Netzwerks statt an den des VPNs, und sie sieht die echte Adresse dieses Geräts — manche Apps brauchen das, etwa für lokale Geräte oder die Prüfung eines Captive Portals. + Es ist kein Remote-VPN eingerichtet, daher verlässt bereits der gesamte Verkehr dieses Gerät direkt. + Diese App umgeht TrackerControl vollständig, daher gibt es keinen Verkehr zu leiten. + Dein Remote-VPN überträgt nicht den gesamten Verkehr (seine AllowedIPs bilden keinen vollständigen Tunnel). Per-App-Routing benötigt einen vollständigen Tunnel, da Routen von allen Apps geteilt werden. diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 654ff5a39..d1bdb96cd 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -330,4 +330,18 @@ Ισχύει και για το %1$s, το οποίο μοιράζεται αναγνωριστικό χρήστη Android με αυτήν την εφαρμογή. Παράκαμψη του TrackerControl Η εφαρμογή συνδέεται απευθείας, εκτός του TrackerControl. Τίποτα δεν παρακολουθείται ούτε αποκλείεται για αυτήν. Χρησιμοποιήστε το ως έσχατη λύση αν η εφαρμογή εξακολουθεί να μη λειτουργεί.\n\nΣημείωση: Η επιλογή \"Αποκλεισμός συνδέσεων χωρίς VPN\" στις ρυθμίσεις VPN του Android πρέπει να είναι ΑΠΕΝΕΡΓΟΠΟΙΗΜΕΝΗ για να λειτουργήσει αυτό. + + + Δρομολόγηση μέσω απομακρυσμένου VPN + Ποιες εφαρμογές προωθούνται μέσω του απομακρυσμένου VPN. Όσες δεν προωθούνται παραμένουν πλήρως παρακολουθούμενες και φιλτραρισμένες — απλώς συνδέονται από το δίκτυο αυτής της συσκευής. + Όλες οι εφαρμογές + Μόνο επιλεγμένες εφαρμογές + Απομακρυσμένο VPN + Μέσω του απομακρυσμένου VPN + Αυτή η εφαρμογή συνδέεται μέσω του απομακρυσμένου VPN σας, το οποίο βλέπει την κίνησή της αντί για το δίκτυό σας. + Απευθείας από αυτήν τη συσκευή + Αυτή η εφαρμογή συνδέεται από το δικό σας δίκτυο. Η παρακολούθηση και ο αποκλεισμός ιχνηλατών εξακολουθούν να ισχύουν. Τα ερωτήματα DNS της πηγαίνουν στον resolver του δικτύου σας αντί του VPN, και βλέπει την πραγματική διεύθυνση της συσκευής — ορισμένες εφαρμογές το χρειάζονται, π.χ. για πρόσβαση σε τοπικές συσκευές ή έλεγχο captive portal. + Δεν έχει ρυθμιστεί απομακρυσμένο VPN, οπότε όλη η κίνηση φεύγει ήδη απευθείας από αυτήν τη συσκευή. + Αυτή η εφαρμογή παρακάμπτει πλήρως το TrackerControl, οπότε δεν υπάρχει κίνηση προς δρομολόγηση. + Το απομακρυσμένο VPN σας δεν μεταφέρει όλη την κίνηση (τα AllowedIPs του δεν είναι πλήρης σήραγγα). Η δρομολόγηση ανά εφαρμογή απαιτεί πλήρη σήραγγα, καθώς οι διαδρομές είναι κοινές για όλες τις εφαρμογές. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index a53c0ab0c..06f8f7214 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -405,4 +405,18 @@ Atentamente,\n\n]]> También se aplica a %1$s, que comparte un ID de usuario de Android con esta aplicación. Omitir TrackerControl La aplicación se conecta directamente, fuera de TrackerControl. No se supervisa ni se bloquea nada para ella. Usa esto como último recurso si la aplicación sigue sin funcionar.\n\nNota: \"Bloquear conexiones sin VPN\" en los ajustes de VPN de Android debe estar DESACTIVADO para que esto funcione. + + + Enrutar por el VPN remoto + Qué aplicaciones se envían a través del VPN remoto. Las que no lo hacen siguen totalmente supervisadas y filtradas — simplemente se conectan desde la red de este dispositivo. + Todas las aplicaciones + Solo aplicaciones seleccionadas + VPN remoto + A través del VPN remoto + Esta aplicación se conecta a través de tu VPN remoto, que ve su tráfico en lugar de tu red. + Directamente desde este dispositivo + Esta aplicación se conecta desde tu propia red. La supervisión y el bloqueo de rastreadores siguen aplicándose. Sus consultas DNS van al resolutor de tu red en lugar del VPN, y ve la dirección real de este dispositivo — algunas aplicaciones lo necesitan, por ejemplo para llegar a dispositivos locales o comprobar un portal cautivo. + No hay ningún VPN remoto configurado, así que todo el tráfico ya sale directamente de este dispositivo. + Esta aplicación omite TrackerControl por completo, así que no hay tráfico que enrutar. + Tu VPN remoto no transporta todo el tráfico (sus AllowedIPs no forman un túnel completo). El enrutamiento por aplicación necesita un túnel completo, porque las rutas las comparten todas las aplicaciones. diff --git a/app/src/main/res/values-et-rEE/strings.xml b/app/src/main/res/values-et-rEE/strings.xml index de7343b9c..588db1049 100644 --- a/app/src/main/res/values-et-rEE/strings.xml +++ b/app/src/main/res/values-et-rEE/strings.xml @@ -248,4 +248,18 @@ Kehtib ka rakendusele %1$s, mis jagab selle rakendusega Androidi kasutaja-ID-d. TrackerControlist mööda Rakendus ühendub otse, TrackerControlist mööda. Tema jaoks ei jälgita ega blokeerita midagi. Kasuta seda viimase abinõuna, kui rakendus ikka ei tööta.\n\nMärkus: Androidi VPN-i sätetes peab \"Blokeeri ühendused ilma VPN-ita\" olema VÄLJA LÜLITATUD, et see toimiks. + + + Suuna läbi kaug-VPN-i + Millised rakendused suunatakse läbi kaug-VPN-i. Ülejäänud jäävad täielikult jälgituks ja filtreerituks — nad lihtsalt ühenduvad selle seadme enda võrgust. + Kõik rakendused + Ainult valitud rakendused + Kaug-VPN + Läbi kaug-VPN-i + See rakendus ühendub sinu kaug-VPN-i kaudu, mis näeb selle liiklust sinu võrgu asemel. + Otse sellest seadmest + See rakendus ühendub sinu enda võrgust. Jälitajate seire ja blokeerimine kehtivad edasi. Selle DNS-päringud lähevad sinu võrgu nimeserverisse, mitte VPN-i omasse, ja rakendus näeb seadme tegelikku aadressi — mõni rakendus vajab seda, näiteks kohalike seadmete jaoks või captive portali kontrolliks. + Kaug-VPN-i pole seadistatud, seega kogu liiklus lahkub juba otse sellest seadmest. + See rakendus möödub TrackerControlist täielikult, seega pole liiklust, mida suunata. + Sinu kaug-VPN ei kanna kogu liiklust (selle AllowedIPs pole täistunnel). Rakendusepõhine suunamine vajab täistunnelit, sest marsruudid on kõigil rakendustel ühised. diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index 6765cc6f5..cb177e636 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -369,4 +369,18 @@ Sareko trafikoan antzematen diren aztarnariak TrackerControl-ekin blokeatu daite %1$s aplikazioari ere aplikatzen zaio, Android erabiltzaile-ID bera partekatzen baitu honekin. Saihestu TrackerControl Aplikazioa zuzenean konektatzen da, TrackerControletik kanpo. Ez zaio ezer monitorizatzen ez blokeatzen. Erabili hau azken aukera gisa aplikazioak oraindik funtzionatzen ez badu.\n\nOharra: Androiden VPN ezarpenetako \"Blokeatu VPNrik gabeko konexioak\" DESAKTIBATUTA egon behar da hau funtziona dezan. + + + Urruneko VPN bidez bideratu + Zein aplikazio bidaltzen diren urruneko VPN bidez. Gainerakoak guztiz monitorizatuta eta iragazita jarraitzen dute — gailu honen sare propiotik konektatzen dira, besterik ez. + Aplikazio guztiak + Hautatutako aplikazioak bakarrik + Urruneko VPNa + Urruneko VPN bidez + Aplikazio hau zure urruneko VPN bidez konektatzen da, eta hark ikusten du bere trafikoa zure sarearen ordez. + Zuzenean gailu honetatik + Aplikazio hau zure sare propiotik konektatzen da. Jarraitzaileen monitorizazioa eta blokeoa indarrean daude oraindik. Bere DNS kontsultak zure sarearen ebazlera doaz, ez VPNarenera, eta gailu honen benetako helbidea ikusten du — aplikazio batzuek hori behar dute, adibidez tokiko gailuetara iristeko edo captive portal bat egiaztatzeko. + Ez dago urruneko VPNrik konfiguratuta, beraz trafiko guztia dagoeneko zuzenean ateratzen da gailu honetatik. + Aplikazio honek TrackerControl guztiz saihesten du, beraz ez dago bideratzeko trafikorik. + Zure urruneko VPNak ez du trafiko guztia garraiatzen (bere AllowedIPs ez da tunel osoa). Aplikazioz aplikazioko bideratzeak tunel osoa behar du, ibilbideak aplikazio guztien artean partekatzen baitira. diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index a37ac8618..06813ba29 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -28,4 +28,18 @@ برای %1$s نیز اعمال می‌شود، که شناسهٔ کاربری اندروید را با این برنامه به اشتراک می‌گذارد. دور زدن TrackerControl برنامه مستقیماً و خارج از TrackerControl متصل می‌شود. هیچ چیزی برای آن پایش یا مسدود نمی‌شود. اگر برنامه هنوز کار نمی‌کند، این را به‌عنوان آخرین راه‌حل استفاده کنید.\n\nتوجه: گزینهٔ \"مسدودسازی اتصال‌های بدون VPN\" در تنظیمات VPN اندروید باید غیرفعال باشد تا این کار کند. + + + مسیریابی از طریق VPN راه دور + کدام برنامه‌ها از طریق VPN راه دور فرستاده شوند. برنامه‌هایی که فرستاده نمی‌شوند همچنان به‌طور کامل پایش و فیلتر می‌شوند — فقط از شبکهٔ خودِ این دستگاه متصل می‌شوند. + همهٔ برنامه‌ها + فقط برنامه‌های انتخاب‌شده + VPN راه دور + از طریق VPN راه دور + این برنامه از طریق VPN راه دور شما متصل می‌شود، که به‌جای شبکهٔ شما ترافیک آن را می‌بیند. + مستقیم از این دستگاه + این برنامه از شبکهٔ خودتان متصل می‌شود. پایش و مسدودسازی ردیاب‌ها همچنان اعمال می‌شود. پرس‌وجوهای DNS آن به‌جای VPN به حل‌کنندهٔ شبکهٔ شما می‌رود و برنامه نشانی واقعی این دستگاه را می‌بیند — برخی برنامه‌ها به این نیاز دارند، مثلاً برای دسترسی به دستگاه‌های محلی یا بررسی captive portal. + هیچ VPN راه دوری تنظیم نشده است، بنابراین همهٔ ترافیک از پیش مستقیماً این دستگاه را ترک می‌کند. + این برنامه به‌طور کامل TrackerControl را دور می‌زند، بنابراین ترافیکی برای مسیریابی وجود ندارد. + VPN راه دور شما همهٔ ترافیک را حمل نمی‌کند (AllowedIPs آن تونل کامل نیست). مسیریابی جداگانه برای هر برنامه به تونل کامل نیاز دارد، چون مسیرها میان همهٔ برنامه‌ها مشترک است. diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index d20c8328b..c5b74a484 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -458,4 +458,18 @@ Ystävällisin terveisin,\n\n]]> Koskee myös sovellusta %1$s, jolla on sama Android-käyttäjätunnus kuin tällä sovelluksella. Ohita TrackerControl Sovellus muodostaa yhteyden suoraan, TrackerControlin ohi. Sille ei valvota eikä estetä mitään. Käytä tätä viimeisenä keinona, jos sovellus ei vieläkään toimi.\n\nHuomaa: Androidin VPN-asetusten kohdan \"Estä yhteydet ilman VPN:ää\" on oltava POIS KÄYTÖSTÄ, jotta tämä toimii. + + + Reititä etä-VPN:n kautta + Mitkä sovellukset kulkevat etä-VPN:n kautta. Muita valvotaan ja suodatetaan edelleen täysin — ne vain yhdistävät tämän laitteen omasta verkosta. + Kaikki sovellukset + Vain valitut sovellukset + Etä-VPN + Etä-VPN:n kautta + Tämä sovellus yhdistää etä-VPN:si kautta, joka näkee sen liikenteen verkkosi sijaan. + Suoraan tästä laitteesta + Tämä sovellus yhdistää omasta verkostasi. Seuraimien valvonta ja esto ovat edelleen voimassa. Sen DNS-kyselyt menevät verkkosi nimipalvelimelle VPN:n sijaan, ja sovellus näkee laitteen todellisen osoitteen — jotkin sovellukset tarvitsevat sitä, esimerkiksi paikallisten laitteiden tavoittamiseen tai captive portalin tarkistamiseen. + Etä-VPN:ää ei ole määritetty, joten kaikki liikenne lähtee jo suoraan tästä laitteesta. + Tämä sovellus ohittaa TrackerControlin kokonaan, joten reititettävää liikennettä ei ole. + Etä-VPN:si ei kuljeta kaikkea liikennettä (sen AllowedIPs ei ole täysi tunneli). Sovelluskohtainen reititys vaatii täyden tunnelin, koska reitit ovat kaikille sovelluksille yhteiset. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6a85fd3a2..7c99004a1 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -586,4 +586,18 @@ Cordialement,\n\n]]> S\'applique également à %1$s, qui partage un identifiant utilisateur Android avec cette application. Contourner TrackerControl L\'application se connecte directement, en dehors de TrackerControl. Rien n\'est surveillé ni bloqué pour elle. À utiliser en dernier recours si l\'application ne fonctionne toujours pas.\n\nRemarque : \"Bloquer les connexions sans VPN\" doit être DÉSACTIVÉ dans les paramètres VPN d\'Android pour que cela fonctionne. + + + Faire passer par le VPN distant + Quelles applications sont acheminées via le VPN distant. Celles qui ne le sont pas restent entièrement surveillées et filtrées — elles se connectent simplement depuis le réseau de cet appareil. + Toutes les applications + Seulement les applications sélectionnées + VPN distant + Via le VPN distant + Cette application se connecte via votre VPN distant, qui voit son trafic à la place de votre réseau. + Directement depuis cet appareil + Cette application se connecte depuis votre propre réseau. La surveillance et le blocage des traqueurs continuent de s\'appliquer. Ses requêtes DNS vont au résolveur de votre réseau plutôt qu\'à celui du VPN, et elle voit l\'adresse réelle de cet appareil — certaines applications en ont besoin, par exemple pour joindre des appareils locaux ou vérifier un portail captif. + Aucun VPN distant n\'est configuré, tout le trafic quitte donc déjà cet appareil directement. + Cette application contourne entièrement TrackerControl, il n\'y a donc aucun trafic à acheminer. + Votre VPN distant ne transporte pas tout le trafic (ses AllowedIPs ne forment pas un tunnel complet). Le routage par application nécessite un tunnel complet, car les routes sont partagées par toutes les applications. diff --git a/app/src/main/res/values-gl-rES/strings.xml b/app/src/main/res/values-gl-rES/strings.xml index 0919b4446..28880e79b 100644 --- a/app/src/main/res/values-gl-rES/strings.xml +++ b/app/src/main/res/values-gl-rES/strings.xml @@ -91,4 +91,18 @@ O seu tráfico de internet non será enviado a ningún servidor VPN remoto.Tamén se aplica a %1$s, que comparte un ID de usuario de Android con esta aplicación. Omitir TrackerControl A aplicación conéctase directamente, fóra de TrackerControl. Non se supervisa nin se bloquea nada para ela. Usa isto como último recurso se a aplicación segue sen funcionar.\n\nNota: \"Bloquear conexións sen VPN\" nos axustes de VPN de Android debe estar DESACTIVADO para que isto funcione. + + + Encamiñar polo VPN remoto + Que aplicacións se envían a través do VPN remoto. As que non seguen totalmente supervisadas e filtradas — simplemente conéctanse desde a rede deste dispositivo. + Todas as aplicacións + Só aplicacións seleccionadas + VPN remoto + A través do VPN remoto + Esta aplicación conéctase a través do teu VPN remoto, que ve o seu tráfico no canto da túa rede. + Directamente desde este dispositivo + Esta aplicación conéctase desde a túa propia rede. A supervisión e o bloqueo de rastrexadores seguen a aplicarse. As súas consultas DNS van ao resolvedor da túa rede no canto do VPN, e ve o enderezo real deste dispositivo — algunhas aplicacións precísano, por exemplo para chegar a dispositivos locais ou comprobar un portal cativo. + Non hai ningún VPN remoto configurado, así que todo o tráfico xa sae directamente deste dispositivo. + Esta aplicación omite TrackerControl por completo, así que non hai tráfico que encamiñar. + O teu VPN remoto non transporta todo o tráfico (os seus AllowedIPs non forman un túnel completo). O encamiñamento por aplicación precisa un túnel completo, porque as rutas compártenas todas as aplicacións. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 6252a5252..f81fce65c 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -368,4 +368,18 @@ Tisztelettel,\n\n]]> Erre is vonatkozik: %1$s, amely Android-felhasználóazonosítón osztozik ezzel az alkalmazással. TrackerControl megkerülése Az alkalmazás közvetlenül, a TrackerControlon kívül csatlakozik. Semmit sem figyel és blokkol nála. Végső megoldásként használja, ha az alkalmazás továbbra sem működik.\n\nMegjegyzés: az Android VPN-beállításaiban a \"Kapcsolatok blokkolása VPN nélkül\" beállításnak KIKAPCSOLVA kell lennie, hogy ez működjön. + + + Átirányítás a távoli VPN-en + Mely alkalmazások haladnak át a távoli VPN-en. A többi továbbra is teljesen felügyelt és szűrt — csak az eszköz saját hálózatáról csatlakoznak. + Minden alkalmazás + Csak a kiválasztott alkalmazások + Távoli VPN + A távoli VPN-en át + Ez az alkalmazás a távoli VPN-en át csatlakozik, amely a hálózata helyett látja a forgalmát. + Közvetlenül erről az eszközről + Ez az alkalmazás a saját hálózatáról csatlakozik. A követők felügyelete és blokkolása továbbra is érvényes. DNS-kérései a VPN helyett a hálózat feloldójához mennek, és az alkalmazás látja az eszköz valódi címét — egyes alkalmazásoknak erre szükségük van, például helyi eszközök eléréséhez vagy captive portal ellenőrzéséhez. + Nincs beállítva távoli VPN, így minden forgalom már közvetlenül hagyja el az eszközt. + Ez az alkalmazás teljesen megkerüli a TrackerControlt, így nincs mit átirányítani. + A távoli VPN nem viszi az összes forgalmat (az AllowedIPs nem teljes alagút). Az alkalmazásonkénti átirányításhoz teljes alagút kell, mert az útvonalakat minden alkalmazás megosztja. diff --git a/app/src/main/res/values-is-rIS/strings.xml b/app/src/main/res/values-is-rIS/strings.xml index 964ab407a..b6f6210ae 100644 --- a/app/src/main/res/values-is-rIS/strings.xml +++ b/app/src/main/res/values-is-rIS/strings.xml @@ -15,4 +15,18 @@ Á einnig við um %1$s, sem deilir Android-notandaauðkenni með þessu forriti. Sniðganga TrackerControl Forritið tengist beint, utan TrackerControl. Ekkert er vaktað eða útilokað fyrir það. Notaðu þetta sem síðasta úrræði ef forritið virkar enn ekki.\n\nAthugið: \"Loka á tengingar án VPN\" í VPN-stillingum Android verður að vera SLÖKKT til að þetta virki. + + + Beina um fjartengt VPN + Hvaða forrit fara um fjartengda VPN-ið. Þau sem gera það ekki eru áfram að fullu vöktuð og síuð — þau tengjast einfaldlega um net þessa tækis. + Öll forrit + Aðeins valin forrit + Fjartengt VPN + Um fjartengda VPN-ið + Þetta forrit tengist um fjartengda VPN-ið þitt, sem sér umferð þess í stað netsins þíns. + Beint frá þessu tæki + Þetta forrit tengist um þitt eigið net. Vöktun og útilokun rekjara gilda áfram. DNS-fyrirspurnir þess fara á nafnaþjón netsins þíns í stað VPN-sins og forritið sér raunverulegt vistfang tækisins — sum forrit þurfa það, til dæmis til að ná í staðbundin tæki eða athuga captive portal. + Ekkert fjartengt VPN er uppsett, svo öll umferð fer nú þegar beint frá þessu tæki. + Þetta forrit sniðgengur TrackerControl algjörlega, svo það er engin umferð til að beina. + Fjartengda VPN-ið þitt ber ekki alla umferð (AllowedIPs þess er ekki full göng). Beining eftir forriti krefst fullra ganga því allar leiðir eru sameiginlegar öllum forritum. diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 63869b276..8cb6b8fb3 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -365,4 +365,18 @@ Cordiali saluti,\n\n]]> Vale anche per %1$s, che condivide un ID utente Android con questa app. Ignora TrackerControl L\'app si connette direttamente, al di fuori di TrackerControl. Per essa non viene monitorato né bloccato nulla. Usa questa opzione come ultima risorsa se l\'app continua a non funzionare.\n\nNota: \"Blocca connessioni senza VPN\" nelle impostazioni VPN di Android deve essere DISATTIVATO perché funzioni. + + + Instrada tramite VPN remota + Quali app vengono inoltrate attraverso la VPN remota. Quelle che non lo sono restano completamente monitorate e filtrate — si connettono semplicemente dalla rete di questo dispositivo. + Tutte le app + Solo le app selezionate + VPN remota + Tramite la VPN remota + Questa app si connette tramite la tua VPN remota, che vede il suo traffico al posto della tua rete. + Direttamente da questo dispositivo + Questa app si connette dalla tua rete. Il monitoraggio e il blocco dei tracker continuano ad applicarsi. Le sue richieste DNS vanno al resolver della tua rete anziché a quello della VPN, e l\'app vede l\'indirizzo reale di questo dispositivo — alcune app ne hanno bisogno, per esempio per raggiungere dispositivi locali o verificare un captive portal. + Non è configurata alcuna VPN remota, quindi tutto il traffico esce già direttamente da questo dispositivo. + Questa app ignora completamente TrackerControl, quindi non c\'è traffico da instradare. + La tua VPN remota non trasporta tutto il traffico (i suoi AllowedIPs non formano un tunnel completo). L\'instradamento per app richiede un tunnel completo, perché le rotte sono condivise da tutte le app. diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml index 8640e788b..280e943ee 100644 --- a/app/src/main/res/values-iw-rIL/strings.xml +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -349,4 +349,18 @@ חל גם על %1$s, שחולקת מזהה משתמש של Android עם אפליקציה זו. עקיפת TrackerControl האפליקציה מתחברת ישירות, מחוץ ל-TrackerControl. דבר אינו מנוטר או נחסם עבורה. השתמשו בכך כמוצא אחרון אם האפליקציה עדיין לא עובדת.\n\nהערה: האפשרות \"חסום חיבורים ללא VPN\" בהגדרות ה-VPN של Android חייבת להיות מושבתת כדי שזה יעבוד. + + + ניתוב דרך VPN מרוחק + אילו אפליקציות מועברות דרך ה-VPN המרוחק. אלה שלא, ממשיכות להיות מנוטרות ומסוננות במלואן — הן פשוט מתחברות מהרשת של המכשיר הזה. + כל האפליקציות + רק אפליקציות נבחרות + VPN מרוחק + דרך ה-VPN המרוחק + אפליקציה זו מתחברת דרך ה-VPN המרוחק שלך, שרואה את התעבורה שלה במקום הרשת שלך. + ישירות מהמכשיר הזה + אפליקציה זו מתחברת מהרשת שלך. ניטור וחסימה של רכיבי מעקב ממשיכים לחול. שאילתות ה-DNS שלה הולכות לפותר של הרשת שלך במקום של ה-VPN, והיא רואה את הכתובת האמיתית של המכשיר — חלק מהאפליקציות זקוקות לכך, למשל כדי להגיע למכשירים מקומיים או לבדוק captive portal. + לא מוגדר VPN מרוחק, ולכן כל התעבורה כבר יוצאת ישירות מהמכשיר הזה. + אפליקציה זו עוקפת את TrackerControl לחלוטין, ולכן אין תעבורה לנתב. + ה-VPN המרוחק שלך אינו נושא את כל התעבורה (ה-AllowedIPs שלו אינו מנהרה מלאה). ניתוב לכל אפליקציה דורש מנהרה מלאה, מכיוון שהנתיבים משותפים לכל האפליקציות. diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index c733ccc42..02ec55705 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -325,4 +325,18 @@ このアプリと Android のユーザー ID を共有する %1$s にも適用されます。 TrackerControl を迂回 アプリは TrackerControl を経由せず直接接続します。監視もブロックも行われません。アプリがそれでも動作しない場合の最終手段として使用してください。\n\n注意: これを機能させるには、Android の VPN 設定で \"VPN なしの接続をブロック\" を無効にする必要があります。 + + + リモート VPN 経由で通す + どのアプリをリモート VPN 経由で通すか。通さないアプリも引き続き完全に監視・ブロックされ、この端末自身のネットワークから接続するだけです。 + すべてのアプリ + 選択したアプリのみ + リモート VPN + リモート VPN 経由 + このアプリはリモート VPN 経由で接続し、あなたのネットワークではなく VPN が通信内容を見ます。 + この端末から直接 + このアプリはあなた自身のネットワークから接続します。トラッカーの監視とブロックは引き続き適用されます。DNS クエリは VPN ではなくネットワークのリゾルバに送られ、アプリはこの端末の実際のアドレスを見ます。ローカル機器への接続やキャプティブポータルの確認など、これを必要とするアプリもあります。 + リモート VPN が設定されていないため、すべての通信はすでにこの端末から直接出ています。 + このアプリは TrackerControl を完全に迂回するため、通すべき通信がありません。 + リモート VPN がすべての通信を運んでいません(AllowedIPs がフルトンネルではありません)。経路はすべてのアプリで共有されるため、アプリ単位の切り替えにはフルトンネルが必要です。 diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 22d1e7b21..062904228 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -100,4 +100,18 @@ 이 앱과 Android 사용자 ID를 공유하는 %1$s에도 적용됩니다. TrackerControl 우회 앱이 TrackerControl을 거치지 않고 직접 연결합니다. 이 앱에 대해서는 아무것도 감시하거나 차단하지 않습니다. 앱이 여전히 동작하지 않을 때 최후의 수단으로 사용하세요.\n\n참고: 이 기능이 동작하려면 Android VPN 설정에서 \"VPN 없이 연결 차단\"이 사용 중지되어 있어야 합니다. + + + 원격 VPN으로 보내기 + 어떤 앱을 원격 VPN으로 보낼지 정합니다. 보내지 않는 앱도 트래커 감시와 차단은 그대로 적용되며, 이 기기의 네트워크로 직접 연결할 뿐입니다. + 모든 앱 + 선택한 앱만 + 원격 VPN + 원격 VPN을 통해 + 이 앱은 원격 VPN을 통해 연결하며, 내 네트워크 대신 VPN이 트래픽을 봅니다. + 이 기기에서 직접 + 이 앱은 내 네트워크로 연결합니다. 트래커 감시와 차단은 계속 적용됩니다. DNS 질의는 VPN이 아니라 내 네트워크의 리졸버로 가고, 앱은 이 기기의 실제 주소를 봅니다. 로컬 기기 접근이나 캡티브 포털 확인처럼 이것이 필요한 앱도 있습니다. + 설정된 원격 VPN이 없어 모든 트래픽이 이미 이 기기에서 직접 나갑니다. + 이 앱은 TrackerControl을 완전히 우회하므로 보낼 트래픽이 없습니다. + 원격 VPN이 모든 트래픽을 나르지 않습니다(AllowedIPs가 전체 터널이 아닙니다). 경로는 모든 앱이 공유하므로 앱별 라우팅에는 전체 터널이 필요합니다. diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 3cdd7d218..5a4b3d52d 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -472,4 +472,18 @@ Het internetverkeer wordt niet naar een externe VPN-server gestuurd. Geldt ook voor %1$s, die een Android-gebruikers-ID deelt met deze app. TrackerControl omzeilen De app maakt rechtstreeks verbinding, buiten TrackerControl om. Er wordt niets voor gecontroleerd of geblokkeerd. Gebruik dit als laatste redmiddel als de app nog steeds niet werkt.\n\nLet op: \"Verbindingen zonder VPN blokkeren\" in de Android-VPN-instellingen moet UITGESCHAKELD zijn om dit te laten werken. + + + Via externe VPN leiden + Welke apps via de externe VPN worden geleid. Apps die dat niet doen blijven volledig gecontroleerd en gefilterd — ze verbinden gewoon via het eigen netwerk van dit apparaat. + Alle apps + Alleen geselecteerde apps + Externe VPN + Via de externe VPN + Deze app verbindt via je externe VPN, die het verkeer ziet in plaats van je netwerk. + Rechtstreeks vanaf dit apparaat + Deze app verbindt via je eigen netwerk. Trackercontrole en -blokkering blijven gelden. De DNS-aanvragen gaan naar de resolver van je netwerk in plaats van die van de VPN, en de app ziet het echte adres van dit apparaat — sommige apps hebben dat nodig, bijvoorbeeld om lokale apparaten te bereiken of een captive portal te controleren. + Er is geen externe VPN ingesteld, dus al het verkeer verlaat dit apparaat al rechtstreeks. + Deze app omzeilt TrackerControl volledig, dus er is geen verkeer om te leiden. + Je externe VPN draagt niet al het verkeer (de AllowedIPs vormen geen volledige tunnel). Routering per app vereist een volledige tunnel, omdat routes door alle apps worden gedeeld. diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml index 0b792dea5..8ea4ae809 100644 --- a/app/src/main/res/values-no-rNO/strings.xml +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -365,4 +365,18 @@ Vennlig hilsen,\n\n]]> Gjelder også %1$s, som deler en Android-bruker-ID med denne appen. Omgå TrackerControl Appen kobler til direkte, utenfor TrackerControl. Ingenting overvåkes eller blokkeres for den. Bruk dette som siste utvei hvis appen fortsatt ikke virker.\n\nMerk: \"Blokker tilkoblinger uten VPN\" i Androids VPN-innstillinger må være DEAKTIVERT for at dette skal virke. + + + Send gjennom ekstern VPN + Hvilke apper som sendes gjennom den eksterne VPN-en. De øvrige overvåkes og filtreres fortsatt fullt ut — de kobler bare til fra enhetens eget nettverk. + Alle apper + Bare valgte apper + Ekstern VPN + Gjennom den eksterne VPN-en + Denne appen kobler til gjennom din eksterne VPN, som ser trafikken dens i stedet for nettverket ditt. + Direkte fra denne enheten + Denne appen kobler til fra ditt eget nettverk. Sporerovervåking og blokkering gjelder fortsatt. DNS-forespørslene går til nettverkets resolver i stedet for VPN-ens, og appen ser enhetens virkelige adresse — noen apper trenger det, for eksempel for å nå lokale enheter eller sjekke en captive portal. + Ingen ekstern VPN er satt opp, så all trafikk forlater allerede enheten direkte. + Denne appen omgår TrackerControl helt, så det finnes ingen trafikk å sende. + Den eksterne VPN-en bærer ikke all trafikk (AllowedIPs er ikke en full tunnel). Ruting per app krever en full tunnel, siden ruter deles av alle apper. diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index bd1bc7c6e..8af8e9028 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -373,4 +373,18 @@ Z poważaniem,\n\n]]> Dotyczy też %1$s, która współdzieli z tą aplikacją identyfikator użytkownika Androida. Pomiń TrackerControl Aplikacja łączy się bezpośrednio, poza TrackerControl. Nic nie jest dla niej monitorowane ani blokowane. Użyj tego w ostateczności, jeśli aplikacja nadal nie działa.\n\nUwaga: opcja \"Blokuj połączenia bez VPN\" w ustawieniach VPN Androida musi być WYŁĄCZONA, aby to zadziałało. + + + Kieruj przez zdalny VPN + Które aplikacje są przekazywane przez zdalny VPN. Pozostałe nadal są w pełni monitorowane i filtrowane — po prostu łączą się przez sieć tego urządzenia. + Wszystkie aplikacje + Tylko wybrane aplikacje + Zdalny VPN + Przez zdalny VPN + Ta aplikacja łączy się przez Twój zdalny VPN, który widzi jej ruch zamiast Twojej sieci. + Bezpośrednio z tego urządzenia + Ta aplikacja łączy się przez Twoją własną sieć. Monitorowanie i blokowanie trackerów nadal działa. Jej zapytania DNS trafiają do resolwera Twojej sieci zamiast do VPN, a aplikacja widzi prawdziwy adres tego urządzenia — niektóre aplikacje tego potrzebują, na przykład by dotrzeć do urządzeń lokalnych lub sprawdzić captive portal. + Nie skonfigurowano zdalnego VPN, więc cały ruch już wychodzi bezpośrednio z tego urządzenia. + Ta aplikacja całkowicie pomija TrackerControl, więc nie ma ruchu do kierowania. + Twój zdalny VPN nie przenosi całego ruchu (jego AllowedIPs nie tworzy pełnego tunelu). Kierowanie na poziomie aplikacji wymaga pełnego tunelu, ponieważ trasy są wspólne dla wszystkich aplikacji. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 66ec6cbec..658785d09 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -461,4 +461,18 @@ O seu tráfego de internet não está sendo enviado para um servidor VPN remoto. Também se aplica a %1$s, que compartilha um ID de usuário do Android com este aplicativo. Ignorar o TrackerControl O aplicativo se conecta diretamente, fora do TrackerControl. Nada é monitorado nem bloqueado para ele. Use isto como último recurso se o aplicativo ainda não funcionar.\n\nObservação: \"Bloquear conexões sem VPN\" nas configurações de VPN do Android precisa estar DESATIVADO para que isto funcione. + + + Rotear pela VPN remota + Quais aplicativos são encaminhados pela VPN remota. Os que não são continuam totalmente monitorados e filtrados — apenas se conectam pela rede deste dispositivo. + Todos os aplicativos + Somente aplicativos selecionados + VPN remota + Pela VPN remota + Este aplicativo se conecta pela sua VPN remota, que vê o tráfego dele no lugar da sua rede. + Diretamente deste dispositivo + Este aplicativo se conecta pela sua própria rede. O monitoramento e o bloqueio de rastreadores continuam valendo. As consultas DNS vão para o resolvedor da sua rede em vez do da VPN, e ele vê o endereço real deste dispositivo — alguns aplicativos precisam disso, por exemplo para alcançar dispositivos locais ou verificar um portal cativo. + Nenhuma VPN remota está configurada, então todo o tráfego já sai diretamente deste dispositivo. + Este aplicativo ignora o TrackerControl por completo, então não há tráfego a rotear. + Sua VPN remota não transporta todo o tráfego (os AllowedIPs dela não formam um túnel completo). O roteamento por aplicativo exige um túnel completo, porque as rotas são compartilhadas por todos os aplicativos. diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 0c90201ee..74a080fd7 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -341,4 +341,18 @@ disso,\n\n]]> Aplica-se também a %1$s, que partilha um ID de utilizador Android com esta aplicação. Ignorar o TrackerControl A aplicação liga-se diretamente, fora do TrackerControl. Nada é monitorizado nem bloqueado para ela. Utilize isto como último recurso se a aplicação continuar a não funcionar.\n\nNota: \"Bloquear ligações sem VPN\" nas definições de VPN do Android tem de estar DESATIVADO para que isto funcione. + + + Encaminhar pela VPN remota + Que aplicações são encaminhadas pela VPN remota. As que não são continuam totalmente monitorizadas e filtradas — apenas se ligam pela rede deste dispositivo. + Todas as aplicações + Apenas aplicações selecionadas + VPN remota + Pela VPN remota + Esta aplicação liga-se pela sua VPN remota, que vê o tráfego dela em vez da sua rede. + Diretamente deste dispositivo + Esta aplicação liga-se pela sua própria rede. A monitorização e o bloqueio de rastreadores continuam a aplicar-se. As consultas DNS vão para o resolvedor da sua rede em vez do da VPN, e a aplicação vê o endereço real deste dispositivo — algumas aplicações precisam disso, por exemplo para alcançar dispositivos locais ou verificar um portal cativo. + Não está configurada nenhuma VPN remota, por isso todo o tráfego já sai diretamente deste dispositivo. + Esta aplicação ignora o TrackerControl por completo, por isso não há tráfego a encaminhar. + A sua VPN remota não transporta todo o tráfego (os AllowedIPs dela não formam um túnel completo). O encaminhamento por aplicação exige um túnel completo, porque as rotas são partilhadas por todas as aplicações. diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index fc76fc54f..984751433 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -85,4 +85,18 @@ Se aplică și pentru %1$s, care împarte un ID de utilizator Android cu această aplicație. Ocolește TrackerControl Aplicația se conectează direct, în afara TrackerControl. Nimic nu este monitorizat sau blocat pentru ea. Folosiți această opțiune ca ultimă soluție dacă aplicația tot nu funcționează.\n\nNotă: \"Blochează conexiunile fără VPN\" din setările VPN Android trebuie să fie DEZACTIVAT pentru ca aceasta să funcționeze. + + + Rutează prin VPN-ul la distanță + Care aplicații sunt trimise prin VPN-ul la distanță. Celelalte rămân complet monitorizate și filtrate — doar se conectează din rețeaua acestui dispozitiv. + Toate aplicațiile + Doar aplicațiile selectate + VPN la distanță + Prin VPN-ul la distanță + Această aplicație se conectează prin VPN-ul dvs. la distanță, care îi vede traficul în locul rețelei dvs. + Direct de pe acest dispozitiv + Această aplicație se conectează din propria rețea. Monitorizarea și blocarea urmăritorilor rămân valabile. Interogările ei DNS merg la rezolvatorul rețelei dvs., nu la cel al VPN-ului, iar aplicația vede adresa reală a dispozitivului — unele aplicații au nevoie de asta, de exemplu pentru a ajunge la dispozitive locale sau a verifica un captive portal. + Nu este configurat niciun VPN la distanță, așa că tot traficul iese deja direct de pe acest dispozitiv. + Această aplicație ocolește complet TrackerControl, deci nu există trafic de rutat. + VPN-ul dvs. la distanță nu transportă tot traficul (AllowedIPs nu formează un tunel complet). Rutarea per aplicație necesită un tunel complet, deoarece rutele sunt partajate de toate aplicațiile. diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index cbee352ea..af10d61a4 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -498,4 +498,18 @@ Относится и к %1$s: это приложение использует общий с ним идентификатор пользователя Android. В обход TrackerControl Приложение подключается напрямую, минуя TrackerControl. Для него ничего не отслеживается и не блокируется. Используйте это как крайнюю меру, если приложение по-прежнему не работает.\n\nПримечание: параметр \"Блокировать соединения без VPN\" в настройках VPN Android должен быть ОТКЛЮЧЁН, чтобы это работало. + + + Направлять через удалённый VPN + Какие приложения направляются через удалённый VPN. Остальные по-прежнему полностью отслеживаются и фильтруются — они просто подключаются через сеть этого устройства. + Все приложения + Только выбранные приложения + Удалённый VPN + Через удалённый VPN + Это приложение подключается через ваш удалённый VPN, который видит его трафик вместо вашей сети. + Напрямую с этого устройства + Это приложение подключается через вашу собственную сеть. Отслеживание и блокировка трекеров по-прежнему действуют. Его DNS-запросы идут к резолверу вашей сети, а не VPN, и оно видит настоящий адрес устройства — некоторым приложениям это нужно, например для доступа к локальным устройствам или проверки captive portal. + Удалённый VPN не настроен, поэтому весь трафик и так уходит напрямую с этого устройства. + Это приложение полностью обходит TrackerControl, поэтому направлять нечего. + Ваш удалённый VPN передаёт не весь трафик (его AllowedIPs не образует полный туннель). Маршрутизация по приложениям требует полного туннеля, так как маршруты общие для всех приложений. diff --git a/app/src/main/res/values-sl-rSI/strings.xml b/app/src/main/res/values-sl-rSI/strings.xml index be56e0b22..a09a96bfb 100644 --- a/app/src/main/res/values-sl-rSI/strings.xml +++ b/app/src/main/res/values-sl-rSI/strings.xml @@ -620,4 +620,18 @@ Vaš internetni promet se ne pošilja na oddaljeni strežnik VPN. Velja tudi za %1$s, ki si s to aplikacijo deli Androidov ID uporabnika. Obidi TrackerControl Aplikacija se poveže neposredno, mimo TrackerControla. Zanjo se nič ne spremlja in nič ne blokira. Uporabite to kot zadnjo možnost, če aplikacija še vedno ne deluje.\n\nOpomba: možnost \"Blokiraj povezave brez VPN\" v Androidovih nastavitvah VPN mora biti IZKLOPLJENA, da to deluje. + + + Usmeri prek oddaljenega VPN + Katere aplikacije gredo prek oddaljenega VPN. Preostale so še naprej v celoti nadzorovane in filtrirane — le povežejo se prek omrežja te naprave. + Vse aplikacije + Samo izbrane aplikacije + Oddaljeni VPN + Prek oddaljenega VPN + Ta aplikacija se poveže prek vašega oddaljenega VPN, ki namesto vašega omrežja vidi njen promet. + Neposredno s te naprave + Ta aplikacija se poveže iz vašega omrežja. Nadzor in blokiranje sledilnikov še naprej veljata. Njene poizvedbe DNS gredo na razreševalnik vašega omrežja namesto na VPN, aplikacija pa vidi pravi naslov te naprave — nekatere aplikacije to potrebujejo, na primer za dostop do lokalnih naprav ali preverjanje captive portala. + Oddaljeni VPN ni nastavljen, zato ves promet že zdaj odhaja neposredno s te naprave. + Ta aplikacija povsem obide TrackerControl, zato ni prometa za usmerjanje. + Vaš oddaljeni VPN ne prenaša vsega prometa (njegov AllowedIPs ni poln predor). Usmerjanje po aplikacijah zahteva poln predor, ker si poti delijo vse aplikacije. diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 315c0552f..98fac79ca 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -15,4 +15,18 @@ Gäller även %1$s, som delar ett Android-användar-ID med den här appen. Förbigå TrackerControl Appen ansluter direkt, utanför TrackerControl. Ingenting övervakas eller blockeras för den. Använd detta som sista utväg om appen fortfarande inte fungerar.\n\nObs: \"Blockera anslutningar utan VPN\" i Androids VPN-inställningar måste vara INAKTIVERAT för att detta ska fungera. + + + Dirigera via fjärr-VPN + Vilka appar som skickas genom fjärr-VPN:et. De som inte gör det övervakas och filtreras fortfarande fullt ut — de ansluter bara från enhetens eget nätverk. + Alla appar + Endast valda appar + Fjärr-VPN + Via fjärr-VPN:et + Den här appen ansluter via ditt fjärr-VPN, som ser dess trafik i stället för ditt nätverk. + Direkt från den här enheten + Den här appen ansluter från ditt eget nätverk. Spårarövervakning och blockering gäller fortfarande. Dess DNS-frågor går till nätverkets resolver i stället för VPN:ets, och appen ser enhetens riktiga adress — vissa appar behöver det, till exempel för att nå lokala enheter eller kontrollera en captive portal. + Inget fjärr-VPN är konfigurerat, så all trafik lämnar redan enheten direkt. + Den här appen förbigår TrackerControl helt, så det finns ingen trafik att dirigera. + Ditt fjärr-VPN bär inte all trafik (dess AllowedIPs är inte en full tunnel). Dirigering per app kräver en full tunnel, eftersom rutter delas av alla appar. diff --git a/app/src/main/res/values-ta-rIN/strings.xml b/app/src/main/res/values-ta-rIN/strings.xml index 6c1a1a946..908c36b44 100644 --- a/app/src/main/res/values-ta-rIN/strings.xml +++ b/app/src/main/res/values-ta-rIN/strings.xml @@ -24,4 +24,18 @@ இந்த ஆப்ஸுடன் Android பயனர் ஐடியைப் பகிர்ந்துகொள்ளும் %1$s-க்கும் இது பொருந்தும். TrackerControl-ஐத் தவிர் ஆப்ஸ் TrackerControl-ஐத் தவிர்த்து நேரடியாக இணைகிறது. அதற்காக எதுவும் கண்காணிக்கப்படுவதோ தடுக்கப்படுவதோ இல்லை. ஆப்ஸ் இன்னும் வேலை செய்யாவிட்டால் கடைசி வழியாக இதைப் பயன்படுத்தவும்.\n\nகுறிப்பு: இது வேலை செய்ய Android VPN அமைப்புகளில் \"VPN இல்லாத இணைப்புகளைத் தடு\" முடக்கப்பட்டிருக்க வேண்டும். + + + தொலைநிலை VPN வழியாக அனுப்பு + எந்த ஆப்ஸ் தொலைநிலை VPN வழியாகச் செல்லும். செல்லாதவையும் முழுமையாகக் கண்காணிக்கப்பட்டு தடுக்கப்படுகின்றன — அவை இந்தச் சாதனத்தின் சொந்த நெட்வொர்க்கிலிருந்து இணைகின்றன. + எல்லா ஆப்ஸும் + தேர்ந்தெடுத்த ஆப்ஸ் மட்டும் + தொலைநிலை VPN + தொலைநிலை VPN வழியாக + இந்த ஆப்ஸ் உங்கள் தொலைநிலை VPN வழியாக இணைகிறது; உங்கள் நெட்வொர்க்குக்குப் பதிலாக VPN அதன் போக்குவரத்தைப் பார்க்கிறது. + இந்தச் சாதனத்திலிருந்து நேரடியாக + இந்த ஆப்ஸ் உங்கள் சொந்த நெட்வொர்க்கிலிருந்து இணைகிறது. டிராக்கர் கண்காணிப்பும் தடுப்பும் தொடர்ந்து பொருந்தும். அதன் DNS வினவல்கள் VPN-க்குப் பதிலாக உங்கள் நெட்வொர்க்கின் தீர்ப்பானுக்குச் செல்கின்றன, மேலும் அது இந்தச் சாதனத்தின் உண்மையான முகவரியைப் பார்க்கிறது — சில ஆப்ஸுக்கு இது தேவை, எடுத்துக்காட்டாக உள்ளூர் சாதனங்களை அணுகவோ captive portal-ஐச் சரிபார்க்கவோ. + தொலைநிலை VPN எதுவும் அமைக்கப்படவில்லை, எனவே எல்லாப் போக்குவரத்தும் ஏற்கெனவே நேரடியாக இந்தச் சாதனத்திலிருந்து செல்கிறது. + இந்த ஆப்ஸ் TrackerControl-ஐ முழுமையாகத் தவிர்க்கிறது, எனவே அனுப்ப எந்தப் போக்குவரத்தும் இல்லை. + உங்கள் தொலைநிலை VPN எல்லாப் போக்குவரத்தையும் எடுத்துச் செல்வதில்லை (அதன் AllowedIPs முழு சுரங்கம் அல்ல). வழிகள் எல்லா ஆப்ஸாலும் பகிரப்படுவதால், ஆப்ஸ்வாரி வழியமைப்புக்கு முழு சுரங்கம் தேவை. diff --git a/app/src/main/res/values-te-rIN/strings.xml b/app/src/main/res/values-te-rIN/strings.xml index bcecf9644..1861f9fb2 100644 --- a/app/src/main/res/values-te-rIN/strings.xml +++ b/app/src/main/res/values-te-rIN/strings.xml @@ -24,4 +24,18 @@ ఈ యాప్‌తో Android వినియోగదారు ID‌ను పంచుకునే %1$sకు కూడా ఇది వర్తిస్తుంది. TrackerControlను దాటవేయి యాప్ TrackerControl వెలుపల నేరుగా కనెక్ట్ అవుతుంది. దాని కోసం ఏదీ పర్యవేక్షించబడదు లేదా నిరోధించబడదు. యాప్ ఇప్పటికీ పని చేయకపోతే చివరి ప్రయత్నంగా దీన్ని ఉపయోగించండి.\n\nగమనిక: ఇది పని చేయాలంటే Android VPN సెట్టింగ్‌లలో \"VPN లేకుండా కనెక్షన్‌లను నిరోధించు\" నిలిపివేయబడాలి. + + + రిమోట్ VPN ద్వారా పంపు + ఏ యాప్‌లు రిమోట్ VPN ద్వారా వెళ్తాయో నిర్ణయిస్తుంది. వెళ్లని యాప్‌లు కూడా పూర్తిగా పర్యవేక్షించబడతాయి, నిరోధించబడతాయి — అవి ఈ పరికరం సొంత నెట్‌వర్క్ నుండి కనెక్ట్ అవుతాయి. + అన్ని యాప్‌లు + ఎంచుకున్న యాప్‌లు మాత్రమే + రిమోట్ VPN + రిమోట్ VPN ద్వారా + ఈ యాప్ మీ రిమోట్ VPN ద్వారా కనెక్ట్ అవుతుంది; మీ నెట్‌వర్క్ బదులు VPN దాని ట్రాఫిక్‌ను చూస్తుంది. + ఈ పరికరం నుండి నేరుగా + ఈ యాప్ మీ సొంత నెట్‌వర్క్ నుండి కనెక్ట్ అవుతుంది. ట్రాకర్ పర్యవేక్షణ, నిరోధం ఇంకా వర్తిస్తాయి. దాని DNS ప్రశ్నలు VPN బదులు మీ నెట్‌వర్క్ రిజాల్వర్‌కు వెళ్తాయి, అలాగే అది ఈ పరికరం అసలు చిరునామాను చూస్తుంది — కొన్ని యాప్‌లకు ఇది అవసరం, ఉదాహరణకు స్థానిక పరికరాలను చేరుకోవడానికి లేదా captive portal తనిఖీకి. + రిమోట్ VPN ఏదీ సెటప్ చేయలేదు, కాబట్టి మొత్తం ట్రాఫిక్ ఇప్పటికే నేరుగా ఈ పరికరం నుండి వెళ్తోంది. + ఈ యాప్ TrackerControlను పూర్తిగా దాటవేస్తుంది, కాబట్టి పంపడానికి ట్రాఫిక్ లేదు. + మీ రిమోట్ VPN మొత్తం ట్రాఫిక్‌ను మోయదు (దాని AllowedIPs పూర్తి టన్నెల్ కాదు). మార్గాలను అన్ని యాప్‌లు పంచుకుంటాయి కాబట్టి యాప్‌వారీ రూటింగ్‌కు పూర్తి టన్నెల్ అవసరం. diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 3d4863efe..fbed1579c 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -367,4 +367,18 @@ Saygılarımla,\n\n]]> Bu uygulamayla Android kullanıcı kimliğini paylaşan %1$s için de geçerlidir. TrackerControl\'ü atla Uygulama, TrackerControl dışında doğrudan bağlanır. Onun için hiçbir şey izlenmez veya engellenmez. Uygulama hâlâ çalışmıyorsa son çare olarak bunu kullanın.\n\nNot: Bunun çalışması için Android VPN ayarlarındaki \"VPN olmadan bağlantıları engelle\" seçeneği KAPALI olmalıdır. + + + Uzak VPN üzerinden yönlendir + Hangi uygulamaların uzak VPN üzerinden iletileceği. İletilmeyenler yine tümüyle izlenir ve filtrelenir — yalnızca bu cihazın kendi ağından bağlanırlar. + Tüm uygulamalar + Yalnızca seçili uygulamalar + Uzak VPN + Uzak VPN üzerinden + Bu uygulama, trafiğini ağınız yerine gören uzak VPN\'iniz üzerinden bağlanır. + Doğrudan bu cihazdan + Bu uygulama kendi ağınızdan bağlanır. İzleyici izleme ve engelleme geçerliliğini korur. DNS sorguları VPN yerine ağınızın çözücüsüne gider ve uygulama bu cihazın gerçek adresini görür — bazı uygulamalar buna ihtiyaç duyar, örneğin yerel cihazlara erişmek veya bir captive portal denetlemek için. + Kurulu bir uzak VPN yok, bu yüzden tüm trafik zaten doğrudan bu cihazdan çıkıyor. + Bu uygulama TrackerControl\'ü tamamen atlıyor, dolayısıyla yönlendirilecek trafik yok. + Uzak VPN\'iniz tüm trafiği taşımıyor (AllowedIPs değeri tam tünel değil). Uygulama başına yönlendirme tam tünel gerektirir, çünkü rotalar tüm uygulamalarca paylaşılır. diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index a99b2c335..fec206723 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -651,4 +651,18 @@ Стосується також %1$s, який має спільний із цим застосунком ідентифікатор користувача Android. Обійти TrackerControl Застосунок з\'єднується напряму, поза TrackerControl. Для нього нічого не відстежується й не блокується. Використовуйте це як останній засіб, якщо застосунок і далі не працює.\n\nПримітка: параметр \"Блокувати з\'єднання без VPN\" у налаштуваннях VPN Android має бути ВИМКНЕНИЙ, щоб це працювало. + + + Спрямовувати через віддалений VPN + Які застосунки спрямовуються через віддалений VPN. Решта й далі повністю відстежується та фільтрується — вони просто з\'єднуються через мережу цього пристрою. + Усі застосунки + Лише вибрані застосунки + Віддалений VPN + Через віддалений VPN + Цей застосунок з\'єднується через ваш віддалений VPN, який бачить його трафік замість вашої мережі. + Напряму з цього пристрою + Цей застосунок з\'єднується через вашу власну мережу. Відстеження й блокування трекерів і далі діють. Його DNS-запити йдуть до резолвера вашої мережі, а не VPN, і він бачить справжню адресу пристрою — деяким застосункам це потрібно, наприклад для доступу до локальних пристроїв або перевірки captive portal. + Віддалений VPN не налаштовано, тож увесь трафік і так виходить напряму з цього пристрою. + Цей застосунок повністю обходить TrackerControl, тож спрямовувати нічого. + Ваш віддалений VPN передає не весь трафік (його AllowedIPs не утворює повний тунель). Маршрутизація за застосунками потребує повного тунелю, бо маршрути спільні для всіх застосунків. diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index 9a3d5f78e..dfd809fdd 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -386,4 +386,18 @@ Cũng áp dụng cho %1$s, ứng dụng dùng chung ID người dùng Android với ứng dụng này. Bỏ qua TrackerControl Ứng dụng kết nối trực tiếp, bên ngoài TrackerControl. Không có gì được giám sát hay chặn cho nó. Hãy dùng tuỳ chọn này như biện pháp cuối cùng nếu ứng dụng vẫn không hoạt động.\n\nLưu ý: \"Chặn kết nối khi không có VPN\" trong cài đặt VPN của Android phải được TẮT thì tuỳ chọn này mới hoạt động. + + + Định tuyến qua VPN từ xa + Những ứng dụng nào được chuyển tiếp qua VPN từ xa. Các ứng dụng còn lại vẫn được giám sát và chặn đầy đủ — chúng chỉ kết nối từ mạng của chính thiết bị này. + Mọi ứng dụng + Chỉ ứng dụng đã chọn + VPN từ xa + Qua VPN từ xa + Ứng dụng này kết nối qua VPN từ xa của bạn, và VPN thấy lưu lượng của nó thay vì mạng của bạn. + Trực tiếp từ thiết bị này + Ứng dụng này kết nối từ mạng của bạn. Việc giám sát và chặn trình theo dõi vẫn được áp dụng. Truy vấn DNS của nó đi tới bộ phân giải của mạng bạn thay vì của VPN, và nó thấy địa chỉ thật của thiết bị — một số ứng dụng cần điều đó, ví dụ để truy cập thiết bị nội bộ hoặc kiểm tra captive portal. + Chưa thiết lập VPN từ xa nào, nên toàn bộ lưu lượng vốn đã rời thiết bị này trực tiếp. + Ứng dụng này bỏ qua hoàn toàn TrackerControl, nên không có lưu lượng để định tuyến. + VPN từ xa của bạn không mang toàn bộ lưu lượng (AllowedIPs của nó không phải đường hầm đầy đủ). Định tuyến theo ứng dụng cần đường hầm đầy đủ, vì các tuyến được mọi ứng dụng dùng chung. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c59d20d3d..29cdcd003 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -646,4 +646,18 @@ 同样适用于 %1$s,它与此应用共用同一个 Android 用户 ID。 绕过 TrackerControl 应用将绕过 TrackerControl 直接联网,不会对其进行任何监测或拦截。仅在应用仍然无法使用时作为最后手段使用。\n\n注意:必须在 Android 的 VPN 设置中停用\"屏蔽不使用 VPN 的连接\",此项才能生效。 + + + 通过远程 VPN 转发 + 哪些应用经远程 VPN 转发。未转发的应用仍然受到完整的跟踪器监测与拦截,只是改从本机自己的网络连接。 + 所有应用 + 仅所选应用 + 远程 VPN + 经远程 VPN + 此应用经你的远程 VPN 连接,由 VPN 而非你的网络看到它的流量。 + 直接从本机连接 + 此应用从你自己的网络连接。跟踪器监测与拦截依然生效。它的 DNS 查询会发往你网络的解析器而非 VPN 的,并且它看到的是本机的真实地址——某些应用需要这样,例如访问局域网设备或检测强制门户。 + 尚未设置远程 VPN,因此所有流量已经直接从本机发出。 + 此应用完全绕过 TrackerControl,因此没有可转发的流量。 + 你的远程 VPN 并未承载全部流量(其 AllowedIPs 不是全隧道)。路由由所有应用共享,因此按应用分流需要全隧道。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9a361761d..ba4efe1f0 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -176,4 +176,18 @@ 同樣適用於 %1$s,它與此應用程式共用同一個 Android 使用者 ID。 略過 TrackerControl 應用程式會略過 TrackerControl 直接連線,不會對其進行任何監控或封鎖。僅在應用程式仍無法使用時作為最後手段使用。\n\n注意:必須在 Android 的 VPN 設定中停用\"封鎖不使用 VPN 的連線\",此項才會生效。 + + + 透過遠端 VPN 轉送 + 哪些應用程式經遠端 VPN 轉送。未轉送的應用程式仍受到完整的追蹤器監控與封鎖,只是改從本機自己的網路連線。 + 所有應用程式 + 僅所選應用程式 + 遠端 VPN + 經遠端 VPN + 此應用程式經你的遠端 VPN 連線,由 VPN 而非你的網路看到它的流量。 + 直接從本機連線 + 此應用程式從你自己的網路連線。追蹤器監控與封鎖仍然生效。它的 DNS 查詢會送往你網路的解析器而非 VPN 的,而且它看到的是本機的真實位址——某些應用程式需要這樣,例如存取區域網路裝置或偵測強制網路入口。 + 尚未設定遠端 VPN,因此所有流量已經直接從本機送出。 + 此應用程式完全略過 TrackerControl,因此沒有可轉送的流量。 + 你的遠端 VPN 並未承載全部流量(其 AllowedIPs 不是全隧道)。路由由所有應用程式共用,因此依應用程式分流需要全隧道。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ff419dad..87e15a8bd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -458,6 +458,16 @@ Your internet traffic is not being sent to a remote VPN server. strict + + @string/wg_route_mode_all + @string/wg_route_mode_selected + + + + all + selected + + Verbose Debug @@ -631,6 +641,21 @@ Sincerely,\n\n]]> Research No tracker blocking. Logs transmissions to ADB and enables SNI extraction for better hostname detection. Research only: this leaks your IP address to tracker servers. + + Route through remote VPN + Which apps are forwarded through the remote VPN. Apps that are not still get full tracker monitoring and blocking — they simply connect from this device\'s own network. + All apps + Only selected apps + + Remote VPN + Through the remote VPN + This app connects through your remote VPN, which sees its traffic instead of your network. + Directly from this device + This app connects from your own network. Tracker monitoring and blocking still apply. Its DNS queries go to your network\'s resolver rather than the VPN\'s, and it sees this device\'s real address — some apps need that, for example to reach local devices or check a captive portal. + No remote VPN is set up, so all traffic already leaves from this device. + This app bypasses TrackerControl entirely, so there is no traffic to route. + Your remote VPN does not carry all traffic (its AllowedIPs is not a full tunnel). Per-app routing needs a full tunnel, because routes are shared by every app. + Protection Protected diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index df0c9b6f5..7097d1925 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -219,6 +219,13 @@ android:key="wg_profile_manage" android:summary="@string/summary_wg_profile_manage" android:title="@string/setting_wg_profile_manage" /> +