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

Merge pull request #74 from rod-hynes/master

Get current DNS server at time of domain lookup
Rod Hynes 11 лет назад
Родитель
Сommit
b84fdfe571

+ 26 - 25
AndroidApp/app/src/main/java/ca/psiphon/PsiphonVpn.java

@@ -136,6 +136,7 @@ public class PsiphonVpn extends Psi.PsiphonProvider.Stub {
     private final static String VPN_INTERFACE_NETMASK = "255.255.255.0";
     private final static int VPN_INTERFACE_MTU = 1500;
     private final static int UDPGW_SERVER_PORT = 7300;
+    private final static String DEFAULT_DNS_SERVER = "8.8.4.4";
 
     private boolean startVpn() throws Exception {
 
@@ -237,6 +238,18 @@ public class PsiphonVpn extends Psi.PsiphonProvider.Stub {
         return hasNetworkConnectivity(mHostService.getVpnService()) ? 1 : 0;
     }
 
+    @Override
+    public String GetDnsServer() {
+        String dnsResolver = null;
+        try {
+            dnsResolver = getFirstActiveNetworkDnsResolver(mHostService.getVpnService());
+        } catch (Exception e) {
+            mHostService.logWarning("failed to get active network DNS resolver: " + e.getMessage());
+            dnsResolver = DEFAULT_DNS_SERVER;
+        }
+        return dnsResolver;
+    }
+
     //----------------------------------------------------------------------------------------------
     // Psiphon Tunnel Core
     //----------------------------------------------------------------------------------------------
@@ -264,26 +277,12 @@ public class PsiphonVpn extends Psi.PsiphonProvider.Stub {
     private String loadPsiphonConfig(Context context)
             throws IOException, JSONException {
 
-        // If we can obtain a DNS resolver for the active network,
-        // prefer that for DNS resolution in BindToDevice mode.
-        String dnsResolver = null;
-        try {
-            dnsResolver = getFirstActiveNetworkDnsResolver(context);
-        } catch (Exception e) {
-            mHostService.logWarning("failed to get active network DNS resolver: " + e.getMessage());
-            // Proceed with default value in config file
-        }
-
         // Load settings from the raw resource JSON config file and
         // update as necessary. Then write JSON to disk for the Go client.
         JSONObject json = new JSONObject(
                 readInputStreamToString(
                     mHostService.getPsiphonConfigResource()));
 
-        if (dnsResolver != null) {
-            json.put("BindToDeviceDnsServer", dnsResolver);
-        }
-
         // On Android, these directories must be set to the app private storage area.
         // The Psiphon library won't be able to use its current working directory
         // and the standard temporary directories do not exist.
@@ -419,7 +418,7 @@ public class PsiphonVpn extends Psi.PsiphonProvider.Stub {
         // which private address range isn't in use.
 
         Map<String, PrivateAddress> candidates = new HashMap<String, PrivateAddress>();
-        candidates.put("10", new PrivateAddress("10.0.0.1",    "10.0.0.0",     8, "10.0.0.2"));
+        candidates.put( "10", new PrivateAddress("10.0.0.1",    "10.0.0.0",     8, "10.0.0.2"));
         candidates.put("172", new PrivateAddress("172.16.0.1",  "172.16.0.0",  12, "172.16.0.2"));
         candidates.put("192", new PrivateAddress("192.168.0.1", "192.168.0.0", 16, "192.168.0.2"));
         candidates.put("169", new PrivateAddress("169.254.1.1", "169.254.1.0", 24, "169.254.1.2"));
@@ -486,16 +485,18 @@ public class PsiphonVpn extends Psi.PsiphonProvider.Stub {
             Class<?> LinkPropertiesClass = Class.forName("android.net.LinkProperties");
             Method getActiveLinkPropertiesMethod = ConnectivityManager.class.getMethod("getActiveLinkProperties", new Class []{});
             Object linkProperties = getActiveLinkPropertiesMethod.invoke(connectivityManager);
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-                Method getDnsesMethod = LinkPropertiesClass.getMethod("getDnses", new Class []{});
-                Collection<?> dnses = (Collection<?>)getDnsesMethod.invoke(linkProperties);
-                for (Object dns : dnses) {
-                    dnsAddresses.add((InetAddress)dns);
-                }
-            } else {
-                // LinkProperties is public in API 21 (and the DNS function signature has changed)
-                for (InetAddress dns : ((LinkProperties)linkProperties).getDnsServers()) {
-                    dnsAddresses.add(dns);
+            if (linkProperties != null) {
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                    Method getDnsesMethod = LinkPropertiesClass.getMethod("getDnses", new Class []{});
+                    Collection<?> dnses = (Collection<?>)getDnsesMethod.invoke(linkProperties);
+                    for (Object dns : dnses) {
+                        dnsAddresses.add((InetAddress)dns);
+                    }
+                } else {
+                    // LinkProperties is public in API 21 (and the DNS function signature has changed)
+                    for (InetAddress dns : ((LinkProperties)linkProperties).getDnsServers()) {
+                        dnsAddresses.add(dns);
+                    }
                 }
             }
         } catch (ClassNotFoundException e) {

+ 3 - 1
AndroidApp/app/src/main/java/ca/psiphon/psibot/Service.java

@@ -43,7 +43,9 @@ public class Service extends VpnService
         mPsiphonVpn = PsiphonVpn.newPsiphonVpn(this);
         startForeground(R.string.foregroundServiceNotificationId, makeForegroundNotification());
         try {
-            mPsiphonVpn.startRouting();
+            if (!mPsiphonVpn.startRouting()) {
+                throw new PsiphonVpn.Exception("VPN not prepared");
+            }
             mPsiphonVpn.startTunneling();
         } catch (PsiphonVpn.Exception e) {
             Log.addEntry("failed to start Psiphon VPN: " + e.getMessage());

+ 20 - 2
AndroidApp/app/src/main/java/go/psi/Psi.java

@@ -12,6 +12,8 @@ public abstract class Psi {
     public interface PsiphonProvider extends go.Seq.Object {
         public void BindToDevice(long fileDescriptor) throws Exception;
         
+        public String GetDnsServer();
+        
         public long HasNetworkConnectivity();
         
         public void Notice(String noticeJSON);
@@ -38,6 +40,11 @@ public abstract class Psi {
                     }
                     return;
                 }
+                case Proxy.CALL_GetDnsServer: {
+                    String result = this.GetDnsServer();
+                    out.writeUTF16(result);
+                    return;
+                }
                 case Proxy.CALL_HasNetworkConnectivity: {
                     long result = this.HasNetworkConnectivity();
                     out.writeInt(result);
@@ -79,6 +86,16 @@ public abstract class Psi {
                 }
             }
             
+            public String GetDnsServer() {
+                go.Seq _in = new go.Seq();
+                go.Seq _out = new go.Seq();
+                String _result;
+                _in.writeRef(ref);
+                Seq.send(DESCRIPTOR, CALL_GetDnsServer, _in, _out);
+                _result = _out.readUTF16();
+                return _result;
+            }
+            
             public long HasNetworkConnectivity() {
                 go.Seq _in = new go.Seq();
                 go.Seq _out = new go.Seq();
@@ -98,8 +115,9 @@ public abstract class Psi {
             }
             
             static final int CALL_BindToDevice = 0x10a;
-            static final int CALL_HasNetworkConnectivity = 0x20a;
-            static final int CALL_Notice = 0x30a;
+            static final int CALL_GetDnsServer = 0x20a;
+            static final int CALL_HasNetworkConnectivity = 0x30a;
+            static final int CALL_Notice = 0x40a;
         }
     }
     

+ 1 - 2
AndroidApp/app/src/main/res/raw/psiphon_config_stub

@@ -13,6 +13,5 @@
     "ConnectionWorkerPoolSize" : 10,
     "TunnelPoolSize" : 1,
     "PortForwardFailureThreshold" : 10,
-    "UpstreamHttpProxyAddress" : "",
-    "BindToDeviceDnsServer" : "8.8.4.4"
+    "UpstreamHttpProxyAddress" : ""
 }

+ 18 - 2
AndroidLibrary/go_psi/go_psi.go

@@ -12,8 +12,9 @@ import (
 const (
 	proxyPsiphonProviderDescriptor                 = "go.psi.PsiphonProvider"
 	proxyPsiphonProviderBindToDeviceCode           = 0x10a
-	proxyPsiphonProviderHasNetworkConnectivityCode = 0x20a
-	proxyPsiphonProviderNoticeCode                 = 0x30a
+	proxyPsiphonProviderGetDnsServerCode           = 0x20a
+	proxyPsiphonProviderHasNetworkConnectivityCode = 0x30a
+	proxyPsiphonProviderNoticeCode                 = 0x40a
 )
 
 func proxyPsiphonProviderBindToDevice(out, in *seq.Buffer) {
@@ -28,6 +29,13 @@ func proxyPsiphonProviderBindToDevice(out, in *seq.Buffer) {
 	}
 }
 
+func proxyPsiphonProviderGetDnsServer(out, in *seq.Buffer) {
+	ref := in.ReadRef()
+	v := ref.Get().(psi.PsiphonProvider)
+	res := v.GetDnsServer()
+	out.WriteUTF16(res)
+}
+
 func proxyPsiphonProviderHasNetworkConnectivity(out, in *seq.Buffer) {
 	ref := in.ReadRef()
 	v := ref.Get().(psi.PsiphonProvider)
@@ -44,6 +52,7 @@ func proxyPsiphonProviderNotice(out, in *seq.Buffer) {
 
 func init() {
 	seq.Register(proxyPsiphonProviderDescriptor, proxyPsiphonProviderBindToDeviceCode, proxyPsiphonProviderBindToDevice)
+	seq.Register(proxyPsiphonProviderDescriptor, proxyPsiphonProviderGetDnsServerCode, proxyPsiphonProviderGetDnsServer)
 	seq.Register(proxyPsiphonProviderDescriptor, proxyPsiphonProviderHasNetworkConnectivityCode, proxyPsiphonProviderHasNetworkConnectivity)
 	seq.Register(proxyPsiphonProviderDescriptor, proxyPsiphonProviderNoticeCode, proxyPsiphonProviderNotice)
 }
@@ -58,6 +67,13 @@ func (p *proxyPsiphonProvider) BindToDevice(fileDescriptor int) error {
 	return res_0
 }
 
+func (p *proxyPsiphonProvider) GetDnsServer() string {
+	in := new(seq.Buffer)
+	out := seq.Transact((*seq.Ref)(p), proxyPsiphonProviderGetDnsServerCode, in)
+	res_0 := out.ReadUTF16()
+	return res_0
+}
+
 func (p *proxyPsiphonProvider) HasNetworkConnectivity() int {
 	in := new(seq.Buffer)
 	out := seq.Transact((*seq.Ref)(p), proxyPsiphonProviderHasNetworkConnectivityCode, in)

+ 20 - 2
AndroidLibrary/java_psi/go/psi/Psi.java

@@ -12,6 +12,8 @@ public abstract class Psi {
     public interface PsiphonProvider extends go.Seq.Object {
         public void BindToDevice(long fileDescriptor) throws Exception;
         
+        public String GetDnsServer();
+        
         public long HasNetworkConnectivity();
         
         public void Notice(String noticeJSON);
@@ -38,6 +40,11 @@ public abstract class Psi {
                     }
                     return;
                 }
+                case Proxy.CALL_GetDnsServer: {
+                    String result = this.GetDnsServer();
+                    out.writeUTF16(result);
+                    return;
+                }
                 case Proxy.CALL_HasNetworkConnectivity: {
                     long result = this.HasNetworkConnectivity();
                     out.writeInt(result);
@@ -79,6 +86,16 @@ public abstract class Psi {
                 }
             }
             
+            public String GetDnsServer() {
+                go.Seq _in = new go.Seq();
+                go.Seq _out = new go.Seq();
+                String _result;
+                _in.writeRef(ref);
+                Seq.send(DESCRIPTOR, CALL_GetDnsServer, _in, _out);
+                _result = _out.readUTF16();
+                return _result;
+            }
+            
             public long HasNetworkConnectivity() {
                 go.Seq _in = new go.Seq();
                 go.Seq _out = new go.Seq();
@@ -98,8 +115,9 @@ public abstract class Psi {
             }
             
             static final int CALL_BindToDevice = 0x10a;
-            static final int CALL_HasNetworkConnectivity = 0x20a;
-            static final int CALL_Notice = 0x30a;
+            static final int CALL_GetDnsServer = 0x20a;
+            static final int CALL_HasNetworkConnectivity = 0x30a;
+            static final int CALL_Notice = 0x40a;
         }
     }
     

+ 4 - 2
AndroidLibrary/psi/psi.go

@@ -36,6 +36,7 @@ type PsiphonProvider interface {
 	Notice(noticeJSON string)
 	HasNetworkConnectivity() int
 	BindToDevice(fileDescriptor int) error
+	GetDnsServer() string
 }
 
 var controller *psiphon.Controller
@@ -52,8 +53,9 @@ func Start(configJson, embeddedServerEntryList string, provider PsiphonProvider)
 	if err != nil {
 		return fmt.Errorf("error loading configuration file: %s", err)
 	}
-	config.CheckNetworkConnectivityProvider = provider
-	config.BindToDeviceProvider = provider
+	config.NetworkConnectivityChecker = provider
+	config.DeviceBinder = provider
+	config.DnsServerGetter = provider
 
 	err = psiphon.InitDataStore(config)
 	if err != nil {

+ 4 - 4
psiphon/LookupIP.go

@@ -39,7 +39,7 @@ const DNS_PORT = 53
 // socket, binds it to the device, and makes an explicit DNS request
 // to the specified DNS resolver.
 func LookupIP(host string, config *DialConfig) (addrs []net.IP, err error) {
-	if config.BindToDeviceProvider != nil {
+	if config.DeviceBinder != nil {
 		return bindLookupIP(host, config)
 	}
 	return net.LookupIP(host)
@@ -63,13 +63,13 @@ func bindLookupIP(host string, config *DialConfig) (addrs []net.IP, err error) {
 	}
 	defer syscall.Close(socketFd)
 
-	err = config.BindToDeviceProvider.BindToDevice(socketFd)
+	err = config.DeviceBinder.BindToDevice(socketFd)
 	if err != nil {
 		return nil, ContextError(fmt.Errorf("BindToDevice failed: %s", err))
 	}
 
-	// config.BindToDeviceDnsServer must be an IP address
-	ipAddr = net.ParseIP(config.BindToDeviceDnsServer)
+	// config.DnsServerGetter.GetDnsServer must return an IP address
+	ipAddr = net.ParseIP(config.DnsServerGetter.GetDnsServer())
 	if ipAddr == nil {
 		return nil, ContextError(errors.New("invalid IP address"))
 	}

+ 2 - 2
psiphon/LookupIP_nobind.go

@@ -29,8 +29,8 @@ import (
 // LookupIP resolves a hostname. When BindToDevice is not required, it
 // simply uses net.LookuIP.
 func LookupIP(host string, config *DialConfig) (addrs []net.IP, err error) {
-	if config.BindToDeviceProvider != nil {
-		return nil, ContextError(errors.New("LookupIP with bind not supported on this platform"))
+	if config.DeviceBinder != nil {
+		return nil, ContextError(errors.New("LookupIP with DeviceBinder not supported on this platform"))
 	}
 	return net.LookupIP(host)
 }

+ 2 - 2
psiphon/TCPConn_unix.go

@@ -61,8 +61,8 @@ func interruptibleTCPDial(addr string, config *DialConfig) (conn *TCPConn, err e
 		}
 	}()
 
-	if config.BindToDeviceProvider != nil {
-		err = config.BindToDeviceProvider.BindToDevice(socketFd)
+	if config.DeviceBinder != nil {
+		err = config.DeviceBinder.BindToDevice(socketFd)
 		if err != nil {
 			return nil, ContextError(fmt.Errorf("BindToDevice failed: %s", err))
 		}

+ 2 - 2
psiphon/TCPConn_windows.go

@@ -46,8 +46,8 @@ type interruptibleDialResult struct {
 // to config.PendingConns before blocking on network IO, which enables interruption.
 // The caller is responsible for removing an established conn from PendingConns.
 func interruptibleTCPDial(addr string, config *DialConfig) (conn *TCPConn, err error) {
-	if config.BindToDeviceProvider != nil {
-		return nil, ContextError(errors.New("psiphon.interruptibleTCPDial with bind not supported on Windows"))
+	if config.DeviceBinder != nil {
+		return nil, ContextError(errors.New("psiphon.interruptibleTCPDial with DeviceBinder not supported on Windows"))
 	}
 
 	// Enable interruption

+ 11 - 7
psiphon/config.go

@@ -81,9 +81,9 @@ type Config struct {
 	TunnelPoolSize                     int
 	PortForwardFailureThreshold        int
 	UpstreamHttpProxyAddress           string
-	CheckNetworkConnectivityProvider   NetworkConnectivityChecker
-	BindToDeviceProvider               DeviceBinder
-	BindToDeviceDnsServer              string
+	NetworkConnectivityChecker         NetworkConnectivityChecker
+	DeviceBinder                       DeviceBinder
+	DnsServerGetter                    DnsServerGetter
 	TargetServerEntry                  string
 	DisableApi                         bool
 	DisableRemoteServerListFetcher     bool
@@ -151,12 +151,16 @@ func LoadConfig(configJson []byte) (*Config, error) {
 		config.PortForwardFailureThreshold = PORT_FORWARD_FAILURE_THRESHOLD
 	}
 
-	if config.CheckNetworkConnectivityProvider != nil {
-		return nil, ContextError(errors.New("CheckNetworkConnectivityProvider interface must be set at runtime"))
+	if config.NetworkConnectivityChecker != nil {
+		return nil, ContextError(errors.New("NetworkConnectivityChecker interface must be set at runtime"))
 	}
 
-	if config.BindToDeviceProvider != nil {
-		return nil, ContextError(errors.New("BindToDeviceProvider interface must be set at runtime"))
+	if config.DeviceBinder != nil {
+		return nil, ContextError(errors.New("DeviceBinder interface must be set at runtime"))
+	}
+
+	if config.DnsServerGetter != nil {
+		return nil, ContextError(errors.New("DnsServerGetter interface must be set at runtime"))
 	}
 
 	return &config, nil

+ 10 - 5
psiphon/conn.go

@@ -52,14 +52,14 @@ type DialConfig struct {
 
 	// BindToDevice parameters are used to exclude connections and
 	// associated DNS requests from VPN routing.
-	// When BindToDeviceProvider is set, any underlying socket is
+	// When DeviceBinder is set, any underlying socket is
 	// submitted to the device binding servicebefore connecting.
 	// The service should bind the socket to a device so that it doesn't route
 	// through a VPN interface. This service is also used to bind UDP sockets used
-	// for DNS requests, in which case BindToDeviceDnsServer is used as the
-	// DNS server.
-	BindToDeviceProvider  DeviceBinder
-	BindToDeviceDnsServer string
+	// for DNS requests, in which case DnsServerGetter is used to get the
+	// current active untunneled network DNS server.
+	DeviceBinder    DeviceBinder
+	DnsServerGetter DnsServerGetter
 }
 
 // DeviceBinder defines the interface to the external BindToDevice provider
@@ -74,6 +74,11 @@ type NetworkConnectivityChecker interface {
 	HasNetworkConnectivity() int
 }
 
+// DnsServerGetter defines the interface to the external GetDnsServer provider
+type DnsServerGetter interface {
+	GetDnsServer() string
+}
+
 // WaitForNetworkConnectivity uses a NetworkConnectivityChecker to
 // periodically check for network connectivity. It returns true if
 // no NetworkConnectivityChecker is provided (waiting is disabled)

+ 2 - 2
psiphon/controller.go

@@ -166,7 +166,7 @@ func (controller *Controller) remoteServerListFetcher() {
 loop:
 	for {
 		if !WaitForNetworkConnectivity(
-			controller.config.CheckNetworkConnectivityProvider,
+			controller.config.NetworkConnectivityChecker,
 			controller.shutdownBroadcast) {
 			break
 		}
@@ -615,7 +615,7 @@ loop:
 		}
 
 		if !WaitForNetworkConnectivity(
-			controller.config.CheckNetworkConnectivityProvider,
+			controller.config.NetworkConnectivityChecker,
 			controller.stopEstablishingBroadcast) {
 			break loop
 		}

+ 2 - 2
psiphon/remoteServerList.go

@@ -52,8 +52,8 @@ func FetchRemoteServerList(config *Config, pendingConns *Conns) (err error) {
 	dialConfig := &DialConfig{
 		UpstreamHttpProxyAddress: config.UpstreamHttpProxyAddress,
 		PendingConns:             pendingConns,
-		BindToDeviceProvider:     config.BindToDeviceProvider,
-		BindToDeviceDnsServer:    config.BindToDeviceDnsServer,
+		DeviceBinder:             config.DeviceBinder,
+		DnsServerGetter:          config.DnsServerGetter,
 	}
 	transport := &http.Transport{
 		Dial: NewTCPDialer(dialConfig),

+ 2 - 2
psiphon/tunnel.go

@@ -351,8 +351,8 @@ func dialSsh(
 		ReadTimeout:              TUNNEL_READ_TIMEOUT,
 		WriteTimeout:             TUNNEL_WRITE_TIMEOUT,
 		PendingConns:             pendingConns,
-		BindToDeviceProvider:     config.BindToDeviceProvider,
-		BindToDeviceDnsServer:    config.BindToDeviceDnsServer,
+		DeviceBinder:             config.DeviceBinder,
+		DnsServerGetter:          config.DnsServerGetter,
 	}
 	if useMeek {
 		conn, err = DialMeek(serverEntry, sessionId, useFronting, dialConfig)