Przeglądaj źródła

Added param to override server entry fronting domain

* Enables experimenting with alternate addresses
* Known limitation: server cert verification is skipped for
IP address alternate addresses
Rod Hynes 11 lat temu
rodzic
commit
e9e640cba2
5 zmienionych plików z 35 dodań i 7 usunięć
  1. 2 2
      psiphon/TCPConn_unix.go
  2. 1 0
      psiphon/config.go
  3. 14 0
      psiphon/controller.go
  4. 8 0
      psiphon/meekConn.go
  5. 10 5
      psiphon/tlsDialer.go

+ 2 - 2
psiphon/TCPConn_unix.go

@@ -93,8 +93,8 @@ func interruptibleTCPDial(addr string, config *DialConfig) (conn *TCPConn, err e
 		return nil, ContextError(errors.New("no IP address"))
 	}
 
-	// Select an IP at random, so we're not always trying the same IP,
-	// which ay be blocked.
+	// Select an IP at random from the list, so we're not always
+	// trying the same IP (when > 1) which may be blocked.
 	// TODO: retry all IPs until one connects? For now, this retry
 	// will happen on subsequent TCPDial calls, when a different IP
 	// is selected.

+ 1 - 0
psiphon/config.go

@@ -91,6 +91,7 @@ type Config struct {
 	SplitTunnelRoutesUrlFormat          string
 	SplitTunnelRoutesSignaturePublicKey string
 	SplitTunnelDnsServer                string
+	AlternateMeekFrontingAddresses      map[string][]string
 }
 
 // LoadConfig parses and validates a JSON format Psiphon config JSON

+ 14 - 0
psiphon/controller.go

@@ -629,6 +629,20 @@ loop:
 				// Completed this iteration
 				break
 			}
+
+			// Override fronting domain, if configured to do so.
+			// TODO: we could generate multiple candidates from
+			// the current server entry when there are many
+			// AlternateMeekFrontingAddresses for this MeekFrontingHost.
+			if addresses, ok := controller.config.AlternateMeekFrontingAddresses[serverEntry.MeekFrontingDomain]; ok {
+				index, err := MakeSecureRandomInt(len(addresses))
+				if err == nil {
+					address := addresses[index]
+					NoticeAlert("using alternate address for %s: %s", serverEntry.MeekFrontingDomain, address)
+					serverEntry.MeekFrontingDomain = address
+				}
+			}
+
 			select {
 			case controller.candidateServerEntries <- serverEntry:
 			case <-controller.stopEstablishingBroadcast:

+ 8 - 0
psiphon/meekConn.go

@@ -112,6 +112,13 @@ func DialMeek(
 	if useFronting {
 		// In this case, host is not what is dialed but is what ends up in the HTTP Host header
 		host = serverEntry.MeekFrontingHost
+
+		// We skip verifying the server certificate when the host address is an IP address. In the
+		// short term, this is a circumvention weakness: it's vulnerable to an active MiM attack
+		// which injects its own cert and decrypts the TLS and reads the custom Host header.
+		// We need to know which server cert to expect in order to perform verification in this case.
+		skipVerify := (net.ParseIP(serverEntry.MeekFrontingDomain) != nil)
+
 		// Custom TLS dialer:
 		//  - ignores the HTTP request address and uses the fronting domain
 		//  - disables SNI -- SNI breaks fronting when used with CDNs that support SNI on the server side.
@@ -121,6 +128,7 @@ func DialMeek(
 				Timeout:        meekConfig.ConnectTimeout,
 				FrontingAddr:   fmt.Sprintf("%s:%d", serverEntry.MeekFrontingDomain, 443),
 				SendServerName: false,
+				SkipVerify:     skipVerify,
 			})
 	} else {
 		// In this case, host is both what is dialed and what ends up in the HTTP Host header

+ 10 - 5
psiphon/tlsDialer.go

@@ -104,6 +104,9 @@ type CustomTLSConfig struct {
 	// (tlsdialer functionality)
 	SendServerName bool
 
+	// SkipVerify completely disables server certificate verification.
+	SkipVerify bool
+
 	// VerifyLegacyCertificate is a special case self-signed server
 	// certificate case. Ignores IP SANs and basic constraints. No
 	// certificate chain. Just checks that the server presented the
@@ -192,11 +195,13 @@ func CustomTLSDial(network, addr string, config *CustomTLSConfig) (*tls.Conn, er
 		err = <-errChannel
 	}
 
-	if err == nil && config.VerifyLegacyCertificate != nil {
-		err = verifyLegacyCertificate(conn, config.VerifyLegacyCertificate)
-	} else if err == nil && !config.SendServerName && !tlsConfig.InsecureSkipVerify {
-		// Manually verify certificates
-		err = verifyServerCerts(conn, serverName, tlsConfigCopy)
+	if !config.SkipVerify {
+		if err == nil && config.VerifyLegacyCertificate != nil {
+			err = verifyLegacyCertificate(conn, config.VerifyLegacyCertificate)
+		} else if err == nil && !config.SendServerName && !tlsConfig.InsecureSkipVerify {
+			// Manually verify certificates
+			err = verifyServerCerts(conn, serverName, tlsConfigCopy)
+		}
 	}
 
 	if err != nil {