Jelajahi Sumber

Allow tactics without request key material

- Untunneled tactics requests are disabled in
  this case, but handshake still returns tactics
  payloads.
Rod Hynes 8 tahun lalu
induk
melakukan
4dbbb4b23a
2 mengubah file dengan 59 tambahan dan 6 penghapusan
  1. 16 6
      psiphon/common/tactics/tactics.go
  2. 43 0
      psiphon/common/tactics/tactics_test.go

+ 16 - 6
psiphon/common/tactics/tactics.go

@@ -466,10 +466,18 @@ func NewServer(
 // Validate checks for correct tactics configuration values.
 // Validate checks for correct tactics configuration values.
 func (server *Server) Validate() error {
 func (server *Server) Validate() error {
 
 
-	if len(server.RequestPublicKey) != 32 ||
-		len(server.RequestPrivateKey) != 32 ||
-		len(server.RequestObfuscatedKey) != common.OBFUSCATE_KEY_LENGTH {
-		return common.ContextError(errors.New("invalid request key"))
+	// Key material must either be entirely omitted, or fully populated.
+	if len(server.RequestPublicKey) == 0 {
+		if len(server.RequestPrivateKey) != 0 ||
+			len(server.RequestObfuscatedKey) != 0 {
+			return common.ContextError(errors.New("unexpected request key"))
+		}
+	} else {
+		if len(server.RequestPublicKey) != 32 ||
+			len(server.RequestPrivateKey) != 32 ||
+			len(server.RequestObfuscatedKey) != common.OBFUSCATE_KEY_LENGTH {
+			return common.ContextError(errors.New("invalid request key"))
+		}
 	}
 	}
 
 
 	validateTactics := func(tactics *Tactics, isDefault bool) error {
 	validateTactics := func(tactics *Tactics, isDefault bool) error {
@@ -901,10 +909,12 @@ func (server *Server) HandleEndPoint(
 
 
 	server.ReloadableFile.RLock()
 	server.ReloadableFile.RLock()
 	loaded := server.loaded
 	loaded := server.loaded
+	hasRequestKeys := len(server.RequestPublicKey) > 0
 	server.ReloadableFile.RUnlock()
 	server.ReloadableFile.RUnlock()
 
 
-	if !loaded {
-		// No tactics configuration was loaded.
+	if !loaded || !hasRequestKeys {
+		// No tactics configuration was loaded, or the configuration contained
+		// no key material for tactics requests.
 		return false
 		return false
 	}
 	}
 
 

+ 43 - 0
psiphon/common/tactics/tactics_test.go

@@ -637,6 +637,49 @@ func TestTactics(t *testing.T) {
 		t.Fatalf("FetchTactics succeeded unexpectedly with incorrect obfuscated key")
 		t.Fatalf("FetchTactics succeeded unexpectedly with incorrect obfuscated key")
 	}
 	}
 
 
+	// When no keys are supplied, untunneled tactics requests are not supported, but
+	// handshake tactics (GetTacticsPayload) should still work.
+
+	tacticsConfig = fmt.Sprintf(
+		tacticsConfigTemplate,
+		"",
+		"",
+		"",
+		tacticsProbability,
+		tacticsNetworkLatencyMultiplier,
+		tacticsConnectionWorkerPoolSize,
+		jsonTacticsLimitTunnelProtocols,
+		tacticsConnectionWorkerPoolSize+1)
+
+	err = ioutil.WriteFile(configFileName, []byte(tacticsConfig), 0600)
+	if err != nil {
+		t.Fatalf("WriteFile failed: %s", err)
+	}
+
+	reloaded, err = server.Reload()
+	if err != nil {
+		t.Fatalf("Reload failed: %s", err)
+	}
+
+	if !reloaded {
+		t.Fatalf("Server config failed to reload")
+	}
+
+	_, err = server.GetTacticsPayload(clientGeoIPData, handshakeParams)
+	if err != nil {
+		t.Fatalf("GetTacticsPayload failed: %s", err)
+	}
+
+	handled := server.HandleEndPoint(TACTICS_END_POINT, clientGeoIPData, nil, nil)
+	if handled {
+		t.Fatalf("HandleEndPoint unexpectedly handled request")
+	}
+
+	handled = server.HandleEndPoint(SPEED_TEST_END_POINT, clientGeoIPData, nil, nil)
+	if handled {
+		t.Fatalf("HandleEndPoint unexpectedly handled request")
+	}
+
 	// TODO: test replay attack defence
 	// TODO: test replay attack defence
 
 
 	// TODO: test Server.Validate with invalid tactics configurations
 	// TODO: test Server.Validate with invalid tactics configurations