Parcourir la source

Fix: use network info callbacks in StartSendFeedback

- Fixes network ID defaulting to "UNKNOWN"
mirokuratczyk il y a 5 ans
Parent
commit
d4a835be9d

+ 34 - 12
MobileLibrary/Android/PsiphonTunnel/PsiphonTunnel.java

@@ -73,6 +73,7 @@ import java.util.concurrent.TimeUnit;
 
 import psi.Psi;
 import psi.PsiphonProvider;
+import psi.PsiphonProviderNetwork;
 import psi.PsiphonProviderNoticeHandler;
 import psi.PsiphonProviderFeedbackHandler;
 
@@ -405,6 +406,25 @@ public class PsiphonTunnel {
                                         });
                                     }
                                 },
+                                new PsiphonProviderNetwork() {
+                                    @Override
+                                    public long hasNetworkConnectivity() {
+                                        boolean hasConnectivity = PsiphonTunnel.hasNetworkConnectivity(context);
+                                        // TODO: change to bool return value once gobind supports that type
+                                        return hasConnectivity ? 1 : 0;
+                                    }
+
+                                    @Override
+                                    public String getNetworkID() {
+                                        return PsiphonTunnel.getNetworkID(context);
+                                    }
+
+                                    @Override
+                                    public String iPv6Synthesize(String IPv4Addr) {
+                                        // Unused on Android.
+                                        return PsiphonTunnel.iPv6Synthesize(IPv4Addr);
+                                    }
+                                },
                                 new PsiphonProviderNoticeHandler() {
                                     @Override
                                     public void notice(String noticeJSON) {
@@ -438,7 +458,9 @@ public class PsiphonTunnel {
                                             });
                                         }
                                     }
-                                });
+                                },
+                                // Do not use IPv6 synthesizer for android
+                                false);
                     } catch (java.lang.Exception e) {
                         callbackQueue.submit(new Runnable() {
                             @Override
@@ -618,22 +640,22 @@ public class PsiphonTunnel {
 
         @Override
         public String getPrimaryDnsServer() {
-            return mPsiphonTunnel.getPrimaryDnsServer();
+            return PsiphonTunnel.getPrimaryDnsServer(mHostService.getContext(), mHostService);
         }
 
         @Override
         public String getSecondaryDnsServer() {
-            return mPsiphonTunnel.getSecondaryDnsServer();
+            return PsiphonTunnel.getSecondaryDnsServer();
         }
 
         @Override
         public String iPv6Synthesize(String IPv4Addr) {
-            return mPsiphonTunnel.iPv6Synthesize(IPv4Addr);
+            return PsiphonTunnel.iPv6Synthesize(IPv4Addr);
         }
 
         @Override
         public String getNetworkID() {
-            return mPsiphonTunnel.getNetworkID();
+            return PsiphonTunnel.getNetworkID(mHostService.getContext());
         }
     }
 
@@ -664,26 +686,27 @@ public class PsiphonTunnel {
         return hasConnectivity ? 1 : 0;
     }
 
-    private String getPrimaryDnsServer() {
+    private static String getPrimaryDnsServer(Context context, HostLogger logger) {
         String dnsResolver = null;
         try {
-            dnsResolver = getFirstActiveNetworkDnsResolver(mHostService.getContext());
+            dnsResolver = getFirstActiveNetworkDnsResolver(context);
         } catch (Exception e) {
-            mHostService.onDiagnosticMessage("failed to get active network DNS resolver: " + e.getMessage());
+            logger.onDiagnosticMessage("failed to get active network DNS resolver: " + e.getMessage());
             dnsResolver = DEFAULT_PRIMARY_DNS_SERVER;
         }
         return dnsResolver;
     }
 
-    private String getSecondaryDnsServer() {
+    private static String getSecondaryDnsServer() {
         return DEFAULT_SECONDARY_DNS_SERVER;
     }
 
-    private String iPv6Synthesize(String IPv4Addr) {
+    private static String iPv6Synthesize(String IPv4Addr) {
+        // Unused on Android.
         return IPv4Addr;
     }
 
-    private String getNetworkID() {
+    private static String getNetworkID(Context context) {
 
         // The network ID contains potential PII. In tunnel-core, the network ID
         // is used only locally in the client and not sent to the server.
@@ -693,7 +716,6 @@ public class PsiphonTunnel {
 
         String networkID = "UNKNOWN";
 
-        Context context = mHostService.getContext();
         ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo activeNetworkInfo = null;
         try {

+ 46 - 6
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel.xcodeproj/project.pbxproj

@@ -42,8 +42,16 @@
 		66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BDB0591DC26CCC0079384C /* SBJson4Writer.m */; };
 		CE3D1DA523906003009A4AF6 /* Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = CE3D1DA323906003009A4AF6 /* Backups.h */; };
 		CE3D1DA623906003009A4AF6 /* Backups.m in Sources */ = {isa = PBXBuildFile; fileRef = CE3D1DA423906003009A4AF6 /* Backups.m */; };
+		CE4616BF2539493600D1243E /* Reachability+HasNetworkConnectivity.h in Headers */ = {isa = PBXBuildFile; fileRef = CE4616BD2539493600D1243E /* Reachability+HasNetworkConnectivity.h */; };
+		CE4616C02539493600D1243E /* Reachability+HasNetworkConnectivity.m in Sources */ = {isa = PBXBuildFile; fileRef = CE4616BE2539493600D1243E /* Reachability+HasNetworkConnectivity.m */; };
 		CEC229FC24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h in Headers */ = {isa = PBXBuildFile; fileRef = CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */; };
 		CEC229FD24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m in Sources */ = {isa = PBXBuildFile; fileRef = CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */; };
+		CECF01442538D34100CD3E5C /* IPv6Synthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = CECF01422538D34100CD3E5C /* IPv6Synthesizer.h */; };
+		CECF01452538D34100CD3E5C /* IPv6Synthesizer.m in Sources */ = {isa = PBXBuildFile; fileRef = CECF01432538D34100CD3E5C /* IPv6Synthesizer.m */; };
+		CECF01492538DD0B00CD3E5C /* PsiphonProviderNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = CECF01472538DD0B00CD3E5C /* PsiphonProviderNetwork.h */; };
+		CECF014A2538DD0B00CD3E5C /* PsiphonProviderNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = CECF01482538DD0B00CD3E5C /* PsiphonProviderNetwork.m */; };
+		CECF01502538E14B00CD3E5C /* NetworkID.h in Headers */ = {isa = PBXBuildFile; fileRef = CECF014E2538E14B00CD3E5C /* NetworkID.h */; };
+		CECF01512538E14B00CD3E5C /* NetworkID.m in Sources */ = {isa = PBXBuildFile; fileRef = CECF014F2538E14B00CD3E5C /* NetworkID.m */; };
 		CEDE547924EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h in Headers */ = {isa = PBXBuildFile; fileRef = CEDE547724EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h */; };
 		CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */; };
 		EFED7EBF1F587F6E0078980F /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EFED7EBE1F587F6E0078980F /* libresolv.tbd */; };
@@ -110,8 +118,16 @@
 		66BDB0591DC26CCC0079384C /* SBJson4Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4Writer.m; sourceTree = "<group>"; };
 		CE3D1DA323906003009A4AF6 /* Backups.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Backups.h; sourceTree = "<group>"; };
 		CE3D1DA423906003009A4AF6 /* Backups.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Backups.m; sourceTree = "<group>"; };
+		CE4616BD2539493600D1243E /* Reachability+HasNetworkConnectivity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Reachability+HasNetworkConnectivity.h"; sourceTree = "<group>"; };
+		CE4616BE2539493600D1243E /* Reachability+HasNetworkConnectivity.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "Reachability+HasNetworkConnectivity.m"; sourceTree = "<group>"; };
 		CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PsiphonProviderNoticeHandlerShim.h; sourceTree = "<group>"; };
 		CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PsiphonProviderNoticeHandlerShim.m; sourceTree = "<group>"; };
+		CECF01422538D34100CD3E5C /* IPv6Synthesizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IPv6Synthesizer.h; sourceTree = "<group>"; };
+		CECF01432538D34100CD3E5C /* IPv6Synthesizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IPv6Synthesizer.m; sourceTree = "<group>"; };
+		CECF01472538DD0B00CD3E5C /* PsiphonProviderNetwork.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PsiphonProviderNetwork.h; sourceTree = "<group>"; };
+		CECF01482538DD0B00CD3E5C /* PsiphonProviderNetwork.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PsiphonProviderNetwork.m; sourceTree = "<group>"; };
+		CECF014E2538E14B00CD3E5C /* NetworkID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NetworkID.h; sourceTree = "<group>"; };
+		CECF014F2538E14B00CD3E5C /* NetworkID.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NetworkID.m; sourceTree = "<group>"; };
 		CEDE547724EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PsiphonProviderFeedbackHandlerShim.h; path = ../PsiphonProviderFeedbackHandlerShim.h; sourceTree = "<group>"; };
 		CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PsiphonProviderFeedbackHandlerShim.m; path = ../PsiphonProviderFeedbackHandlerShim.m; sourceTree = "<group>"; };
 		EFED7EBE1F587F6E0078980F /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
@@ -138,15 +154,20 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-		662659241DD270E900872F6C /* Reachability */ = {
+		662659241DD270E900872F6C /* Network */ = {
 			isa = PBXGroup;
 			children = (
-				662659251DD270E900872F6C /* Reachability.h */,
-				662659261DD270E900872F6C /* Reachability.m */,
+				CECF01542538FC5900CD3E5C /* Reachability */,
 				4E89F7FC1E2ED3CE00005F4C /* LookupIPv6.c */,
 				4E89F7FD1E2ED3CE00005F4C /* LookupIPv6.h */,
-			);
-			path = Reachability;
+				CECF01422538D34100CD3E5C /* IPv6Synthesizer.h */,
+				CECF01432538D34100CD3E5C /* IPv6Synthesizer.m */,
+				CECF014E2538E14B00CD3E5C /* NetworkID.h */,
+				CECF014F2538E14B00CD3E5C /* NetworkID.m */,
+				CE4616BD2539493600D1243E /* Reachability+HasNetworkConnectivity.h */,
+				CE4616BE2539493600D1243E /* Reachability+HasNetworkConnectivity.m */,
+			);
+			path = Network;
 			sourceTree = "<group>";
 		};
 		6685BDC31E2E881200F0E414 /* Psi */ = {
@@ -198,7 +219,7 @@
 				66BAD3321E525FBC00CD06DE /* JailbreakCheck */,
 				66BDB04A1DC26CCC0079384C /* json-framework */,
 				CEDE547B24EBF5A00053566E /* Psiphon */,
-				662659241DD270E900872F6C /* Reachability */,
+				662659241DD270E900872F6C /* Network */,
 				CEC22A0624F0689000534D04 /* Utils */,
 				66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */,
 				66BDB0431DA6C7DD0079384C /* PsiphonTunnel.m */,
@@ -256,6 +277,15 @@
 			path = Utils;
 			sourceTree = "<group>";
 		};
+		CECF01542538FC5900CD3E5C /* Reachability */ = {
+			isa = PBXGroup;
+			children = (
+				662659251DD270E900872F6C /* Reachability.h */,
+				662659261DD270E900872F6C /* Reachability.m */,
+			);
+			path = Reachability;
+			sourceTree = "<group>";
+		};
 		CEDE547B24EBF5A00053566E /* Psiphon */ = {
 			isa = PBXGroup;
 			children = (
@@ -263,6 +293,8 @@
 				CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */,
 				CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */,
 				CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */,
+				CECF01472538DD0B00CD3E5C /* PsiphonProviderNetwork.h */,
+				CECF01482538DD0B00CD3E5C /* PsiphonProviderNetwork.m */,
 			);
 			path = Psiphon;
 			sourceTree = "<group>";
@@ -286,14 +318,17 @@
 				6685BDCB1E2E882800F0E414 /* ref.h in Headers */,
 				66BAD3351E525FBC00CD06DE /* JailbreakCheck.h in Headers */,
 				4E89F7FF1E2ED3CE00005F4C /* LookupIPv6.h in Headers */,
+				CE4616BF2539493600D1243E /* Reachability+HasNetworkConnectivity.h in Headers */,
 				662659271DD270E900872F6C /* Reachability.h in Headers */,
 				66BDB05D1DC26CCC0079384C /* SBJson4StreamParser.h in Headers */,
 				6685BDD41E2EBB1000F0E414 /* GoPsi.objc.h in Headers */,
 				6685BDD51E2EBB1000F0E414 /* Universe.objc.h in Headers */,
+				CECF01492538DD0B00CD3E5C /* PsiphonProviderNetwork.h in Headers */,
 				66BDB05F1DC26CCC0079384C /* SBJson4StreamParserState.h in Headers */,
 				66BDB0311DA6BFCC0079384C /* PsiphonTunnel.h in Headers */,
 				6685BDCA1E2E882800F0E414 /* Psi.h in Headers */,
 				66BDB0651DC26CCC0079384C /* SBJson4StreamWriterState.h in Headers */,
+				CECF01502538E14B00CD3E5C /* NetworkID.h in Headers */,
 				66BDB05B1DC26CCC0079384C /* SBJson4Parser.h in Headers */,
 				CEDE547924EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h in Headers */,
 				6685BDCD1E2E88A200F0E414 /* Psi-meta.h in Headers */,
@@ -301,6 +336,7 @@
 				66BDB0611DC26CCC0079384C /* SBJson4StreamTokeniser.h in Headers */,
 				CEC229FC24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h in Headers */,
 				66BDB0631DC26CCC0079384C /* SBJson4StreamWriter.h in Headers */,
+				CECF01442538D34100CD3E5C /* IPv6Synthesizer.h in Headers */,
 				66BDB0671DC26CCC0079384C /* SBJson4Writer.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -430,13 +466,17 @@
 				66BDB0641DC26CCC0079384C /* SBJson4StreamWriter.m in Sources */,
 				CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */,
 				66BDB0661DC26CCC0079384C /* SBJson4StreamWriterState.m in Sources */,
+				CECF01452538D34100CD3E5C /* IPv6Synthesizer.m in Sources */,
 				66BDB05C1DC26CCC0079384C /* SBJson4Parser.m in Sources */,
 				4E89F7FE1E2ED3CE00005F4C /* LookupIPv6.c in Sources */,
+				CECF01512538E14B00CD3E5C /* NetworkID.m in Sources */,
 				66BAD3361E525FBC00CD06DE /* JailbreakCheck.m in Sources */,
 				66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */,
 				66BDB0621DC26CCC0079384C /* SBJson4StreamTokeniser.m in Sources */,
 				66BDB0441DA6C7DD0079384C /* PsiphonTunnel.m in Sources */,
 				CEC229FD24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m in Sources */,
+				CE4616C02539493600D1243E /* Reachability+HasNetworkConnectivity.m in Sources */,
+				CECF014A2538DD0B00CD3E5C /* PsiphonProviderNetwork.m in Sources */,
 				662659281DD270E900872F6C /* Reachability.m in Sources */,
 				66BDB0601DC26CCC0079384C /* SBJson4StreamParserState.m in Sources */,
 				CE3D1DA623906003009A4AF6 /* Backups.m in Sources */,

+ 32 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/IPv6Synthesizer.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "Psi-meta.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface IPv6Synthesizer : NSObject
+
+/// Synthesize an IPv6 address from an IPv4 address on a DNS64/NAT64 network
++ (NSString *)IPv4ToIPv6:(NSString *)IPv4Addr;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 35 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/IPv6Synthesizer.m

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import "IPv6Synthesizer.h"
+#import "LookupIPv6.h"
+
+@implementation IPv6Synthesizer
+
++ (NSString *)IPv4ToIPv6:(NSString *)IPv4Addr {
+    char *result = getIPv6ForIPv4([IPv4Addr UTF8String]);
+    if (result != NULL) {
+        NSString *IPv6Addr = [NSString stringWithUTF8String:result];
+        free(result);
+        return IPv6Addr;
+    }
+    return @"";
+}
+
+@end

+ 0 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/LookupIPv6.c → MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/LookupIPv6.c


+ 0 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/LookupIPv6.h → MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/LookupIPv6.h


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

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "Reachability.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface NetworkID : NSObject
+
+/// The network ID contains potential PII. In tunnel-core, the network ID
+/// is used only locally in the client and not sent to the server.
+///
+/// See network ID requirements here:
+/// https://godoc.org/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon#NetworkIDGetter
++ (NSString *)getNetworkID:(NetworkStatus)networkStatus;
+
+@end
+
+NS_ASSUME_NONNULL_END

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

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import "NetworkID.h"
+#import <CoreTelephony/CTTelephonyNetworkInfo.h>
+#import <CoreTelephony/CTCarrier.h>
+#import <SystemConfiguration/CaptiveNetwork.h>
+
+@implementation NetworkID
+
++ (NSString *)getNetworkID:(NetworkStatus)networkStatus {
+
+    NSMutableString *networkID = [NSMutableString stringWithString:@"UNKNOWN"];
+    if (networkStatus == ReachableViaWiFi) {
+        [networkID setString:@"WIFI"];
+        NSArray *networkInterfaceNames = (__bridge_transfer id)CNCopySupportedInterfaces();
+        for (NSString *networkInterfaceName in networkInterfaceNames) {
+            NSDictionary *networkInterfaceInfo = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)networkInterfaceName);
+            if (networkInterfaceInfo[@"BSSID"]) {
+                [networkID appendFormat:@"-%@", networkInterfaceInfo[@"BSSID"]];
+            }
+        }
+    } else if (networkStatus == ReachableViaWWAN) {
+        [networkID setString:@"MOBILE"];
+        CTTelephonyNetworkInfo *telephonyNetworkinfo = [[CTTelephonyNetworkInfo alloc] init];
+        CTCarrier *cellularProvider = [telephonyNetworkinfo subscriberCellularProvider];
+        if (cellularProvider != nil) {
+            NSString *mcc = [cellularProvider mobileCountryCode];
+            NSString *mnc = [cellularProvider mobileNetworkCode];
+            [networkID appendFormat:@"-%@-%@", mcc, mnc];
+        }
+    }
+    return networkID;
+}
+
+@end

+ 32 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability+HasNetworkConnectivity.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "Reachability.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface Reachability (HasNetworkConnectivity)
+
+/// Returns 1 if there is network connectivity. Otherwise returns 0.
+- (long)hasNetworkConnectivity;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 28 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability+HasNetworkConnectivity.m

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import "Reachability+HasNetworkConnectivity.h"
+
+@implementation Reachability (NetworkConnectivity)
+
+- (long)hasNetworkConnectivity {
+    return [self currentReachabilityStatus] != NotReachable;
+}
+
+@end

+ 0 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/README.md → MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/README.md


+ 0 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/Reachability.h → MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/Reachability.h


+ 0 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Reachability/Reachability.m → MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/Reachability.m


+ 28 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "Psi-meta.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface PsiphonProviderNetwork : NSObject <GoPsiPsiphonProviderNetwork>
+@end
+
+NS_ASSUME_NONNULL_END

+ 51 - 0
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.m

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#import "PsiphonProviderNetwork.h"
+#import "IPv6Synthesizer.h"
+#import "Reachability.h"
+#import "Reachability+HasNetworkConnectivity.h"
+#import "NetworkID.h"
+
+@implementation PsiphonProviderNetwork {
+    Reachability *reachability;
+}
+
+- (id)init {
+    self = [super init];
+    if (self) {
+        self->reachability = [Reachability reachabilityForInternetConnection];
+    }
+    return self;
+}
+
+- (long)hasNetworkConnectivity {
+    return [self->reachability hasNetworkConnectivity];
+}
+
+
+- (NSString *)iPv6Synthesize:(NSString *)IPv4Addr {
+    return [IPv6Synthesizer IPv4ToIPv6:IPv4Addr];
+}
+
+- (NSString *)getNetworkID {
+    return [NetworkID getNetworkID:reachability.currentReachabilityStatus];
+}
+
+@end

+ 27 - 44
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

@@ -22,15 +22,17 @@
 #import <stdatomic.h>
 #import <CoreTelephony/CTTelephonyNetworkInfo.h>
 #import <CoreTelephony/CTCarrier.h>
-#import <SystemConfiguration/CaptiveNetwork.h>
-#import "LookupIPv6.h"
+#import "IPv6Synthesizer.h"
 #import "Psi-meta.h"
 #import "PsiphonProviderFeedbackHandlerShim.h"
 #import "PsiphonProviderNoticeHandlerShim.h"
+#import "PsiphonProviderNetwork.h"
 #import "PsiphonTunnel.h"
+#import "Reachability+HasNetworkConnectivity.h"
 #import "Backups.h"
 #import "json-framework/SBJson4.h"
 #import "JailbreakCheck/JailbreakCheck.h"
+#import "NetworkID.h"
 #import <ifaddrs.h>
 #import <resolv.h>
 #import <netdb.h>
@@ -40,6 +42,8 @@
 
 NSErrorDomain _Nonnull const PsiphonTunnelErrorDomain = @"com.psiphon3.ios.PsiphonTunnelErrorDomain";
 
+const BOOL UseIPv6Synthesizer = TRUE; // Must always use IPv6Synthesizer for iOS
+
 /// Error codes which can returned by PsiphonTunnel
 typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 
@@ -272,9 +276,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 
         [self logMessage:@"Starting Psiphon library"];
 
-        // Must always use IPv6Synthesizer for iOS
-        const BOOL useIPv6Synthesizer = TRUE;
-
         BOOL usingNoticeFiles = FALSE;
 
         NSError *err;
@@ -329,7 +330,7 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
                 embeddedServerEntriesPath,
                 self,
                 self->tunnelWholeDevice, // useDeviceBinder
-                useIPv6Synthesizer,
+                UseIPv6Synthesizer,
                 &e);
             
             if (e != nil) {
@@ -1339,46 +1340,11 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 }
 
 - (NSString *)iPv6Synthesize:(NSString *)IPv4Addr {
-    // This function is called to synthesize an ipv6 address from an ipv4 one on a DNS64/NAT64 network
-    char *result = getIPv6ForIPv4([IPv4Addr UTF8String]);
-    if (result != NULL) {
-        NSString *IPv6Addr = [NSString stringWithUTF8String:result];
-        free(result);
-        return IPv6Addr;
-    }
-    return @"";
+    return [IPv6Synthesizer IPv4ToIPv6:IPv4Addr];
 }
 
 - (NSString *)getNetworkID {
-
-    // The network ID contains potential PII. In tunnel-core, the network ID
-    // is used only locally in the client and not sent to the server.
-    //
-    // See network ID requirements here:
-    // https://godoc.org/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon#NetworkIDGetter
-
-    NSMutableString *networkID = [NSMutableString stringWithString:@"UNKNOWN"];
-    NetworkStatus status = [self->reachability currentReachabilityStatus];
-    if (status == ReachableViaWiFi) {
-        [networkID setString:@"WIFI"];
-        NSArray *networkInterfaceNames = (__bridge_transfer id)CNCopySupportedInterfaces();
-        for (NSString *networkInterfaceName in networkInterfaceNames) {
-            NSDictionary *networkInterfaceInfo = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)networkInterfaceName);
-            if (networkInterfaceInfo[@"BSSID"]) {
-                [networkID appendFormat:@"-%@", networkInterfaceInfo[@"BSSID"]];
-            }
-        }
-    } else if (status == ReachableViaWWAN) {
-        [networkID setString:@"MOBILE"];
-        CTTelephonyNetworkInfo *telephonyNetworkinfo = [[CTTelephonyNetworkInfo alloc] init];
-        CTCarrier *cellularProvider = [telephonyNetworkinfo subscriberCellularProvider];
-        if (cellularProvider != nil) {
-            NSString *mcc = [cellularProvider mobileCountryCode];
-            NSString *mnc = [cellularProvider mobileNetworkCode];
-            [networkID appendFormat:@"-%@-%@", mcc, mnc];
-        }
-    }
-    return networkID;
+    return [NetworkID getNetworkID:[self->reachability currentReachabilityStatus]];
 }
 
 - (void)notice:(NSString *)noticeJSON {
@@ -1806,7 +1772,24 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
         PsiphonProviderNoticeHandlerShim *noticeHandler =
             [[PsiphonProviderNoticeHandlerShim alloc] initWithLogger:logNotice];
 
-        GoPsiStartSendFeedback(psiphonConfig, feedbackJson, uploadPath, innerFeedbackHandler, noticeHandler);
+        PsiphonProviderNetwork *networkInfoProvider = [[PsiphonProviderNetwork alloc] init];
+
+        GoPsiStartSendFeedback(psiphonConfig, feedbackJson, uploadPath,
+                               innerFeedbackHandler, networkInfoProvider, noticeHandler,
+                               UseIPv6Synthesizer, &err);
+        if (err != nil) {
+            NSError *outError = [NSError errorWithDomain:PsiphonTunnelErrorDomain
+                                                    code:PsiphonTunnelErrorCodeSendFeedbackError
+                                                userInfo:@{NSLocalizedDescriptionKey:@"Error sending feedback",
+                                                           NSUnderlyingErrorKey:err}];
+            dispatch_sync(self->callbackQueue, ^{
+                __strong id<PsiphonTunnelFeedbackDelegate> strongFeedbackDelegate = weakFeedbackDelegate;
+                if (strongFeedbackDelegate == nil) {
+                    return;
+                }
+                [strongFeedbackDelegate sendFeedbackCompleted:outError];
+            });
+        }
     });
 }
 

+ 34 - 6
MobileLibrary/psi/psi.go

@@ -44,14 +44,18 @@ type PsiphonProviderNoticeHandler interface {
 	Notice(noticeJSON string)
 }
 
+type PsiphonProviderNetwork interface {
+	HasNetworkConnectivity() int
+	GetNetworkID() string
+	IPv6Synthesize(IPv4Addr string) string
+}
+
 type PsiphonProvider interface {
 	PsiphonProviderNoticeHandler
-	HasNetworkConnectivity() int
+	PsiphonProviderNetwork
 	BindToDevice(fileDescriptor int) (string, error)
-	IPv6Synthesize(IPv4Addr string) string
 	GetPrimaryDnsServer() string
 	GetSecondaryDnsServer() string
-	GetNetworkID() string
 }
 
 type PsiphonProviderFeedbackHandler interface {
@@ -336,7 +340,9 @@ func StartSendFeedback(
 	diagnosticsJson,
 	uploadPath string,
 	feedbackHandler PsiphonProviderFeedbackHandler,
-	noticeHandler PsiphonProviderNoticeHandler) {
+	networkInfoProvider PsiphonProviderNetwork,
+	noticeHandler PsiphonProviderNoticeHandler,
+	useIPv6Synthesizer bool) error {
 
 	// Cancel any ongoing uploads.
 	StopSendFeedback()
@@ -355,14 +361,36 @@ func StartSendFeedback(
 			noticeHandler.Notice(string(notice))
 		}))
 
+	config, err := psiphon.LoadConfig([]byte(configJson))
+	if err != nil {
+		return fmt.Errorf("error loading configuration file: %s", err)
+	}
+
+	config.NetworkConnectivityChecker = networkInfoProvider
+
+	config.NetworkIDGetter = networkInfoProvider
+
+	if useIPv6Synthesizer {
+		config.IPv6Synthesizer = networkInfoProvider
+	}
+
+	// All config fields should be set before calling Commit.
+
+	err = config.Commit(true)
+	if err != nil {
+		return fmt.Errorf("error committing configuration file: %s", err)
+	}
+
 	sendFeedbackWaitGroup = new(sync.WaitGroup)
 	sendFeedbackWaitGroup.Add(1)
-
 	go func() {
 		defer sendFeedbackWaitGroup.Done()
-		err := psiphon.SendFeedback(sendFeedbackCtx, configJson, diagnosticsJson, uploadPath)
+		err := psiphon.SendFeedback(sendFeedbackCtx, config,
+			diagnosticsJson, uploadPath)
 		feedbackHandler.SendFeedbackCompleted(err)
 	}()
+
+	return nil
 }
 
 // StopSendFeedback interrupts an in-progress feedback upload operation

+ 1 - 10
psiphon/feedback.go

@@ -98,16 +98,7 @@ func encryptFeedback(diagnosticsJson, b64EncodedPublicKey string) ([]byte, error
 
 // Encrypt feedback and upload to server. If upload fails
 // the routine will sleep and retry multiple times.
-func SendFeedback(ctx context.Context, configJson, diagnosticsJson, uploadPath string) error {
-
-	config, err := LoadConfig([]byte(configJson))
-	if err != nil {
-		return errors.Trace(err)
-	}
-	err = config.Commit(true)
-	if err != nil {
-		return errors.Trace(err)
-	}
+func SendFeedback(ctx context.Context, config *Config, diagnosticsJson, uploadPath string) error {
 
 	// Get tactics, may update client parameters
 	p := config.GetClientParameters().Get()