diff --git a/.gitignore b/.gitignore index e6e450a7a07ef2a5fc622e9ebe122b7f5d037564..66acf8dce544d5c249bc8f0e2da9d73e27e4fe1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,11 @@ *.iml .gradle /local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml +.idea .DS_Store /build /captures .externalNativeBuild .cxx -.idea/ /src/main/libs /src/main/obj diff --git a/build.gradle b/build.gradle index 560fe8042a631eed7cd39e731c22ebea3556dfd4..dc9a9865218ea9ab3d2e59f19c65b87567d2948a 100644 --- a/build.gradle +++ b/build.gradle @@ -6,16 +6,9 @@ apply from : '../exportdependencies/publish.gradle' android { ndkVersion '21.3.6528147' - /** - sourceSets { - main { - jniLibs.srcDirs = ['./src/main/libs'] - } - }**/ - defaultConfig { minSdkVersion 24 - targetSdkVersion 31 + targetSdkVersion 33 } buildTypes { @@ -24,35 +17,38 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + packagingOptions { + resources { + excludes += ['META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version'] + } + } - - lintOptions { - checkReleaseBuilds false + lint { abortOnError true + checkReleaseBuilds false + disable "InvalidPackage" htmlReport true - xmlReport false - textReport false lintConfig file("../lint.xml") - disable "InvalidPackage" - } - - packagingOptions { - exclude 'META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version' + textReport false + xmlReport false } + namespace 'org.torproject.android.service' } dependencies { api orbotlibs.guardian_jtorctl + api orbotlibs.orbotlib + + api orbotlibs.tor_android + implementation( orbotlibs.android_shell, orbotlibs.androidx_core, orbotlibs.androidx_localbroadcast, - orbotlibs.ipt_proxy, orbotlibs.guardian_geoip, - orbotlibs.guardian_jsocks, - orbotlibs.portmapper, - orbotlibs.tor_android, orbotlibs.pcap_core, - orbotlibs.pcap_factory + orbotlibs.pcap_factory, + orbotlibs.androidx_work, + orbotlibs.androidx_work_kotlin ) } diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 0b300c68a6341a3e0d51be5c80ed0a2fdb01f6b3..335ae6e615669f469d7e29f5c0635033b12f0c9f 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/src/main/assets/fronts b/src/main/assets/fronts index 5270295871b00ef2185789acc98f717ed27ccafc..606349c8662c914a6dc23930596d34736d6eda41 100644 --- a/src/main/assets/fronts +++ b/src/main/assets/fronts @@ -1,12 +1,14 @@ snowflake-target https://snowflake-broker.torproject.net.global.prod.fastly.net/ -snowflake-fingerprint 2B280B23E1107BB62ABFC40DDCC8824814F80A72 -snowflake-front cdn.sstatic.net -snowflake-alt-front ajax.aspnetcdn.com -snowflake-alt-target https://snowflake-broker.azureedge.net/ -snowflake-stun stun:stun.l.google.com:19302,stun:stun.voip.blackberry.com:3478,stun:stun.altar.com.pl:3478,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.sonetel.net:3478,stun:stun.stunprotocol.org:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 +snowflake-front github.githubassets.com +snowflake-stun stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.sonetel.net:3478,stun:stun.stunprotocol.org:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 +snowflake-target-direct https://snowflake-broker.torproject.net/ +snowflake-amp-front www.google.com +snowflake-amp-cache https://cdn.ampproject.org/ moat-cdn https://d50gd378qj74g.cloudfront.net/ moat-url https://moat.torproject.org.global.prod.fastly.net/ -moat-front cdn.sstatic.net -snowflake-amp-target https://snowflake-broker.torproject.net/ -snowflake-amp-front www.google.com -snowflake-amp-cache https://cdn.ampproject.org/ \ No newline at end of file +moat-front github.githubassets.com +snowflake-relay-url wss://snowflake.bamsoftware.com +snowflake-nat-probe https://snowflake-broker.torproject.net:8443/probe +snowflake-broker-1 snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=github.githubassets.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn +snowflake-broker-2 snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=github.githubassets.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn +snowflake-proxy-stun stun:stun.l.google.com:19302 diff --git a/src/main/java/org/torproject/android/service/OrbotConstants.java b/src/main/java/org/torproject/android/service/OrbotConstants.java index 4a477600abd763f736294202351cdf359718ce25..189a210b976f66dca1b873047d81c7647c642fa0 100644 --- a/src/main/java/org/torproject/android/service/OrbotConstants.java +++ b/src/main/java/org/torproject/android/service/OrbotConstants.java @@ -5,6 +5,8 @@ package org.torproject.android.service; import android.content.Intent; +import org.torproject.jni.TorService; + import java.util.Arrays; import java.util.List; @@ -18,8 +20,6 @@ public interface OrbotConstants { String PREF_REACHABLE_ADDRESSES = "pref_reachable_addresses"; String PREF_REACHABLE_ADDRESSES_PORTS = "pref_reachable_addresses_ports"; - String PREF_DISABLE_NETWORK = "pref_disable_network"; - String PREF_TOR_SHARED_PREFS = "org.torproject.android_preferences"; String PREF_SOCKS = "pref_socks"; @@ -27,6 +27,8 @@ public interface OrbotConstants { String PREF_HTTP = "pref_http"; String PREF_ISOLATE_DEST = "pref_isolate_dest"; + String PREF_ISOLATE_PORT = "pref_isolate_port"; + String PREF_ISOLATE_PROTOCOL = "pref_isolate_protocol"; String PREF_CONNECTION_PADDING = "pref_connection_padding"; String PREF_REDUCED_CONNECTION_PADDING = "pref_reduced_connection_padding"; @@ -43,13 +45,11 @@ public interface OrbotConstants { String DIRECTORY_TOR_DATA = "tordata"; - String LOG_SNOWFLAKE = "snowflake-log"; //geoip data file asset key String GEOIP_ASSET_KEY = "geoip"; String GEOIP6_ASSET_KEY = "geoip6"; - String IP_LOCALHOST = "127.0.0.1"; int TOR_TRANSPROXY_PORT_DEFAULT = 9040; int TOR_DNS_PORT_DEFAULT = 5400; @@ -64,7 +64,7 @@ public interface OrbotConstants { /** * A request to Orbot to transparently start Tor services */ - String ACTION_START = "org.torproject.android.intent.action.START"; + String ACTION_START = TorService.ACTION_START; String ACTION_STOP = "org.torproject.android.intent.action.STOP"; // needed when Orbot exits and tor is not running, but the notification is still active @@ -74,28 +74,28 @@ public interface OrbotConstants { String ACTION_STOP_VPN = "org.torproject.android.intent.action.STOP_VPN"; String ACTION_RESTART_VPN = "org.torproject.android.intent.action.RESTART_VPN"; + String ACTION_LOCAL_LOCALE_SET = "org.torproject.android.intent.LOCAL_LOCALE_SET"; String ACTION_UPDATE_ONION_NAMES = "org.torproject.android.intent.action.UPDATE_ONION_NAMES"; /** * {@link Intent} send by Orbot with {@code ON/OFF/STARTING/STOPPING} status */ - String ACTION_STATUS = "org.torproject.android.intent.action.STATUS"; + String ACTION_STATUS = TorService.ACTION_STATUS; String ACTION_CHECK_RUNNING_SYNC = "org.torproject.android.intent.action.CHECK_RUNNING_SYNC"; String ACTION_RUNNING_SYNC = "org.torproject.android.intent.action.RUNNING_SYNC"; - /** * {@code String} that contains a status constant: {@link #STATUS_ON}, * {@link #STATUS_OFF}, {@link #STATUS_STARTING}, or * {@link #STATUS_STOPPING} */ - String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS"; + String EXTRA_STATUS = TorService.EXTRA_STATUS; /** * A {@link String} {@code packageName} for Orbot to direct its status reply * to, used in {@link #ACTION_START} {@link Intent}s sent to Orbot */ - String EXTRA_PACKAGE_NAME = "org.torproject.android.intent.extra.PACKAGE_NAME"; + String EXTRA_PACKAGE_NAME = TorService.EXTRA_PACKAGE_NAME; /** * The SOCKS proxy settings in URL form. */ @@ -111,28 +111,44 @@ public interface OrbotConstants { String EXTRA_DNS_PORT = "org.torproject.android.intent.extra.DNS_PORT"; String EXTRA_TRANS_PORT = "org.torproject.android.intent.extra.TRANS_PORT"; + /** + * When present, indicates with certainty that the system itself did *not* send the Intent. + * Effectively, the lack of this extra indicates that the VPN is being started by the system + * as a result of the user's always-on preference for the VPN. + * See: + * Detect always-on | VPN | Android Developers + */ + String EXTRA_NOT_SYSTEM = "org.torproject.android.intent.extra.NOT_SYSTEM"; String LOCAL_ACTION_LOG = "log"; String LOCAL_ACTION_STATUS = "status"; String LOCAL_ACTION_BANDWIDTH = "bandwidth"; + String LOCAL_EXTRA_TOTAL_READ = "totalRead"; + String LOCAL_EXTRA_TOTAL_WRITTEN = "totalWritten"; + String LOCAL_EXTRA_LAST_WRITTEN = "lastWritten"; + String LOCAL_EXTRA_LAST_READ = "lastRead"; String LOCAL_EXTRA_LOG = "log"; + String LOCAL_EXTRA_BOOTSTRAP_PERCENT = "percent"; String LOCAL_ACTION_PORTS = "ports"; String LOCAL_ACTION_V3_NAMES_UPDATED = "V3_NAMES_UPDATED"; String LOCAL_ACTION_NOTIFICATION_START = "notification_start"; - String LOCAL_ACTION_SNOWFLAKE_PROXY = "action_snowflake_proxy"; + String LOCAL_ACTION_SMART_CONNECT_EVENT = "smart"; + String LOCAL_EXTRA_SMART_STATUS = "status"; + String SMART_STATUS_NO_DIRECT = "no_direct"; + String SMART_STATUS_CIRCUMVENTION_ATTEMPT_FAILED = "bad_attempt_suggestion"; /** * All tor-related services and daemons are stopped */ - String STATUS_OFF = "OFF"; + String STATUS_OFF = TorService.STATUS_OFF; /** * All tor-related services and daemons have completed starting */ - String STATUS_ON = "ON"; - String STATUS_STARTING = "STARTING"; - String STATUS_STOPPING = "STOPPING"; + String STATUS_ON = TorService.STATUS_ON; + String STATUS_STARTING = TorService.STATUS_STARTING; + String STATUS_STOPPING = TorService.STATUS_STOPPING; /** * The user has disabled the ability for background starts triggered by @@ -144,6 +160,7 @@ public interface OrbotConstants { // actions for internal command Intents String CMD_SET_EXIT = "setexit"; String CMD_ACTIVE = "ACTIVE"; + String CMD_SNOWFLAKE_PROXY = "sf_proxy"; String ONION_SERVICES_DIR = "v3_onion_services"; String V3_CLIENT_AUTH_DIR = "v3_client_auth"; @@ -153,16 +170,19 @@ public interface OrbotConstants { String PREFS_KEY_TORIFIED = "PrefTord"; /** - * Include packages here to make the VPNService ignore these apps (On Lollipop+). This is to + * Include packages here to make the VPNService ignore these apps. This is to * prevent tor over tor scenarios... */ - List BYPASS_VPN_PACKAGES = Arrays.asList("org.torproject.torbrowser_alpha", + List BYPASS_VPN_PACKAGES = Arrays.asList( + "org.torproject.torbrowser_alpha", "org.torproject.torbrowser", "org.onionshare.android", // issue #618 - "org.briarproject.briar.android" // https://github.com/guardianproject/orbot/issues/474 + "org.briarproject.briar.android", // https://github.com/guardianproject/orbot/issues/474 + "org.torproject.android" // /e/OS update : bypass Orbot app, if used as proxy. ); - String SNOWFLAKE_EMOJI = "❄️"; - String SNOWFLAKE_PROXY_EMOJI = "\uD83D\uDCF2"; + List VPN_SUGGESTED_APPS = Arrays.asList("org.thoughtcrime.securesms", // Signal + "com.whatsapp", "com.instagram.android", "im.vector.app", "org.telegram.messenger", "com.twitter.android", "com.facebook.orca", "com.facebook.mlite", "com.brave.browser", "org.mozilla.focus"); + String ONION_EMOJI = "\uD83E\uDDC5"; } diff --git a/src/main/java/org/torproject/android/service/OrbotRawEventListener.java b/src/main/java/org/torproject/android/service/OrbotRawEventListener.java index 3a27e1a6271b264a2c3bc558df350153308d008c..85726a671b5403cbbc6a749899171c302e7ccd54 100644 --- a/src/main/java/org/torproject/android/service/OrbotRawEventListener.java +++ b/src/main/java/org/torproject/android/service/OrbotRawEventListener.java @@ -18,8 +18,8 @@ public class OrbotRawEventListener implements RawEventListener { private final OrbotService mService; private long mTotalBandwidthWritten, mTotalBandwidthRead; private final Map hmBuiltNodes; - private Map exitNodeMap; - private Set ignoredInternalCircuits; + private final Map exitNodeMap; + private final Set ignoredInternalCircuits; private static final String CIRCUIT_BUILD_FLAG_IS_INTERNAL = "IS_INTERNAL"; private static final String CIRCUIT_BUILD_FLAG_ONE_HOP_TUNNEL = "ONEHOP_TUNNEL"; @@ -30,10 +30,9 @@ public class OrbotRawEventListener implements RawEventListener { mTotalBandwidthWritten = 0; hmBuiltNodes = new HashMap<>(); - if (Prefs.showExpandedNotifications()) { - exitNodeMap = new HashMap<>(); - ignoredInternalCircuits = new HashSet<>(); - } + exitNodeMap = new HashMap<>(); + ignoredInternalCircuits = new HashSet<>(); + } @Override @@ -44,10 +43,10 @@ public class OrbotRawEventListener implements RawEventListener { } else if (TorControlCommands.EVENT_NEW_DESC.equals(keyword)) { handleNewDescriptors(payload); } else if (TorControlCommands.EVENT_STREAM_STATUS.equals(keyword)) { - if (Prefs.showExpandedNotifications()) - handleStreamEventExpandedNotifications(payload[1], payload[3], payload[2], payload[4]); - if (Prefs.useDebugLogging()) - handleStreamEventsDebugLogging(payload[1], payload[0]); + + handleStreamEventExpandedNotifications(payload[1], payload[3], payload[2], payload[4]); + + if (Prefs.useDebugLogging()) handleStreamEventsDebugLogging(payload[1], payload[0]); } else if (TorControlCommands.EVENT_CIRCUIT_STATUS.equals(keyword)) { String status = payload[1]; String circuitId = payload[0]; @@ -56,18 +55,16 @@ public class OrbotRawEventListener implements RawEventListener { path = ""; else path = payload[2]; handleCircuitStatus(status, circuitId, path); - if (Prefs.showExpandedNotifications()) { - // don't bother looking up internal circuits that Orbot clients won't directly use - if (data.contains(CIRCUIT_BUILD_FLAG_ONE_HOP_TUNNEL) || data.contains(CIRCUIT_BUILD_FLAG_IS_INTERNAL)) { - ignoredInternalCircuits.add(Integer.parseInt(circuitId)); - } - handleCircuitStatusExpandedNotifications(status, circuitId, path); + + // don't bother looking up internal circuits that Orbot clients won't directly use + if (data.contains(CIRCUIT_BUILD_FLAG_ONE_HOP_TUNNEL) || data.contains(CIRCUIT_BUILD_FLAG_IS_INTERNAL)) { + ignoredInternalCircuits.add(Integer.parseInt(circuitId)); } + handleCircuitStatusExpandedNotifications(status, circuitId, path); + } else if (TorControlCommands.EVENT_OR_CONN_STATUS.equals(keyword)) { handleConnectionStatus(payload[1], payload[0]); - } else if (TorControlCommands.EVENT_DEBUG_MSG.equals(keyword) || TorControlCommands.EVENT_INFO_MSG.equals(keyword) || - TorControlCommands.EVENT_NOTICE_MSG.equals(keyword) || TorControlCommands.EVENT_WARN_MSG.equals(keyword) || - TorControlCommands.EVENT_ERR_MSG.equals(keyword)) { + } else if (TorControlCommands.EVENT_DEBUG_MSG.equals(keyword) || TorControlCommands.EVENT_INFO_MSG.equals(keyword) || TorControlCommands.EVENT_NOTICE_MSG.equals(keyword) || TorControlCommands.EVENT_WARN_MSG.equals(keyword) || TorControlCommands.EVENT_ERR_MSG.equals(keyword)) { handleDebugMessage(keyword, data); } else { String unrecognized = "Message (" + keyword + "): " + data; @@ -76,8 +73,7 @@ public class OrbotRawEventListener implements RawEventListener { } private void handleBandwidth(long read, long written) { - String message = OrbotService.formatBandwidthCount(mService, read) + " \u2193" + " / " + - OrbotService.formatBandwidthCount(mService, written) + " \u2191"; + String message = OrbotService.formatBandwidthCount(mService, read) + " ↓ / " + OrbotService.formatBandwidthCount(mService, written) + " ↑"; if (mService.getCurrentStatus().equals(TorService.STATUS_ON)) mService.showBandwidthNotification(message, read != 0 || written != 0); @@ -98,7 +94,8 @@ public class OrbotRawEventListener implements RawEventListener { if (!status.equals(TorControlCommands.STREAM_EVENT_SUCCEEDED)) return; if (!clientProtocol.contains("SOCKS5")) return; int id = Integer.parseInt(circuitId); - if (target.contains(".onion")) return; // don't display to users exit node info for onion addresses! + if (target.contains(".onion")) + return; // don't display to users exit node info for onion addresses! ExitNode node = exitNodeMap.get(id); if (node != null) { if (node.country == null && !node.querying) { @@ -118,8 +115,7 @@ public class OrbotRawEventListener implements RawEventListener { } }); } else { - if (node.country != null) - mService.setNotificationSubtext(node.toString()); + if (node.country != null) mService.setNotificationSubtext(node.toString()); else mService.setNotificationSubtext(null); } } @@ -133,17 +129,20 @@ public class OrbotRawEventListener implements RawEventListener { private void handleCircuitStatusExpandedNotifications(String circuitStatus, String circuitId, String path) { int id = Integer.parseInt(circuitId); - if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_BUILT)) { - if (ignoredInternalCircuits.contains(id)) return; // this circuit won't be used by user clients - String[] nodes = path.split(","); - String exit = nodes[nodes.length - 1]; - String fingerprint = exit.split("~")[0]; - exitNodeMap.put(id, new ExitNode(fingerprint)); - } else if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_CLOSED)) { - exitNodeMap.remove(id); - ignoredInternalCircuits.remove(id); - } else if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_FAILED)) { - ignoredInternalCircuits.remove(id); + switch (circuitStatus) { + case TorControlCommands.CIRC_EVENT_BUILT -> { + if (ignoredInternalCircuits.contains(id)) + return; // this circuit won't be used by user clients + String[] nodes = path.split(","); + String exit = nodes[nodes.length - 1]; + String fingerprint = exit.split("~")[0]; + exitNodeMap.put(id, new ExitNode(fingerprint)); + } + case TorControlCommands.CIRC_EVENT_CLOSED -> { + exitNodeMap.remove(id); + ignoredInternalCircuits.remove(id); + } + case TorControlCommands.CIRC_EVENT_FAILED -> ignoredInternalCircuits.remove(id); } } @@ -169,10 +168,8 @@ public class OrbotRawEventListener implements RawEventListener { String[] nodeParts; - if (nodePath.contains("=")) - nodeParts = nodePath.split("="); - else - nodeParts = nodePath.split("~"); + if (nodePath.contains("=")) nodeParts = nodePath.split("="); + else nodeParts = nodePath.split("~"); if (nodeParts.length == 1) { nodeId = nodeParts[0].substring(1); @@ -182,8 +179,7 @@ public class OrbotRawEventListener implements RawEventListener { nodeName = nodeParts[1]; } - if (nodeId == null) - continue; + if (nodeId == null) continue; node = hmBuiltNodes.get(nodeId); @@ -197,15 +193,13 @@ public class OrbotRawEventListener implements RawEventListener { sb.append(node.name); - if (st.hasMoreTokens()) - sb.append(" > "); + if (st.hasMoreTokens()) sb.append(" > "); if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_EXTENDED) && isFirstNode) { hmBuiltNodes.put(node.id, node); isFirstNode = false; } else if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_LAUNCHED)) { - if (Prefs.useDebugLogging() && nodeCount > 3) - mService.debug(sb.toString()); + if (Prefs.useDebugLogging() && nodeCount > 3) mService.debug(sb.toString()); } else if (circuitStatus.equals(TorControlCommands.CIRC_EVENT_CLOSED)) { hmBuiltNodes.remove(node.id); } @@ -219,10 +213,8 @@ public class OrbotRawEventListener implements RawEventListener { } private void handleDebugMessage(String severity, String message) { - if (severity.equalsIgnoreCase("debug")) - mService.debug(severity + ": " + message); - else - mService.logNotice(severity + ": " + message); + if (severity.equalsIgnoreCase("debug")) mService.debug(severity + ": " + message); + else mService.logNotice(severity + ": " + message); } public Map getNodes() { @@ -236,6 +228,7 @@ public class OrbotRawEventListener implements RawEventListener { ExitNode(String fingerPrint) { this.fingerPrint = fingerPrint; } + public final String fingerPrint; public String country; public String ipAddress; diff --git a/src/main/java/org/torproject/android/service/OrbotService.java b/src/main/java/org/torproject/android/service/OrbotService.java index 26bd1332caa305fe025886f27b095943c508a219..f1b86e9a298c9c532b859c04fdb351804c03ff2e 100644 --- a/src/main/java/org/torproject/android/service/OrbotService.java +++ b/src/main/java/org/torproject/android/service/OrbotService.java @@ -20,11 +20,17 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.res.Configuration; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; import android.net.Uri; import android.net.VpnService; import android.os.Build; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; @@ -35,6 +41,8 @@ import net.freehaven.tor.control.TorControlConnection; import org.pcap4j.packet.DnsPacket; import org.torproject.android.service.util.CustomTorResourceInstaller; +import org.torproject.android.service.util.CustomTorResourceInstaller; +import org.torproject.android.service.util.PowerConnectionReceiver; import org.torproject.android.service.util.Prefs; import org.torproject.android.service.util.Utils; import org.torproject.android.service.vpn.OrbotVpnManager; @@ -50,6 +58,13 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; +import java.security.SecureRandom; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import java.util.Objects; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; @@ -66,6 +81,10 @@ import java.util.function.Function; import IPtProxy.IPtProxy; import androidx.annotation.ChecksSdkIntAtLeast; + +import IPtProxy.IPtProxy; + +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -77,18 +96,16 @@ public class OrbotService extends VpnService implements OrbotConstants { public static Function shouldBlock = null; + static final int NOTIFY_ID = 1; private static final int ERROR_NOTIFY_ID = 3; - private static final Uri V3_ONION_SERVICES_CONTENT_URI = Uri.parse("content://org.torproject.android.ui.v3onionservice/v3"); - private static final Uri V3_CLIENT_AUTH_URI = Uri.parse("content://org.torproject.android.ui.v3onionservice.clientauth/v3auth"); + + //these will be set dynamically due to build flavors + private static Uri V3_ONION_SERVICES_CONTENT_URI = null;//Uri.parse("content://org.torproject.android.ui.v3onionservice/v3"); + private static Uri V3_CLIENT_AUTH_URI = null;//Uri.parse("content://org.torproject.android.ui.v3onionservice.clientauth/v3auth"); private final static String NOTIFICATION_CHANNEL_ID = "orbot_channel_1"; - private static final String[] V3_ONION_SERVICE_PROJECTION = new String[]{ - OnionService._ID, OnionService.NAME, OnionService.DOMAIN, - OnionService.PORT, OnionService.ONION_PORT, OnionService.ENABLED, OnionService.PATH - }; - private static final String[] V3_CLIENT_AUTH_PROJECTION = new String[]{ - V3ClientAuth._ID, V3ClientAuth.DOMAIN, V3ClientAuth.HASH, V3ClientAuth.ENABLED - }; + private static final String[] V3_ONION_SERVICE_PROJECTION = new String[]{OnionService._ID, OnionService.NAME, OnionService.DOMAIN, OnionService.PORT, OnionService.ONION_PORT, OnionService.ENABLED, OnionService.PATH}; + private static final String[] V3_CLIENT_AUTH_PROJECTION = new String[]{V3ClientAuth._ID, V3ClientAuth.DOMAIN, V3ClientAuth.HASH, V3ClientAuth.ENABLED}; public static int mPortSOCKS = -1; public static int mPortHTTP = -1; @@ -97,13 +114,9 @@ public class OrbotService extends VpnService implements OrbotConstants { public static File appBinHome; public static File appCacheHome; private final ExecutorService mExecutor = Executors.newCachedThreadPool(); - @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.LOLLIPOP) - final boolean mIsLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; OrbotRawEventListener mOrbotRawEventListener; OrbotVpnManager mVpnManager; Handler mHandler; - //we should randomly sort alBridges so we don't have the same bridge order each time - final Random bridgeSelectRandom = new Random(System.nanoTime()); ActionBroadcastReceiver mActionBroadcastReceiver; private IsServiceRunningBroadcastReceiver mIsServiceRunningBroadcastReceiver; private String mCurrentStatus = STATUS_OFF; @@ -113,8 +126,11 @@ public class OrbotService extends VpnService implements OrbotConstants { private NotificationManager mNotificationManager = null; private NotificationCompat.Builder mNotifyBuilder; private File mV3OnionBasePath, mV3AuthBasePath; - private ArrayList alBridges = null; - private int snowflakeClientsConnected; + + private PowerConnectionReceiver mPowerReceiver; + + private boolean mHasPower = false; + private boolean mHasWifi = false; /** * @param bridgeList bridges that were manually entered into Orbot settings @@ -140,9 +156,8 @@ public class OrbotService extends VpnService implements OrbotConstants { var baos = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(baos)); - sendCallbackLogMessage(msg + '\n' + baos.toString()); - } else - sendCallbackLogMessage(msg); + sendCallbackLogMessage(msg + '\n' + baos); + } else sendCallbackLogMessage(msg); } @@ -156,15 +171,14 @@ public class OrbotService extends VpnService implements OrbotConstants { @Override public void onLowMemory() { super.onLowMemory(); - // logNotice(getString(R.string.log_notice_low_memory_warning)); + //this doesn't need to be shown to the user unless there is something to do + debug(getString(R.string.log_notice_low_memory_warning)); } private void clearNotifications() { - if (mNotificationManager != null) - mNotificationManager.cancel(NOTIFY_ID); + if (mNotificationManager != null) mNotificationManager.cancelAll(); - if (mOrbotRawEventListener != null) - mOrbotRawEventListener.getNodes().clear(); + if (mOrbotRawEventListener != null) mOrbotRawEventListener.getNodes().clear(); } @RequiresApi(api = Build.VERSION_CODES.O) @@ -190,10 +204,7 @@ public class OrbotService extends VpnService implements OrbotConstants { if (mNotifyBuilder == null) { mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - mNotifyBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) - .setSmallIcon(R.drawable.ic_stat_tor) - .setContentIntent(pendIntent) - .setCategory(Notification.CATEGORY_SERVICE); + mNotifyBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID).setSmallIcon(R.drawable.ic_stat_tor).setContentIntent(pendIntent).setCategory(Notification.CATEGORY_SERVICE); } mNotifyBuilder.setOngoing(true); @@ -203,25 +214,20 @@ public class OrbotService extends VpnService implements OrbotConstants { title = getString(R.string.status_starting_up); else if (mCurrentStatus.equals(STATUS_ON)) { title = getString(R.string.status_activated); - if (IPtProxy.isSnowflakeProxyRunning()) { - title += " (" + SNOWFLAKE_EMOJI + " " + snowflakeClientsConnected + ")"; - } } mNotifyBuilder.setContentTitle(title); mNotifyBuilder.mActions.clear(); // clear out any notification actions, if any if (conn != null && mCurrentStatus.equals(STATUS_ON)) { // only add new identity action when there is a connection - var pendingIntentNewNym = PendingIntent.getBroadcast(this, 0, new Intent(TorControlCommands.SIGNAL_NEWNYM), PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE); + var pendingIntentNewNym = PendingIntent.getBroadcast(this, 0, new Intent(TorControlCommands.SIGNAL_NEWNYM), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mNotifyBuilder.addAction(R.drawable.ic_refresh_white_24dp, getString(R.string.menu_new_identity), pendingIntentNewNym); } else if (mCurrentStatus.equals(STATUS_OFF)) { - var pendingIntentConnect = PendingIntent.getBroadcast(this, 0, new Intent(LOCAL_ACTION_NOTIFICATION_START), PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE); + var pendingIntentConnect = PendingIntent.getBroadcast(this, 0, new Intent(LOCAL_ACTION_NOTIFICATION_START), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mNotifyBuilder.addAction(R.drawable.ic_stat_tor, getString(R.string.connect_to_tor), pendingIntentConnect); } - mNotifyBuilder.setContentText(notifyMsg) - .setSmallIcon(icon) - .setTicker(notifyType != NOTIFY_ID ? notifyMsg : null); + mNotifyBuilder.setContentText(notifyMsg).setSmallIcon(icon).setTicker(notifyType != NOTIFY_ID ? notifyMsg : null); if (!mCurrentStatus.equals(STATUS_ON)) { mNotifyBuilder.setSubText(null); @@ -235,13 +241,35 @@ public class OrbotService extends VpnService implements OrbotConstants { } public int onStartCommand(Intent intent, int flags, int startId) { - if (mCurrentStatus.equals(STATUS_OFF)) - showToolbarNotification(getString(R.string.open_orbot_to_connect_to_tor), NOTIFY_ID, R.drawable.ic_stat_tor); + try { + if (intent == null) { + Log.d(TAG, "Got null onStartCommand() intent"); + return Service.START_REDELIVER_INTENT; + } - if (intent != null) - mExecutor.execute(new IncomingIntentRouter(intent)); - else - Log.d(TAG, "Got null onStartCommand() intent"); + final boolean shouldStartVpnFromSystemIntent = !intent.getBooleanExtra(OrbotConstants.EXTRA_NOT_SYSTEM, false); + + if (mCurrentStatus.equals(STATUS_OFF)) + showToolbarNotification(getString(R.string.open_orbot_to_connect_to_tor), NOTIFY_ID, R.drawable.ic_stat_tor); + + if (shouldStartVpnFromSystemIntent) { + Log.d(TAG, "Starting VPN from system intent: " + intent); + showToolbarNotification(getString(R.string.status_starting_up), NOTIFY_ID, R.drawable.ic_stat_tor); + if (VpnService.prepare(this) == null) { + // Power-user mode doesn't matter here. If the system is starting the VPN, i.e. + // via always-on VPN, we need to start it regardless. + Prefs.putUseVpn(true); + mExecutor.execute(new IncomingIntentRouter(new Intent(ACTION_START))); + mExecutor.execute(new IncomingIntentRouter(new Intent(ACTION_START_VPN))); + } else { + Log.wtf(TAG, "Could not start VPN from system because it is not prepared, which should be impossible!"); + } + } else { + mExecutor.execute(new IncomingIntentRouter(intent)); + } + } catch (RuntimeException re) { + //catch this to avoid malicious launches as document Cure53 Audit: ORB-01-009 WP1/2: Orbot DoS via exported activity (High) + } return Service.START_REDELIVER_INTENT; } @@ -254,6 +282,15 @@ public class OrbotService extends VpnService implements OrbotConstants { public void onDestroy() { try { unregisterReceiver(mActionBroadcastReceiver); + + unregisterReceiver(mPowerReceiver); + + ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + connMgr.unregisterNetworkCallback(netCall); + } + LocalBroadcastManager.getInstance(this).unregisterReceiver(mIsServiceRunningBroadcastReceiver); } catch (IllegalArgumentException iae) { //not registered yet @@ -266,18 +303,14 @@ public class OrbotService extends VpnService implements OrbotConstants { if (showNotification) sendCallbackLogMessage(getString(R.string.status_shutting_down)); - if (Prefs.bridgesEnabled()) { - if (useIPtObfsMeekProxy()) - IPtProxy.stopObfs4Proxy(); - else if (useIPtSnowflakeProxyDomainFronting()||useIPtSnowflakeProxyAMPRendezvous()) { - IPtProxy.stopSnowflake(); - File fileLog = new File(appCacheHome, LOG_SNOWFLAKE); - if (fileLog.exists()) - fileLog.delete(); - } + var connectionPathway = Prefs.getConnectionPathway(); + // todo this needs to handle a lot of different cases that haven't been defined yet + // todo particularly this is true for the smart connection case... + if (connectionPathway.startsWith(Prefs.PATHWAY_SNOWFLAKE) || Prefs.getPrefSmartTrySnowflake()) { + IPtProxy.stopSnowflake(); + } else if (connectionPathway.equals(Prefs.PATHWAY_CUSTOM) || Prefs.getPrefSmartTryObfs4() != null) { + IPtProxy.stopLyrebird(); } - else if (Prefs.beSnowflakeProxy()) - disableSnowflakeProxy(); stopTor(); @@ -299,38 +332,23 @@ public class OrbotService extends VpnService implements OrbotConstants { private void stopTorOnError(String message) { stopTorAsync(false); - showToolbarNotification( - getString(R.string.unable_to_start_tor) + ": " + message, - ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); + showToolbarNotification(getString(R.string.unable_to_start_tor) + ": " + message, ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); } - private static boolean useIPtObfsMeekProxy() { - var bridgeList = Prefs.getBridgesList(); - return bridgeList.contains("obfs") || bridgeList.contains("meek"); - } + private static HashMap mFronts; - private static boolean useIPtSnowflakeProxyDomainFronting() { - return Prefs.getBridgesList().equals("snowflake"); - } - - private static boolean useIPtSnowflakeProxyAMPRendezvous() { - return Prefs.getBridgesList().equals("snowflake-amp"); - } - - private static HashMap mFronts; - - public static void loadCdnFronts (Context context) { + public static void loadCdnFronts(Context context) { if (mFronts == null) { mFronts = new HashMap<>(); try { var reader = new BufferedReader(new InputStreamReader(context.getAssets().open("fronts"))); String line; - while ((line = reader.readLine())!=null) { - String[] front = line.split(" "); - //add some code to test the connection here - - mFronts.put(front[0],front[1]); + while ((line = reader.readLine()) != null) { + int spaceIdx = line.indexOf(' '); + String key = line.substring(0, spaceIdx); + String val = line.substring(spaceIdx + 1); + mFronts.put(key, val); } reader.close(); } catch (IOException e) { @@ -348,76 +366,147 @@ public class OrbotService extends VpnService implements OrbotConstants { //this is using the current, default Tor snowflake infrastructure var target = getCdnFront("snowflake-target"); var front = getCdnFront("snowflake-front"); + var stunServer = getCdnFront("snowflake-stun"); + + /* + // @param ice Comma-separated list of ICE servers. + // @param url URL of signaling broker. + // @param fronts Comma-separated list of front domains. + // @param ampCache OPTIONAL. URL of AMP cache to use as a proxy for signaling. + // Only needed when you want to do the rendezvous over AMP instead of a domain fronted server. + // @param sqsQueueURL OPTIONAL. URL of SQS Queue to use as a proxy for signaling. + // @param sqsCredsStr OPTIONAL. Credentials to access SQS Queue. + // @param logFile Name of log file. OPTIONAL. Defaults to no log. + // @param logToStateDir Resolve the log file relative to Tor's PT state dir. + // @param keepLocalAddresses Keep local LAN address ICE candidates. + // @param unsafeLogging Prevent logs from being scrubbed. + // @param maxPeers Capacity for number of multiplexed WebRTC peers. DEFAULTs to 1 if less than that. + // @return Port number where Snowflake will listen on, if no error happens during start up. + */ + IPtProxy.startSnowflake(stunServer, target, front, null, null, null, null,true, false, false, 1); + + } + + private void startSnowflakeClientAmpRendezvous() { var stunServers = getCdnFront("snowflake-stun"); + var target = getCdnFront("snowflake-target-direct"); + var front = getCdnFront("snowflake-amp-front"); + var ampCache = getCdnFront("snowflake-amp-cache"); + IPtProxy.startSnowflake(stunServers, target, front, ampCache, null, null, null, true, false, false, 1); + } - String logFile = null; - if (Prefs.useSnowflakeLogging()) { - File fileLog = new File(appCacheHome, LOG_SNOWFLAKE); - if (fileLog.exists()) - fileLog.delete(); - logFile = fileLog.getAbsolutePath(); - } + private final SecureRandom mSecureRandGen = new SecureRandom(); //used to randomly select STUN servers for snowflake + + public synchronized void enableSnowflakeProxy() { // This is to host a snowflake entrance node / bridge + if (!IPtProxy.isSnowflakeProxyRunning()) { + + if (Prefs.limitSnowflakeProxyingWifi() && (!mHasWifi)) + return; - var logToStateDir = false; - var keepLocalAddresses = true; - var unsafeLogging = Prefs.useDebugLogging(); - int maxPeers = 1; + if (Prefs.limitSnowflakeProxyingCharging() && (!mHasPower)) + return; + + var capacity = 1; + var keepLocalAddresses = false; + var unsafeLogging = false; + var stunServers = getCdnFront("snowflake-stun").split(","); + + int randomIndex = mSecureRandGen.nextInt(stunServers.length); + var stunUrl = stunServers[randomIndex]; + var relayUrl = getCdnFront("snowflake-relay-url"); + var natProbeUrl = getCdnFront("snowflake-nat-probe"); + var brokerUrl = getCdnFront("snowflake-target-direct"); + IPtProxy.startSnowflakeProxy(capacity, brokerUrl, relayUrl, stunUrl, natProbeUrl, null, keepLocalAddresses, unsafeLogging, () -> { + Prefs.addSnowflakeServed(); + if (!Prefs.showSnowflakeProxyMessage()) return; + var message = String.format(getString(R.string.snowflake_proxy_client_connected_msg), ONION_EMOJI, ONION_EMOJI); + new Handler(getMainLooper()).post(() -> Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show()); + }); + logNotice(getString(R.string.log_notice_snowflake_proxy_enabled)); + + if (Prefs.showSnowflakeProxyMessage()) { + var message = getString(R.string.log_notice_snowflake_proxy_enabled); + new Handler(getMainLooper()).post(() -> Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show()); + } - IPtProxy.startSnowflake(stunServers, target, front, null, logFile, logToStateDir, keepLocalAddresses, unsafeLogging, maxPeers); + } } - private void startSnowflakeClientAmpRendezvous() { - var stunServers = getCdnFront("snowflake-stun"); - var target = getCdnFront("snowflake-amp-target");//"https://snowflake-broker.torproject.net/"; - var front = getCdnFront("snowflake-amp-front");//"www.google.com"; - var ampCache =getCdnFront("snowflake-amp-cache");//"https://cdn.ampproject.org/"; - - String logFile = null; - if (Prefs.useSnowflakeLogging()) { - File fileLog = new File(appCacheHome, LOG_SNOWFLAKE); - if (fileLog.exists()) - fileLog.delete(); - logFile = fileLog.getAbsolutePath(); + private final ConnectivityManager.NetworkCallback netCall = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(@NonNull Network network) { + super.onAvailable(network); + checkNetworkForSnowflakeProxy (); } - var logToStateDir = false; - var keepLocalAddresses = true; - var unsafeLogging = Prefs.useDebugLogging(); - var maxPeers = 1; + @Override + public void onLost(@NonNull Network network) { + super.onLost(network); + checkNetworkForSnowflakeProxy (); + } + }; + + private void enableSnowflakeProxyNetworkListener () { + if (Prefs.limitSnowflakeProxyingWifi()) { + //check if on wifi + ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - IPtProxy.startSnowflake(stunServers, target, front, ampCache, logFile, logToStateDir, keepLocalAddresses, unsafeLogging, maxPeers); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + connMgr.registerDefaultNetworkCallback(netCall); + } + } } - @SuppressWarnings("ConstantConditions") - private void enableSnowflakeProxy () { // This is to host a snowflake entrance node / bridge - var capacity = 1; - var keepLocalAddresses = false; - var unsafeLogging = false; - var stunUrl = "stun:stun.stunprotocol.org:3478"; - var relayUrl = "wss://snowflake.bamsoftware.com"; - var natProbeUrl = "https://snowflake-broker.torproject.net:8443/probe"; - var brokerUrl = "https://snowflake-broker.torproject.net/"; - IPtProxy.startSnowflakeProxy(capacity, brokerUrl, relayUrl, stunUrl, natProbeUrl, null, keepLocalAddresses, unsafeLogging, () -> { - snowflakeClientsConnected++; - Prefs.addSnowflakeServed(); - LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(LOCAL_ACTION_SNOWFLAKE_PROXY)); + public void setHasPower (boolean hasPower) { + mHasPower = hasPower; + if (Prefs.beSnowflakeProxy()) { + if (Prefs.limitSnowflakeProxyingCharging()) { + if (mHasPower) enableSnowflakeProxy(); + else disableSnowflakeProxy(); + } + } + } + private void checkNetworkForSnowflakeProxy () { + ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - if (!Prefs.showSnowflakeProxyMessage()) return; - var message = String.format(getString(R.string.snowflake_proxy_client_connected_msg), SNOWFLAKE_EMOJI, SNOWFLAKE_EMOJI); - new Handler(getMainLooper()).post(() -> Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show()); - }); - logNotice(getString(R.string.log_notice_snowflake_proxy_enabled)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + NetworkCapabilities netCap = connMgr.getNetworkCapabilities(connMgr.getActiveNetwork()); + if (netCap != null) + mHasWifi = netCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI); + else + mHasWifi = false; + } + else { + NetworkInfo netInfo = connMgr.getActiveNetworkInfo(); + if (netInfo != null) + mHasWifi = netInfo.getType() == ConnectivityManager.TYPE_WIFI; + } + + if (Prefs.beSnowflakeProxy()) { + if (Prefs.limitSnowflakeProxyingWifi()) { + if (mHasWifi) enableSnowflakeProxy(); + else disableSnowflakeProxy(); + } + } } - private void disableSnowflakeProxy() { - IPtProxy.stopSnowflakeProxy(); - logNotice(getString(R.string.log_notice_snowflake_proxy_disabled)); + public synchronized void disableSnowflakeProxy() { + if (IPtProxy.isSnowflakeProxyRunning()) { + IPtProxy.stopSnowflakeProxy(); + logNotice(getString(R.string.log_notice_snowflake_proxy_disabled)); + + if (Prefs.showSnowflakeProxyMessage()) { + var message = getString(R.string.log_notice_snowflake_proxy_disabled); + new Handler(getMainLooper()).post(() -> Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show()); + } + + } } // if someone stops during startup, we may have to wait for the conn port to be setup, so we can properly shutdown tor - private void stopTor() { + private void stopTor() { if (shouldUnbindTorService) { unbindService(torServiceConnection); //unbinding from the tor service will stop tor shouldUnbindTorService = false; @@ -448,74 +537,102 @@ public class OrbotService extends VpnService implements OrbotConstants { @Override public void onCreate() { super.onCreate(); - + configLanguage(); try { - mHandler = new Handler(); + //set proper content URIs for current build flavor + V3_ONION_SERVICES_CONTENT_URI = Uri.parse("content://" + getApplicationContext().getPackageName() + ".ui.v3onionservice/v3"); + V3_CLIENT_AUTH_URI = Uri.parse("content://" + getApplicationContext().getPackageName() + ".ui.v3onionservice.clientauth/v3auth"); - appBinHome = getFilesDir(); - if (!appBinHome.exists()) - appBinHome.mkdirs(); + try { + mHandler = new Handler(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - appCacheHome = new File(getDataDir(), DIRECTORY_TOR_DATA); - } else { - appCacheHome = getDir(DIRECTORY_TOR_DATA, Application.MODE_PRIVATE); - } + appBinHome = getFilesDir(); + if (!appBinHome.exists()) appBinHome.mkdirs(); - if (!appCacheHome.exists()) - appCacheHome.mkdirs(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + appCacheHome = new File(getDataDir(), DIRECTORY_TOR_DATA); + } else { + appCacheHome = getDir(DIRECTORY_TOR_DATA, Application.MODE_PRIVATE); + } - mV3OnionBasePath = new File(getFilesDir().getAbsolutePath(), ONION_SERVICES_DIR); - if (!mV3OnionBasePath.isDirectory()) - mV3OnionBasePath.mkdirs(); + if (!appCacheHome.exists()) appCacheHome.mkdirs(); - mV3AuthBasePath = new File(getFilesDir().getAbsolutePath(), V3_CLIENT_AUTH_DIR); - if (!mV3AuthBasePath.isDirectory()) - mV3AuthBasePath.mkdirs(); + mV3OnionBasePath = new File(getFilesDir().getAbsolutePath(), ONION_SERVICES_DIR); + if (!mV3OnionBasePath.isDirectory()) mV3OnionBasePath.mkdirs(); - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - } + mV3AuthBasePath = new File(getFilesDir().getAbsolutePath(), V3_CLIENT_AUTH_DIR); + if (!mV3AuthBasePath.isDirectory()) mV3AuthBasePath.mkdirs(); - IntentFilter filter = new IntentFilter(TorControlCommands.SIGNAL_NEWNYM); - filter.addAction(CMD_ACTIVE); - filter.addAction(ACTION_STATUS); - filter.addAction(ACTION_ERROR); - filter.addAction(LOCAL_ACTION_NOTIFICATION_START); + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } - mActionBroadcastReceiver = new ActionBroadcastReceiver(); - registerReceiver(mActionBroadcastReceiver, filter); + IntentFilter filter = new IntentFilter(TorControlCommands.SIGNAL_NEWNYM); + filter.addAction(CMD_ACTIVE); + filter.addAction(ACTION_STATUS); + filter.addAction(ACTION_ERROR); + filter.addAction(LOCAL_ACTION_NOTIFICATION_START); - mIsServiceRunningBroadcastReceiver = new IsServiceRunningBroadcastReceiver(); - LocalBroadcastManager.getInstance(this).registerReceiver( - mIsServiceRunningBroadcastReceiver, - new IntentFilter(ACTION_CHECK_RUNNING_SYNC)); + mActionBroadcastReceiver = new ActionBroadcastReceiver(); + registerReceiver(mActionBroadcastReceiver, filter); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) - createNotificationChannel(); + mIsServiceRunningBroadcastReceiver = new IsServiceRunningBroadcastReceiver(); + LocalBroadcastManager.getInstance(this).registerReceiver( + mIsServiceRunningBroadcastReceiver, + new IntentFilter(ACTION_CHECK_RUNNING_SYNC)); - try { - CustomTorResourceInstaller installer = new CustomTorResourceInstaller(this, appBinHome); - installer.installGeoIP(); - } - catch (IOException io) { - Log.e(TAG, "Error installing geoip files", io); - logNotice(getString(R.string.log_notice_geoip_error)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createNotificationChannel(); + + var hasGeoip = new File(appBinHome, GEOIP_ASSET_KEY).exists(); + var hasGeoip6 = new File(appBinHome, GEOIP6_ASSET_KEY).exists(); + + // only write out geoip files if there's an app update or they don't exist + if (!hasGeoip || !hasGeoip6 || Prefs.isGeoIpReinstallNeeded()) { + try { + Log.d(TAG, "Installing geoip files..."); + new CustomTorResourceInstaller(this, appBinHome).installGeoIP(); + Prefs.setIsGeoIpReinstallNeeded(false); + } catch (IOException io) { // user has < 10MB free space on disk... + Log.e(TAG, "Error installing geoip files", io); + } + } + + + pluggableTransportInstall(); + + mVpnManager = new OrbotVpnManager(this); + + loadCdnFronts(this); + } catch (Exception e) { + Log.e(TAG, "Error setting up Orbot", e); + logNotice(getString(R.string.couldn_t_start_tor_process_) + " " + e.getClass().getSimpleName()); } - pluggableTransportInstall(); + mPowerReceiver = new PowerConnectionReceiver(this); - mVpnManager = new OrbotVpnManager(this); + IntentFilter ifilter = new IntentFilter(); + ifilter.addAction(Intent.ACTION_POWER_CONNECTED); + ifilter.addAction(Intent.ACTION_POWER_DISCONNECTED); + registerReceiver(mPowerReceiver, ifilter); - loadCdnFronts(this); - } catch (Exception e) { - Log.e(TAG, "Error setting up Orbot", e); - logNotice(getString(R.string.couldn_t_start_tor_process_) + " " + e.getClass().getSimpleName()); - } + enableSnowflakeProxyNetworkListener(); - snowflakeClientsConnected = Prefs.getSnowflakesServed(); + if (Prefs.beSnowflakeProxy() + && !(Prefs.limitSnowflakeProxyingCharging() || Prefs.limitSnowflakeProxyingWifi())) + enableSnowflakeProxy(); - Log.i("OrbotService", "onCreate end"); + } catch (RuntimeException re) { + //catch this to avoid malicious launches as document Cure53 Audit: ORB-01-009 WP1/2: Orbot DoS via exported activity (High) + } + } + + private void configLanguage() { + Configuration config = getBaseContext().getResources().getConfiguration(); + Locale locale = new Locale(Prefs.getDefaultLocale()); + Locale.setDefault(locale); + config.locale = locale; + getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics()); } protected String getCurrentStatus() { @@ -527,8 +644,14 @@ public class OrbotService extends VpnService implements OrbotConstants { if (!fileCacheDir.exists()) //noinspection ResultOfMethodCallIgnored fileCacheDir.mkdir(); - IPtProxy.setStateLocation(fileCacheDir.getAbsolutePath()); - debug("IPtProxy state: " + IPtProxy.getStateLocation()); + + try { + IPtProxy.setStateLocation(fileCacheDir.getAbsolutePath()); + debug("IPtProxy state: " + IPtProxy.getStateLocation()); + } catch (Error e) { + debug("IPtProxy state: not installed; " + e.getLocalizedMessage()); + + } } private File updateTorrcCustomFile() throws IOException { @@ -540,14 +663,12 @@ public class OrbotService extends VpnService implements OrbotConstants { extraLines.append("AvoidDiskWrites 1").append('\n'); var socksPortPref = prefs.getString(PREF_SOCKS, SOCKS_PROXY_PORT_DEFAULT); - if (socksPortPref.indexOf(':') != -1) - socksPortPref = socksPortPref.split(":")[1]; + if (socksPortPref.indexOf(':') != -1) socksPortPref = socksPortPref.split(":")[1]; socksPortPref = checkPortOrAuto(socksPortPref); var httpPortPref = prefs.getString(PREF_HTTP, HTTP_PROXY_PORT_DEFAULT); - if (httpPortPref.indexOf(':') != -1) - httpPortPref = httpPortPref.split(":")[1]; + if (httpPortPref.indexOf(':') != -1) httpPortPref = httpPortPref.split(":")[1]; httpPortPref = checkPortOrAuto(httpPortPref); @@ -555,6 +676,12 @@ public class OrbotService extends VpnService implements OrbotConstants { if (prefs.getBoolean(PREF_ISOLATE_DEST, false)) { isolate += " IsolateDestAddr "; } + if (prefs.getBoolean(PREF_ISOLATE_PORT, false)) { + isolate += " IsolateDestPort "; + } + if (prefs.getBoolean(PREF_ISOLATE_PROTOCOL, false)) { + isolate += " IsolateClientProtocol "; + } var ipv6Pref = ""; if (prefs.getBoolean(PREF_PREFER_IPV6, true)) { @@ -617,15 +744,14 @@ public class OrbotService extends VpnService implements OrbotConstants { extraLines = processSettingsImpl(extraLines); - if (extraLines == null) - return null; + if (extraLines == null) return null; extraLines.append('\n'); extraLines.append(prefs.getString("pref_custom_torrc", "")).append('\n'); logNotice(getString(R.string.log_notice_updating_torrc)); - debug("torrc.custom=" + extraLines.toString()); + debug("torrc.custom=" + extraLines); var fileTorRcCustom = TorService.getTorrc(this); updateTorConfigCustom(fileTorRcCustom, extraLines.toString(), false); @@ -690,6 +816,8 @@ public class OrbotService extends VpnService implements OrbotConstants { private boolean showTorServiceErrorMsg = false; + private static final int TIMEOUT_MS = 15000; + /** * The entire process for starting tor and related services is run from this method. */ @@ -706,14 +834,71 @@ public class OrbotService extends VpnService implements OrbotConstants { } showToolbarNotification("", NOTIFY_ID, R.drawable.ic_stat_tor); + if (Prefs.getConnectionPathway().equals(Prefs.PATHWAY_SMART)) { + smartConnectionPathwayStartTor(); + } startTorService(); showTorServiceErrorMsg = true; + + if (Prefs.hostOnionServicesEnabled()) { + try { + updateV3OnionNames(); + } catch (SecurityException se) { + logNotice(getString(R.string.log_notice_unable_to_update_onions)); + } + } } catch (Exception e) { - logException(getString(R.string.unable_to_start_tor) + " " + e.getLocalizedMessage(), e); + logException(getString(R.string.unable_to_start_tor) + " " + e.getLocalizedMessage(), e); stopTorOnError(e.getLocalizedMessage()); } } + static int TRIES_DELETE = 0; + + private void smartConnectionPathwayStartTor() { + Log.d(TAG, "timing out in " + TIMEOUT_MS + "ms"); + new Handler(Looper.getMainLooper()).postDelayed(() -> { + Log.d(TAG, "timed out mCurrentStatus=" + mCurrentStatus); + if (!mCurrentStatus.equals(STATUS_ON)) { + Log.d(TAG, "stopping tor..."); + if (Prefs.getPrefSmartTrySnowflake()) { + Log.d(TAG, "trying snowflake didnt work"); + clearEphemeralSmartConnectionSettings(); + sendSmartStatusToActivity(SMART_STATUS_CIRCUMVENTION_ATTEMPT_FAILED); + } else if (Prefs.getPrefSmartTryObfs4() != null) { + Log.d(TAG, "trying obfs4 didnt work"); + clearEphemeralSmartConnectionSettings(); + sendSmartStatusToActivity(SMART_STATUS_CIRCUMVENTION_ATTEMPT_FAILED); + } else { + sendSmartStatusToActivity(SMART_STATUS_NO_DIRECT); + } + stopTorAsync(true); + } else { + // tor was connected in the allotted time + var obfs4 = Prefs.getPrefSmartTryObfs4(); + if (obfs4 != null) { + // set these obfs4 bridges + Prefs.setBridgesList(obfs4); + Prefs.putConnectionPathway(Prefs.PATHWAY_CUSTOM); + } else if (Prefs.getPrefSmartTrySnowflake()) { + // set snowflake + Prefs.putConnectionPathway(Prefs.PATHWAY_SNOWFLAKE); + } + clearEphemeralSmartConnectionSettings(); + } + }, ((TRIES_DELETE++) != 2) ? TIMEOUT_MS : 10000); + } + + private void clearEphemeralSmartConnectionSettings() { + Prefs.putPrefSmartTryObfs4(null); + Prefs.putPrefSmartTrySnowflake(false); + } + + private void sendSmartStatusToActivity(String status) { + var intent = new Intent(LOCAL_ACTION_SMART_CONNECT_EVENT).putExtra(LOCAL_EXTRA_SMART_STATUS, status); + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + } + private void updateV3OnionNames() throws SecurityException { var contentResolver = getApplicationContext().getContentResolver(); @@ -721,14 +906,18 @@ public class OrbotService extends VpnService implements OrbotConstants { if (onionServices != null) { try { while (onionServices.moveToNext()) { - var domain = onionServices.getString(onionServices.getColumnIndex(OnionService.DOMAIN)); + var domain_index = onionServices.getColumnIndex(OnionService.DOMAIN); + var path_index = onionServices.getColumnIndex(OnionService.PATH); + var id_index = onionServices.getColumnIndex(OnionService._ID); + if (domain_index < 0 || path_index < 0 || id_index < 0) continue; + var domain = onionServices.getString(domain_index); if (domain == null || TextUtils.isEmpty(domain)) { - var path = onionServices.getString(onionServices.getColumnIndex(OnionService.PATH)); + var path = onionServices.getString(path_index); var v3OnionDirPath = new File(mV3OnionBasePath.getAbsolutePath(), path).getCanonicalPath(); var hostname = new File(v3OnionDirPath, "hostname"); if (hostname.exists()) { - int id = onionServices.getInt(onionServices.getColumnIndex(OnionService._ID)); - domain = Utils.readString(new FileInputStream(hostname)).trim(); + int id = onionServices.getInt(id_index); + domain = Utils.readInputStreamAsString(new FileInputStream(hostname)).trim(); var fields = new ContentValues(); fields.put(OnionService.DOMAIN, domain); contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, fields, OnionService._ID + "=" + id, null); @@ -754,14 +943,14 @@ public class OrbotService extends VpnService implements OrbotConstants { } private synchronized void startTorService() throws Exception { - updateTorConfigCustom(TorService.getDefaultsTorrc(this), - "DNSPort 0\n" + - "TransPort 0\n" + - "DisableNetwork 1\n", false); + updateTorConfigCustom(TorService.getDefaultsTorrc(this), """ + DNSPort 0 + TransPort 0 + DisableNetwork 1 + """, false); var fileTorrcCustom = updateTorrcCustomFile(); - if ((!fileTorrcCustom.exists()) || (!fileTorrcCustom.canRead())) - return; + if ((!fileTorrcCustom.exists()) || (!fileTorrcCustom.canRead())) return; sendCallbackLogMessage(getString(R.string.status_starting_up)); @@ -772,8 +961,7 @@ public class OrbotService extends VpnService implements OrbotConstants { //moved torService to a local variable, since we only need it once TorService torService = ((TorService.LocalBinder) iBinder).getService(); - while ((conn = torService.getTorControlConnection())==null) - { + while ((conn = torService.getTorControlConnection()) == null) { try { Thread.sleep(500); } catch (InterruptedException e) { @@ -793,7 +981,8 @@ public class OrbotService extends VpnService implements OrbotConstants { if (conn != null) { try { initControlConnection(); - if (conn == null) return; // maybe there was an error setting up the control connection + if (conn == null) + return; // maybe there was an error setting up the control connection //override the TorService event listener conn.addRawEventListener(mOrbotRawEventListener); @@ -801,17 +990,13 @@ public class OrbotService extends VpnService implements OrbotConstants { logNotice(getString(R.string.log_notice_connected_to_tor_control_port)); //now set our own events - ArrayList events = new ArrayList<>(Arrays.asList(TorControlCommands.EVENT_OR_CONN_STATUS, - TorControlCommands.EVENT_CIRCUIT_STATUS, TorControlCommands.EVENT_NOTICE_MSG, - TorControlCommands.EVENT_WARN_MSG, TorControlCommands.EVENT_ERR_MSG, - TorControlCommands.EVENT_BANDWIDTH_USED, TorControlCommands.EVENT_NEW_DESC, - TorControlCommands.EVENT_ADDRMAP)); + ArrayList events = new ArrayList<>(Arrays.asList(TorControlCommands.EVENT_OR_CONN_STATUS, TorControlCommands.EVENT_CIRCUIT_STATUS, TorControlCommands.EVENT_NOTICE_MSG, TorControlCommands.EVENT_WARN_MSG, TorControlCommands.EVENT_ERR_MSG, TorControlCommands.EVENT_BANDWIDTH_USED, TorControlCommands.EVENT_NEW_DESC, TorControlCommands.EVENT_ADDRMAP)); if (Prefs.useDebugLogging()) { events.add(TorControlCommands.EVENT_DEBUG_MSG); events.add(TorControlCommands.EVENT_INFO_MSG); } - if (Prefs.useDebugLogging() || Prefs.showExpandedNotifications()) + if (Prefs.useDebugLogging()) events.add(TorControlCommands.EVENT_STREAM_STATUS); conn.setEvents(events); @@ -824,8 +1009,7 @@ public class OrbotService extends VpnService implements OrbotConstants { @Override public void onServiceDisconnected(ComponentName componentName) { - if (Prefs.useDebugLogging()) - Log.d(TAG, "TorService: onServiceDisconnected"); + if (Prefs.useDebugLogging()) Log.d(TAG, "TorService: onServiceDisconnected"); sendLocalStatusOffBroadcast(); } @@ -902,6 +1086,11 @@ public class OrbotService extends VpnService implements OrbotConstants { e.printStackTrace(); stopTorOnError(e.getLocalizedMessage()); conn = null; + } catch (NullPointerException npe) { + Log.e(TAG, "NPE reached... how???"); + npe.printStackTrace(); + stopTorOnError("stopping from NPE"); + conn = null; } } } @@ -921,10 +1110,12 @@ public class OrbotService extends VpnService implements OrbotConstants { new Thread() { public void run() { try { - if (conn != null && mCurrentStatus.equals(STATUS_ON)) { + if (conn != null && mCurrentStatus.equals(STATUS_ON)) { + if (mNotifyBuilder != null) { mNotifyBuilder.setSubText(null); // clear previous exit node info if present - showToolbarNotification(getString(R.string.newnym), NOTIFY_ID, R.drawable.ic_stat_tor); - conn.signal(TorControlCommands.SIGNAL_NEWNYM); + } + showToolbarNotification(getString(R.string.newnym), NOTIFY_ID, R.drawable.ic_stat_tor); + conn.signal(TorControlCommands.SIGNAL_NEWNYM); } } catch (Exception ioe) { debug("error requesting newnym: " + ioe.getLocalizedMessage()); @@ -934,20 +1125,18 @@ public class OrbotService extends VpnService implements OrbotConstants { } protected void sendCallbackBandwidth(long lastWritten, long lastRead, long totalWritten, long totalRead) { - LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(LOCAL_ACTION_BANDWIDTH) - .putExtra("totalWritten", totalWritten) - .putExtra("totalRead", totalRead) - .putExtra("lastWritten", lastWritten) - .putExtra("lastRead", lastRead)); + LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(LOCAL_ACTION_BANDWIDTH).putExtra(LOCAL_EXTRA_TOTAL_WRITTEN, totalWritten).putExtra(LOCAL_EXTRA_TOTAL_READ, totalRead).putExtra(LOCAL_EXTRA_LAST_WRITTEN, lastWritten).putExtra(LOCAL_EXTRA_LAST_READ, lastRead)); } private void sendCallbackLogMessage(final String logMessage) { var notificationMessage = logMessage; + var localIntent = new Intent(LOCAL_ACTION_LOG).putExtra(LOCAL_EXTRA_LOG, logMessage); if (logMessage.contains(LOG_NOTICE_HEADER)) { notificationMessage = notificationMessage.substring(LOG_NOTICE_HEADER.length()); if (notificationMessage.contains(LOG_NOTICE_BOOTSTRAPPED)) { var percent = notificationMessage.substring(LOG_NOTICE_BOOTSTRAPPED.length()); percent = percent.substring(0, percent.indexOf('%')).trim(); + localIntent.putExtra(LOCAL_EXTRA_BOOTSTRAP_PERCENT, percent); if (mNotifyBuilder != null) { mNotifyBuilder.setProgress(100, Integer.parseInt(percent), false); } @@ -955,20 +1144,14 @@ public class OrbotService extends VpnService implements OrbotConstants { } } showToolbarNotification(notificationMessage, NOTIFY_ID, R.drawable.ic_stat_tor); - mHandler.post(() -> LocalBroadcastManager.getInstance(OrbotService.this).sendBroadcast(new Intent(LOCAL_ACTION_LOG) - .putExtra(LOCAL_EXTRA_LOG, logMessage))); + mHandler.post(() -> LocalBroadcastManager.getInstance(OrbotService.this).sendBroadcast(localIntent)); } private void sendCallbackPorts(int socksPort, int httpPort, int dnsPort, int transPort) { - var intent = new Intent(LOCAL_ACTION_PORTS) - .putExtra(EXTRA_SOCKS_PROXY_PORT, socksPort) - .putExtra(EXTRA_HTTP_PROXY_PORT, httpPort) - .putExtra(EXTRA_DNS_PORT, dnsPort) - .putExtra(EXTRA_TRANS_PORT, transPort); + var intent = new Intent(LOCAL_ACTION_PORTS).putExtra(EXTRA_SOCKS_PROXY_PORT, socksPort).putExtra(EXTRA_HTTP_PROXY_PORT, httpPort).putExtra(EXTRA_DNS_PORT, dnsPort).putExtra(EXTRA_TRANS_PORT, transPort); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); - if (Prefs.useVpn() && mVpnManager != null) - mVpnManager.handleIntent(new Builder(), intent); + if (Prefs.useVpn() && mVpnManager != null) mVpnManager.handleIntent(new Builder(), intent); } private StringBuffer processSettingsImpl(StringBuffer extraLines) throws IOException { @@ -981,98 +1164,40 @@ public class OrbotService extends VpnService implements OrbotConstants { var exitNodes = prefs.getString("pref_exit_nodes", ""); var excludeNodes = prefs.getString("pref_exclude_nodes", ""); - if (!Prefs.bridgesEnabled()) { - extraLines.append("UseBridges 0").append('\n'); - if (Prefs.useVpn()) { //set the proxy here if we aren't using a bridge - if (!mIsLollipop) { - var proxyType = "socks5"; - extraLines.append(proxyType + "Proxy" + ' ' + OrbotVpnManager.sSocksProxyLocalhost + ':' + OrbotVpnManager.sSocksProxyServerPort).append('\n'); - } - } else { - var proxyType = prefs.getString("pref_proxy_type", null); - if (proxyType != null && proxyType.length() > 0) { - var proxyHost = prefs.getString("pref_proxy_host", null); - var proxyPort = prefs.getString("pref_proxy_port", null); - var proxyUser = prefs.getString("pref_proxy_username", null); - var proxyPass = prefs.getString("pref_proxy_password", null); - - if ((proxyHost != null && proxyHost.length() > 0) && (proxyPort != null && proxyPort.length() > 0)) { - extraLines.append(proxyType).append("Proxy").append(' ').append(proxyHost).append(':').append(proxyPort).append('\n'); - - if (proxyUser != null && proxyPass != null) { - if (proxyType.equalsIgnoreCase("socks5")) { - extraLines.append("Socks5ProxyUsername").append(' ').append(proxyUser).append('\n'); - extraLines.append("Socks5ProxyPassword").append(' ').append(proxyPass).append('\n'); - } else - extraLines.append(proxyType).append("ProxyAuthenticator").append(' ').append(proxyUser).append(':').append(proxyPort).append('\n'); - - } else if (proxyPass != null) - extraLines.append(proxyType).append("ProxyAuthenticator").append(' ').append(proxyUser).append(':').append(proxyPort).append('\n'); - } - } - } + String pathway = Prefs.getConnectionPathway(); + if (pathway.equals(Prefs.PATHWAY_SMART)) { + // todo for now ... + } else if (pathway.equals(Prefs.PATHWAY_DIRECT)) { + extraLines = processSettingsImplDirectPathway(extraLines); } else { - - loadBridgeDefaults(); + // snowflake or obfs4 extraLines.append("UseBridges 1").append('\n'); - // extraLines.append("UpdateBridgesFromAuthority 1").append('\n'); - - var bridgeList = Prefs.getBridgesList(); - String builtInBridgeType = null; - - //check if any PT bridges are needed - if (bridgeList.contains("obfs")) { - - extraLines.append("ClientTransportPlugin obfs3 socks5 127.0.0.1:" + IPtProxy.obfs3Port()).append('\n'); - extraLines.append("ClientTransportPlugin obfs4 socks5 127.0.0.1:" + IPtProxy.obfs4Port()).append('\n'); - - if (bridgeList.equals("obfs4")) - builtInBridgeType = "obfs4"; - } - - if (bridgeList.equals("meek")) { - extraLines.append("ClientTransportPlugin meek_lite socks5 127.0.0.1:" + IPtProxy.meekPort()).append('\n'); - builtInBridgeType = "meek_lite"; - } - - if (bridgeList.equals("snowflake") || bridgeList.equals("snowflake-amp")) { - extraLines.append("ClientTransportPlugin snowflake socks5 127.0.0.1:" + IPtProxy.snowflakePort()).append('\n'); - builtInBridgeType = "snowflake"; - } - - if (!TextUtils.isEmpty(builtInBridgeType)) - getBridges(builtInBridgeType, extraLines); - else { - String[] bridgeListLines = parseBridgesFromSettings(bridgeList); - int bridgeIdx = (int) Math.floor(Math.random() * ((double) bridgeListLines.length)); - String bridgeLine = bridgeListLines[bridgeIdx]; - if (!TextUtils.isEmpty(bridgeLine)) { - extraLines.append("Bridge "); - extraLines.append(bridgeLine); - extraLines.append("\n"); - } + if (pathway.startsWith(Prefs.PATHWAY_SNOWFLAKE) || Prefs.getPrefSmartTrySnowflake()) { + extraLines = processSettingsImplSnowflake(extraLines); + } else if (pathway.equals(Prefs.PATHWAY_CUSTOM) || Prefs.getPrefSmartTryObfs4() != null) { + extraLines = processSettingsImplObfs4(extraLines); } } - - //only apply GeoIP if you need it var fileGeoIP = new File(appBinHome, GEOIP_ASSET_KEY); var fileGeoIP6 = new File(appBinHome, GEOIP6_ASSET_KEY); - if (fileGeoIP.exists()) { + if (fileGeoIP.exists()) { // only apply geoip if it exists extraLines.append("GeoIPFile" + ' ').append(fileGeoIP.getCanonicalPath()).append('\n'); extraLines.append("GeoIPv6File" + ' ').append(fileGeoIP6.getCanonicalPath()).append('\n'); } if (!TextUtils.isEmpty(entranceNodes)) - extraLines.append("EntryNodes" + ' ').append(entranceNodes).append('\n'); + extraLines.append("EntryNodes ").append(entranceNodes).append('\n'); if (!TextUtils.isEmpty(exitNodes)) - extraLines.append("ExitNodes" + ' ').append(exitNodes).append('\n'); + extraLines.append("ExitNodes ").append(exitNodes).append('\n'); if (!TextUtils.isEmpty(excludeNodes)) - extraLines.append("ExcludeNodes" + ' ').append(excludeNodes).append('\n'); + extraLines.append("ExcludeNodes ").append(excludeNodes).append('\n'); + + extraLines.append("StrictNodes ").append(enableStrictNodes ? "1" : "0").append('\n'); - extraLines.append("StrictNodes" + ' ').append(enableStrictNodes ? "1" : "0").append('\n'); + extraLines.append("\n"); try { if (ReachableAddresses) { @@ -1101,6 +1226,64 @@ public class OrbotService extends VpnService implements OrbotConstants { showToolbarNotification(getString(R.string.your_relay_settings_caused_an_exception_), ERROR_NOTIFY_ID, R.drawable.ic_stat_notifyerr); return null; } + + if (Prefs.hostOnionServicesEnabled()) { + var contentResolver = getApplicationContext().getContentResolver(); + addV3OnionServicesToTorrc(extraLines, contentResolver); + addV3ClientAuthToTorrc(extraLines, contentResolver); + } + + return extraLines; + } + + private StringBuffer processSettingsImplSnowflake(StringBuffer extraLines) { + Log.d(TAG, "in snowflake torrc config"); + extraLines.append("ClientTransportPlugin snowflake socks5 127.0.0.1:" + IPtProxy.snowflakePort()).append('\n'); + extraLines.append("Bridge ").append(getCdnFront("snowflake-broker-1")).append("\n"); + extraLines.append("Bridge ").append(getCdnFront("snowflake-broker-2")).append("\n"); + return extraLines; + } + + private StringBuffer processSettingsImplObfs4(StringBuffer extraLines) { + Log.d(TAG, "in obfs4 torrc config"); + extraLines.append("ClientTransportPlugin obfs3 socks5 127.0.0.1:" + IPtProxy.obfs3Port()).append('\n'); + extraLines.append("ClientTransportPlugin obfs4 socks5 127.0.0.1:" + IPtProxy.obfs4Port()).append('\n'); + var bridgeList = ""; + if (Prefs.getConnectionPathway().equals(Prefs.PATHWAY_CUSTOM)) { + bridgeList = Prefs.getBridgesList(); + } else bridgeList = Prefs.getPrefSmartTryObfs4(); + var customBridges = parseBridgesFromSettings(bridgeList); + for (var b : customBridges) + extraLines.append("Bridge ").append(b).append("\n"); + return extraLines; + } + + private StringBuffer processSettingsImplDirectPathway(StringBuffer extraLines) { + var prefs = Prefs.getSharedPrefs(getApplicationContext()); + extraLines.append("UseBridges 0").append('\n'); + if (!Prefs.useVpn()) { //set the proxy here if we aren't using a bridge + var proxyType = prefs.getString("pref_proxy_type", null); + if (proxyType != null && proxyType.length() > 0) { + var proxyHost = prefs.getString("pref_proxy_host", null); + var proxyPort = prefs.getString("pref_proxy_port", null); + var proxyUser = prefs.getString("pref_proxy_username", null); + var proxyPass = prefs.getString("pref_proxy_password", null); + + if ((proxyHost != null && proxyHost.length() > 0) && (proxyPort != null && proxyPort.length() > 0)) { + extraLines.append(proxyType).append("Proxy").append(' ').append(proxyHost).append(':').append(proxyPort).append('\n'); + + if (proxyUser != null && proxyPass != null) { + if (proxyType.equalsIgnoreCase("socks5")) { + extraLines.append("Socks5ProxyUsername").append(' ').append(proxyUser).append('\n'); + extraLines.append("Socks5ProxyPassword").append(' ').append(proxyPass).append('\n'); + } else + extraLines.append(proxyType).append("ProxyAuthenticator").append(' ').append(proxyUser).append(':').append(proxyPort).append('\n'); + + } else if (proxyPass != null) + extraLines.append(proxyType).append("ProxyAuthenticator").append(' ').append(proxyUser).append(':').append(proxyPort).append('\n'); + } + } + } return extraLines; } @@ -1113,11 +1296,9 @@ public class OrbotService extends VpnService implements OrbotConstants { public static String formatBandwidthCount(Context context, long bitsPerSecond) { var nf = NumberFormat.getInstance(Locale.getDefault()); if (bitsPerSecond < 1e6) - return nf.format(Math.round(((float) ((int) (bitsPerSecond * 10 / 1024)) / 10))) - + context.getString(R.string.kibibyte_per_second); + return nf.format(Math.round(((float) ((int) (bitsPerSecond * 10 / 1024)) / 10))) + context.getString(R.string.kibibyte_per_second); else - return nf.format(Math.round(((float) ((int) (bitsPerSecond * 100 / 1024 / 1024)) / 100))) - + context.getString(R.string.mebibyte_per_second); + return nf.format(Math.round(((float) ((int) (bitsPerSecond * 100 / 1024 / 1024)) / 100))) + context.getString(R.string.mebibyte_per_second); } private void addV3OnionServicesToTorrc(StringBuffer torrc, ContentResolver contentResolver) { @@ -1125,17 +1306,24 @@ public class OrbotService extends VpnService implements OrbotConstants { var onionServices = contentResolver.query(V3_ONION_SERVICES_CONTENT_URI, V3_ONION_SERVICE_PROJECTION, OnionService.ENABLED + "=1", null, null); if (onionServices != null) { while (onionServices.moveToNext()) { - var id = onionServices.getInt(onionServices.getColumnIndex(OnionService._ID)); - var localPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.PORT)); - var onionPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.ONION_PORT)); - var path = onionServices.getString(onionServices.getColumnIndex(OnionService.PATH)); - var domain = onionServices.getString(onionServices.getColumnIndex(OnionService.DOMAIN)); + var id_index = onionServices.getColumnIndex(OnionService._ID); + var port_index = onionServices.getColumnIndex(OnionService.PORT); + var onion_port_index = onionServices.getColumnIndex(OnionService.ONION_PORT); + var path_index = onionServices.getColumnIndex(OnionService.PATH); + var domain_index = onionServices.getColumnIndex(OnionService.DOMAIN); + // Ensure that are have all the indexes before trying to use them + if (id_index < 0 || port_index < 0 || onion_port_index < 0 || path_index < 0 || domain_index < 0) + continue; + + var id = onionServices.getInt(id_index); + var localPort = onionServices.getInt(port_index); + var onionPort = onionServices.getInt(onion_port_index); + var path = onionServices.getString(path_index); + var domain = onionServices.getString(domain_index); if (path == null) { path = "v3"; - if (domain == null) - path += UUID.randomUUID().toString(); - else - path += localPort; + if (domain == null) path += UUID.randomUUID().toString(); + else path += localPort; var cv = new ContentValues(); cv.put(OnionService.PATH, path); contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, cv, OnionService._ID + "=" + id, null); @@ -1148,7 +1336,7 @@ public class OrbotService extends VpnService implements OrbotConstants { onionServices.close(); } } catch (Exception e) { - Log.e(TAG, e.getLocalizedMessage()); + Log.e(TAG, e.getMessage()); } } @@ -1167,8 +1355,12 @@ public class OrbotService extends VpnService implements OrbotConstants { try { int i = 0; while (v3auths.moveToNext()) { - var domain = v3auths.getString(v3auths.getColumnIndex(V3ClientAuth.DOMAIN)); - var hash = v3auths.getString(v3auths.getColumnIndex(V3ClientAuth.HASH)); + var domain_index = v3auths.getColumnIndex(V3ClientAuth.DOMAIN); + var hash_index = v3auths.getColumnIndex(V3ClientAuth.HASH); + // Ensure that are have all the indexes before trying to use them + if (domain_index < 0 || hash_index < 0) continue; + var domain = v3auths.getString(domain_index); + var hash = v3auths.getString(hash_index); var authFile = new File(mV3AuthBasePath, (i++) + ".auth_private"); authFile.createNewFile(); var fos = new FileOutputStream(authFile); @@ -1197,42 +1389,21 @@ public class OrbotService extends VpnService implements OrbotConstants { @Override public void onTrimMemory(int level) { super.onTrimMemory(level); - switch (level) { - case TRIM_MEMORY_BACKGROUND: - debug("trim memory requested: app in the background"); - break; - - case TRIM_MEMORY_COMPLETE: - debug("trim memory requested: cleanup all memory"); - break; - - case TRIM_MEMORY_MODERATE: - debug("trim memory requested: clean up some memory"); - break; - - case TRIM_MEMORY_RUNNING_CRITICAL: - debug("trim memory requested: memory on device is very low and critical"); - break; - - case TRIM_MEMORY_RUNNING_LOW: - debug("trim memory requested: memory on device is running low"); - break; - - case TRIM_MEMORY_RUNNING_MODERATE: - debug("trim memory requested: memory on device is moderate"); - break; - - case TRIM_MEMORY_UI_HIDDEN: - debug("trim memory requested: app is not showing UI anymore"); - break; + case TRIM_MEMORY_BACKGROUND -> debug("trim memory requested: app in the background"); + case TRIM_MEMORY_COMPLETE -> debug("trim memory requested: cleanup all memory"); + case TRIM_MEMORY_MODERATE -> debug("trim memory requested: clean up some memory"); + case TRIM_MEMORY_RUNNING_CRITICAL -> debug("trim memory requested: memory on device is very low and critical"); + case TRIM_MEMORY_RUNNING_LOW -> debug("trim memory requested: memory on device is running low"); + case TRIM_MEMORY_RUNNING_MODERATE -> debug("trim memory requested: memory on device is moderate"); + case TRIM_MEMORY_UI_HIDDEN -> debug("trim memory requested: app is not showing UI anymore"); } } public void setNotificationSubtext(String message) { if (mNotifyBuilder != null) { // stop showing expanded notifications if the user changed the after starting Orbot - if (!Prefs.showExpandedNotifications()) message = null; + // if (!Prefs.showExpandedNotifications()) message = null; mNotifyBuilder.setSubText(message); } } @@ -1253,10 +1424,9 @@ public class OrbotService extends VpnService implements OrbotConstants { } private void setExitNode(String newExits) { - var prefs = Prefs.getSharedPrefs(getApplicationContext()); if (TextUtils.isEmpty(newExits)) { - prefs.edit().remove("pref_exit_nodes").apply(); + Prefs.setExitNodes(""); if (conn != null) { try { @@ -1272,7 +1442,8 @@ public class OrbotService extends VpnService implements OrbotConstants { } } } else { - prefs.edit().putString("pref_exit_nodes", newExits).apply(); + + Prefs.setExitNodes("{" + newExits + "}"); if (conn != null) { try { @@ -1293,65 +1464,6 @@ public class OrbotService extends VpnService implements OrbotConstants { } } - private void loadBridgeDefaults() { - if (alBridges == null) { - alBridges = new ArrayList<>(); - - try { - var in = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.bridges), "UTF-8")); - String str; - - while ((str = in.readLine()) != null) { - var st = new StringTokenizer(str, " "); - var b = new Bridge(); - b.type = st.nextToken(); - - var sbConfig = new StringBuilder(); - while (st.hasMoreTokens()) - sbConfig.append(st.nextToken()).append(' '); - - b.config = sbConfig.toString().trim(); - alBridges.add(b); - } - - in.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private void getBridges(String type, StringBuffer extraLines) { - Collections.shuffle(alBridges, bridgeSelectRandom); - - //let's just pull up to 2 bridges from the defaults at time - var maxBridges = 2; - var bridgeCount = 0; - - //now go through the list to find the bridges we want - for (var b : alBridges) { - if (b.type.equals(type)) { - extraLines.append("Bridge "); - extraLines.append(b.type); - extraLines.append(' '); - extraLines.append(b.config); - extraLines.append('\n'); - /** - * You can experiment with different settings of utls-imitate in the bridge line: - * - * hellochrome_auto - * helloios_auto - * hellorandomizedalpn - */ - - bridgeCount++; - - if (bridgeCount > maxBridges) - break; - } - } - } - public static final class OnionService implements BaseColumns { public static final String NAME = "name"; public static final String PORT = "port"; @@ -1368,12 +1480,6 @@ public class OrbotService extends VpnService implements OrbotConstants { } - // for bridge loading from the assets default bridges.txt file - static class Bridge { - String type; - String config; - } - private class IncomingIntentRouter implements Runnable { final Intent mIntent; @@ -1384,76 +1490,72 @@ public class OrbotService extends VpnService implements OrbotConstants { public void run() { var action = mIntent.getAction(); if (TextUtils.isEmpty(action)) return; - if (action.equals(ACTION_START)) { - if (Prefs.bridgesEnabled()) { - if (useIPtObfsMeekProxy()) - IPtProxy.startObfs4Proxy("DEBUG", false, false, null); - else if (useIPtSnowflakeProxyDomainFronting()) + switch (action) { + case ACTION_START -> { + var connectionPathway = Prefs.getConnectionPathway(); + if (connectionPathway.equals(Prefs.PATHWAY_SNOWFLAKE) || Prefs.getPrefSmartTrySnowflake()) { startSnowflakeClientDomainFronting(); - else if (useIPtSnowflakeProxyAMPRendezvous()) + } else if (connectionPathway.equals(Prefs.PATHWAY_SNOWFLAKE_AMP)) { startSnowflakeClientAmpRendezvous(); - } else if (Prefs.beSnowflakeProxy()) { - enableSnowflakeProxy(); - } - - startTor(); - replyWithStatus(mIntent); + } else if (connectionPathway.equals(Prefs.PATHWAY_CUSTOM) || Prefs.getPrefSmartTryObfs4() != null) { + IPtProxy.startLyrebird("DEBUG", false, false, null); + } + startTor(); + replyWithStatus(mIntent); + if (Prefs.useVpn()) { + if (mVpnManager != null && (!mVpnManager.isStarted())) { // start VPN here + Intent vpnIntent = VpnService.prepare(OrbotService.this); + if (vpnIntent == null) { //then we can run the VPN + mVpnManager.handleIntent(new Builder(), mIntent); + } + } - if (Prefs.useVpn()) { - if (mVpnManager != null && (!mVpnManager.isStarted())) { // start VPN here + if (mPortSOCKS != -1 && mPortHTTP != -1) + sendCallbackPorts(mPortSOCKS, mPortHTTP, mPortDns, mPortTrans); + } + } + case ACTION_STOP -> { + var userIsQuittingOrbot = mIntent.getBooleanExtra(ACTION_STOP_FOREGROUND_TASK, false); + stopTorAsync(!userIsQuittingOrbot); + } + case ACTION_UPDATE_ONION_NAMES -> updateV3OnionNames(); + case ACTION_STOP_FOREGROUND_TASK -> stopForeground(true); + case ACTION_START_VPN -> { + if (mVpnManager != null && (!mVpnManager.isStarted())) { + //start VPN here Intent vpnIntent = VpnService.prepare(OrbotService.this); if (vpnIntent == null) { //then we can run the VPN mVpnManager.handleIntent(new Builder(), mIntent); } } - if (mPortSOCKS != -1 && mPortHTTP != -1) sendCallbackPorts(mPortSOCKS, mPortHTTP, mPortDns, mPortTrans); } - } else if (action.equals(ACTION_STOP)) { - var userIsQuittingOrbot = mIntent.getBooleanExtra(ACTION_STOP_FOREGROUND_TASK, false); - stopTorAsync(!userIsQuittingOrbot); - } else if (action.equals(ACTION_UPDATE_ONION_NAMES)) { - updateV3OnionNames(); - } else if (action.equals(ACTION_STOP_FOREGROUND_TASK)) { - stopForeground(true); - } - else if (action.equals(ACTION_START_VPN)) { - if (mVpnManager != null && (!mVpnManager.isStarted())) { - //start VPN here - Intent vpnIntent = VpnService.prepare(OrbotService.this); - if (vpnIntent == null) { //then we can run the VPN - mVpnManager.handleIntent(new Builder(), mIntent); - } + case ACTION_STOP_VPN -> { + if (mVpnManager != null) mVpnManager.handleIntent(new Builder(), mIntent); } - - if (mPortSOCKS != -1 && mPortHTTP != -1) - sendCallbackPorts(mPortSOCKS, mPortHTTP, mPortDns, mPortTrans); - - - } else if (action.equals(ACTION_STOP_VPN)) { - if (mVpnManager != null) - mVpnManager.handleIntent(new Builder(), mIntent); - } else if (action.equals(ACTION_RESTART_VPN)) { - - if (mVpnManager != null) - mVpnManager.restartVPN(new Builder()); - - } else if (action.equals(ACTION_STATUS)) { - if (mCurrentStatus.equals(STATUS_OFF)) - showToolbarNotification(getString(R.string.open_orbot_to_connect_to_tor), NOTIFY_ID, R.drawable.ic_stat_tor); - replyWithStatus(mIntent); - - } else if (action.equals(TorControlCommands.SIGNAL_RELOAD)) { - requestTorRereadConfig(); - } else if (action.equals(TorControlCommands.SIGNAL_NEWNYM)) { - newIdentity(); - } else if (action.equals(CMD_ACTIVE)) { - sendSignalActive(); - } else if (action.equals(CMD_SET_EXIT)) { - setExitNode(mIntent.getStringExtra("exit")); - } else { - Log.w(TAG, "unhandled OrbotService Intent: " + action); + case ACTION_RESTART_VPN -> { + if (mVpnManager != null) mVpnManager.restartVPN(new Builder()); + } + case ACTION_STATUS -> { + if (mCurrentStatus.equals(STATUS_OFF)) + showToolbarNotification(getString(R.string.open_orbot_to_connect_to_tor), NOTIFY_ID, R.drawable.ic_stat_tor); + replyWithStatus(mIntent); + } + case TorControlCommands.SIGNAL_RELOAD -> requestTorRereadConfig(); + case TorControlCommands.SIGNAL_NEWNYM -> newIdentity(); + case CMD_ACTIVE -> { + sendSignalActive(); + replyWithStatus(mIntent); + } + case CMD_SET_EXIT -> setExitNode(mIntent.getStringExtra("exit")); + case ACTION_LOCAL_LOCALE_SET -> configLanguage(); + case CMD_SNOWFLAKE_PROXY -> { + if (Prefs.beSnowflakeProxy()) { + enableSnowflakeProxy(); + } else disableSnowflakeProxy(); + } + default -> Log.w(TAG, "unhandled OrbotService Intent: " + action); } } } @@ -1461,36 +1563,26 @@ public class OrbotService extends VpnService implements OrbotConstants { private class ActionBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { - case TorControlCommands.SIGNAL_NEWNYM: { - newIdentity(); - break; - } - case CMD_ACTIVE: { - sendSignalActive(); - break; - } - case LOCAL_ACTION_NOTIFICATION_START: { - startTor(); - break; - } - case ACTION_ERROR: { + case TorControlCommands.SIGNAL_NEWNYM -> newIdentity(); + case CMD_ACTIVE -> sendSignalActive(); + case LOCAL_ACTION_NOTIFICATION_START -> startTor(); + case ACTION_ERROR -> { if (showTorServiceErrorMsg) { Toast.makeText(context, getString(R.string.orbot_config_invalid), Toast.LENGTH_LONG).show(); showTorServiceErrorMsg = false; } stopTor(); - break; } - case ACTION_STATUS: { + case ACTION_STATUS -> { // hack for https://github.com/guardianproject/tor-android/issues/73 remove when fixed var newStatus = intent.getStringExtra(EXTRA_STATUS); - if (mCurrentStatus.equals(STATUS_OFF) && newStatus.equals(STATUS_STOPPING)) break; + if (mCurrentStatus.equals(STATUS_OFF) && newStatus.equals(STATUS_STOPPING)) + break; mCurrentStatus = newStatus; if (mCurrentStatus.equals(STATUS_OFF)) { showDeactivatedNotification(); } sendStatusToOrbotActivity(); - break; } } } diff --git a/src/main/java/org/torproject/android/service/StartTorReceiver.java b/src/main/java/org/torproject/android/service/StartTorReceiver.java index 32746f765bcd19dbbace5f98535029ea4d53a372..fa5229bdc8ffdec50d625982556cc8451d4abf5d 100644 --- a/src/main/java/org/torproject/android/service/StartTorReceiver.java +++ b/src/main/java/org/torproject/android/service/StartTorReceiver.java @@ -14,26 +14,30 @@ public class StartTorReceiver extends BroadcastReceiver implements OrbotConstant @Override public void onReceive(Context context, Intent intent) { - /* sanitize the Intent before forwarding it to OrbotService */ - Prefs.setContext(context); - String action = intent.getAction(); - if (TextUtils.equals(action, ACTION_START)) { - String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - if (Prefs.allowBackgroundStarts()) { - Intent startTorIntent = new Intent(context, OrbotService.class) - .setAction(action); - if (packageName != null) { - startTorIntent.putExtra(OrbotService.EXTRA_PACKAGE_NAME, packageName); + + try { + /* sanitize the Intent before forwarding it to OrbotService */ + Prefs.setContext(context); + String action = intent.getAction(); + if (TextUtils.equals(action, ACTION_START)) { + String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + if (Prefs.allowBackgroundStarts()) { + Intent startTorIntent = new Intent(context, OrbotService.class).setAction(action).putExtra(OrbotConstants.EXTRA_NOT_SYSTEM, true); + if (packageName != null) { + startTorIntent.putExtra(OrbotService.EXTRA_PACKAGE_NAME, packageName); + } + ContextCompat.startForegroundService(context, startTorIntent); + } else if (!TextUtils.isEmpty(packageName)) { + // let the requesting app know that the user has disabled + // starting via Intent + Intent startsDisabledIntent = new Intent(ACTION_STATUS); + startsDisabledIntent.putExtra(EXTRA_STATUS, STATUS_STARTS_DISABLED); + startsDisabledIntent.setPackage(packageName); + context.sendBroadcast(startsDisabledIntent); } - ContextCompat.startForegroundService(context, startTorIntent); - } else if (!TextUtils.isEmpty(packageName)) { - // let the requesting app know that the user has disabled - // starting via Intent - Intent startsDisabledIntent = new Intent(ACTION_STATUS); - startsDisabledIntent.putExtra(EXTRA_STATUS, STATUS_STARTS_DISABLED); - startsDisabledIntent.setPackage(packageName); - context.sendBroadcast(startsDisabledIntent); } + } catch (RuntimeException re) { + //catch this to avoid malicious launches as document Cure53 Audit: ORB-01-009 WP1/2: Orbot DoS via exported activity (High) } } } diff --git a/src/main/java/org/torproject/android/service/util/CustomTorResourceInstaller.java b/src/main/java/org/torproject/android/service/util/CustomTorResourceInstaller.java index 6b662555b208e6d440aa5d62fa425f1ddf53b0a5..4bd19fca24607b65ad523f7ee17d8ef7cc87b070 100644 --- a/src/main/java/org/torproject/android/service/util/CustomTorResourceInstaller.java +++ b/src/main/java/org/torproject/android/service/util/CustomTorResourceInstaller.java @@ -45,16 +45,14 @@ public class CustomTorResourceInstaller { stmOut.close(); stm.close(); - if (zis != null) - zis.close(); + if (zis != null) zis.close(); } /* * Extract the Tor resources from the APK file using ZIP */ public void installGeoIP() throws IOException { - if (!installFolder.exists()) - installFolder.mkdirs(); + if (!installFolder.exists()) installFolder.mkdirs(); assetToFile(OrbotConstants.GEOIP_ASSET_KEY, OrbotConstants.GEOIP_ASSET_KEY, false, false); assetToFile(OrbotConstants.GEOIP6_ASSET_KEY, OrbotConstants.GEOIP6_ASSET_KEY, false, false); } diff --git a/src/main/java/org/torproject/android/service/util/PowerConnectionReceiver.java b/src/main/java/org/torproject/android/service/util/PowerConnectionReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..b0ac28e26a21e093bb275d9f64bb79153f347c3e --- /dev/null +++ b/src/main/java/org/torproject/android/service/util/PowerConnectionReceiver.java @@ -0,0 +1,32 @@ +package org.torproject.android.service.util; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.torproject.android.service.OrbotService; + +import java.util.Objects; + +public class PowerConnectionReceiver extends BroadcastReceiver { + + private final OrbotService mService; + + public PowerConnectionReceiver(OrbotService service) { + mService = service; + } + + @Override + public void onReceive(Context context, Intent intent) { + + if (Prefs.limitSnowflakeProxyingCharging()) { + if (Objects.equals(intent.getAction(), Intent.ACTION_POWER_CONNECTED)) { + mService.setHasPower(true); + + } else if (Objects.equals(intent.getAction(), Intent.ACTION_POWER_DISCONNECTED)) { + mService.setHasPower(false); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/torproject/android/service/util/Prefs.java b/src/main/java/org/torproject/android/service/util/Prefs.java index 294e5fa207fb233fba864cd84f881c138ef34911..8d6ad833f457844a6d5aa2efaae5b7ccfce1768c 100644 --- a/src/main/java/org/torproject/android/service/util/Prefs.java +++ b/src/main/java/org/torproject/android/service/util/Prefs.java @@ -2,6 +2,15 @@ package org.torproject.android.service.util; import android.content.Context; import android.content.SharedPreferences; + +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; + +import org.torproject.android.service.OrbotConstants; + +import java.util.Locale; +import java.util.concurrent.TimeUnit; import android.text.TextUtils; import org.torproject.android.service.OrbotConstants; @@ -14,10 +23,8 @@ public class Prefs { private final static String PREF_BRIDGES_ENABLED = "pref_bridges_enabled"; private final static String PREF_BRIDGES_LIST = "pref_bridges_list"; private final static String PREF_DEFAULT_LOCALE = "pref_default_locale"; + private final static String PREF_DETECT_ROOT = "pref_detect_root"; private final static String PREF_ENABLE_LOGGING = "pref_enable_logging"; - private final static String PREF_ENABLE_SNOWFLAKE_LOGGING = "pref_enable_snowflake_logging"; - private final static String PREF_EXPANDED_NOTIFICATIONS = "pref_expanded_notifications"; - private final static String PREF_PERSIST_NOTIFICATIONS = "pref_persistent_notifications"; private final static String PREF_START_ON_BOOT = "pref_start_boot"; private final static String PREF_ALLOW_BACKGROUND_STARTS = "pref_allow_background_starts"; private final static String PREF_OPEN_PROXY_ON_ALL_INTERFACES = "pref_open_proxy_on_all_interfaces"; @@ -25,22 +32,61 @@ public class Prefs { private final static String PREF_EXIT_NODES = "pref_exit_nodes"; private final static String PREF_BE_A_SNOWFLAKE = "pref_be_a_snowflake"; private final static String PREF_SHOW_SNOWFLAKE_MSG = "pref_show_snowflake_proxy_msg"; - private final static String PREF_BE_A_SNOWFLAKE_LIMIT = "pref_be_a_snowflake_limit"; + private final static String PREF_BE_A_SNOWFLAKE_LIMIT_WIFI = "pref_be_a_snowflake_limit_wifi"; + private final static String PREF_BE_A_SNOWFLAKE_LIMIT_CHARGING = "pref_be_a_snowflake_limit_charing"; + + private final static String PREF_SMART_TRY_SNOWFLAKE = "pref_smart_try_snowflake"; + private final static String PREF_SMART_TRY_OBFS4 = "pref_smart_try_obfs"; + private static final String PREF_POWER_USER_MODE = "pref_power_user"; + private final static String PREF_HOST_ONION_SERVICES = "pref_host_onionservices"; private final static String PREF_SNOWFLAKES_SERVED_COUNT = "pref_snowflakes_served"; - private final static String PREF_ENABLE_NOTIFICATION = "pref_enable_notification"; + private final static String PREF_SNOWFLAKES_SERVED_COUNT_WEEKLY = "pref_snowflakes_served_weekly"; + private static final String PREF_CURRENT_VERSION = "pref_current_version"; + + private static final String PREF_CONNECTION_PATHWAY = "pref_connection_pathway"; + public static final String PATHWAY_SMART = "smart", PATHWAY_DIRECT = "direct", + PATHWAY_SNOWFLAKE = "snowflake", PATHWAY_SNOWFLAKE_AMP = "snowflake_amp", PATHWAY_CUSTOM = "custom"; + + public static final String PREF_SECURE_WINDOW_FLAG = "pref_flag_secure"; + + private final static String PREF_ENABLE_NOTIFICATION = "pref_enable_notification"; private static SharedPreferences prefs; - private static Context sContext; + + public static int getCurrentVersionForUpdate() { + return prefs.getInt(PREF_CURRENT_VERSION, 0); + } + + public static void setCurrentVersionForUpdate(int version) { + putInt(PREF_CURRENT_VERSION, version); + } + + private static final String PREF_REINSTALL_GEOIP = "pref_geoip"; + public static boolean isGeoIpReinstallNeeded() { + return prefs.getBoolean(PREF_REINSTALL_GEOIP, true); + } + public static void setIsGeoIpReinstallNeeded(boolean reinstallNeeded) { + putBoolean(PREF_REINSTALL_GEOIP, reinstallNeeded); + } public static void setContext(Context context) { - if (prefs == null) + if (prefs == null) { prefs = getSharedPrefs(context); + } + + } + + public static void initWeeklyWorker () { + PeriodicWorkRequest.Builder myWorkBuilder = + new PeriodicWorkRequest.Builder(PrefsWeeklyWorker.class, 7, TimeUnit.DAYS); - sContext = context; + PeriodicWorkRequest myWork = myWorkBuilder.build(); + WorkManager.getInstance() + .enqueueUniquePeriodicWork("prefsWeeklyWorker", ExistingPeriodicWorkPolicy.KEEP, myWork); } private static void putBoolean(String key, boolean value) { @@ -64,8 +110,9 @@ public class Prefs { } public static boolean bridgesEnabled() { - boolean bridgesEnabled = !TextUtils.isEmpty(getBridgesList()); - return prefs.getBoolean(PREF_BRIDGES_ENABLED, bridgesEnabled); + //if phone is in Farsi, enable bridges by default + boolean bridgesEnabledDefault = Locale.getDefault().getLanguage().equals("fa"); + return prefs.getBoolean(PREF_BRIDGES_ENABLED, bridgesEnabledDefault); } public static void putBridgesEnabled(boolean value) { @@ -73,8 +120,10 @@ public class Prefs { } public static String getBridgesList() { - String defaultBridge = sContext.getString(R.string.default_bridge); - return prefs.getString(PREF_BRIDGES_LIST, defaultBridge); + String defaultBridgeType = "obfs4"; + if (Locale.getDefault().getLanguage().equals("fa")) + defaultBridgeType = "meek"; //if Farsi, use meek as the default bridge type + return prefs.getString(PREF_BRIDGES_LIST, defaultBridgeType); } public static void setBridgesList(String value) { @@ -85,8 +134,15 @@ public class Prefs { return prefs.getString(PREF_DEFAULT_LOCALE, Locale.getDefault().getLanguage()); } + public static void setDefaultLocale(String value) { + putString(PREF_DEFAULT_LOCALE, value); + } + + public static boolean detectRoot () { + return prefs.getBoolean(PREF_DETECT_ROOT,true); + } + public static boolean beSnowflakeProxy () { - if (Prefs.bridgesEnabled()) return false; return prefs.getBoolean(PREF_BE_A_SNOWFLAKE,false); } @@ -98,24 +154,24 @@ public class Prefs { putBoolean(PREF_BE_A_SNOWFLAKE,beSnowflakeProxy); } - public static boolean limitSnowflakeProxying () { - return prefs.getBoolean(PREF_BE_A_SNOWFLAKE_LIMIT,true); + public static void setBeSnowflakeProxyLimitWifi (boolean beSnowflakeProxy) { + putBoolean(PREF_BE_A_SNOWFLAKE_LIMIT_WIFI,beSnowflakeProxy); } - public static void setDefaultLocale(String value) { - putString(PREF_DEFAULT_LOCALE, value); + public static void setBeSnowflakeProxyLimitCharging (boolean beSnowflakeProxy) { + putBoolean(PREF_BE_A_SNOWFLAKE_LIMIT_CHARGING,beSnowflakeProxy); } - public static boolean showExpandedNotifications() { - return prefs.getBoolean(PREF_EXPANDED_NOTIFICATIONS, true); + public static boolean limitSnowflakeProxyingWifi () { + return prefs.getBoolean(PREF_BE_A_SNOWFLAKE_LIMIT_WIFI,false); } - public static boolean useDebugLogging() { - return prefs.getBoolean(PREF_ENABLE_LOGGING, false); + public static boolean limitSnowflakeProxyingCharging () { + return prefs.getBoolean(PREF_BE_A_SNOWFLAKE_LIMIT_CHARGING,false); } - public static boolean useSnowflakeLogging() { - return prefs.getBoolean(PREF_ENABLE_SNOWFLAKE_LOGGING, false); + public static boolean useDebugLogging() { + return prefs.getBoolean(PREF_ENABLE_LOGGING, false); } public static boolean allowBackgroundStarts() { @@ -154,13 +210,61 @@ public class Prefs { return prefs.getBoolean(PREF_ENABLE_NOTIFICATION, true); } + public static void setExitNodes(String country) { + putString(PREF_EXIT_NODES, country); + } + public static SharedPreferences getSharedPrefs(Context context) { return context.getSharedPreferences(OrbotConstants.PREF_TOR_SHARED_PREFS, Context.MODE_MULTI_PROCESS); } public static int getSnowflakesServed () { return prefs.getInt(PREF_SNOWFLAKES_SERVED_COUNT,0);} + public static int getSnowflakesServedWeekly () { return prefs.getInt(PREF_SNOWFLAKES_SERVED_COUNT_WEEKLY,0);} public static void addSnowflakeServed () { putInt(PREF_SNOWFLAKES_SERVED_COUNT,getSnowflakesServed()+1); + putInt(PREF_SNOWFLAKES_SERVED_COUNT_WEEKLY,getSnowflakesServedWeekly()+1); + } + + public static void resetSnowflakesServedWeekly () { + putInt(PREF_SNOWFLAKES_SERVED_COUNT_WEEKLY,0); + + } + + public static String getConnectionPathway() { + // TODO lots of migration work need to be done here when users upgrade to orbot 17 !!! + return prefs.getString(PREF_CONNECTION_PATHWAY, PATHWAY_SMART); + } + + public static void putConnectionPathway(String pathway) { + putString(PREF_CONNECTION_PATHWAY, pathway); + } + + public static void putPrefSmartTrySnowflake(boolean trySnowflake) { + putBoolean(PREF_SMART_TRY_SNOWFLAKE, trySnowflake); + } + + public static boolean getPrefSmartTrySnowflake() { + return prefs.getBoolean(PREF_SMART_TRY_SNOWFLAKE, false); + } + + public static void putPrefSmartTryObfs4(String bridges) { + putString(PREF_SMART_TRY_OBFS4, bridges); + } + + public static String getPrefSmartTryObfs4() { + return prefs.getString(PREF_SMART_TRY_OBFS4, null); + } + + public static boolean isPowerUserMode() { + return prefs.getBoolean(PREF_POWER_USER_MODE, false); + } + + public static void setSecureWindow (boolean isFlagSecure) { + putBoolean(PREF_SECURE_WINDOW_FLAG, isFlagSecure); + } + + public static boolean isSecureWindow () { + return prefs.getBoolean(PREF_SECURE_WINDOW_FLAG, true); } } diff --git a/src/main/java/org/torproject/android/service/util/PrefsWeeklyWorker.java b/src/main/java/org/torproject/android/service/util/PrefsWeeklyWorker.java new file mode 100644 index 0000000000000000000000000000000000000000..ab1428700785f2ef2d3c0b439c753486fad82b9f --- /dev/null +++ b/src/main/java/org/torproject/android/service/util/PrefsWeeklyWorker.java @@ -0,0 +1,23 @@ +package org.torproject.android.service.util; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +public class PrefsWeeklyWorker extends Worker { + + public PrefsWeeklyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + @NonNull + @Override + public Result doWork() { + + Prefs.resetSnowflakesServedWeekly(); + + return Result.success(); + } +} diff --git a/src/main/java/org/torproject/android/service/util/TCPSourceApp.java b/src/main/java/org/torproject/android/service/util/TCPSourceApp.java index 0d105452c103b8daead01061ac84e9efc5354f5c..14d5039cce9dfba77a67ed4757ec173e6d04ee17 100644 --- a/src/main/java/org/torproject/android/service/util/TCPSourceApp.java +++ b/src/main/java/org/torproject/android/service/util/TCPSourceApp.java @@ -133,9 +133,9 @@ public class TCPSourceApp { if (hasIPv6) while (m6.find()) { - String addressEntry = m6.group(1); +// String addressEntry = m6.group(1); String portEntry = m6.group(2); - int pidEntry = Integer.valueOf(m6.group(3)); + int pidEntry = Integer.parseInt(m6.group(3)); if (Integer.parseInt(portEntry, 16) == dport) { PackageManager manager = context.getPackageManager(); @@ -151,14 +151,6 @@ public class TCPSourceApp { } } - } catch (SocketException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (NameNotFoundException e) { - e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } @@ -198,14 +190,6 @@ public class TCPSourceApp { } } - } catch (SocketException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (NameNotFoundException e) { - e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/org/torproject/android/service/util/Utils.java b/src/main/java/org/torproject/android/service/util/Utils.java index 885ca1fec357baa1e5186b81d2f4b4115586de87..90475af43d95d72cc005b2ea05801651ac8b308d 100644 --- a/src/main/java/org/torproject/android/service/util/Utils.java +++ b/src/main/java/org/torproject/android/service/util/Utils.java @@ -4,19 +4,13 @@ package org.torproject.android.service.util; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.Socket; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; +import java.util.Locale; public class Utils { @@ -32,7 +26,7 @@ public class Utils { } } - public static String readString(InputStream stream) { + public static String readInputStreamAsString(InputStream stream) { String line; StringBuilder out = new StringBuilder(); @@ -53,84 +47,11 @@ public class Utils { } public static String convertCountryCodeToFlagEmoji(String countryCode) { + countryCode = countryCode.toUpperCase(Locale.getDefault()); int flagOffset = 0x1F1E6; int asciiOffset = 0x41; int firstChar = Character.codePointAt(countryCode, 0) - asciiOffset + flagOffset; int secondChar = Character.codePointAt(countryCode, 1) - asciiOffset + flagOffset; return new String(Character.toChars(firstChar)) + new String(Character.toChars(secondChar)); } - - /* - * Zips a file at a location and places the resulting zip file at the toLocation - * Example: zipFileAtPath("downloads/myfolder", "downloads/myFolder.zip"); - */ - public static void zipFileAtPath(String sourcePath, String toLocation) { - final int BUFFER = 2048; - - File sourceFile = new File(sourcePath); - try { - BufferedInputStream origin; - FileOutputStream dest = new FileOutputStream(toLocation); - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream( - dest)); - if (sourceFile.isDirectory()) { - zipSubFolder(out, sourceFile, sourceFile.getParent().length()); - } else { - byte[] data = new byte[BUFFER]; - FileInputStream fi = new FileInputStream(sourcePath); - origin = new BufferedInputStream(fi, BUFFER); - ZipEntry entry = new ZipEntry(getLastPathComponent(sourcePath)); - entry.setTime(sourceFile.lastModified()); // to keep modification time after unzipping - out.putNextEntry(entry); - int count; - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - } - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void zipSubFolder(ZipOutputStream out, File folder, - int basePathLength) throws IOException { - final int BUFFER = 2048; - - File[] fileList = folder.listFiles(); - BufferedInputStream origin; - for (File file : fileList) { - if (file.isDirectory()) { - zipSubFolder(out, file, basePathLength); - } else { - byte[] data = new byte[BUFFER]; - String unmodifiedFilePath = file.getPath(); - String relativePath = unmodifiedFilePath - .substring(basePathLength); - FileInputStream fi = new FileInputStream(unmodifiedFilePath); - origin = new BufferedInputStream(fi, BUFFER); - ZipEntry entry = new ZipEntry(relativePath); - entry.setTime(file.lastModified()); // to keep modification time after unzipping - out.putNextEntry(entry); - int count; - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - origin.close(); - } - } - } - - /* - * gets the last path component - * - * Example: getLastPathComponent("downloads/example/fileToZip"); - * Result: "fileToZip" - */ - public static String getLastPathComponent(String filePath) { - String[] segments = filePath.split("/"); - if (segments.length == 0) - return ""; - return segments[segments.length - 1]; - } } diff --git a/src/main/java/org/torproject/android/service/vpn/DNSResolver.java b/src/main/java/org/torproject/android/service/vpn/DNSResolver.java index 8ceb4a724f49347ba4fb75684b6696998d6830b9..4286955351b47429ef832af1167a30566abf112b 100644 --- a/src/main/java/org/torproject/android/service/vpn/DNSResolver.java +++ b/src/main/java/org/torproject/android/service/vpn/DNSResolver.java @@ -22,8 +22,7 @@ public class DNSResolver { public DnsPacket processDNS(DnsPacket dnsRequest) throws IOException { - if (mLocalhost == null) - mLocalhost = InetAddress.getLocalHost(); + if (mLocalhost == null) mLocalhost = InetAddress.getLocalHost(); if (OrbotService.shouldBlock != null) { DnsPacket blockedResponse = OrbotService.shouldBlock.apply(dnsRequest); @@ -44,6 +43,8 @@ public class DNSResolver { packet = new DatagramPacket(buf, buf.length); datagramSocket.receive(packet); + datagramSocket.close(); + byte[] dnsResp = packet.getData(); DnsPacket dnsResponse = null; if (dnsResp != null) { diff --git a/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java b/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java index 78a15783e4f04a6ed960fb6c01c4b0103f87cc92..348d0fa6b80f9e1e01172e9b23cabc7bdb03aaa3 100644 --- a/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java +++ b/src/main/java/org/torproject/android/service/vpn/OrbotVpnManager.java @@ -16,8 +16,6 @@ package org.torproject.android.service.vpn; -import android.annotation.TargetApi; -import android.app.Service; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; @@ -27,12 +25,10 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.system.OsConstants; import android.util.Log; import android.widget.Toast; -import com.runjva.sourceforge.jsocks.protocol.ProxyServer; -import com.runjva.sourceforge.jsocks.server.ServerAuthenticatorNone; - import org.pcap4j.packet.IllegalRawDataException; import org.pcap4j.packet.IpPacket; import org.pcap4j.packet.IpSelector; @@ -48,29 +44,20 @@ import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.net.InetAddress; import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; - -import androidx.annotation.ChecksSdkIntAtLeast; - import IPtProxy.IPtProxy; import IPtProxy.PacketFlow; public class OrbotVpnManager implements Handler.Callback, OrbotConstants { - private static final String TAG = "OrbotVpnService"; - @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.LOLLIPOP) - private final static boolean mIsLollipop = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - public static int sSocksProxyServerPort = -1; - public static String sSocksProxyLocalhost = null; + private static final String TAG = "OrbotVpnManager"; boolean isStarted = false; private final static String mSessionName = "OrbotVPN"; private ParcelFileDescriptor mInterface; private int mTorSocks = -1; private int mTorDns = -1; - private ProxyServer mSocksProxyServer; private final VpnService mService; private final SharedPreferences prefs; private DNSResolver mDnsResolver; @@ -89,99 +76,50 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { prefs = Prefs.getSharedPrefs(mService.getApplicationContext()); } - public int handleIntent(VpnService.Builder builder, Intent intent) { + public void handleIntent(VpnService.Builder builder, Intent intent) { if (intent != null) { var action = intent.getAction(); if (action != null) { - if (action.equals(ACTION_START_VPN) || action.equals(ACTION_START) ) { - Log.d(TAG, "starting VPN"); - isStarted = true; - } else if (action.equals(ACTION_STOP_VPN) || action.equals(ACTION_STOP)) { - isStarted = false; - Log.d(TAG, "stopping VPN"); - stopVPN(); - - //reset ports - mTorSocks = -1; - mTorDns = -1; - - } else if (action.equals(OrbotConstants.LOCAL_ACTION_PORTS)) { - Log.d(TAG, "setting VPN ports"); - - int torSocks = intent.getIntExtra(OrbotService.EXTRA_SOCKS_PROXY_PORT, -1); - int torHttp = intent.getIntExtra(OrbotService.EXTRA_HTTP_PROXY_PORT,-1); - int torDns = intent.getIntExtra(OrbotService.EXTRA_DNS_PORT, -1); - - //if running, we need to restart - if ((torSocks != -1 && torSocks != mTorSocks - && torDns != -1 && torDns != mTorDns)) { - - mTorSocks = torSocks; - mTorDns = torDns; - - if (!mIsLollipop) { - startSocksBypass(); - } - - setupTun2Socks(builder); + switch (action) { + case ACTION_START_VPN, ACTION_START -> { + Log.d(TAG, "starting VPN"); + isStarted = true; } - } - } - } - return Service.START_STICKY; - } - - public void restartVPN (VpnService.Builder builder) { - stopVPN(); - if (!mIsLollipop) { - startSocksBypass(); - } - setupTun2Socks(builder); - } - - private void startSocksBypass() { - new Thread() { - public void run() { - - //generate the proxy port that the - if (sSocksProxyServerPort == -1) { - try { - sSocksProxyLocalhost = "127.0.0.1";// InetAddress.getLocalHost().getHostAddress(); - sSocksProxyServerPort = (int) ((Math.random() * 1000) + 10000); - - } catch (Exception e) { - Log.e(TAG, "Unable to access localhost", e); - throw new RuntimeException("Unable to access localhost: " + e); + case ACTION_STOP_VPN, ACTION_STOP -> { + isStarted = false; + Log.d(TAG, "stopping VPN"); + stopVPN(); + + //reset ports + mTorSocks = -1; + mTorDns = -1; } - } + case OrbotConstants.LOCAL_ACTION_PORTS -> { + Log.d(TAG, "setting VPN ports"); + int torSocks = intent.getIntExtra(OrbotService.EXTRA_SOCKS_PROXY_PORT, -1); +// int torHttp = intent.getIntExtra(OrbotService.EXTRA_HTTP_PROXY_PORT,-1); + int torDns = intent.getIntExtra(OrbotService.EXTRA_DNS_PORT, -1); - if (mSocksProxyServer != null) { - stopSocksBypass(); - } + //if running, we need to restart + if ((torSocks != -1 && torSocks != mTorSocks && torDns != -1 && torDns != mTorDns)) { - try { - mSocksProxyServer = new ProxyServer(new ServerAuthenticatorNone(null, null)); - ProxyServer.setVpnService(mService); - mSocksProxyServer.start(sSocksProxyServerPort, 5, InetAddress.getLocalHost()); + mTorSocks = torSocks; + mTorDns = torDns; - } catch (Exception e) { - Log.e(TAG, "error getting host", e); + setupTun2Socks(builder); + } + } } } - }.start(); + } } - private synchronized void stopSocksBypass() { - if (mSocksProxyServer != null) { - mSocksProxyServer.stop(); - mSocksProxyServer = null; - } + public void restartVPN(VpnService.Builder builder) { + stopVPN(); + setupTun2Socks(builder); } private void stopVPN() { - if (!mIsLollipop) - stopSocksBypass(); - keepRunningPacket = false; if (mInterface != null) { @@ -200,9 +138,7 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { mInterface.close(); mInterface = null; - } catch (Exception e) { - Log.d(TAG, "error stopping tun2socks", e); - } catch (Error e) { + } catch (Exception | Error e) { Log.d(TAG, "error stopping tun2socks", e); } } @@ -220,67 +156,55 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { return true; } - public final static String FAKE_DNS = "10.10.10.10"; + public final static String FAKE_DNS = "10.0.0.1"; private synchronized void setupTun2Socks(final VpnService.Builder builder) { try { - final String localhost = "127.0.0.1"; final String defaultRoute = "0.0.0.0"; final String virtualGateway = "192.168.50.1"; // builder.setMtu(VPN_MTU); // builder.addAddress(virtualGateway, 32); builder.addAddress(virtualGateway, 24) - //.addRoute(defaultRoute, 0) - .setSession(mService.getString(R.string.orbot_vpn)); - - for (String route : mService.getApplicationContext().getResources() - .getStringArray(R.array.all_routes_except_excluded)) { - String[] splitRoute = route.split("/"); - builder.addRoute(splitRoute[0], Integer.parseInt(splitRoute[1])); - } - - builder.addDnsServer(FAKE_DNS) //just setting a value here so DNS is captured by TUN interface - .addRoute(FAKE_DNS, 32); - + .addRoute(defaultRoute, 0) + .addRoute(FAKE_DNS, 32) + .addDnsServer(FAKE_DNS) //just setting a value here so DNS is captured by TUN interface + .setSession(mService.getString(R.string.orbot_vpn)); //handle ipv6 - //builder.addAddress("fdfe:dcba:9876::1", 126); - //builder.addRoute("::", 0); + builder.addAddress("fdfe:dcba:9876::1", 126); + builder.addRoute("::", 0); + + /* + * Can't use this since our HTTP proxy is only CONNECT and not a full proxy + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + builder.setHttpProxy(ProxyInfo.buildDirectProxy("localhost",mTorHttp)); + }**/ - if (mIsLollipop) - doLollipopAppRouting(builder); + doAppBasedRouting(builder); // https://developer.android.com/reference/android/net/VpnService.Builder#setMetered(boolean) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { builder.setMetered(false); + // Explicitly allow both families, so we do not block + // traffic for ones without DNS servers (issue 129). + builder.allowFamily(OsConstants.AF_INET); + builder.allowFamily(OsConstants.AF_INET6); - /** - // Allow applications to bypass the VPN - builder.allowBypass(); - - // Explicitly allow both families, so we do not block - // traffic for ones without DNS servers (issue 129). - builder.allowFamily(OsConstants.AF_INET); - builder.allowFamily(OsConstants.AF_INET6); - **/ } - builder.setSession(mSessionName) - .setConfigureIntent(null); // previously this was set to a null member variable - - if (mIsLollipop) - builder.setBlocking(true); + builder.setSession(mSessionName) + .setConfigureIntent(null) // previously this was set to a null member variable + .setBlocking(true); mInterface = builder.establish(); - mDnsResolver = new DNSResolver(mTorDns); final Handler handler = new Handler(Looper.getMainLooper()); handler.postDelayed(() -> { try { - startListeningToFD(localhost); + startListeningToFD(); } catch (IOException e) { Log.d(TAG, "VPN tun listening has stopped", e); } @@ -291,7 +215,7 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { } } - private void startListeningToFD(String localhost) throws IOException { + private void startListeningToFD() throws IOException { if (mInterface == null) return; // Prepare hasn't been called yet fis = new FileInputStream(mInterface.getFileDescriptor()); @@ -306,13 +230,13 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { } }; - IPtProxy.startSocks(pFlow,localhost,mTorSocks); + IPtProxy.startSocks(pFlow, "127.0.0.1", mTorSocks); //read packets from TUN and send to go-tun2socks mThreadPacket = new Thread() { - public void run () { + public void run() { - var buffer = new byte[32767*2]; //64k + var buffer = new byte[32767 * 2]; //64k keepRunningPacket = true; while (keepRunningPacket) { try { @@ -321,21 +245,21 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { if (pLen > 0) { var pdata = Arrays.copyOf(buffer, pLen); try { - var packet = IpSelector.newPacket(pdata,0,pdata.length); + var packet = IpSelector.newPacket(pdata, 0, pdata.length); - if (packet instanceof IpPacket) { - IpPacket ipPacket = (IpPacket) packet; + if (packet instanceof IpPacket ipPacket) { if (isPacketDNS(ipPacket)) mExec.execute(new RequestPacketHandler(ipPacket, pFlow, mDnsResolver)); - else - IPtProxy.inputPacket(pdata); + else if (isPacketICMP(ipPacket)) { + //do nothing, drop! + } else IPtProxy.inputPacket(pdata); } } catch (IllegalRawDataException e) { Log.e(TAG, e.getLocalizedMessage()); } } } catch (Exception e) { - Log.d(TAG, "error reading from VPN fd: " + e.getLocalizedMessage()); + Log.d(TAG, "error reading from VPN fd: " + e.getLocalizedMessage()); } } } @@ -351,23 +275,30 @@ public class OrbotVpnManager implements Handler.Callback, OrbotConstants { return false; } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void doLollipopAppRouting(VpnService.Builder builder) throws NameNotFoundException { + private static boolean isPacketICMP(IpPacket p) { + return (p.getHeader().getProtocol() == IpNumber.ICMPV4 || p.getHeader().getProtocol() == IpNumber.ICMPV6); + } + + private void doAppBasedRouting(VpnService.Builder builder) throws NameNotFoundException { var apps = TorifiedApp.getApps(mService, prefs); - var canBypass = !isVpnLockdown(mService); + var isLockdownMode = isVpnLockdown(mService); - if (canBypass) { + if (!isLockdownMode) { for (TorifiedApp app : apps) { if (app.isBypassTor()) { builder.addDisallowedApplication(app.getPackageName()); } } - builder.addDisallowedApplication(mService.getPackageName()); for (String packageName : OrbotConstants.BYPASS_VPN_PACKAGES) builder.addDisallowedApplication(packageName); } else { - Log.i(TAG, "Skip bypass because vpnLockdown: " + !canBypass); + /* TODO https://github.com/guardianproject/orbot/issues/774 + Need to allow briar, onionshare, etc to enter orbot's vpn gateway, but not enter the tor + network, that way these apps can use their own tor connection + // TODO "add" these packages here... + */ + Log.i(TAG, "Skip bypass because vpnLockdown: " + isLockdownMode); } } diff --git a/src/main/java/org/torproject/android/service/vpn/RequestPacketHandler.java b/src/main/java/org/torproject/android/service/vpn/RequestPacketHandler.java index d733bb44a40002d6da7badfbd4685b490295405c..339696fb01f0fb175eb46c653c6e1112cd2aaf98 100644 --- a/src/main/java/org/torproject/android/service/vpn/RequestPacketHandler.java +++ b/src/main/java/org/torproject/android/service/vpn/RequestPacketHandler.java @@ -21,82 +21,58 @@ public class RequestPacketHandler implements Runnable { private static final String TAG = "RequestPacketHandler"; - public RequestPacketHandler (IpPacket packet, PacketFlow pFLow, DNSResolver dnsResolver) { + public RequestPacketHandler(IpPacket packet, PacketFlow pFLow, DNSResolver dnsResolver) { this.packet = packet; this.pFlow = pFLow; this.mDnsResolver = dnsResolver; } + public void run() { - try { - UdpPacket udpPacket = (UdpPacket) packet.getPayload(); - DnsPacket dnsRequest = (DnsPacket) udpPacket.getPayload(); - - DnsPacket dnsResponse = mDnsResolver.processDNS(dnsRequest); - - if (dnsResponse != null) { - DnsPacket.Builder dnsBuilder = new DnsPacket.Builder(); - dnsBuilder.questions(dnsRequest.getHeader().getQuestions()); - dnsBuilder.id(dnsRequest.getHeader().getId()); - - dnsBuilder.answers(dnsResponse.getHeader().getAnswers()); - dnsBuilder.response(dnsResponse.getHeader().isResponse()); - dnsBuilder.additionalInfo(dnsResponse.getHeader().getAdditionalInfo()); - dnsBuilder.qdCount(dnsResponse.getHeader().getQdCount()); - dnsBuilder.anCount(dnsResponse.getHeader().getAnCount()); - dnsBuilder.arCount(dnsResponse.getHeader().getArCount()); - dnsBuilder.opCode(dnsResponse.getHeader().getOpCode()); - dnsBuilder.rCode(dnsResponse.getHeader().getrCode()); - dnsBuilder.authenticData(dnsResponse.getHeader().isAuthenticData()); - dnsBuilder.authoritativeAnswer(dnsResponse.getHeader().isAuthoritativeAnswer()); - dnsBuilder.authorities(dnsResponse.getHeader().getAuthorities()); - - UdpPacket.Builder udpBuilder = new UdpPacket.Builder(udpPacket) - .srcPort(udpPacket.getHeader().getDstPort()) - .dstPort(udpPacket.getHeader().getSrcPort()) - .srcAddr(packet.getHeader().getDstAddr()) - .dstAddr(packet.getHeader().getSrcAddr()) - .correctChecksumAtBuild(true) - .correctLengthAtBuild(true) - .payloadBuilder(dnsBuilder); - - IpPacket respPacket = null; - - if (packet instanceof IpV4Packet) { - - IpV4Packet ipPacket = (IpV4Packet)packet; - IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder(); - ipv4Builder - .version(ipPacket.getHeader().getVersion()) - .protocol(ipPacket.getHeader().getProtocol()) - .tos(ipPacket.getHeader().getTos()) - .srcAddr(ipPacket.getHeader().getDstAddr()) - .dstAddr(ipPacket.getHeader().getSrcAddr()) - .correctChecksumAtBuild(true) - .correctLengthAtBuild(true) - .dontFragmentFlag(ipPacket.getHeader().getDontFragmentFlag()) - .reservedFlag(ipPacket.getHeader().getReservedFlag()) - .moreFragmentFlag(ipPacket.getHeader().getMoreFragmentFlag()) - .ttl(Integer.valueOf(64).byteValue()) - .payloadBuilder(udpBuilder); - - respPacket = ipv4Builder.build(); - - } - else if (packet instanceof IpV6Packet) { - respPacket = new IpV6Packet.Builder((IpV6Packet) packet) - .srcAddr((Inet6Address) packet.getHeader().getDstAddr()) - .dstAddr((Inet6Address) packet.getHeader().getSrcAddr()) - .payloadBuilder(udpBuilder) - .build(); - } - - - byte[] rawResponse = respPacket.getRawData(); - pFlow.writePacket(rawResponse); + try { + UdpPacket udpPacket = (UdpPacket) packet.getPayload(); + DnsPacket dnsRequest = (DnsPacket) udpPacket.getPayload(); + + DnsPacket dnsResponse = mDnsResolver.processDNS(dnsRequest); + + if (dnsResponse != null) { + DnsPacket.Builder dnsBuilder = new DnsPacket.Builder(); + dnsBuilder.questions(dnsRequest.getHeader().getQuestions()); + dnsBuilder.id(dnsRequest.getHeader().getId()); + + dnsBuilder.answers(dnsResponse.getHeader().getAnswers()); + dnsBuilder.response(dnsResponse.getHeader().isResponse()); + dnsBuilder.additionalInfo(dnsResponse.getHeader().getAdditionalInfo()); + dnsBuilder.qdCount(dnsResponse.getHeader().getQdCount()); + dnsBuilder.anCount(dnsResponse.getHeader().getAnCount()); + dnsBuilder.arCount(dnsResponse.getHeader().getArCount()); + dnsBuilder.opCode(dnsResponse.getHeader().getOpCode()); + dnsBuilder.rCode(dnsResponse.getHeader().getrCode()); + dnsBuilder.authenticData(dnsResponse.getHeader().isAuthenticData()); + dnsBuilder.authoritativeAnswer(dnsResponse.getHeader().isAuthoritativeAnswer()); + dnsBuilder.authorities(dnsResponse.getHeader().getAuthorities()); + + UdpPacket.Builder udpBuilder = new UdpPacket.Builder(udpPacket).srcPort(udpPacket.getHeader().getDstPort()).dstPort(udpPacket.getHeader().getSrcPort()).srcAddr(packet.getHeader().getDstAddr()).dstAddr(packet.getHeader().getSrcAddr()).correctChecksumAtBuild(true).correctLengthAtBuild(true).payloadBuilder(dnsBuilder); + + IpPacket respPacket = null; + + if (packet instanceof IpV4Packet ipPacket) { + + IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder(); + ipv4Builder.version(ipPacket.getHeader().getVersion()).protocol(ipPacket.getHeader().getProtocol()).tos(ipPacket.getHeader().getTos()).srcAddr(ipPacket.getHeader().getDstAddr()).dstAddr(ipPacket.getHeader().getSrcAddr()).correctChecksumAtBuild(true).correctLengthAtBuild(true).dontFragmentFlag(ipPacket.getHeader().getDontFragmentFlag()).reservedFlag(ipPacket.getHeader().getReservedFlag()).moreFragmentFlag(ipPacket.getHeader().getMoreFragmentFlag()).ttl(Integer.valueOf(64).byteValue()).payloadBuilder(udpBuilder); + + respPacket = ipv4Builder.build(); + + } else if (packet instanceof IpV6Packet) { + respPacket = new IpV6Packet.Builder((IpV6Packet) packet).srcAddr((Inet6Address) packet.getHeader().getDstAddr()).dstAddr((Inet6Address) packet.getHeader().getSrcAddr()).payloadBuilder(udpBuilder).build(); } - } catch (Exception ioe) { - Log.e(TAG, "could not parse DNS packet: " + ioe); + + byte[] rawResponse = respPacket.getRawData(); + pFlow.writePacket(rawResponse); } + + } catch (Exception ioe) { + Log.e(TAG, "could not parse DNS packet: " + ioe, ioe); + } } } diff --git a/src/main/java/org/torproject/android/service/vpn/TorifiedApp.java b/src/main/java/org/torproject/android/service/vpn/TorifiedApp.java index aa6963c441ddedd4455f9f03a9cd126987a103f1..69c7795ed23d281d55668214718172f2297b7d83 100644 --- a/src/main/java/org/torproject/android/service/vpn/TorifiedApp.java +++ b/src/main/java/org/torproject/android/service/vpn/TorifiedApp.java @@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable; import org.torproject.android.service.OrbotConstants; +import java.text.Normalizer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -29,9 +30,6 @@ public class TorifiedApp implements Comparable { private boolean bypassTor = false; private boolean usesInternet = false; - private int[] enabledPorts; - - public static ArrayList getApps(Context context, SharedPreferences prefs) { @@ -148,14 +146,6 @@ public class TorifiedApp implements Comparable { this.bypassTor = bypassTor; } - public int[] getEnabledPorts() { - return enabledPorts; - } - - public void setEnabledPorts(int[] enabledPorts) { - this.enabledPorts = enabledPorts; - } - public boolean isEnabled() { return enabled; } diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml index 29faf0be6ed4ef01e3926634f779473d86a4ca72..103fd064bfaff16b6760c3141da18ad128b70cdf 100644 --- a/src/main/res/values-ar/strings.xml +++ b/src/main/res/values-ar/strings.xml @@ -1,6 +1,7 @@ - جاري تشغيل اوربوت... + اوربوت هو تطبيق الوكيل-البروكسي الحر الذي يمكّن تطبيقات أخرى لاستخدام الإنترنت بأمان أكثر . يُستخدم اوربوت تور لتشفير تحركات مرورك على الإنترنت ، ثم يخفيك ويجعلك وهمي من خلال سلسلة من أجهزة الكمبيوتر في جميع أنحاء العالم . تور هو تطبيق حر وشبكة مفتوحة والتي تساعدك على حماية نفسك من مراقبة الشبكات التي تهدد الحرية الشخصية والخصوصية ، والأنشطة التجارية السرية والعلاقات ، وأمن الدولة والحكومات القمعيّة والتي تستخدم مايعرف باسم تحليل حركة مرور البيانات . + جاري تشغيل اوربوت... متصل بشبكة تور تم إيقاف اوربوت جاري ايقاف خدمة تور @@ -16,7 +17,6 @@ إعدادات العنوان القابل للاتصال لديك تسببت بخطأ! إعدادات المرحلات لديك تسببت بخطأ! عُثر علي عملية تور سابقة تعمل... - حصل خطأ ما. افحص السجل غير قادر على بدء تور: لقد تحولت الى هوية تور جديدة تحديث الاعدادات في خدمات تور diff --git a/src/main/res/values-az/strings.xml b/src/main/res/values-az/strings.xml index bdda58516e1c787d07da7e0b3dfa5c498b1e93a7..10dee8b62c9a752a73d68a1b467261e32c1a5244 100644 --- a/src/main/res/values-az/strings.xml +++ b/src/main/res/values-az/strings.xml @@ -1,6 +1,7 @@ - Orbot başlayır... + Pulsuz proksi tətbiqetməsi olan Orbot başqa tətbiqetmələrə internetdən daha təhlükəsiz istifadə etmək imkanı verir. Orbot sizin internet trafikinizi şifrələmək üçün Tordan istifadə edir və dünyanın hər yerində kompüterlərin birindən o birinə sıçramaqla bunu gizlədir. Tor pulsuz proqram təminatıdır, eyni zamanda sizin şəxsi azadlığınız və təhlükəsizliyinizə, gizli biznes fəaliyyəti və əlaqələrə, o cümlədən trafik analiz adlanan dövlət təhlükəsizliyinə xələl gətirə biləcək şəbəkə nəzarəti formalarından müdafiə olunmağa yardım edən açıq şəbəkədir. + Orbot başlayır... Tor şəbəkəsinə bağlandı Orbot deaktivasiya edildi Tor xidməti işini başa vurur @@ -16,7 +17,6 @@ Sənin ƏlçatanÜnvanlar seçimin istisnaya səbəb oldu! Sənin keçid seçimlərin istisnaya səbəb oldu! mövcud Tor prosesi tapıldı... - Nə isə pis bir şey oldu. Girişi yoxla Tor-un başlanmasını dayandır: Yeni Tor oxşarına qoşuldun! Tor xidmətində quraşdırmalar yüklənir diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 69b2f2caf6e3b9db25cbbaeb7f893a5fb99823fd..cb28039bc5e85f48863b91aca14cbd857a7539ac 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -1,6 +1,7 @@ - Орбот стартира... + Orbot е безплатна прокси програма, която дава възможноста на други програми да използват интерент по-сигурно. Orbot използва Tor, за да криптира Интернет трафика и след това го скрива като препраща през няколко компютъра по целия свят. Tor е безплатен софтуер и отворена мрежа, която ти помага да се предпазиш от шпиониране по мрежата, което заплашва твоята свобода и лично пространство, конфиденциални бизнес отношение и връзки, и от вид правителствено следене наречено трафик анализ. + Орбот стартира... Свързан към Тор мрежата Орбот е деактивиран TorService спира @@ -16,7 +17,6 @@ Твоята ReachableAddresses настройка предизвика грешка! Твоите настройки за препращане предизвикаха изключение! намерил си съвместим Tor проект... - Нещо лошо се случи. Проверете лога Не може да стартира Тор: Сменихте своята Тор идентичност! обновяване на настройките в Tor услугата diff --git a/src/main/res/values-bn-rBD/strings.xml b/src/main/res/values-bn-rBD/strings.xml index 4e0431d69cae55b03d284c8741f68b2030479882..eaa77672777eaa4e4fe7ef8b48002b7b9662af10 100644 --- a/src/main/res/values-bn-rBD/strings.xml +++ b/src/main/res/values-bn-rBD/strings.xml @@ -1,5 +1,6 @@ + Orbot একটি ফ্রি প্রক্সি অ্যাপ্লিকেশন যা অন্যান্য Apps কে আরও নিরাপদভাবে ইন্টারনেট ব্যবহার করার ক্ষমতাপ্রদান করে। Orbot আপনার ইন্টারনেট ট্রাফিক এনক্রিপ্ট করতে টর ব্যবহার এবং তারপর সারা বিশ্বের কম্পিউটারের সিরিজের moddho diye porichalito kore gopon kore. টর ফ্রি সফটওয়্যার এবং আপনি ট্রাফিক বিশ্লেষণ হিসেবে পরিচিত ব্যক্তিগত স্বাধীনতা ও গোপনীয়তা, গোপনীয় বাণিজ্যিক কার্যক্রম এবং সম্পর্ক, এবং রাষ্ট্রীয় নিরাপত্তা হুমকির মুখে পড়ে নেটওয়ার্ক নজরদারি একটি ফর্ম বিরুদ্ধে রক্ষা করতে সাহায্য করে যে একটি খোলা নেটওয়ার্ক. অরবট চালু হচ্ছে . . . টর নেটওয়ার্কের সাথে সংযুক্ত হয়েছে অরবট নিষ্ক্রিয় করা হয়েছে diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index f5767a5f3bf90fa3356e37edadbd5977481ab56f..735ac4dad0ec8608ac241cd508f3020ee6c4d6ae 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -1,6 +1,6 @@ - L\'Orbot s\'està iniciant... + L\'Orbot s\'està iniciant... Esteu connectat a la xarxa Tor L\'Orbot està desactivat @@ -15,7 +15,6 @@ Els paràmetres d\'adreces accessibles han provocat una excepció. Els paràmetres de reemissió han causat una excepció. s\'ha trobat un procés Tor existent... - Ha fallat alguna cosa. Comproveu el registre Ha estat impossible iniciar Tor: Heu canviat a una nova identitat Tor. diff --git a/src/main/res/values-cs-rCZ/strings.xml b/src/main/res/values-cs-rCZ/strings.xml index cc781617ea28a0fba2f77599f13476fa62453195..8667b4fed45def7e5798bbd8d6d97702cf42dbc1 100644 --- a/src/main/res/values-cs-rCZ/strings.xml +++ b/src/main/res/values-cs-rCZ/strings.xml @@ -15,7 +15,6 @@ Vaše nastavení dostupných adres (ReachableAddresses) způsobilo chybu! Vaše nastavení relace způsobilo výjimku! nalezev existující Tor proces… - Stalo se něco špatného. Zkontrolujte log Nelze spustit Tor: Vaše identita na Toru byla změněna! diff --git a/src/main/res/values-da/strings.xml b/src/main/res/values-da/strings.xml index 864562dfaf06524df451cdeec4af5dccf4a5d922..8122d49133ac0d5b5218cebd00607f514cf5821b 100644 --- a/src/main/res/values-da/strings.xml +++ b/src/main/res/values-da/strings.xml @@ -1,20 +1,12 @@ - Orbot starter op ... - Der er forbindelse til Tor-netværket - Orbot er slået fra - - - - - - - - + Orbot er en gratis og åben proxy-applikation, der gør det muligt at anvende internettet mere sikkert fra andre programmer. Orbot bruger Tor til at kryptere internettrafikken, og skjuler den ved at sende den gennem serverere, lokaliseret i hele verden. Tor er gratis og åben software, der kan hjælpe dig mod netværksovervågning kaldet trafikanalyse, der kan true din personlige frihed, dit privatliv, handelsaktivitet og forhold. + Orbot starter op ... + Der er forbindelse til Tor-netværket + Orbot er slået fra Kunne ikke starte Tor processen: Din ReachableAdresses indstilling forudsagede en fejl! - Dine relæindstillinger forårsagede en fejl! + Dine relæindstillinger forårsagede en fejl! fandt eksisterende Tor process... - Noget slemt er sket. Check loggen Kunne ikke starte Tor: diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index d9b75aa48b9114fdfddfa97d8c0ede45fffd7c00..7a365b7bd29eadced70a3d886710236ebfdc76f1 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -1,6 +1,7 @@ - Orbot startet … + Orbot ist eine kostenlose Proxy-Anwendung, mit deren Hilfe andere Anwendungen das Internet sicherer nutzen können. Orbot verwendet Tor, um Ihren Internetverkehr zu verschlüsseln und ihn dann zu verbergen, indem er über eine Reihe weltweit verteilter Computer geleitet wird. Tor ist ein freies Programm und ein offenes Netzwerk, das Ihnen hilft, sich gegen Angriffe auf die persönliche Freiheit und die Privatsphäre oder auf vertrauliche Geschäftsbeziehungen sowie gegen die Datenüberwachung aus Staatssicherheitsgründen zu wehren. + Orbot startet … Verbunden mit dem Tor-Netzwerk Orbot ist deaktiviert TorService wird heruntergefahren @@ -16,7 +17,6 @@ Ihre eingestellten erreichbaren Adressen haben einen Ausnahmefehler verursacht! Ihre Relaiseinstellungen haben einen Ausnahmefehler verursacht! bestehender Tor-Prozess gefunden … - Etwas ist schief gelaufen. Bitte Protokoll prüfen Tor kann nicht gestartet werden: Sie haben zu einer neuen Tor-Identität gewechselt! Einstellungen im Tor-Dienst werden aktualisiert diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index 8d5887bf7d83b631e3860c5491c40a9b327d4d21..868e02dd0bc9f68908bcde4d8934c4fb9edb8200 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -15,7 +15,6 @@ Οι ρυθμίσεις ReachableAddresses προκάλεσαν μια εξαίρεση! Οι ρυθμίσεις αναμεταδότη σας προκάλεσαν μια εξαίρεση! αναζήτηση διεργασιών Tor... - Κάτι κακό συνέβη. Ελέγξτε τις καταγραφές Αδυναμία εκκίνησης του Tor: Έχετε αλλάξει επιτυχώς την ταυτότητα σας στο Tor! diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 2f4683d57542c1e07420bd4b087e54840d665c71..b60f7fe1f569a876800b33bd9eda030d43ae98e7 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -1,6 +1,7 @@ - Orbot está iniciandose... + Orbot es una aplicación libre de proxy (interpuesto) que faculta a otras aplicaciones para usar Internet de forma más segura. Orbot utiliza Tor para cifrar su tráfico de Internet, y luego lo oculta rebotándolo a través de una serie de computadoras por todo el mundo. Tor es software libre y una red abierta que le ayuda a defenderse contra una forma de vigilancia de red conocida como análisis de tráfico que amenaza la libertad y la privacidad personales, las actividades y relaciones comerciales confidenciales, y la seguridad de estado. + Orbot está iniciandose... Conectado a la red Tor Orbot está desactivado TorService se está cerrando @@ -16,7 +17,6 @@ ¡Sus \'Reglas de direcciones accesibles\' han producido una excepción! ¡La configuración de su repetidor ha producido una excepción! Se encontró un proceso de Tor ya existente... - Hubo algún tipo de problema. Compruebe el registro (log) No fue posible iniciar Tor: ¡Ha cambiado a una nueva identidad de Tor! actualizando la configuración en el servicio Tor diff --git a/src/main/res/values-et/strings.xml b/src/main/res/values-et/strings.xml index e3b2380a0065c8f2f2cd13d110a8ea9d6ed082b5..3d3dc9db1b54cbabd57f7a684532b26432e87e35 100644 --- a/src/main/res/values-et/strings.xml +++ b/src/main/res/values-et/strings.xml @@ -15,7 +15,6 @@ Teie ReachableAddresses seadistus põhjustas ekse! Teie releeseadistus põhjustas ekse! leidus töötav Tor protsess... - Juhtus midagi halba. Kontrollige logi Tor käivitamine ebaõnnestus: Lülitusite uuele Tor identiteedile! diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 7592ca278a12fd70c817dd8e8ce152ae0f60157c..61bfed568d95e7dee8b505a8a9ba81b697a7b9f1 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -15,7 +15,6 @@ Zure helbide atzigarriak salbuespena sortu du! Zure errele ezarpenak salbuespena sortu dute! Aurreko Tor prozesua topatuta... - Zerbait txarra gertatu da. Begiratu logetan Ezin izan da Tor hasi: ChatSecure - Andriodentzako berehalako mezulari bezero ziurra diff --git a/src/main/res/values-fa/strings.xml b/src/main/res/values-fa/strings.xml index 8a6992b1b2e49a179898de9187607bf3f59b9ba0..15599f1fa241b155019be994c0471813c22eb6f7 100644 --- a/src/main/res/values-fa/strings.xml +++ b/src/main/res/values-fa/strings.xml @@ -1,6 +1,7 @@ - اربوت درحال آغاز است... + اربت یک برنامه پروکسی مجانی است که دیگر برنامه ها را به استفاده امن از اینترنت توانمند می کند . اربوت از تور برای رمزگذاری کردن ترافیک اینترنت شما استفاده می کند و بعد آن ها را از طریق کامپیوترهای متفاوت در نقاط مختلف جهان مخفی می کند. تور یک برنامه مجانی و شبکه باز است که شما از شما در مقابل تحت نظر بودن در شبکه٬‌ تهدید آزادی های شخصی٬ خصوصی٬ فعالیت های کاری و رابطه های شخصی بطور امن محافظت می کند. + اربوت درحال آغاز است... متصل به شبکه تور اربوت غیرفعال شده است. TorService خاموش است @@ -16,11 +17,7 @@ تنظیمات شما برای آدرس قابل دسترسی باعث ایجاد خطا شده اند ! تنظیمات رله شما موجب خطا شده اند یک تور درحال اجرا پیدا شد... - اتفاق بدی افتاد. وقایع ثبت شده را چک کنید ناتوان در راه اندازی تور: شما به شناسه جدید تور منتقل شدید به روز رسانی تنظیمات در سرویس Tor - - snowflake-amp - diff --git a/src/main/res/values-fi/strings.xml b/src/main/res/values-fi/strings.xml index 6eee47c77156340954dde0415f5d92e86f758094..8edbbf6c221d21265829fde5f8025d5a3c910607 100644 --- a/src/main/res/values-fi/strings.xml +++ b/src/main/res/values-fi/strings.xml @@ -1,6 +1,7 @@ - Orbot käynnistyy... + Orbot on ilmainen välityspalvelinsovellus, joka tarjoaa muille sovelluksille mahdollisuuden käyttää internetiä turvallisemmin. Orbot käyttää Toria kryptaamaan verkkoliikenteesi ja sitten piilottaa sen kierrättämällä sitä usean tietokoneen kautta ympäri maailman. Tor on vapaa ohjelmisto ja avoin verkosto, jotka auttavat puolustautumaan vapautta ja yksityisyyttä uhkaavalta verkkovalvonnalta ja valtioiden verkonseurannalta sekä suojaamaan salaisia liiketoimintoja ja -yhteyksiä. + Orbot käynnistyy... Yhdistetty Tor-verkkoon Orbot on poistettu käytöstä @@ -15,7 +16,6 @@ ReachableAccess-asetuksesi aiheuttivat virheen! Releasetuksesi aiheuttivat virheen! löytyi olemassaoleva Tor-prosessi... - Jotain pahaa tapahtui. Tarkista loki Torin käynnistys epäonnistui: Vaihdoit Tor-identiteettisi uuteen! päivitetään Tor-palvelun asetuksia diff --git a/src/main/res/values-fr-rFR/strings.xml b/src/main/res/values-fr-rFR/strings.xml index b426a4311f3c37ec47fb6972fef4ed78333d9abe..4195911e9ec4c7fcc4237bd8aba4ddb3406a3c52 100644 --- a/src/main/res/values-fr-rFR/strings.xml +++ b/src/main/res/values-fr-rFR/strings.xml @@ -1,25 +1,17 @@ - Orbot démarre... - Connecté au réseau Tor - Orbot est désactivé - TorService est en cours d\'extinction - - - - - - - - + Orbot est une appli libre de serveur mandataire permettant aux applis d\'utiliser Internet avec une sécurité accrue. Orbot utilise Tor pour chiffrer votre trafic Internet et le cache ensuite en le relayant au travers d\'ordinateurs de par le monde. Tor est un logiciel libre et un réseau ouvert qui vous aide à vous défendre contre une forme de surveillance réseau qui menace la liberté personnelle et la protection des données personnelles, les activités professionnelles confidentielles et les relations, et l\'analyse du trafic des gouvernements. + Orbot démarre… + Connecté au réseau Tor + Orbot est désactivé + TorService est en cours d\'extinction Impossible de démarrer le processus Tor : Vos paramètres ReachableAddresses (adresses accessibles) ont causé une exception ! - Vos paramètres de relais ont causé une exception ! - un processus existant de Tor a été trouvé... - Quelque chose n\'a pas été. Vérifiez le journal + Vos paramètres de relais ont causé une exception ! + un processus existant de Tor a été trouvé… Impossible de démarrer Tor : Vous avez basculé vers une nouvelle identité Tor ! mise à jour des paramètres dans le service Tor - Mio/s - Kio/s + Mio/s + Kio/s diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index fc50b1842b4dc327a6f2f2aed8813e4ef037cc03..87ff33d0ff5abbe4537b771d88b86d0a33f231c5 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -1,15 +1,10 @@ - Démarrage de Orbot... - Connecté au réseau Tor - Orbot est désactivé - Le service Tor est en cours de fermeture - - - - - - - - + Orbot est une application proxy gratuite qui améliore l\'utilisation plus sécurisée des applications. Orbot utilise Tor pour crypter votre trafic internet et le cacher en passant par une série d\'ordinateur partout dans le monde. Tor est un logiciel gratuit et un réseau ouvert qui vous aide à vous défendre contre les surveillances de réseau qui font peur à la liberté personnelle et la vie privée, les activités confidentielles des entreprises et des relations, et l\'état de la sécurité connu sous le nom d\'analyse de trafic. + Démarrage de Orbot… + Connecté au réseau Tor + Orbot est désactivé + Ouvrez Orbot pour vous connecter à Tor + Le service Tor est en cours de fermeture + Se Connecter à Tor diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 42020d9c4ba2862e98374145dca48d7998574ee9..2066fd4ca8789bd81803caf1dd4674f75bf18987 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -1,6 +1,7 @@ - Orbot está a se iniciar... + Orbot é unha aplicación de proxy libre que permite a outras aplicacións usar a internet dun xeito máis seguro. Orbot usa Tor para encriptar o teu tráfico de internet ocultando e rebotándoo a través dunha serie de ordenadores ao redor do mundo. Tor é software libre e unha rede aberta que axuda a defenderte contra unha forma de vixiancia na rede que ameaza a liberdade e privacidade persoal, actividades confidenciáis de negocios e relacións, e estado de seguridade coñecido como análise de tráfico. + Orbot está a se iniciar... Conectado á rede Tor Orbot está desactivado @@ -15,7 +16,6 @@ O seu axuste de ReachableAddresses causou unha excepción! Os seus axustes de relay causou unha excepción! atopado proceso Tor existente... - Algo malo pasou. Comprobe o rexistro Incapaz de arrancar Tor Cambiou a unha nova identidade Tor! diff --git a/src/main/res/values-guc/strings.xml b/src/main/res/values-guc/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..227bbf93d5c273d240ed7f9a11c2429ae62d8d1a --- /dev/null +++ b/src/main/res/values-guc/strings.xml @@ -0,0 +1,43 @@ + + + 0rbot VNP + Orbot shia wane a\'yataaya maliasat, akaalinjia tü wane a\'yataayaakalüirua süpüla anainjatüin shia\'yataaya. Orbot a\'yataasü sulu\'u \"internet\" süka wane kanüliasü Tor je süchikijee sunujuluin sulu\'u wane kojuyasü \"computador\" sainküsü mmakat. Tor maliasat je taashisü süpüla sa\'inmajüin pia suulia eekai mojulaweein pümüin wanaa sümaa pi\'yataain sulu\'u \"internet\". + Eepeja\'asu Orbot… + Antirrawaas jumaa atalaya Tor + Yokutusu\'u Orbot + Pe\'erulaa Orbot jupula puyata ín juma Tor. + Yokuuter Tor + Antirrawaa sunain Tor + sükumajia Orbot maliaasat + + Nojotsü o\'ottuin sukuaipa shiatain Tor + Tü anatiaaka erree juntunuín casaa, nojots jainrre\'in + Tü anatiaka eerjaya maimatuaa, nojots jainrrei´n + Antusü sünain sajia wanee Tor etüjulia … + no jot süpüla achuajaje\'in Tor + + Tü piranaajain sülü wanee jeketü shiyawase Tor + + Anoutuüin tüü akümajiak süpüla Tor + + Anuli\'aa jekets + Atapajus juntia + süntiraya tü süchecheria sütsin + + KiB/s + MiB/s + + %sPuuproxinka copo de nieve munaka amuliajús wayuu jupula nainjuin tu nainrreka.%s + + Nojoluinjat aitanüin junulia cewoolla. + Motée ainrüü + Proxy copo de nieve amuliajús jupula painruuín tu paiinrreka + proxinka copo de nieve Yokúuts + Jeketerr tu anatiakal tu ipünamiukal C + Kaa´muinshi atumaa chi ayawuajuikai kazachiki + Antirrashi Tor juma ipunamuika eki. + Nojots apunuin juchuntia eepeja\'asú + Mojus jukuaipaa junain j\'iitaayaa erre aatunu\'in geoip + + + diff --git a/src/main/res/values-gum/strings.xml b/src/main/res/values-gum/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..c65a1069029121f190458e11644b901f277de417 --- /dev/null +++ b/src/main/res/values-gum/strings.xml @@ -0,0 +1,45 @@ + + + Orbot VPN + Orbotpe chi anwei kɵmɵn ikpape internetyu mentra kenamarmɵ chine maramtik kɵn. +Orbotpe, internet yu wammeran mentra lasrpitsɵsrkɵmɵntrappe Tor teik tɵka wetɵ ashmɵntrai isua marik kɵn, trek chippe chi wam merane esekawa ampumai imai purep ipik kɵn ik pirau mupa kuin pɵrap. +Torpe kan software kɵn mayaelai chi anwei kɵmɵ, incha chu puisrɵ, kape chu pasriksrɵpe, wam kerilan mu kɵpen wamipikelɵ wetɵ ashmɵntrai purukupik kɵn, trek tɵwai chutɵ kucha maya misakwan aship pasrapik Estado teik wan purukupik kɵn, kan \"analisis de tráfico\" teik tɵka. + Orbotpe pɵlpasrɵp pasran… + Toryu kelicha pasrik + Orbotpe kuetsik pasran + Orbotwan kur Toryu kelichap + Orbotpe kasrɵp pasran + Tor yu kelitsik pasran + Orborwan tamartrentikpe kalɵ kɵn + + Torwan p­‎​ɵlpasrtrap kaimeik pasran + ReachableAddresses wan tamartrentikpe nɵrɵ pek tamarik kenamisran + Relay wan tamartrentikpe nɵrɵ pek tamarik kenamisran + Wetɵtraik kenamisran Tor… + Torpe pɵlpasrtrap kaiman + + Tor maik kenamisrɵpik kuipe yunɵmaran + + Toryu srɵitɵ tamaramelɵ + + Srɵitɵ malɵ kena maramik + Puerto de controlwan munirap + Puerto de controlyu kelichip + + KiB/s + MiB/s + + 1%sÑui proxy snowflake purukun munkɵsrɵn asam keilan ashchap inchen 1%s + + Ishik munchi meran asam kaik k​­ɵn + Memoria patsap pasran + Snowflake proxype kurik pasran + Snowflake proxype kasreik pasran + Torrcwan na isuikmai tamaramik + Control portwan keerik pasramisran + Control portwan kelitsik pasran + Katɵle pɵlpasramik cha mieikwan ka tan, yantɵ pɵlmarik pasran + Geoipyu mariklan tamara pasramikyu, kalɵ wepian + + + diff --git a/src/main/res/values-hi/strings.xml b/src/main/res/values-hi/strings.xml index 7df4740f75a870b3baa3ae4fe71c760105f1729a..34fdbd894a22cae5925c89812a386e23b05af4d4 100644 --- a/src/main/res/values-hi/strings.xml +++ b/src/main/res/values-hi/strings.xml @@ -1,5 +1,6 @@ + औरबौट एक मुफ्त अैप diff --git a/src/main/res/values-hr/strings.xml b/src/main/res/values-hr/strings.xml index c2cad30f311a9500715c6e30470d7623105001b0..26607a79486611853e666254aa1f9d252f4f18dd 100644 --- a/src/main/res/values-hr/strings.xml +++ b/src/main/res/values-hr/strings.xml @@ -1,6 +1,7 @@ - Orbot se pokreće... + Orbot je besplatna proxy aplikacija koja omogućuje ostalim aplikacijama da koriste internet sigurnije. Orbot koristi Tor za enkripciju Vašeg Internet prometa, a zatim ga skriva šaljući ga kroz seriju računala diljem svijeta. Tor je besplatan software i otvorena mreža koja pomaže u borbi protiv nadzora mreže koji ugrožava osobne slobode i privatnost, povjerljive poslovne aktivnosti i odnose, te pomaže u borbi protiv analize prometa. + Orbot se pokreće... Spojen na Tor mrežu Orbot je deaktiviran TorService se gasi @@ -16,7 +17,6 @@ Vaše ReachableAddresses postavke su uzrokovale iznimku! Vaše postavke releja su uzrokovale iznimku! pronađeni postojeći Tor procesi... - Nešto loše se dogodilo. Provjerite dnevnik Nije moguće pokrenuti Tor: Prebacili ste se na nov Tor identitet! ažuriram postavke u Tor usluzi diff --git a/src/main/res/values-hu/strings.xml b/src/main/res/values-hu/strings.xml index 50efdcd39e79a3f3b07933f93ec1c6fa487f0953..ef7aaa808d34414a74135a4b48a501eaf17d1e42 100644 --- a/src/main/res/values-hu/strings.xml +++ b/src/main/res/values-hu/strings.xml @@ -1,6 +1,7 @@ - Az Orbot indul... + Az Orbot egy ingyenes proxy alkalmazás, ami képessé tesz alkalmazásokat, hogy biztonságosabban használhassák az internetet. Az Orbot Tor-t használ, hogy titkosítsa az internetforgalmadat és elrejtse azáltal, hogy pattogtatja számítógépek sorozatain keresztül a világ körül. A Tor ingyenes szoftver és nyitott hálózat, ami segít megvédeni a hálózati felügyelettől, ami fenyegeti a személyi szabadságot és magánéletet, a bizalmas céges tevékenységeket és kapcsolatokat, és állambiztonság címén a forgalomelemzéstől. + Az Orbot indul... Csatlakozva a Tor hálózathoz Az Orbot deaktiválva A TorService leáll @@ -16,7 +17,6 @@ Az elérhető címeid beállításai kivételt okoztak! Az átjátszód beállításai kivételt okoztak! létező Tor folyamat találva... - Valami rossz történt. Nézd meg a naplót. A Tor indítása sikertelen: Új Tor identitásra váltottál! a Tor szolgáltatás beállításainak frissítése diff --git a/src/main/res/values-in/strings.xml b/src/main/res/values-in/strings.xml index 73f14eb8862b31b6984df9db7cfc3032a9852cd6..1ba1cabc92b2b37214928201b39c4210cdac07f4 100644 --- a/src/main/res/values-in/strings.xml +++ b/src/main/res/values-in/strings.xml @@ -1,6 +1,5 @@ - Orbot Orbot adalah aplikasi proxy gratis yang membuat aplikasi-aplikasi lainnya dapat terkoneksi dengan internet secara aman. Orbot menggunakan Tor untuk mengenkripsi hubungan internet anda dan menyalurkannya melewati berbagai komputer di seluruh dunia. Tor adalah software gratis dan suatu network terbuka, yang membantu anda menghindari pengawasan network yang mengancam kebebasan pribadi dan privasi, aktivitas bisnis rahasia dan relasi, serta keamanan negara yang dikenal dengan analisa traffic. Orbot sedang dimulai... Tersambung ke Jaringan Tor @@ -10,7 +9,7 @@ - + @@ -18,7 +17,6 @@ Pengaturan ReachableAddresses anda menyebabkan kesalahan! Pengaturan relay anda menyebabkan kesalahan! menemukan proses Tor yang ada... - Sesuatu yang buruk terjadi. Periksa log Tidak dapat memulai Tor: Anda telah beralih ke identitas Tor baru! memperbarui setting pada layanan Tor diff --git a/src/main/res/values-is/strings.xml b/src/main/res/values-is/strings.xml index 2f4e9af820008b23a48afdf0ea6ad2694d0e1208..5b02a816662331068b25b593ea2bf722c7e70c17 100644 --- a/src/main/res/values-is/strings.xml +++ b/src/main/res/values-is/strings.xml @@ -1,6 +1,7 @@ - Orbot er að ræsa... + Orbot er ókeypis proxy smáforrit sem gerir öðrum smáforritum kleift að nota veraldarvefinn á öruggari hátt. Orbot notar Tor til að dulkóða umferð þína á netinu og felur hana svo með að hoppa í gegnum fjölda tölva um allan heim. Tor er ókeypis hugbúnaður og opið net sem aðstoðar þig við að verjast gegn eftirliti á netinu sem vinnur gegn frelsi einkalífsins og friðhelgi, trúnaðar viðskiptamálum og samböndum, og ríkisöryggi þekkt sem umferðargreining. + Orbot er að ræsa... Tengdur við Tor netið Orbot er slökkt @@ -15,7 +16,6 @@ Þitt ReachableAddressur stillingar ollu undanþágu! Endurvarp stillingar þínar ollu undanþágu! fann annan Tor þráð... - Eitthvað slæmt gerðist. Athugaðu skráninguna Get ekki kveikt á Tor: Þú ert komin með nýtt Tor auðkenni! uppfæri stillingar í Tor þjónustu diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index ed397d9afb04749f7891615c3e7cbd5ba4356eef..a4a13532df4c776429854708e864fa240bd3ba64 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -1,6 +1,7 @@ - Orbot è in esecuzione... + Orbot è un\'applicazione proxy che permette alle altre applicazioni di accedere a internet in maniera più sicura. Orbot usa Tor per cifrare il traffico internet e lo nasconde poi facendolo rimbalzare attraverso una serie di computer attorno al mondo. Tor è un software libero e una rete aperta che aiuta a difendersi da una forma di sorveglianza della rete conosciuta come analisi del traffico. Quest\'ultima minaccia libertà e privacy personale, attività commerciali riservate, rapporti interpersonali, e persino la sicurezza di stato. + Orbot è in esecuzione... Connesso alla rete Tor \"Orbot è disattivato TorService si sta spegnendo @@ -16,7 +17,6 @@ La tua configurazione dell\'indirizzo raggiungibile ha causato un\'eccezione! La configurazione del tuo relay ha causato un\'eccezione! trovato un processo Tor esistente... - E\' accaduto un evento indesiderato. Controllare i log. Impossibile avviare Tor: Sei passato a una nuova identità Tor! aggiornamento impostazioni nel servizio Tor diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index 4cee7d90f101504d5d99cc8d77f5816ab487b4eb..ce7510aeb04695098a48fd7c99ed7d52cc2fb1eb 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -1,6 +1,7 @@ - Orbot מתחיל… + Orbot הינה אפליקציית פרוקסי חינמית המאפשרת לאפליקציות אחרות להשתמש באינטרנט בבטחה. Orbot נעזרת ב-Tor כדי להצפין את תעבורת האינטרנט שלך ולהסוותה באמצעותה ניתובה דרך מספר מחשבים ברחבי העולם. Tor היא תוכנה חופשית ורשת פתוחה המסייעת לך להתגונן מפני סוגים מסוימים של אמצעי ניטור ומעקב אחר רשת האינטרנט המאיימים על הפרטיות, החירות האישית, פעילויות עסקיות ומערכות יחסים חשאיות. + Orbot מתחיל… מחובר לרשת Tor Orbot כבוי @@ -13,7 +14,6 @@ אין אפשרות להתחיל תהליך Tor: נמצא תהליך Tor קיים… - משהו רע התרחש. בדוק את היומן לא מסוגל להתחיל את Tor: החלפת אל זהות Tor חדשה! מעדכן הגדרות Tor במכשיר diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 572795c1148a00ffa162ee9057a268c7cb14fcf6..f744cb87dcf82073976b282a0fa08c0b40616823 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -1,6 +1,7 @@ - Orbotが開始されています... + Orbotは他のアプリがインターネットをより安全に使うことを可能にするフリーのプロキシアプリです。Orbotでは、Torを用いてあなたの端末のトラフィックを暗号化し、世界中のコンピューターを中継することで、そのトラフィックを隠します。Torはフリーのソフトウェアとオープンなネットワークであり、ユーザーの自由とプライバシーを脅かす監視活動や、機密のビジネス活動、国家によるトラフィック分析から身を守ることを助けてくれます。 + Orbotが開始されています... Torネットワークに接続しています \"Orbotが解除されました TorServiceが終了しています @@ -16,7 +17,6 @@ あなたのReachableAddresses設定により例外が発生しました! あなたのリレー設定により例外が発生しました! Torプロセスを発見 - 何かが起こりました。ログを確認してください。 Torを実行できませんでした 新たな Tor の身元に切り替えました。 Torサービスの設定を更新中 diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index 720adba0052b8c0beb68fd2687c2759a2331a09b..4243e65cfad01f77c0653d876bf702aa3ba51580 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -15,7 +15,6 @@ 귀하의 ReachableAddress 설정은 예외를 발생시켰습니다! 귀하의 중계서버 설정은 예외를 발생시켰습니다! 존재하고 있는 Tor 프로세스 발견 - 어떤 나쁜 것이 발생. 로그 확인하세요. Tor 시작 불가능 새로운 Tor 신원으로 전환되었습니다! diff --git a/src/main/res/values-lv/strings.xml b/src/main/res/values-lv/strings.xml index b08c3ecedfa86a37210ede88ee613018d9406db2..70747bae342d1abe2a227e47b4a2849642373ff2 100644 --- a/src/main/res/values-lv/strings.xml +++ b/src/main/res/values-lv/strings.xml @@ -1,6 +1,7 @@ - Orbot startē... + Orbot ir starpniekserveru bezmaksas lietotne, kas sniedz iespēju citām lietotnēm drošāk lietot internetu. Orbot izmanto Tor, lai šifrētu Jūsu interneta datplūsmu, tad to paslēpj, pārsūtot to caur daudziem datoriem visā pasaulē. Tor ir bezmaksas programmatūra un atvērts tīkls, kas palīdz Jums aizsargāties pret tīkla uzraudzības veidu - datplūsmas analīzi -, ar kuras palīdzību tiek apdraudēta personiskā brīvība un privātums, konfidenciālas lietišķas darbības un attiecības, kā arī valsts drošība. + Orbot startē... Izveidots savienojums ar tīklu Tor Orbot ir deaktivēts @@ -15,7 +16,6 @@ Jūsu ReachableAddresses iestatījumi izraisīja izņēmuma stāvokli! Jūsu retranslatora iestatījumi izraisīja izņēmuma situāciju! Atrada esošu Tor procesu... - Nav labi. Pārbaudiet žurnālu Nevar startēt Tor: Jūs pārslēdzāties uz jaunu Tor\'a identitāti! atjaunina Tor pakalpojuma iestatījumus diff --git a/src/main/res/values-mk/strings.xml b/src/main/res/values-mk/strings.xml index f68bde887844da36c35643275348354451713b89..73ce0b66e3f4ac99cc6173676df05e62e6390940 100644 --- a/src/main/res/values-mk/strings.xml +++ b/src/main/res/values-mk/strings.xml @@ -1,6 +1,7 @@ - Орбот се стартува... + Orbot е слободна прокси апликација која им овозможува на другите апликации да го користат интернетот побезбедно. Orbot користи Tor за шифрирање на интернет-сообраќајот, а потоа го сокрива и го доставува преку неколку компјутери во целиот свет. Tor е слободен софтвер и отворена мрежа која се справува со вид надзор на мрежата која штети на личната слобода и приватноста, доверливи деловни активности и односи, и државната безбедност позната како анализа на сообраќајот. + Орбот се стартува... Поврзан на мрежата на Tor Орбот е деактивиран @@ -15,7 +16,6 @@ Вашите поставки за достапните адреси предизвикаа грешка! Вашите поставки за реле предизвикаа грешка! Пронајден постоечки Tor-процес ... - Настана грешка. Проверете во дневникот Tor не може да се стартува: Се префрливте на нов идентитет на Tor! ажурирање на поставките во сервисот Tor diff --git a/src/main/res/values-ms-rMY/strings.xml b/src/main/res/values-ms-rMY/strings.xml index b83d4a5bebfa87a7f39221333e36e9abe3393068..b57896c77cc657f9d85c8a646744dd633a94d5ae 100644 --- a/src/main/res/values-ms-rMY/strings.xml +++ b/src/main/res/values-ms-rMY/strings.xml @@ -15,6 +15,5 @@ Tetapan ReachableAddresses anda menyebabkan pengecualian! Tetapan relay anda menyebabkan pengecualian! Proses Tor sedia ada ditemui.. - Sesuatu yang buruk berlaku. Semak log. Tidak dapat memulakan Tor: diff --git a/src/main/res/values-ms/strings.xml b/src/main/res/values-ms/strings.xml index d6ac3493ba261f4392a72b0f7647c7e2bb095986..c86bff7404d140fea9d78e841642b862eedba2c3 100644 --- a/src/main/res/values-ms/strings.xml +++ b/src/main/res/values-ms/strings.xml @@ -16,6 +16,5 @@ Tetapan ReachableAddresses anda menyebabkan pengecualian! Tetapan relay anda menyebabkan pengecualian! Proses Tor sedia ada ditemui.. - Sesuatu yang buruk berlaku. Semak log. Tidak dapat memulakan Tor: diff --git a/src/main/res/values-nah/strings.xml b/src/main/res/values-nah/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0af34e6b5f8bf3f4e95e8764e3ee58af9be9598e --- /dev/null +++ b/src/main/res/values-nah/strings.xml @@ -0,0 +1,43 @@ + + + Orbot VPN + Tepoztlatlatquitl proxy ahmotlazotli Orbot, mitzmaca netlacaneconiliztli. Orbot tlamanitiliz Tor pampa nahuati ichtaca amatlacuiloli nochi tepoztlapohualoni in tlalticpac. Tor ca tlanemacuatextli ihuan metlatl tlapouhqui inin quipalehui huicpa pihpiyaliztli, ihuan quicuitlauh tlacaxoxouhcayotl ihuan tlacaconemiliztli ica hueyi altepetl. + Orbot pehualtica … + Tencuitica matlatl Tor Network + Orbot ahmo tequitica + Xictlapoz Orbot pampa xictencuiz Tor + Orbot tlaltzacuatica + Xictencuiz Tor + Ahmo melahuac mocentilis Orbot + + Ahmo huel opehua Tor + ¡Mocentiliz ReachableAddresses ye omochihua, yehce za iyopa! + ¡Mocentilis tepozteknolotilistli ye omochihua, yehce za iyopa! + Otinamiqueh ce ayiliztli cenyuhqui quenime Tor … + Ahmo opehua Tor + + ¡Axan tiyancuitlacauh ica Tor! + + Mochihua yancuic in mocentilis ipan Tor + + Yancuic in ixtli in yollotl + Ticchiatocqueh in huelititzalantli + Nican xictencuiz huelititzalantli + + KiB/s + MiB/s + + %sMocepayahuiproxy otepalehui oquitzicuini ahmo huelmati%s + + Ahmo huel xictlecahuiz xonacatl itocalhuan + ¡Ihuaniamatlacuiloli, ocachi tlamantli ahmo actica motepoznonotza! + Yuhcayotl proxy Snowflake neconiliztli + Yuhcayotl proxy Snowflake ahmo neconiliztli + Mocentiliz torrc quenime mitzpactia, papatica. + Mocahuaz in ihuelititzalantli + Ye octencui huelititzalantli + Ahmo onicma pehuaicihuitiliztli, ye opehua. + Onca ce neixpololiztli ihcuac otictlali tlanechicolli geoip + + + diff --git a/src/main/res/values-nb/strings.xml b/src/main/res/values-nb/strings.xml index 5e73959f408e1800d8a43681ec65543928cab371..d8e36494993966c43b3009ece93ca8f8b0debac2 100644 --- a/src/main/res/values-nb/strings.xml +++ b/src/main/res/values-nb/strings.xml @@ -1,6 +1,7 @@ - Orbot starter... + Orbot er en gratis proxy app som gjør det mulig for andre apps å bruke Internett mer sikkert. Orbot bruker Tor for å kryptere din Internettrafikk, og skjuler da din trafikk ved å sende trafikken gjennom en lang rekke datamaskiner over hele verden. Tor er et gratis dataprogram, og et åpent nettverk som hjelper deg å forsvare deg mot en form for nettverksovervåking som truer din personlige frihet og privatliv, konfidensiell bedriftsvirksomhet og relasjoner, og statlig sikkerhet kjent som trafikkanalyse. + Orbot starter... Koblet til Tor-nettverket Orbot er deaktivert @@ -15,7 +16,6 @@ Dine \"adresser som kan nås\"-innstillinger forårsaket et unntak! Dine relé-innstillinger forårsaket et unntak! fant eksisterende Tor-prosess... - Noe alvorlig skjedde. Sjekk loggen. Klarte ikke å starte Tor: Du har byttet til en ny Tor-identitet! Oppdaterer innstillinger i Tor service diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 4f6fe5be5814635a053726ad52e0ea0ad2ccec50..a611c21c0dae0a3ca13e9a128cc660c950846647 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -1,6 +1,7 @@ - Orbot is bezig met starten… + Orbot is een gratis en vrije proxy-app die het andere apps mogelijk maakt het internet veiliger te gebruiken. Orbot gebruikt Tor om je internetverkeer te coderen en het vervolgens te verhullen het door het door een serie computers over de hele wereld te routeren. Tor is vrije software en een open netwerk dat je helpt te verdedigen tegen een vorm van netwerktoezicht die persoonlijke vrijheid en privacy, vertrouwelijke bedrijfsactiviteiten en relaties en staatsveiligheid genaamd \'traffic analyse\' bedreigt. + Orbot is bezig met starten… Verbonden met het Tor-netwerk Orbot is uitgeschakeld TorService wordt afgesloten @@ -16,7 +17,6 @@ Je ReachableAddresses-instellingen veroorzaakten een fout! Je relay-instellingen veroorzaakten een fout! bestaand Tor-proces gevonden… - Er is een fout opgetreden. Controleer de log Kan Tor niet starten: Je bent naar een nieuwe Tor identiteit gewisseld! instellingen in Tor-dienst worden bijgewerkt diff --git a/src/main/res/values-pbb/strings.xml b/src/main/res/values-pbb/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..dd2fbb9186da746df8c6d1f779205d254f267e3b --- /dev/null +++ b/src/main/res/values-pbb/strings.xml @@ -0,0 +1,43 @@ + + + Orbot VPN + ORBOTa’ teeçx PROXY’, çaamte spahtxçxa’ dewemee vxiswa’ja’; naayu’ vxite çaam wejxatxku ũukhmee kvxisu’ju’. ORBOTa’ TORa’sku kseelpi’ji’ mjĩitx jxpa’yahtx jxaawkaan. TORa’ vxite çaam wejxa’, txa’wẽyçxa dewewa’jme’, naa wejxa’ wala pu’çxhin kĩhsupa jiyuwẽte, txãa pa’ka kwe’sx mjĩitx nwe’wek peethegkameen; sa’ ũukhmee vxiswa’ja’. + Orbota’ takhna ũsa’… + Tor Networkte txitxanxi ũsa’ + Orbota’ fxĩçxhanxi ũsa’ + Orbota’s phade Torte txitxaya’pacxa + Orbota’ aphnxi ũsa’ + Torte mtxiitxaa + Orbot phewu’jnxi’ ewmee’ + + Tora’ takhya’ ewuume’ + !Idx ReachableAddresses phewu’jnxi´ teeçx yuwek nvxiht! + !Idx relay phewu’jnxi’ teeçx yuwek nvxiht! + Teeçx Tor vxitnxiya’sak uy… + Tor takhya’ ewuume’ + + ¡Yu’ptheg vxite use Tor yase! + + Tor Kpuuse’jnxi mjĩi’s phewu’j naa tudte + + U’se yase + Vxitxkwe phadewa’ ũythasna + U’kawa’ ũythasna + + KiB/s + MiB/s + + Idx snowflake proxi pu’çxhku maasume kaajxkhẽwu’jxa + + Spulxa yase kaateka’jya ewuumeen + ¡çaam pe’pe utaya’pa’! + Naa proxy Snowflake vxiswa’ ewa’ + Naa proxy Snowflake vxiswa’ ewme’ + Torrc Khpuusee’jnxi’s phewu’jna… + Khẽkh vxite u’kacxa thegwa’ + Txitxanxi ũsa’ çaam pe’pete u’kaya’ + Pki’taya jxkaahnxi’s wẽse’jme’. Takhya’k + Ewuume’ geoiptxi ki’pwẽte’ + + + diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index e9e0391b9bd7e4768ffda415d84a3708eb592016..7ce4b83633c8048d14d81c40cfbfbd9b6c65a19b 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -1,6 +1,7 @@ - Orbot startuje... + Orbot jest darmową aplikacją proxy która wspomaga inne aplikacje do używania internetu bezpiecznie. Orbot używa Tora do szyfrowania Twojego ruchu internetowego i następnie przepuszczania go przez wiele innych komputereów pororzucanych na całym świecie. Tor jest darmowym oprogramowaniem i otwartą siecią która pomaga Tobie w obronie przed monitoringiem sieci która zagrarza osobistej wolności i prywatności, poufnym biznesowym aktywnościom. + Orbot startuje... Podłączony do sieci Tor Orbot wyłączony TorService wyłącza się @@ -16,7 +17,6 @@ Twoje ustawienia dostępnych adresów spowodowały wyjątek! Ustawienia Twojego przekaźnika spowodowały wyjątek! znaleziono istniejący proces Tora... - Coś nie poszło nie tak. Sprawdź logi Nie można wystartować aplikacji Tor: Nowa tożsamość Tor\'a została zmieniona! aktualizowanie ustawień w serwisie Tor diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml index 474b9fa1ee746d3c3f2887357d8a4c242f70fa74..80c6e8c3d669872574ded309e370e21050f546ca 100644 --- a/src/main/res/values-pt-rBR/strings.xml +++ b/src/main/res/values-pt-rBR/strings.xml @@ -1,6 +1,7 @@ - Orbot está iniciando... + Orbot é um aplicativo de proxy livre que capacita outros aplicativos a usar a internet com mais segurança. Orbot usa o Tor para criptografar seu tráfego na internet e então o esconde \"saltando\" entre uma série de computadores ao redor do mundo. Tor é um software livre e de rede aberta que ajuda você a se defender de certas formas de vigilância que ameaçam privacidade e liberdade pessoais, atividades e relações comerciais confidenciais e segurança estatal conhecida como análise de tráfego. + Orbot está iniciando... Conectado à rede Tor Orbot está desativado TorService está desligando @@ -16,7 +17,6 @@ Suas configurações de Endereços Acessíveis causou uma exceção! Suas configurações de retransmissão causaram uma exceção! procurando processos Tor existentes... - Algo ruim aconteceu. Cheque o lo Habilitar iniciar o Tor: Você trocou para uma nova identidade Tor! atualizando configurações no serviço Tor diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index b261c6754b86d70cb5cf161a53d25dd04f57ebf0..cf9356374e5158f815d344b1ba3d83e54e447670 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -13,7 +13,6 @@ Não foi possível iniciar o processo Tor: encontrado o processo Tor existente... - Aconteceu algo de mau. Verifique o registo de eventos. Não é possível iniciar o Tor: Mudou para uma nova identidade do Tor! a atualizar as definições no serviço Tor diff --git a/src/main/res/values-ro/strings.xml b/src/main/res/values-ro/strings.xml index 59ca457c82b41fca809752ad5ad360b09e81bbec..4b943021883465f4089c17d4f6d33314802c1911 100644 --- a/src/main/res/values-ro/strings.xml +++ b/src/main/res/values-ro/strings.xml @@ -15,7 +15,6 @@ Setarile tale pentru adrese accesibile au cauzat o exceptie! Setarile tale de relay au cauzat o exceptie! gasit proces Tor existent... - Ceva rau s-a intamplat. Verifica log-ul Nu am reusit sa pornesc Tor: Ați comutat la o nouă identitate Tor! se actualizează configurările în serviciul Tor diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index c6146fe5053b8816eddfdb5e1f6734a8158d4a50..b0493e929f22e2f736a810a3b903eda2acf5a673 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -1,6 +1,7 @@ - Запуск Orbot... + Orbot - это свободная программа для прокси-соединений, она позволяет другим приложениям более безопасно использовать интернет-соединение. Orbot использует Tor для шифрования интернет-трафика, который затем скрывается в ходе пересылки через несколько компьютеров в разных частях планеты. Tor является свободным программным приложением, а также открытой сетью, помогающей защититься от слежки в сетях, угрожающей личной свободе и частной жизни, конфиденциальным бизнес-деятельности и контактам, а также государственной программе безопасности, известной как анализ трафика. + Запуск Orbot... Подключён к сети Tor Orbot отключён Служба Tor выключается @@ -16,7 +17,6 @@ Ваши настройки доступных адресов вызвали исключение! Настройки вашего ретранслятора вызвали исключение! найден существующий процесс Tor... - Произошла какая-то ошибка. Проверьте журнал. Невозможно запустить Tor: Вы переключились на новый идентификатор Tor! обновление настроек в сервисе Tor diff --git a/src/main/res/values-si-rLK/strings.xml b/src/main/res/values-si-rLK/strings.xml index a618405878f950e81f13589cb0f228b4bb3391af..80255642e705b131a1324539f70b0fa6e8bd6119 100644 --- a/src/main/res/values-si-rLK/strings.xml +++ b/src/main/res/values-si-rLK/strings.xml @@ -15,6 +15,5 @@ ඔබේ සේන්දුවන ලිපිනයෙහි සිටුවම්වල ව්‍යතිරේකයක් හටගෙන ඇත! ඔබේ ප්‍රතියෝජක සිටුවම්වල ව්‍යතිරේකයක් හටගෙන ඇත! පවතින Tor ක්‍රියාවලි හමුවිය... - යම් නොමනා දෙයක් සිදුවිය. ලොගය පරික්ෂා කර බලන්න Tor ආරම්භ කිරීමට නොහැකිය: diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 37ef7a19ea0c7d1695b02192d9c9620c8c12577c..05dbcb5162a5f354dc8e989332e2620e47307fad 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -1,6 +1,7 @@ - Орбот се покреће... + Орбот је бесплатна прокси апликација која даје моћ другим апликацијама да безбедније користе интернет. Орбот користи Тор за шифровање вашег интернет саобраћаја и онда га скрива слањем кроз низ рачунара широм света. Тор је слободан софтвер и отворена мрежа која помаже да се одбраните од разних облика надзора мрежа који угрожавају личну слободу и приватност, поверљиве пословне активности и личне односе и државне безбедности познате као анализа саобраћаја. + Орбот се покреће... Повезан са Тор мрежом Орбот је деактивиран @@ -15,6 +16,5 @@ Ваше ReachableAddresses поставке су изазвале изузетак! Ваше поставке релеја су изазвале изузетак! нађен покренути Тор процес... - Нешто лоше се догодило. Прегледајте логове Тор није у могућности да се покрене: diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index 7471ebd741c13ec5bff593e593e8152d702d26e2..7f1edd91663a19936b03ffe6195fb4a877bd762e 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -1,6 +1,7 @@ - Orbot startar... + Orbot är en gratis proxyapp som möjliggör andra appar att använda internet mer säkert. Orbot använder Tor för att kryptera din internettrafik och döljer den genom att den studsar genom ett antal datorer världen över. Tor är fri programvara och ett öppet nätverk som hjälper dig att skydda dig mot en form av nätverksövervakning som hotar personlig integritet och frihet, hemliga affärsaktiviteter och relationer, och skyddar mot statlig övervakning även kallad trafikanalys. + Orbot startar... Uppkopplad till Tor nätverket Orbot är inaktiverad TorService avslutas @@ -16,7 +17,6 @@ Din NåbaraAdresser inställning orsakade ett undantag! Din relä inställning orsakade ett undantag! hittade existerande Tor process... - Något dåligt hände. Kolla loggen. Kan inte starta Tor: Du har bytt till en ny Tor identitet! uppdaterar inställningar i Tor-tjänsten diff --git a/src/main/res/values-ta/strings.xml b/src/main/res/values-ta/strings.xml index ec4ec3d3b135edd3d871d56a85fcff57db108222..70ee75d254132ad7b3aa814329ad7c3f16ebb500 100644 --- a/src/main/res/values-ta/strings.xml +++ b/src/main/res/values-ta/strings.xml @@ -1,5 +1,6 @@ + ஆர்பாட், இன்னும பாதுகாப்பான முறையில் இணைய பயன்படுத்த மற்ற பயன்பாடுகள் பலப்படுத்துகிறார் என்று ஒரு இலவச ப்ராக்ஸி பயன்பாடு ஆகும். ஆர்பாட் உங்கள் இணைய போக்குவரத்து குறியாக்க தோர் பயன்படுத்துகிறது மற்றும் அதன் பின்னர் உலகம் முழுவதும் கணினிகள் ஒரு தொடர் மூலம் எதிர்க்கிறது அதை மறுத்தவர். தோர் இலவச மென்பொருள் மற்றும் நீங்கள் போக்குவரத்து பகுப்பாய்வு என்ற தனிப்பட்ட சுதந்திரம் மற்றும் தனியுரிமை, ரகசிய வணிக நடவடிக்கைகள் மற்றும் உறவுகள், மற்றும் மாநில பாதுகாப்பை அச்சுறுத்தும் நெட்வொர்க் கண்காணிப்பு வடிவ எதிராக பாதுகாக்க உதவுகிறது என்று ஒரு திறந்த நெட்வொர்க் ஆகும். ஆர்பாட் துவங்குகிறது... தோர் நெட்வொர்க் இணைக்கப்பட்ட ஆர்பாட் நிறுத்தப்பட்டது diff --git a/src/main/res/values-th/strings.xml b/src/main/res/values-th/strings.xml index 971aeaf502068dbddeab5d240c6db8319586cd8d..deb120fa3b537d05395ecb4a6a713eef7150c11c 100644 --- a/src/main/res/values-th/strings.xml +++ b/src/main/res/values-th/strings.xml @@ -12,6 +12,5 @@ ไม่สามารถเริ่มโพรเซสของ Tor การตั้งค่า ReachableAddresses ของคุณทำให้เกิดข้อผิดพลาด การตั้งค่ารีเลย์ของคุณทำให้เกิดข้อผิดพลาด - เกิดอะไรไม่ดีสักอย่าง ให้ตรวจดูจากปูม ไม่สามารถเริ่ม Tor diff --git a/src/main/res/values-tl/strings.xml b/src/main/res/values-tl/strings.xml index 63cd9b6120f101b9601a2257d8c7822298ea1bb6..412739f356feaa2333017b7cee508008a2bc097d 100644 --- a/src/main/res/values-tl/strings.xml +++ b/src/main/res/values-tl/strings.xml @@ -15,7 +15,6 @@ Ang iyong ReachableAddresses settings ay nag sanhi ng exception! Ang iyong relay settings ay nag sanhi ng exception! nakakita ng umiiral na Tor process... - May nangyaring masama. Tingnan ang log Hindi masimulan ang Tor: Ikaw ay nagpalit ng bagong pagkakakilanlan sa Tor! diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml index b7fb8167719a156328b6794900eb2331e0ad3061..eb90c5872a8fec5c6e8402bc79b8fde5bff29cfe 100644 --- a/src/main/res/values-tr/strings.xml +++ b/src/main/res/values-tr/strings.xml @@ -1,6 +1,7 @@ - Orbot başlatılıyor... + Orbot başka uygulamaların interneti daha güvenli olarak kullanmasını sağlayan ücretsiz bir proxy uygulamasıdır. Orbot Tor\'u kullanarak internet trafiğinizi şifreler ve dünya üzerindeki pek çok farklı bilgisayardan geçirerek gizler. Tor sizin kişisel özgürlüğünüzü ve mahremiyetinizi, gizli ticari aktivitelerinizi ve bağlantılarınızı koruma altına alan bir yazılım ve açık ağdır. + Orbot başlatılıyor... Tor ağına bağlandı Orbot devre dışı bırakıldı Tor hizmeti kapatılıyor @@ -16,7 +17,6 @@ ErişilebilirAdresleriniz ayarlarınız bir istisnaya yol açtı! Tor aktarıcı ayarlarınız bir istisnaya yol açtı! varolan bir Tor işlemi bulundu... - Kötü bir şey oldu. Kayıtlara bakınız Tor başlatılamadı: Yeni bir Tor kimliğine geçiş yaptınız! Tor hizmet ayarları güncellemesi diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml index cbab677b727251fcc84e7d91bfa4bd59bab5bbc7..a3550feaba5a210bec85a9e3544732fb97dc650e 100644 --- a/src/main/res/values-uk/strings.xml +++ b/src/main/res/values-uk/strings.xml @@ -1,6 +1,7 @@ - Запуск Orbot... + Orbot — це вільна програма для проксі-з\'єднань, яка дозволяє іншим додаткам безпечніше використовувати інтернет-з\'єднання. Orbot використовує Tor для шифрування інтернет-трафіку, який далі приховується під час пересилання через кілька комп\'ютерів у різних частинах планети. Tor є вільним програмним забезпеченням, а також відкритою мережею, що допомагає захиститися від мережевого стеження, яке загрожує особистій свободі та приватному життю, конфіденційній бізнес-діяльності і контактам, а також державної програми безпеки, що відома як аналіз трафіку. + Запуск Orbot... Під\'єднаний до мережі Tor «Orbot» від\'єднаний @@ -15,7 +16,6 @@ Ваші налаштування Доступних Адрес викликали виключення! Налаштування вашого ретранслятора викликали виключення! знайдено існуючий процес Tor... - Виникла якась помилка. Перевірте лог Неможливо запустити Tor: Ви перемкнулись на новий ідентифікатор Tor! оновлення налаштувань у сервісі Tor diff --git a/src/main/res/values-vi/strings.xml b/src/main/res/values-vi/strings.xml index 7f4b03a4edba5b7fb87059e925ac1f6ffe16d293..f04af69ea2779ceff2ee37bbd617e0713c1e0f2f 100644 --- a/src/main/res/values-vi/strings.xml +++ b/src/main/res/values-vi/strings.xml @@ -1,6 +1,7 @@ - Ortbot đang khởi động... + Orbot là một ứng dụng proxy miễn phí, được thiết kế để làm cho các ứng dụng khác kết nối với Internet một cách an toàn. Orbot sử dụng Tor để mã hóa các kết nối Internet rồi ẩn danh nó thông qua một loạt các nút trong mạng Tor. Tor là phần mềm miễn phí và là một mạng lưới mở giúp bạn chống lại sự giám sát mạng, vốn đe dọa riêng tư trực tuyến, hay các hoạt động bí mật... + Ortbot đang khởi động... Đã kết nối với mạng Tor Orbot đã được vô hiệu hóa Đang tắt dịch vụ Tor @@ -16,7 +17,6 @@ Thiết lập ReachableAddresses đã gây ra một vấn đề! Thiết lập relay của bạn đã gây ra một vấn đề! tìm ra tiến trình hiện hành của Tor... - Có gì đó không ổn. Xin xem lại nhật ký Không thể khởi động Tor được: Bạn đã chuyển sang một mạch Tor mới! đang cập nhật cài đặt dịch vụ Tor diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index a04c53fabc9de76e07afef62a4c3f12d40058cf0..0e146e0a3f6e2d230df4dab61a2bacf8603f408f 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -1,6 +1,7 @@ - Orbot 正在启动... + Orbot 是一款免费的代理应用,能够让其他应用更安全地使用互联网。通过在位于世界各地的一系列计算机之间进行跳转,Orbot 可利用 Tor 对网络通信进行加密并隐藏。Tor 是一款免费的软件,并且是一个开放的网络。它可以保护用户免受流量分析的危害,这种网络监控可对个人自由与隐私、商业机密活动和关系以及国家安全造成威胁。 + Orbot 正在启动... 已连接到 Tor 网络 Orbot 已停用 Tor服务 正在关闭 @@ -16,13 +17,9 @@ 可访问地址设置导致异常! 中继设置导致异常! 发现当前已存在 Tor 进程... - 发生错误,请检查日志 无法启动 Tor: 已切换为新的 Tor 标识! 正在更新 Tor 服务中的设置 MiB/秒 KiB/秒 - - snowflake - diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 591249fb2e108b5a30770fb631c4c7dce7db4e01..9a860ba00e682200da652dedb6088860ddad2cb4 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -1,5 +1,7 @@ + Orbot是一款免費的網絡代理應用程式,用來保護其他應用程式的上網安全。 +Orbot使用Tor在全球一系列的電腦間跳躍,以便隱藏網路流量並加密。Tor是個免費軟體也是個開放網路,能幫您抵禦流量分析。它是某一種網路監控,牽涉到個人的自由與隱私、商業部分的機密關係和活動、甚至國家安全。 Orbot 正在啟動中... 已連線至 Tor 網路 Orbot 已停用 diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e7039afb3d20779f02ecfe82c9efff36a38b2d23..22220c9969f574352f7c093dc15abe3b1c737bcc 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - Orbot + Orbot Orbot VPN Orbot is a free proxy app that empowers other apps to use the internet more securely. Orbot uses Tor to encrypt your Internet traffic and then hides it by bouncing through a series of computers around the world. Tor is free software and an open network that helps you defend against a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security known as traffic analysis. Orbot is Starting… @@ -15,7 +15,6 @@ Your ReachableAddresses settings caused an exception! Your relay settings caused an exception! found existing Tor process… - Something bad happened. Check the log Unable to start Tor: You\'ve switched to a new Tor identity! @@ -29,7 +28,7 @@ KiB/s MiB/s - %s Your snowflake proxy helped someone circumvent censorship %s + %s Kindness Mode helped someone circumvent censorship %s unable to upload onion names Low memory warning! @@ -39,8 +38,6 @@ Added control port event handler Connected to tor control port Ignoring start request, already started. - There was an error installing geoip files -