ソースを参照

Merge pull request #573 from mirokuratczyk/master

 Fix: use network info callbacks in StartSendFeedback
Rod Hynes 5 年 前
コミット
8ff1c2b7bb
19 ファイル変更436 行追加96 行削除
  1. 34 12
      MobileLibrary/Android/PsiphonTunnel/PsiphonTunnel.java
  2. 46 6
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel.xcodeproj/project.pbxproj
  3. 32 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/IPv6Synthesizer.h
  4. 35 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/IPv6Synthesizer.m
  5. 0 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/LookupIPv6.c
  6. 0 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/LookupIPv6.h
  7. 36 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/NetworkID.h
  8. 52 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/NetworkID.m
  9. 32 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability+HasNetworkConnectivity.h
  10. 28 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability+HasNetworkConnectivity.m
  11. 0 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/README.md
  12. 0 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/Reachability.h
  13. 0 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Network/Reachability/Reachability.m
  14. 28 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.h
  15. 51 0
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/Psiphon/PsiphonProviderNetwork.m
  16. 0 5
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.h
  17. 27 57
      MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m
  18. 34 6
      MobileLibrary/psi/psi.go
  19. 1 10
      psiphon/feedback.go

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

@@ -73,6 +73,7 @@ import java.util.concurrent.TimeUnit;
 
 
 import psi.Psi;
 import psi.Psi;
 import psi.PsiphonProvider;
 import psi.PsiphonProvider;
+import psi.PsiphonProviderNetwork;
 import psi.PsiphonProviderNoticeHandler;
 import psi.PsiphonProviderNoticeHandler;
 import psi.PsiphonProviderFeedbackHandler;
 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() {
                                 new PsiphonProviderNoticeHandler() {
                                     @Override
                                     @Override
                                     public void notice(String noticeJSON) {
                                     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) {
                     } catch (java.lang.Exception e) {
                         callbackQueue.submit(new Runnable() {
                         callbackQueue.submit(new Runnable() {
                             @Override
                             @Override
@@ -618,22 +640,22 @@ public class PsiphonTunnel {
 
 
         @Override
         @Override
         public String getPrimaryDnsServer() {
         public String getPrimaryDnsServer() {
-            return mPsiphonTunnel.getPrimaryDnsServer();
+            return PsiphonTunnel.getPrimaryDnsServer(mHostService.getContext(), mHostService);
         }
         }
 
 
         @Override
         @Override
         public String getSecondaryDnsServer() {
         public String getSecondaryDnsServer() {
-            return mPsiphonTunnel.getSecondaryDnsServer();
+            return PsiphonTunnel.getSecondaryDnsServer();
         }
         }
 
 
         @Override
         @Override
         public String iPv6Synthesize(String IPv4Addr) {
         public String iPv6Synthesize(String IPv4Addr) {
-            return mPsiphonTunnel.iPv6Synthesize(IPv4Addr);
+            return PsiphonTunnel.iPv6Synthesize(IPv4Addr);
         }
         }
 
 
         @Override
         @Override
         public String getNetworkID() {
         public String getNetworkID() {
-            return mPsiphonTunnel.getNetworkID();
+            return PsiphonTunnel.getNetworkID(mHostService.getContext());
         }
         }
     }
     }
 
 
@@ -664,26 +686,27 @@ public class PsiphonTunnel {
         return hasConnectivity ? 1 : 0;
         return hasConnectivity ? 1 : 0;
     }
     }
 
 
-    private String getPrimaryDnsServer() {
+    private static String getPrimaryDnsServer(Context context, HostLogger logger) {
         String dnsResolver = null;
         String dnsResolver = null;
         try {
         try {
-            dnsResolver = getFirstActiveNetworkDnsResolver(mHostService.getContext());
+            dnsResolver = getFirstActiveNetworkDnsResolver(context);
         } catch (Exception e) {
         } 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;
             dnsResolver = DEFAULT_PRIMARY_DNS_SERVER;
         }
         }
         return dnsResolver;
         return dnsResolver;
     }
     }
 
 
-    private String getSecondaryDnsServer() {
+    private static String getSecondaryDnsServer() {
         return DEFAULT_SECONDARY_DNS_SERVER;
         return DEFAULT_SECONDARY_DNS_SERVER;
     }
     }
 
 
-    private String iPv6Synthesize(String IPv4Addr) {
+    private static String iPv6Synthesize(String IPv4Addr) {
+        // Unused on Android.
         return IPv4Addr;
         return IPv4Addr;
     }
     }
 
 
-    private String getNetworkID() {
+    private static String getNetworkID(Context context) {
 
 
         // The network ID contains potential PII. In tunnel-core, the network ID
         // 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.
         // is used only locally in the client and not sent to the server.
@@ -693,7 +716,6 @@ public class PsiphonTunnel {
 
 
         String networkID = "UNKNOWN";
         String networkID = "UNKNOWN";
 
 
-        Context context = mHostService.getContext();
         ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
         ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo activeNetworkInfo = null;
         NetworkInfo activeNetworkInfo = null;
         try {
         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 */; };
 		66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 66BDB0591DC26CCC0079384C /* SBJson4Writer.m */; };
 		CE3D1DA523906003009A4AF6 /* Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = CE3D1DA323906003009A4AF6 /* Backups.h */; };
 		CE3D1DA523906003009A4AF6 /* Backups.h in Headers */ = {isa = PBXBuildFile; fileRef = CE3D1DA323906003009A4AF6 /* Backups.h */; };
 		CE3D1DA623906003009A4AF6 /* Backups.m in Sources */ = {isa = PBXBuildFile; fileRef = CE3D1DA423906003009A4AF6 /* Backups.m */; };
 		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 */; };
 		CEC229FC24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h in Headers */ = {isa = PBXBuildFile; fileRef = CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */; };
 		CEC229FD24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m in Sources */ = {isa = PBXBuildFile; fileRef = CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */; };
 		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 */; };
 		CEDE547924EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h in Headers */ = {isa = PBXBuildFile; fileRef = CEDE547724EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h */; };
 		CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */; };
 		CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */; };
 		EFED7EBF1F587F6E0078980F /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EFED7EBE1F587F6E0078980F /* libresolv.tbd */; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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; };
 		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 */
 /* End PBXFrameworksBuildPhase section */
 
 
 /* Begin PBXGroup section */
 /* Begin PBXGroup section */
-		662659241DD270E900872F6C /* Reachability */ = {
+		662659241DD270E900872F6C /* Network */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				662659251DD270E900872F6C /* Reachability.h */,
-				662659261DD270E900872F6C /* Reachability.m */,
+				CECF01542538FC5900CD3E5C /* Reachability */,
 				4E89F7FC1E2ED3CE00005F4C /* LookupIPv6.c */,
 				4E89F7FC1E2ED3CE00005F4C /* LookupIPv6.c */,
 				4E89F7FD1E2ED3CE00005F4C /* LookupIPv6.h */,
 				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>";
 			sourceTree = "<group>";
 		};
 		};
 		6685BDC31E2E881200F0E414 /* Psi */ = {
 		6685BDC31E2E881200F0E414 /* Psi */ = {
@@ -198,7 +219,7 @@
 				66BAD3321E525FBC00CD06DE /* JailbreakCheck */,
 				66BAD3321E525FBC00CD06DE /* JailbreakCheck */,
 				66BDB04A1DC26CCC0079384C /* json-framework */,
 				66BDB04A1DC26CCC0079384C /* json-framework */,
 				CEDE547B24EBF5A00053566E /* Psiphon */,
 				CEDE547B24EBF5A00053566E /* Psiphon */,
-				662659241DD270E900872F6C /* Reachability */,
+				662659241DD270E900872F6C /* Network */,
 				CEC22A0624F0689000534D04 /* Utils */,
 				CEC22A0624F0689000534D04 /* Utils */,
 				66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */,
 				66BDB0231DA6BFCC0079384C /* PsiphonTunnel.h */,
 				66BDB0431DA6C7DD0079384C /* PsiphonTunnel.m */,
 				66BDB0431DA6C7DD0079384C /* PsiphonTunnel.m */,
@@ -256,6 +277,15 @@
 			path = Utils;
 			path = Utils;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		CECF01542538FC5900CD3E5C /* Reachability */ = {
+			isa = PBXGroup;
+			children = (
+				662659251DD270E900872F6C /* Reachability.h */,
+				662659261DD270E900872F6C /* Reachability.m */,
+			);
+			path = Reachability;
+			sourceTree = "<group>";
+		};
 		CEDE547B24EBF5A00053566E /* Psiphon */ = {
 		CEDE547B24EBF5A00053566E /* Psiphon */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -263,6 +293,8 @@
 				CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */,
 				CEDE547824EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m */,
 				CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */,
 				CEC229FA24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h */,
 				CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */,
 				CEC229FB24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m */,
+				CECF01472538DD0B00CD3E5C /* PsiphonProviderNetwork.h */,
+				CECF01482538DD0B00CD3E5C /* PsiphonProviderNetwork.m */,
 			);
 			);
 			path = Psiphon;
 			path = Psiphon;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -286,14 +318,17 @@
 				6685BDCB1E2E882800F0E414 /* ref.h in Headers */,
 				6685BDCB1E2E882800F0E414 /* ref.h in Headers */,
 				66BAD3351E525FBC00CD06DE /* JailbreakCheck.h in Headers */,
 				66BAD3351E525FBC00CD06DE /* JailbreakCheck.h in Headers */,
 				4E89F7FF1E2ED3CE00005F4C /* LookupIPv6.h in Headers */,
 				4E89F7FF1E2ED3CE00005F4C /* LookupIPv6.h in Headers */,
+				CE4616BF2539493600D1243E /* Reachability+HasNetworkConnectivity.h in Headers */,
 				662659271DD270E900872F6C /* Reachability.h in Headers */,
 				662659271DD270E900872F6C /* Reachability.h in Headers */,
 				66BDB05D1DC26CCC0079384C /* SBJson4StreamParser.h in Headers */,
 				66BDB05D1DC26CCC0079384C /* SBJson4StreamParser.h in Headers */,
 				6685BDD41E2EBB1000F0E414 /* GoPsi.objc.h in Headers */,
 				6685BDD41E2EBB1000F0E414 /* GoPsi.objc.h in Headers */,
 				6685BDD51E2EBB1000F0E414 /* Universe.objc.h in Headers */,
 				6685BDD51E2EBB1000F0E414 /* Universe.objc.h in Headers */,
+				CECF01492538DD0B00CD3E5C /* PsiphonProviderNetwork.h in Headers */,
 				66BDB05F1DC26CCC0079384C /* SBJson4StreamParserState.h in Headers */,
 				66BDB05F1DC26CCC0079384C /* SBJson4StreamParserState.h in Headers */,
 				66BDB0311DA6BFCC0079384C /* PsiphonTunnel.h in Headers */,
 				66BDB0311DA6BFCC0079384C /* PsiphonTunnel.h in Headers */,
 				6685BDCA1E2E882800F0E414 /* Psi.h in Headers */,
 				6685BDCA1E2E882800F0E414 /* Psi.h in Headers */,
 				66BDB0651DC26CCC0079384C /* SBJson4StreamWriterState.h in Headers */,
 				66BDB0651DC26CCC0079384C /* SBJson4StreamWriterState.h in Headers */,
+				CECF01502538E14B00CD3E5C /* NetworkID.h in Headers */,
 				66BDB05B1DC26CCC0079384C /* SBJson4Parser.h in Headers */,
 				66BDB05B1DC26CCC0079384C /* SBJson4Parser.h in Headers */,
 				CEDE547924EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h in Headers */,
 				CEDE547924EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.h in Headers */,
 				6685BDCD1E2E88A200F0E414 /* Psi-meta.h in Headers */,
 				6685BDCD1E2E88A200F0E414 /* Psi-meta.h in Headers */,
@@ -301,6 +336,7 @@
 				66BDB0611DC26CCC0079384C /* SBJson4StreamTokeniser.h in Headers */,
 				66BDB0611DC26CCC0079384C /* SBJson4StreamTokeniser.h in Headers */,
 				CEC229FC24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h in Headers */,
 				CEC229FC24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.h in Headers */,
 				66BDB0631DC26CCC0079384C /* SBJson4StreamWriter.h in Headers */,
 				66BDB0631DC26CCC0079384C /* SBJson4StreamWriter.h in Headers */,
+				CECF01442538D34100CD3E5C /* IPv6Synthesizer.h in Headers */,
 				66BDB0671DC26CCC0079384C /* SBJson4Writer.h in Headers */,
 				66BDB0671DC26CCC0079384C /* SBJson4Writer.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
@@ -430,13 +466,17 @@
 				66BDB0641DC26CCC0079384C /* SBJson4StreamWriter.m in Sources */,
 				66BDB0641DC26CCC0079384C /* SBJson4StreamWriter.m in Sources */,
 				CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */,
 				CEDE547A24EBF5980053566E /* PsiphonProviderFeedbackHandlerShim.m in Sources */,
 				66BDB0661DC26CCC0079384C /* SBJson4StreamWriterState.m in Sources */,
 				66BDB0661DC26CCC0079384C /* SBJson4StreamWriterState.m in Sources */,
+				CECF01452538D34100CD3E5C /* IPv6Synthesizer.m in Sources */,
 				66BDB05C1DC26CCC0079384C /* SBJson4Parser.m in Sources */,
 				66BDB05C1DC26CCC0079384C /* SBJson4Parser.m in Sources */,
 				4E89F7FE1E2ED3CE00005F4C /* LookupIPv6.c in Sources */,
 				4E89F7FE1E2ED3CE00005F4C /* LookupIPv6.c in Sources */,
+				CECF01512538E14B00CD3E5C /* NetworkID.m in Sources */,
 				66BAD3361E525FBC00CD06DE /* JailbreakCheck.m in Sources */,
 				66BAD3361E525FBC00CD06DE /* JailbreakCheck.m in Sources */,
 				66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */,
 				66BDB0681DC26CCC0079384C /* SBJson4Writer.m in Sources */,
 				66BDB0621DC26CCC0079384C /* SBJson4StreamTokeniser.m in Sources */,
 				66BDB0621DC26CCC0079384C /* SBJson4StreamTokeniser.m in Sources */,
 				66BDB0441DA6C7DD0079384C /* PsiphonTunnel.m in Sources */,
 				66BDB0441DA6C7DD0079384C /* PsiphonTunnel.m in Sources */,
 				CEC229FD24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m in Sources */,
 				CEC229FD24F047E700534D04 /* PsiphonProviderNoticeHandlerShim.m in Sources */,
+				CE4616C02539493600D1243E /* Reachability+HasNetworkConnectivity.m in Sources */,
+				CECF014A2538DD0B00CD3E5C /* PsiphonProviderNetwork.m in Sources */,
 				662659281DD270E900872F6C /* Reachability.m in Sources */,
 				662659281DD270E900872F6C /* Reachability.m in Sources */,
 				66BDB0601DC26CCC0079384C /* SBJson4StreamParserState.m in Sources */,
 				66BDB0601DC26CCC0079384C /* SBJson4StreamParserState.m in Sources */,
 				CE3D1DA623906003009A4AF6 /* Backups.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

+ 0 - 5
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.h

@@ -366,11 +366,6 @@ Returns the path where the rotated notices file will be created.
  */
  */
 - (void)stop;
 - (void)stop;
 
 
-/*!
- Indicate if the device is sleeping. This logs a diagnostic message and forces hasNetworkConnectivity to false when sleeping.
- */
-- (void)setSleeping:(BOOL)isSleeping;
-
 /*!
 /*!
  Returns the current tunnel connection state.
  Returns the current tunnel connection state.
  @return  The current connection state.
  @return  The current connection state.

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

@@ -22,15 +22,17 @@
 #import <stdatomic.h>
 #import <stdatomic.h>
 #import <CoreTelephony/CTTelephonyNetworkInfo.h>
 #import <CoreTelephony/CTTelephonyNetworkInfo.h>
 #import <CoreTelephony/CTCarrier.h>
 #import <CoreTelephony/CTCarrier.h>
-#import <SystemConfiguration/CaptiveNetwork.h>
-#import "LookupIPv6.h"
+#import "IPv6Synthesizer.h"
 #import "Psi-meta.h"
 #import "Psi-meta.h"
 #import "PsiphonProviderFeedbackHandlerShim.h"
 #import "PsiphonProviderFeedbackHandlerShim.h"
 #import "PsiphonProviderNoticeHandlerShim.h"
 #import "PsiphonProviderNoticeHandlerShim.h"
+#import "PsiphonProviderNetwork.h"
 #import "PsiphonTunnel.h"
 #import "PsiphonTunnel.h"
+#import "Reachability+HasNetworkConnectivity.h"
 #import "Backups.h"
 #import "Backups.h"
 #import "json-framework/SBJson4.h"
 #import "json-framework/SBJson4.h"
 #import "JailbreakCheck/JailbreakCheck.h"
 #import "JailbreakCheck/JailbreakCheck.h"
+#import "NetworkID.h"
 #import <ifaddrs.h>
 #import <ifaddrs.h>
 #import <resolv.h>
 #import <resolv.h>
 #import <netdb.h>
 #import <netdb.h>
@@ -40,6 +42,8 @@
 
 
 NSErrorDomain _Nonnull const PsiphonTunnelErrorDomain = @"com.psiphon3.ios.PsiphonTunnelErrorDomain";
 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
 /// Error codes which can returned by PsiphonTunnel
 typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 
 
@@ -106,8 +110,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
     _Atomic NSInteger localSocksProxyPort;
     _Atomic NSInteger localSocksProxyPort;
     _Atomic NSInteger localHttpProxyPort;
     _Atomic NSInteger localHttpProxyPort;
 
 
-    _Atomic BOOL isSleeping;
-
     Reachability* reachability;
     Reachability* reachability;
     _Atomic NetworkStatus currentNetworkStatus;
     _Atomic NetworkStatus currentNetworkStatus;
 
 
@@ -135,7 +137,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
     atomic_init(&self->connectionState, PsiphonConnectionStateDisconnected);
     atomic_init(&self->connectionState, PsiphonConnectionStateDisconnected);
     atomic_init(&self->localSocksProxyPort, 0);
     atomic_init(&self->localSocksProxyPort, 0);
     atomic_init(&self->localHttpProxyPort, 0);
     atomic_init(&self->localHttpProxyPort, 0);
-    atomic_init(&self->isSleeping, FALSE);
     self->reachability = [Reachability reachabilityForInternetConnection];
     self->reachability = [Reachability reachabilityForInternetConnection];
     atomic_init(&self->currentNetworkStatus, NotReachable);
     atomic_init(&self->currentNetworkStatus, NotReachable);
     self->tunnelWholeDevice = FALSE;
     self->tunnelWholeDevice = FALSE;
@@ -254,12 +255,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
     return [self start];
     return [self start];
 }
 }
 
 
-// See comment in header
-- (void)setSleeping:(BOOL)isSleeping {
-    [self logMessage: isSleeping ? @"Sleeping" : @"Waking"];
-    atomic_store(&self->isSleeping, isSleeping);
-}
-
 /*!
 /*!
  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
  Assumes self.sessionID has been initialized -- i.e., assumes that
@@ -272,9 +267,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 
 
         [self logMessage:@"Starting Psiphon library"];
         [self logMessage:@"Starting Psiphon library"];
 
 
-        // Must always use IPv6Synthesizer for iOS
-        const BOOL useIPv6Synthesizer = TRUE;
-
         BOOL usingNoticeFiles = FALSE;
         BOOL usingNoticeFiles = FALSE;
 
 
         NSError *err;
         NSError *err;
@@ -329,7 +321,7 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
                 embeddedServerEntriesPath,
                 embeddedServerEntriesPath,
                 self,
                 self,
                 self->tunnelWholeDevice, // useDeviceBinder
                 self->tunnelWholeDevice, // useDeviceBinder
-                useIPv6Synthesizer,
+                UseIPv6Synthesizer,
                 &e);
                 &e);
             
             
             if (e != nil) {
             if (e != nil) {
@@ -1323,10 +1315,6 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 
 
 - (long)hasNetworkConnectivity {
 - (long)hasNetworkConnectivity {
 
 
-    if (atomic_load(&self->isSleeping)) {
-        return FALSE;
-    }
-
     BOOL hasConnectivity = [self->reachability currentReachabilityStatus] != NotReachable;
     BOOL hasConnectivity = [self->reachability currentReachabilityStatus] != NotReachable;
 
 
     if (!hasConnectivity) {
     if (!hasConnectivity) {
@@ -1339,46 +1327,11 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
 }
 }
 
 
 - (NSString *)iPv6Synthesize:(NSString *)IPv4Addr {
 - (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 {
 - (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 {
 - (void)notice:(NSString *)noticeJSON {
@@ -1806,7 +1759,24 @@ typedef NS_ERROR_ENUM(PsiphonTunnelErrorDomain, PsiphonTunnelErrorCode) {
         PsiphonProviderNoticeHandlerShim *noticeHandler =
         PsiphonProviderNoticeHandlerShim *noticeHandler =
             [[PsiphonProviderNoticeHandlerShim alloc] initWithLogger:logNotice];
             [[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)
 	Notice(noticeJSON string)
 }
 }
 
 
+type PsiphonProviderNetwork interface {
+	HasNetworkConnectivity() int
+	GetNetworkID() string
+	IPv6Synthesize(IPv4Addr string) string
+}
+
 type PsiphonProvider interface {
 type PsiphonProvider interface {
 	PsiphonProviderNoticeHandler
 	PsiphonProviderNoticeHandler
-	HasNetworkConnectivity() int
+	PsiphonProviderNetwork
 	BindToDevice(fileDescriptor int) (string, error)
 	BindToDevice(fileDescriptor int) (string, error)
-	IPv6Synthesize(IPv4Addr string) string
 	GetPrimaryDnsServer() string
 	GetPrimaryDnsServer() string
 	GetSecondaryDnsServer() string
 	GetSecondaryDnsServer() string
-	GetNetworkID() string
 }
 }
 
 
 type PsiphonProviderFeedbackHandler interface {
 type PsiphonProviderFeedbackHandler interface {
@@ -336,7 +340,9 @@ func StartSendFeedback(
 	diagnosticsJson,
 	diagnosticsJson,
 	uploadPath string,
 	uploadPath string,
 	feedbackHandler PsiphonProviderFeedbackHandler,
 	feedbackHandler PsiphonProviderFeedbackHandler,
-	noticeHandler PsiphonProviderNoticeHandler) {
+	networkInfoProvider PsiphonProviderNetwork,
+	noticeHandler PsiphonProviderNoticeHandler,
+	useIPv6Synthesizer bool) error {
 
 
 	// Cancel any ongoing uploads.
 	// Cancel any ongoing uploads.
 	StopSendFeedback()
 	StopSendFeedback()
@@ -355,14 +361,36 @@ func StartSendFeedback(
 			noticeHandler.Notice(string(notice))
 			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 = new(sync.WaitGroup)
 	sendFeedbackWaitGroup.Add(1)
 	sendFeedbackWaitGroup.Add(1)
-
 	go func() {
 	go func() {
 		defer sendFeedbackWaitGroup.Done()
 		defer sendFeedbackWaitGroup.Done()
-		err := psiphon.SendFeedback(sendFeedbackCtx, configJson, diagnosticsJson, uploadPath)
+		err := psiphon.SendFeedback(sendFeedbackCtx, config,
+			diagnosticsJson, uploadPath)
 		feedbackHandler.SendFeedbackCompleted(err)
 		feedbackHandler.SendFeedbackCompleted(err)
 	}()
 	}()
+
+	return nil
 }
 }
 
 
 // StopSendFeedback interrupts an in-progress feedback upload operation
 // 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
 // Encrypt feedback and upload to server. If upload fails
 // the routine will sleep and retry multiple times.
 // 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
 	// Get tactics, may update client parameters
 	p := config.GetClientParameters().Get()
 	p := config.GetClientParameters().Get()