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

Merge branch 'packet-tunnel' of https://github.com/rod-hynes/psiphon-tunnel-core into packet-tunnel

Rod Hynes 8 лет назад
Родитель
Сommit
8e2c36877f
1 измененных файлов с 66 добавлено и 5 удалено
  1. 66 5
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

+ 66 - 5
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

@@ -27,6 +27,7 @@
 #import "PsiphonTunnel.h"
 #import "json-framework/SBJson4.h"
 #import "JailbreakCheck/JailbreakCheck.h"
+#include <ifaddrs.h>
 
 
 @interface PsiphonTunnel () <GoPsiPsiphonProvider>
@@ -693,19 +694,79 @@
     if (!tunnelWholeDevice) {
         return FALSE;
     }
-
-    // TODO: Select correct WiFi or mobile data interface.
-    unsigned int interfaceIndex = if_nametoindex("en0");
-
+    
+    NSString *activeInterface = [self getActiveInterface];
+    if (activeInterface == nil) {
+        return FALSE;
+    }
+    [self logMessage:[NSString stringWithFormat:@"bindToDevice: Active interface: %@", activeInterface]];
+    
+    unsigned int interfaceIndex = if_nametoindex([activeInterface UTF8String]);
+    if (interfaceIndex == 0) {
+        // if_nametoindex returns 0 on error.
+        [self logMessage:[NSString stringWithFormat:@"bindToDevice: if_nametoindex error for interface (%@)", activeInterface]];
+        return FALSE;
+    }
+    
     int ret = setsockopt((int)fileDescriptor, IPPROTO_IP, IP_BOUND_IF, &interfaceIndex, sizeof(interfaceIndex));
     if (ret != 0) {
         [self logMessage:[NSString stringWithFormat: @"bindToDevice: setsockopt failed; errno: %d", errno]];
         return FALSE;
     }
-
+    
     return TRUE;
 }
 
+/*!
+ @brief Returns name of active network interface.
+ @return Active interface name, nil otherwise.
+ */
+- (NSString *)getActiveInterface {
+    
+    // Getting list of all active interfaces
+    NSMutableArray *upIffList = [NSMutableArray new];
+    
+    struct ifaddrs *interfaces;
+    if (getifaddrs(&interfaces) != 0) {
+        return nil;
+    }
+    
+    struct ifaddrs *interface;
+    for (interface=interfaces; interface; interface=interface->ifa_next) {
+        
+        // Only IFF_UP interfaces. Loopback is ignored.
+        if (interface->ifa_flags & IFF_UP && !(interface->ifa_flags & IFF_LOOPBACK)) {
+            
+            if (interface->ifa_addr && (interface->ifa_addr->sa_family==AF_INET || interface->ifa_addr->sa_family==AF_INET6)) {
+                
+                NSString *interfaceName = [NSString stringWithUTF8String:interface->ifa_name];
+                [upIffList addObject:interfaceName];
+            }
+        }
+    }
+    
+    // Free getifaddrs data
+    freeifaddrs(interfaces);
+    
+    [self logMessage:[NSString stringWithFormat:@"getActiveInterace: List of UP interfaces: %@", upIffList]];
+    
+    // TODO: following is a heuristic for choosing active network interface
+    // Only Wi-Fi and Cellular interfaces are considered
+    // @see : https://forums.developer.apple.com/thread/76711
+    NSArray *iffPriorityList = @[ @"en0", @"pdp_ip0"];
+    for (NSString * key in iffPriorityList) {
+        for (NSString * upIff in upIffList) {
+            if ([key isEqualToString:upIff]) {
+                return [NSString stringWithString:upIff];
+            }
+        }
+    }
+    
+    [self logMessage:@"getActiveInterface: No active interface found."];
+    
+    return nil;
+}
+
 - (NSString *)getPrimaryDnsServer {
     // This function is only called when BindToDevice is used/supported.
     // TODO: Implement correctly