Преглед изворни кода

psiphond: support OSL and tactics testing in "generate" mode

Rod Hynes пре 7 година
родитељ
комит
be9073679a
3 измењених фајлова са 170 додато и 72 уклоњено
  1. 71 38
      Server/main.go
  2. 98 33
      psiphon/server/config.go
  3. 1 1
      psiphon/server/server_test.go

+ 71 - 38
Server/main.go

@@ -41,32 +41,22 @@ var loadedConfigJSON []byte
 
 
 func main() {
 func main() {
 
 
-	var generateTrafficRulesFilename string
-	var generateServerEntryFilename string
-	var generateLogFilename string
+	var configFilename string
 	var generateServerIPaddress string
 	var generateServerIPaddress string
 	var generateServerNetworkInterface string
 	var generateServerNetworkInterface string
-	var generateWebServerPort int
 	var generateProtocolPorts stringListFlag
 	var generateProtocolPorts stringListFlag
-	var configFilename string
-
-	flag.StringVar(
-		&generateTrafficRulesFilename,
-		"trafficRules",
-		server.SERVER_TRAFFIC_RULES_FILENAME,
-		"generate with this traffic rules `filename`")
-
-	flag.StringVar(
-		&generateServerEntryFilename,
-		"serverEntry",
-		server.SERVER_ENTRY_FILENAME,
-		"generate with this server entry `filename`")
+	var generateWebServerPort int
+	var generateLogFilename string
+	var generateTrafficRulesConfigFilename string
+	var generateOSLConfigFilename string
+	var generateTacticsConfigFilename string
+	var generateServerEntryFilename string
 
 
 	flag.StringVar(
 	flag.StringVar(
-		&generateLogFilename,
-		"logFilename",
-		"",
-		"set application log file name and path; blank for stderr")
+		&configFilename,
+		"config",
+		server.SERVER_CONFIG_FILENAME,
+		"run or generate with this config `filename`")
 
 
 	flag.StringVar(
 	flag.StringVar(
 		&generateServerIPaddress,
 		&generateServerIPaddress,
@@ -80,22 +70,46 @@ func main() {
 		"",
 		"",
 		"generate with server IP address from this `network-interface`")
 		"generate with server IP address from this `network-interface`")
 
 
+	flag.Var(
+		&generateProtocolPorts,
+		"protocol",
+		"generate with `protocol:port`; flag may be repeated to enable multiple protocols")
+
 	flag.IntVar(
 	flag.IntVar(
 		&generateWebServerPort,
 		&generateWebServerPort,
 		"web",
 		"web",
 		0,
 		0,
 		"generate with web server `port`; 0 for no web server")
 		"generate with web server `port`; 0 for no web server")
 
 
-	flag.Var(
-		&generateProtocolPorts,
-		"protocol",
-		"generate with `protocol:port`; flag may be repeated to enable multiple protocols")
+	flag.StringVar(
+		&generateLogFilename,
+		"logFilename",
+		"",
+		"set application log file name and path; blank for stderr")
 
 
 	flag.StringVar(
 	flag.StringVar(
-		&configFilename,
-		"config",
-		server.SERVER_CONFIG_FILENAME,
-		"run or generate with this config `filename`")
+		&generateTrafficRulesConfigFilename,
+		"trafficRules",
+		server.SERVER_TRAFFIC_RULES_CONFIG_FILENAME,
+		"generate with this traffic rules config `filename`")
+
+	flag.StringVar(
+		&generateOSLConfigFilename,
+		"osl",
+		server.SERVER_OSL_CONFIG_FILENAME,
+		"generate with this OSL config `filename`")
+
+	flag.StringVar(
+		&generateTacticsConfigFilename,
+		"tactics",
+		server.SERVER_TACTICS_CONFIG_FILENAME,
+		"generate with this tactics config `filename`")
+
+	flag.StringVar(
+		&generateServerEntryFilename,
+		"serverEntry",
+		server.SERVER_ENTRY_FILENAME,
+		"generate with this server entry `filename`")
 
 
 	flag.Usage = func() {
 	flag.Usage = func() {
 		fmt.Fprintf(os.Stderr,
 		fmt.Fprintf(os.Stderr,
@@ -143,15 +157,22 @@ func main() {
 			}
 			}
 		}
 		}
 
 
-		configJSON, trafficRulesJSON, encodedServerEntry, err :=
+		configJSON,
+			trafficRulesConfigJSON,
+			OSLConfigJSON,
+			tacticsConfigJSON,
+			encodedServerEntry,
+			err :=
 			server.GenerateConfig(
 			server.GenerateConfig(
 				&server.GenerateConfigParams{
 				&server.GenerateConfigParams{
-					LogFilename:          generateLogFilename,
-					ServerIPAddress:      serverIPaddress,
-					EnableSSHAPIRequests: true,
-					WebServerPort:        generateWebServerPort,
-					TunnelProtocolPorts:  tunnelProtocolPorts,
-					TrafficRulesFilename: generateTrafficRulesFilename,
+					LogFilename:                generateLogFilename,
+					ServerIPAddress:            serverIPaddress,
+					EnableSSHAPIRequests:       true,
+					WebServerPort:              generateWebServerPort,
+					TunnelProtocolPorts:        tunnelProtocolPorts,
+					TrafficRulesConfigFilename: generateTrafficRulesConfigFilename,
+					OSLConfigFilename:          generateOSLConfigFilename,
+					TacticsConfigFilename:      generateTacticsConfigFilename,
 				})
 				})
 		if err != nil {
 		if err != nil {
 			fmt.Printf("generate failed: %s\n", err)
 			fmt.Printf("generate failed: %s\n", err)
@@ -164,9 +185,21 @@ func main() {
 			os.Exit(1)
 			os.Exit(1)
 		}
 		}
 
 
-		err = ioutil.WriteFile(generateTrafficRulesFilename, trafficRulesJSON, 0600)
+		err = ioutil.WriteFile(generateTrafficRulesConfigFilename, trafficRulesConfigJSON, 0600)
+		if err != nil {
+			fmt.Printf("error writing traffic rule config file: %s\n", err)
+			os.Exit(1)
+		}
+
+		err = ioutil.WriteFile(generateOSLConfigFilename, OSLConfigJSON, 0600)
+		if err != nil {
+			fmt.Printf("error writing OSL config file: %s\n", err)
+			os.Exit(1)
+		}
+
+		err = ioutil.WriteFile(generateTacticsConfigFilename, tacticsConfigJSON, 0600)
 		if err != nil {
 		if err != nil {
-			fmt.Printf("error writing traffic rule configuration file: %s\n", err)
+			fmt.Printf("error writing tactics config file: %s\n", err)
 			os.Exit(1)
 			os.Exit(1)
 		}
 		}
 
 

+ 98 - 33
psiphon/server/config.go

@@ -36,20 +36,24 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/accesscontrol"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/accesscontrol"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/nacl/box"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/nacl/box"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/osl"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tactics"
 )
 )
 
 
 const (
 const (
-	SERVER_CONFIG_FILENAME          = "psiphond.config"
-	SERVER_TRAFFIC_RULES_FILENAME   = "psiphond-traffic-rules.config"
-	SERVER_ENTRY_FILENAME           = "server-entry.dat"
-	DEFAULT_SERVER_IP_ADDRESS       = "127.0.0.1"
-	WEB_SERVER_SECRET_BYTE_LENGTH   = 32
-	DISCOVERY_VALUE_KEY_BYTE_LENGTH = 32
-	SSH_USERNAME_SUFFIX_BYTE_LENGTH = 8
-	SSH_PASSWORD_BYTE_LENGTH        = 32
-	SSH_RSA_HOST_KEY_BITS           = 2048
-	SSH_OBFUSCATED_KEY_BYTE_LENGTH  = 32
+	SERVER_CONFIG_FILENAME               = "psiphond.config"
+	SERVER_TRAFFIC_RULES_CONFIG_FILENAME = "psiphond-traffic-rules.config"
+	SERVER_OSL_CONFIG_FILENAME           = "psiphond-osl.config"
+	SERVER_TACTICS_CONFIG_FILENAME       = "psiphond-tactics.config"
+	SERVER_ENTRY_FILENAME                = "server-entry.dat"
+	DEFAULT_SERVER_IP_ADDRESS            = "127.0.0.1"
+	WEB_SERVER_SECRET_BYTE_LENGTH        = 32
+	DISCOVERY_VALUE_KEY_BYTE_LENGTH      = 32
+	SSH_USERNAME_SUFFIX_BYTE_LENGTH      = 8
+	SSH_PASSWORD_BYTE_LENGTH             = 32
+	SSH_RSA_HOST_KEY_BITS                = 2048
+	SSH_OBFUSCATED_KEY_BYTE_LENGTH       = 32
 )
 )
 
 
 // Config specifies the configuration and behavior of a Psiphon
 // Config specifies the configuration and behavior of a Psiphon
@@ -435,7 +439,9 @@ type GenerateConfigParams struct {
 	WebServerPort               int
 	WebServerPort               int
 	EnableSSHAPIRequests        bool
 	EnableSSHAPIRequests        bool
 	TunnelProtocolPorts         map[string]int
 	TunnelProtocolPorts         map[string]int
-	TrafficRulesFilename        string
+	TrafficRulesConfigFilename  string
+	OSLConfigFilename           string
+	TacticsConfigFilename       string
 	TacticsRequestPublicKey     string
 	TacticsRequestPublicKey     string
 	TacticsRequestObfuscatedKey string
 	TacticsRequestObfuscatedKey string
 }
 }
@@ -451,16 +457,16 @@ type GenerateConfigParams struct {
 //
 //
 // When tactics key material is provided in GenerateConfigParams, tactics
 // When tactics key material is provided in GenerateConfigParams, tactics
 // capabilities are added for all meek protocols in TunnelProtocolPorts.
 // capabilities are added for all meek protocols in TunnelProtocolPorts.
-func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error) {
+func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, []byte, []byte, error) {
 
 
 	// Input validation
 	// Input validation
 
 
 	if net.ParseIP(params.ServerIPAddress) == nil {
 	if net.ParseIP(params.ServerIPAddress) == nil {
-		return nil, nil, nil, common.ContextError(errors.New("invalid IP address"))
+		return nil, nil, nil, nil, nil, common.ContextError(errors.New("invalid IP address"))
 	}
 	}
 
 
 	if len(params.TunnelProtocolPorts) == 0 {
 	if len(params.TunnelProtocolPorts) == 0 {
-		return nil, nil, nil, common.ContextError(errors.New("no tunnel protocols"))
+		return nil, nil, nil, nil, nil, common.ContextError(errors.New("no tunnel protocols"))
 	}
 	}
 
 
 	usedPort := make(map[int]bool)
 	usedPort := make(map[int]bool)
@@ -473,11 +479,11 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 	for tunnelProtocol, port := range params.TunnelProtocolPorts {
 	for tunnelProtocol, port := range params.TunnelProtocolPorts {
 
 
 		if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
 		if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
-			return nil, nil, nil, common.ContextError(errors.New("invalid tunnel protocol"))
+			return nil, nil, nil, nil, nil, common.ContextError(errors.New("invalid tunnel protocol"))
 		}
 		}
 
 
 		if usedPort[port] {
 		if usedPort[port] {
-			return nil, nil, nil, common.ContextError(errors.New("duplicate listening port"))
+			return nil, nil, nil, nil, nil, common.ContextError(errors.New("duplicate listening port"))
 		}
 		}
 		usedPort[port] = true
 		usedPort[port] = true
 
 
@@ -487,6 +493,14 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 		}
 		}
 	}
 	}
 
 
+	// One test mode populates the tactics config file; this will generate
+	// keys. Another test mode passes in existing keys to be used in the
+	// server entry. Both the filename and existing keys cannot be passed in.
+	if (params.TacticsConfigFilename != "") &&
+		(params.TacticsRequestPublicKey != "" || params.TacticsRequestObfuscatedKey != "") {
+		return nil, nil, nil, nil, nil, common.ContextError(errors.New("invalid tactics parameters"))
+	}
+
 	// Web server config
 	// Web server config
 
 
 	var webServerSecret, webServerCertificate,
 	var webServerSecret, webServerCertificate,
@@ -496,12 +510,12 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 		var err error
 		var err error
 		webServerSecret, err = common.MakeRandomStringHex(WEB_SERVER_SECRET_BYTE_LENGTH)
 		webServerSecret, err = common.MakeRandomStringHex(WEB_SERVER_SECRET_BYTE_LENGTH)
 		if err != nil {
 		if err != nil {
-			return nil, nil, nil, common.ContextError(err)
+			return nil, nil, nil, nil, nil, common.ContextError(err)
 		}
 		}
 
 
 		webServerCertificate, webServerPrivateKey, err = GenerateWebServerCertificate("")
 		webServerCertificate, webServerPrivateKey, err = GenerateWebServerCertificate("")
 		if err != nil {
 		if err != nil {
-			return nil, nil, nil, common.ContextError(err)
+			return nil, nil, nil, nil, nil, common.ContextError(err)
 		}
 		}
 
 
 		webServerPortForwardAddress = net.JoinHostPort(
 		webServerPortForwardAddress = net.JoinHostPort(
@@ -512,7 +526,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 	rsaKey, err := rsa.GenerateKey(rand.Reader, SSH_RSA_HOST_KEY_BITS)
 	rsaKey, err := rsa.GenerateKey(rand.Reader, SSH_RSA_HOST_KEY_BITS)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	sshPrivateKey := pem.EncodeToMemory(
 	sshPrivateKey := pem.EncodeToMemory(
@@ -524,21 +538,21 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 	signer, err := ssh.NewSignerFromKey(rsaKey)
 	signer, err := ssh.NewSignerFromKey(rsaKey)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	sshPublicKey := signer.PublicKey()
 	sshPublicKey := signer.PublicKey()
 
 
 	sshUserNameSuffix, err := common.MakeRandomStringHex(SSH_USERNAME_SUFFIX_BYTE_LENGTH)
 	sshUserNameSuffix, err := common.MakeRandomStringHex(SSH_USERNAME_SUFFIX_BYTE_LENGTH)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	sshUserName := "psiphon_" + sshUserNameSuffix
 	sshUserName := "psiphon_" + sshUserNameSuffix
 
 
 	sshPassword, err := common.MakeRandomStringHex(SSH_PASSWORD_BYTE_LENGTH)
 	sshPassword, err := common.MakeRandomStringHex(SSH_PASSWORD_BYTE_LENGTH)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	sshServerVersion := "SSH-2.0-Psiphon"
 	sshServerVersion := "SSH-2.0-Psiphon"
@@ -547,7 +561,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 	obfuscatedSSHKey, err := common.MakeRandomStringHex(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
 	obfuscatedSSHKey, err := common.MakeRandomStringHex(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	// Meek config
 	// Meek config
@@ -558,7 +572,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 		rawMeekCookieEncryptionPublicKey, rawMeekCookieEncryptionPrivateKey, err :=
 		rawMeekCookieEncryptionPublicKey, rawMeekCookieEncryptionPrivateKey, err :=
 			box.GenerateKey(rand.Reader)
 			box.GenerateKey(rand.Reader)
 		if err != nil {
 		if err != nil {
-			return nil, nil, nil, common.ContextError(err)
+			return nil, nil, nil, nil, nil, common.ContextError(err)
 		}
 		}
 
 
 		meekCookieEncryptionPublicKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPublicKey[:])
 		meekCookieEncryptionPublicKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPublicKey[:])
@@ -566,7 +580,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 		meekObfuscatedKey, err = common.MakeRandomStringHex(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
 		meekObfuscatedKey, err = common.MakeRandomStringHex(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
 		if err != nil {
 		if err != nil {
-			return nil, nil, nil, common.ContextError(err)
+			return nil, nil, nil, nil, nil, common.ContextError(err)
 		}
 		}
 	}
 	}
 
 
@@ -574,7 +588,7 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 	discoveryValueHMACKey, err := common.MakeRandomStringBase64(DISCOVERY_VALUE_KEY_BYTE_LENGTH)
 	discoveryValueHMACKey, err := common.MakeRandomStringBase64(DISCOVERY_VALUE_KEY_BYTE_LENGTH)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	// Assemble configs and server entry
 	// Assemble configs and server entry
@@ -613,12 +627,14 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 		MeekProhibitedHeaders:          nil,
 		MeekProhibitedHeaders:          nil,
 		MeekProxyForwardedForHeaders:   []string{"X-Forwarded-For"},
 		MeekProxyForwardedForHeaders:   []string{"X-Forwarded-For"},
 		LoadMonitorPeriodSeconds:       300,
 		LoadMonitorPeriodSeconds:       300,
-		TrafficRulesFilename:           params.TrafficRulesFilename,
+		TrafficRulesFilename:           params.TrafficRulesConfigFilename,
+		OSLConfigFilename:              params.OSLConfigFilename,
+		TacticsConfigFilename:          params.TacticsConfigFilename,
 	}
 	}
 
 
 	encodedConfig, err := json.MarshalIndent(config, "\n", "    ")
 	encodedConfig, err := json.MarshalIndent(config, "\n", "    ")
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
 	intPtr := func(i int) *int {
 	intPtr := func(i int) *int {
@@ -644,7 +660,56 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 
 
 	encodedTrafficRulesSet, err := json.MarshalIndent(trafficRulesSet, "\n", "    ")
 	encodedTrafficRulesSet, err := json.MarshalIndent(trafficRulesSet, "\n", "    ")
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
+	}
+
+	encodedOSLConfig, err := json.MarshalIndent(&osl.Config{}, "\n", "    ")
+	if err != nil {
+		return nil, nil, nil, nil, nil, common.ContextError(err)
+	}
+
+	tacticsRequestPublicKey := params.TacticsRequestPublicKey
+	tacticsRequestObfuscatedKey := params.TacticsRequestObfuscatedKey
+	var tacticsRequestPrivateKey string
+	var encodedTacticsConfig []byte
+
+	if params.TacticsConfigFilename != "" {
+
+		tacticsRequestPublicKey, tacticsRequestPrivateKey, tacticsRequestObfuscatedKey, err =
+			tactics.GenerateKeys()
+		if err != nil {
+			return nil, nil, nil, nil, nil, common.ContextError(err)
+		}
+
+		decodedTacticsRequestPublicKey, err := base64.StdEncoding.DecodeString(tacticsRequestPublicKey)
+		if err != nil {
+			return nil, nil, nil, nil, nil, common.ContextError(err)
+		}
+
+		decodedTacticsRequestPrivateKey, err := base64.StdEncoding.DecodeString(tacticsRequestPrivateKey)
+		if err != nil {
+			return nil, nil, nil, nil, nil, common.ContextError(err)
+		}
+
+		decodedTacticsRequestObfuscatedKey, err := base64.StdEncoding.DecodeString(tacticsRequestObfuscatedKey)
+		if err != nil {
+			return nil, nil, nil, nil, nil, common.ContextError(err)
+		}
+
+		tacticsConfig := &tactics.Server{
+			RequestPublicKey:     decodedTacticsRequestPublicKey,
+			RequestPrivateKey:    decodedTacticsRequestPrivateKey,
+			RequestObfuscatedKey: decodedTacticsRequestObfuscatedKey,
+			DefaultTactics: tactics.Tactics{
+				TTL:         "1m",
+				Probability: 1.0,
+			},
+		}
+
+		encodedTacticsConfig, err = json.MarshalIndent(tacticsConfig, "\n", "    ")
+		if err != nil {
+			return nil, nil, nil, nil, nil, common.ContextError(err)
+		}
 	}
 	}
 
 
 	capabilities := []string{}
 	capabilities := []string{}
@@ -715,15 +780,15 @@ func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, error
 		MeekFrontingHosts:             []string{params.ServerIPAddress},
 		MeekFrontingHosts:             []string{params.ServerIPAddress},
 		MeekFrontingAddresses:         []string{params.ServerIPAddress},
 		MeekFrontingAddresses:         []string{params.ServerIPAddress},
 		MeekFrontingDisableSNI:        false,
 		MeekFrontingDisableSNI:        false,
-		TacticsRequestPublicKey:       params.TacticsRequestPublicKey,
-		TacticsRequestObfuscatedKey:   params.TacticsRequestObfuscatedKey,
+		TacticsRequestPublicKey:       tacticsRequestPublicKey,
+		TacticsRequestObfuscatedKey:   tacticsRequestObfuscatedKey,
 		ConfigurationVersion:          1,
 		ConfigurationVersion:          1,
 	}
 	}
 
 
 	encodedServerEntry, err := protocol.EncodeServerEntry(serverEntry)
 	encodedServerEntry, err := protocol.EncodeServerEntry(serverEntry)
 	if err != nil {
 	if err != nil {
-		return nil, nil, nil, common.ContextError(err)
+		return nil, nil, nil, nil, nil, common.ContextError(err)
 	}
 	}
 
 
-	return encodedConfig, encodedTrafficRulesSet, []byte(encodedServerEntry), nil
+	return encodedConfig, encodedTrafficRulesSet, encodedOSLConfig, encodedTacticsConfig, []byte(encodedServerEntry), nil
 }
 }

+ 1 - 1
psiphon/server/server_test.go

@@ -411,7 +411,7 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 		generateConfigParams.TacticsRequestObfuscatedKey = tacticsRequestObfuscatedKey
 		generateConfigParams.TacticsRequestObfuscatedKey = tacticsRequestObfuscatedKey
 	}
 	}
 
 
-	serverConfigJSON, _, encodedServerEntry, err := GenerateConfig(generateConfigParams)
+	serverConfigJSON, _, _, _, encodedServerEntry, err := GenerateConfig(generateConfigParams)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("error generating server config: %s", err)
 		t.Fatalf("error generating server config: %s", err)
 	}
 	}