Browse Source

Change iOS Library to explicitly set session ID

- Generate a new session ID only when starting due
  to external start command.

- Reuse existing session ID when restarting
  automatically, such as when internetReachabilityChanged
  triggers a restart.
Rod Hynes 8 years ago
parent
commit
e8bf5351c0

+ 3 - 2
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.h

@@ -176,8 +176,9 @@ typedef NS_ENUM(NSInteger, PsiphonConnectionState)
 - (void)onConnectionStateChangedFrom:(PsiphonConnectionState)oldState to:(PsiphonConnectionState)newState;
 - (void)onConnectionStateChangedFrom:(PsiphonConnectionState)oldState to:(PsiphonConnectionState)newState;
 
 
 /*!
 /*!
- Called to indicate that tunnel-core is exiting imminently (usually do to
+ Called to indicate that tunnel-core is exiting imminently (usually due to
  a `stop()` call, but could be due to an unexpected error).
  a `stop()` call, but could be due to an unexpected error).
+ onExiting may be called before or after `stop()` returns.
  Swift: @code func onExiting() @endcode
  Swift: @code func onExiting() @endcode
  */
  */
 - (void)onExiting;
 - (void)onExiting;
@@ -301,7 +302,7 @@ Swift: @code func onInternetReachabilityChanged(_ currentReachability: Reachabil
 - (BOOL)start:(BOOL)ifNeeded;
 - (BOOL)start:(BOOL)ifNeeded;
 
 
 /*!
 /*!
- Stop the tunnel (regardless of its current connection state). Returns before full stop is complete -- `TunneledAppDelegate::onExiting` is called when complete.
+ Stop the tunnel (regardless of its current connection state).
  Swift: @code func stop() @endcode
  Swift: @code func stop() @endcode
  */
  */
 - (void)stop;
 - (void)stop;

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

@@ -39,6 +39,8 @@
 
 
 @property (weak) id <TunneledAppDelegate> tunneledAppDelegate;
 @property (weak) id <TunneledAppDelegate> tunneledAppDelegate;
 
 
+@property (atomic, strong) NSString *sessionID;
+
 @end
 @end
 
 
 @implementation PsiphonTunnel {
 @implementation PsiphonTunnel {
@@ -59,8 +61,6 @@
     // DNS
     // DNS
     NSString *primaryGoogleDNS;
     NSString *primaryGoogleDNS;
     NSString *secondaryGoogleDNS;
     NSString *secondaryGoogleDNS;
-
-    
     _Atomic BOOL useInitialDNS; // initialDNSCache validity flag.
     _Atomic BOOL useInitialDNS; // initialDNSCache validity flag.
     NSArray<NSString *> *initialDNSCache;  // This cache becomes void if internetReachabilityChanged is called.
     NSArray<NSString *> *initialDNSCache;  // This cache becomes void if internetReachabilityChanged is called.
 }
 }
@@ -118,6 +118,15 @@
 
 
 // See comment in header
 // See comment in header
 - (BOOL)start:(BOOL)ifNeeded {
 - (BOOL)start:(BOOL)ifNeeded {
+
+    // Set a new session ID, as this is a user-initiated session start.
+    NSString *sessionID = [self generateSessionID];
+    if (sessionID == nil) {
+        // generateSessionID logs error message
+        return FALSE;
+    }
+    self.sessionID = sessionID;
+
     if (ifNeeded) {
     if (ifNeeded) {
         return [self startIfNeeded];
         return [self startIfNeeded];
     }
     }
@@ -127,10 +136,14 @@
 
 
 /*!
 /*!
  Start the tunnel. If the tunnel is already started it will be stopped first.
  Start the tunnel. If the tunnel is already started it will be stopped first.
+ Assumes self.sessionID has been initialized -- i.e., assumes that
+ start:(BOOL)ifNeeded has been called at least once.
  */
  */
 - (BOOL)start {
 - (BOOL)start {
     @synchronized (PsiphonTunnel.self) {
     @synchronized (PsiphonTunnel.self) {
+
         [self stop];
         [self stop];
+
         [self logMessage:@"Starting Psiphon library"];
         [self logMessage:@"Starting Psiphon library"];
 
 
         // Must always use IPv6Synthesizer for iOS
         // Must always use IPv6Synthesizer for iOS
@@ -525,6 +538,8 @@
     config[@"UpgradeDownloadClientVersionHeader"] = nil;
     config[@"UpgradeDownloadClientVersionHeader"] = nil;
     config[@"UpgradeDownloadFilename"] = nil;
     config[@"UpgradeDownloadFilename"] = nil;
 
 
+    config[@"SessionID"] = self.sessionID;
+
     NSString *finalConfigStr = [[[SBJson4Writer alloc] init] stringWithObject:config];
     NSString *finalConfigStr = [[[SBJson4Writer alloc] init] stringWithObject:config];
     
     
     if (finalConfigStr == nil) {
     if (finalConfigStr == nil) {
@@ -919,7 +934,7 @@
     _state = malloc(sizeof(struct __res_state));
     _state = malloc(sizeof(struct __res_state));
 
 
     if (res_ninit(_state) < 0) {
     if (res_ninit(_state) < 0) {
-        NSLog(@"res_ninit failed.");
+        [self logMessage:@"getDNSServers: res_ninit failed."];
         free(_state);
         free(_state);
         return nil;
         return nil;
     }
     }
@@ -943,7 +958,7 @@
             if (EXIT_SUCCESS == ret_code) {
             if (EXIT_SUCCESS == ret_code) {
                 [serverList addObject:[NSString stringWithUTF8String:hostBuf]];
                 [serverList addObject:[NSString stringWithUTF8String:hostBuf]];
             } else {
             } else {
-                NSLog(@"getnameinfo failed. Retcode: %d", ret_code);
+                [self logMessage:[NSString stringWithFormat: @"getDNSServers: getnameinfo failed: %d", ret_code]];
             }
             }
         }
         }
     }
     }
@@ -1119,4 +1134,22 @@
     return @"US";
     return @"US";
 }
 }
 
 
+/*!
+ generateSessionID generates a session ID suitable for use with the Psiphon API.
+ */
+- (NSString *)generateSessionID {
+    const int sessionIDLen = 16;
+    uint8_t sessionID[sessionIDLen];
+    int result = SecRandomCopyBytes(kSecRandomDefault, sessionIDLen, sessionID);
+    if (result != errSecSuccess) {
+        [self logMessage:[NSString stringWithFormat: @"Error generating session ID: %d", result]];
+        return nil;
+    }
+    NSMutableString *hexEncodedSessionID = [NSMutableString stringWithCapacity:(sessionIDLen*2)];
+    for (int i = 0; i < sessionIDLen; i++) {
+        [hexEncodedSessionID appendFormat:@"%02x", sessionID[i]];
+    }
+    return hexEncodedSessionID;
+}
+
 @end
 @end