Просмотр исходного кода

Updated NetworkID if an active VPN is detected in non-VPN mode

Amir Khan 3 лет назад
Родитель
Сommit
c02f144f50

+ 30 - 4
MobileLibrary/Android/PsiphonTunnel/PsiphonTunnel.java

@@ -429,7 +429,7 @@ public class PsiphonTunnel {
 
                                     @Override
                                     public String getNetworkID() {
-                                        return PsiphonTunnel.getNetworkID(context);
+                                        return PsiphonTunnel.getNetworkID(context, mPsiphonTunnel.isVpnMode());
                                     }
 
                                     @Override
@@ -672,7 +672,7 @@ public class PsiphonTunnel {
 
         @Override
         public String getNetworkID() {
-            return PsiphonTunnel.getNetworkID(mHostService.getContext());
+            return PsiphonTunnel.getNetworkID(mHostService.getContext(), mPsiphonTunnel.isVpnMode());
         }
     }
 
@@ -746,7 +746,7 @@ public class PsiphonTunnel {
         return hasRoute ? 1 : 0;
     }
 
-    private static String getNetworkID(Context context) {
+    private static String getNetworkID(Context context, boolean isVpnMode) {
 
         // TODO: getActiveNetworkInfo is deprecated in API 29; once
         // getActiveNetworkInfo is no longer available, use
@@ -761,6 +761,30 @@ public class PsiphonTunnel {
         String networkID = "UNKNOWN";
 
         ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+
+            if (!isVpnMode) {
+
+                NetworkCapabilities capabilities = null;
+                try {
+                    Network nw = connectivityManager.getActiveNetwork();
+                    capabilities = connectivityManager.getNetworkCapabilities(nw);
+                } catch (java.lang.Exception e)  {
+                    // May get exceptions due to missing permissions like android.permission.ACCESS_NETWORK_STATE.
+
+                    // Apps using the Psiphon Library and lacking android.permission.ACCESS_NETWORK_STATE will
+                    // proceed and use tactics, but with "UNKNOWN" as the sole network ID.
+                }
+
+                if (capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
+                    return "VPN";
+                }
+
+            }
+
+        }
+
         NetworkInfo activeNetworkInfo = null;
         try {
             activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
@@ -1557,7 +1581,9 @@ public class PsiphonTunnel {
                             // mimics the type determination logic in
                             // getNetworkID.
                             NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
-                            if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                            if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
+                                networkType = "VPN";
+                            } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                                 networkType = "MOBILE";
                             } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                                 networkType = "WIFI";

+ 2 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/NetworkID.h

@@ -33,9 +33,11 @@ NS_ASSUME_NONNULL_BEGIN
 /// currentNetworkStatus is NetworkReachabilityReachableViaWired.
 /// @param currentNetworkStatus Used to determine network ID and, on iOS <12, to determine the active interface when
 /// currentNetworkStatus is NetworkReachabilityReachableViaWired.
+/// @param tunnelWholeDevice False if library is used in non-VPN mode, true otherwise.
 /// @param outWarn If non-nil, then a non-fatal error occurred while determining the network ID and a valid network ID will still be returned.
 + (NSString *)getNetworkIDWithReachability:(id<ReachabilityProtocol>)reachability
                    andCurrentNetworkStatus:(NetworkReachability)currentNetworkStatus
+                         tunnelWholeDevice:(BOOL)tunnelWholeDevice
                                    warning:(NSError *_Nullable *_Nonnull)outWarn;
 
 @end

+ 14 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/NetworkID.m

@@ -28,10 +28,24 @@
 // See comment in header.
 + (NSString *)getNetworkIDWithReachability:(id<ReachabilityProtocol>)reachability
                    andCurrentNetworkStatus:(NetworkReachability)currentNetworkStatus
+                         tunnelWholeDevice:(BOOL)tunnelWholeDevice
                                    warning:(NSError *_Nullable *_Nonnull)outWarn {
 
     *outWarn = nil;
 
+    // NetworkID is "VPN" if the library is used in non-VPN mode,
+    // and an active VPN is found on the system.
+    // This method is not exact and relies on CFNetworkCopySystemProxySettings,
+    // specifically it may not return tun interfaces for some VPNs on macOS.
+    if (!tunnelWholeDevice) {
+        NSDictionary *_Nullable proxies = (__bridge NSDictionary *) CFNetworkCopySystemProxySettings();
+        for (NSString *interface in [proxies[@"__SCOPED__"] allKeys]) {
+            if ([interface containsString:@"tun"] || [interface containsString:@"tap"] || [interface containsString:@"ppp"] || [interface containsString:@"ipsec"]) {
+                return @"VPN";
+            }
+        }
+    }
+
     NSMutableString *networkID = [NSMutableString stringWithString:@"UNKNOWN"];
     if (currentNetworkStatus == NetworkReachabilityReachableViaWiFi) {
         [networkID setString:@"WIFI"];

+ 4 - 1
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.h

@@ -24,7 +24,10 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface PsiphonProviderNetwork : NSObject <GoPsiPsiphonProviderNetwork>
 
-- (instancetype)initWithLogger:(void (^__nonnull)(NSString *_Nonnull))logger;
+- (instancetype)init NS_UNAVAILABLE;
+
+- (instancetype)initWithTunnelWholeDevice:(BOOL)tunnelWholeDevice
+                                   logger:(void (^__nonnull)(NSString *_Nonnull))logger NS_DESIGNATED_INITIALIZER;
 
 @end
 

+ 10 - 18
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.m

@@ -27,29 +27,20 @@
 
 @implementation PsiphonProviderNetwork {
     id<ReachabilityProtocol> reachability;
+    BOOL tunnelWholeDevice;
     void (^logger) (NSString *_Nonnull);
 }
 
-- (void)initialize {
-    if (@available(iOS 12.0, *)) {
-        self->reachability = [[DefaultRouteMonitor alloc] init];
-    } else {
-        self->reachability = [Reachability reachabilityForInternetConnection];
-    }
-}
-
-- (id)init {
-    self = [super init];
-    if (self) {
-        [self initialize];
-    }
-    return self;
-}
-
-- (instancetype)initWithLogger:(void (^__nonnull)(NSString *_Nonnull))logger {
+- (instancetype)initWithTunnelWholeDevice:(BOOL)tunnelWholeDevice
+                                   logger:(void (^__nonnull)(NSString *_Nonnull))logger {
     self = [super init];
     if (self) {
-        [self initialize];
+        if (@available(iOS 12.0, *)) {
+            self->reachability = [[DefaultRouteMonitor alloc] init];
+        } else {
+            self->reachability = [Reachability reachabilityForInternetConnection];
+        }
+        self->tunnelWholeDevice = tunnelWholeDevice;
         self->logger = logger;
     }
     return self;
@@ -74,6 +65,7 @@
     NSError *warn;
     NSString *networkID = [NetworkID getNetworkIDWithReachability:self->reachability
                                           andCurrentNetworkStatus:self->reachability.reachabilityStatus
+                                                tunnelWholeDevice:self->tunnelWholeDevice
                                                           warning:&warn];
     if (warn != nil) {
         [self logMessage:[NSString stringWithFormat:@"error getting network ID: %@", warn.localizedDescription]];

+ 4 - 1
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

@@ -1294,6 +1294,7 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
     NSError *warn;
     NSString *networkID = [NetworkID getNetworkIDWithReachability:self->reachability
                                           andCurrentNetworkStatus:atomic_load(&self->currentNetworkStatus)
+                                                tunnelWholeDevice:self->tunnelWholeDevice
                                                           warning:&warn];
     if (warn != nil) {
         [self logMessage:[NSString stringWithFormat:@"error getting network ID: %@", warn.localizedDescription]];
@@ -1797,7 +1798,9 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
         PsiphonProviderNoticeHandlerShim *noticeHandler =
             [[PsiphonProviderNoticeHandlerShim alloc] initWithLogger:logNotice];
 
-        PsiphonProviderNetwork *networkInfoProvider = [[PsiphonProviderNetwork alloc] initWithLogger:logger];
+        PsiphonProviderNetwork *networkInfoProvider = [[PsiphonProviderNetwork alloc]
+                                                       initWithTunnelWholeDevice:tunnelWholeDevice
+                                                       logger:logger];
 
         GoPsiStartSendFeedback(
             psiphonConfig,

+ 3 - 0
psiphon/dialParameters.go

@@ -999,6 +999,9 @@ func (dialParams *DialParameters) GetNetworkType() string {
 	// check for and use the common network type prefixes currently used in
 	// NetworkIDGetter implementations.
 
+	if strings.HasPrefix(dialParams.NetworkID, "VPN") {
+		return "VPN"
+	}
 	if strings.HasPrefix(dialParams.NetworkID, "WIFI") {
 		return "WIFI"
 	}