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

Get current DNS server at time of domain lookup

* Custom LookupIP is used for domain name resolution with
BindToDevice support -- to bypass an Android VPN tunnel.

* Previously, we passed the DNS server to use in the config.
But this server isn't always the right server to use since
the current active network can change (e.g., from WiFi to
mobile data to different WiFi).

* Replaced config param with interface to call back into
Java to get the DNS server for the current active network.

* Sample Android App, Psibot, integrates this change.

* Renamed some library interfaces.
Rod Hynes 11 лет назад
Родитель
Сommit
6dc57b9df2

+ 13 - 14
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.

+ 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)