Refactor client Config

ptspec
Andy Wang 2 years ago
parent 2aa49ce543
commit f30141b388
No known key found for this signature in database
GPG Key ID: 181B49F9F38F3374

@ -13,7 +13,7 @@ import (
)
type CLIConfig struct {
client.RawConfig
client.Config
// LocalHost is the hostname or IP address to listen for incoming proxy client connections
LocalHost string // jsonOptional
@ -111,7 +111,7 @@ type LocalConnConfig struct {
}
func (raw *CLIConfig) ProcessCLIConfig(worldState common.WorldState) (local LocalConnConfig, remote client.RemoteConnConfig, auth client.AuthInfo, err error) {
remote, auth, err = raw.RawConfig.ProcessRawConfig(worldState)
remote, auth, err = raw.Config.Process(worldState)
if err != nil {
return
}

@ -79,7 +79,7 @@ var privateKey, _ = base64.StdEncoding.DecodeString("SMWeC6VuZF8S/id65VuFQFlfa7h
var four = 4
var zero = 0
var basicUDPConfig = client.RawConfig{
var basicUDPConfig = client.Config{
ServerName: "www.example.com",
ProxyMethod: "openvpn",
EncryptionMethod: "plain",
@ -92,7 +92,7 @@ var basicUDPConfig = client.RawConfig{
RemotePort: "9999",
}
var basicTCPConfig = client.RawConfig{
var basicTCPConfig = client.Config{
ServerName: "www.example.com",
ProxyMethod: "shadowsocks",
EncryptionMethod: "plain",
@ -106,7 +106,7 @@ var basicTCPConfig = client.RawConfig{
BrowserSig: "firefox",
}
var singleplexTCPConfig = client.RawConfig{
var singleplexTCPConfig = client.Config{
ServerName: "www.example.com",
ProxyMethod: "shadowsocks",
EncryptionMethod: "plain",
@ -120,8 +120,8 @@ var singleplexTCPConfig = client.RawConfig{
BrowserSig: "chrome",
}
func generateClientConfigs(rawConfig client.RawConfig, state common.WorldState) (client.RemoteConnConfig, client.AuthInfo) {
rmt, auth, err := rawConfig.ProcessRawConfig(state)
func generateClientConfigs(rawConfig client.Config, state common.WorldState) (client.RemoteConnConfig, client.AuthInfo) {
rmt, auth, err := rawConfig.Process(state)
if err != nil {
log.Fatal(err)
}
@ -458,7 +458,7 @@ func TestClosingStreamsFromProxy(t *testing.T) {
log.SetLevel(log.ErrorLevel)
worldState := common.WorldOfTime(time.Unix(10, 0))
for clientConfigName, clientConfig := range map[string]client.RawConfig{"basic": basicTCPConfig, "singleplex": singleplexTCPConfig} {
for clientConfigName, clientConfig := range map[string]client.Config{"basic": basicTCPConfig, "singleplex": singleplexTCPConfig} {
clientConfig := clientConfig
clientConfigName := clientConfigName
t.Run(clientConfigName, func(t *testing.T) {

@ -19,10 +19,8 @@ import (
mux "github.com/cbeuw/Cloak/internal/multiplex"
)
// RawConfig represents the fields in the config json file
// jsonOptional means if the json's empty, its value will be set from environment variables or commandline args
// but it mustn't be empty when ProcessRawConfig is called
type RawConfig struct {
// Config contains the configuration parameter fields for a Cloak client
type Config struct {
// Required fields
// ServerName is the domain you appear to be visiting
// to your Firewall or ISP
@ -38,7 +36,7 @@ type RawConfig struct {
// PublicKey is the 32-byte public Curve25519 ECDH key of your server
PublicKey []byte
// RemoteHost is the Cloak server's hostname or IP address
RemoteHost string // jsonOptional
RemoteHost string
// Optional Fields
// EncryptionMethod is the cryptographic algorithm used to
@ -86,59 +84,57 @@ type RemoteConnConfig struct {
type AuthInfo = transports.AuthInfo
func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (remote RemoteConnConfig, auth AuthInfo, err error) {
nullErr := func(field string) (remote RemoteConnConfig, auth AuthInfo, err error) {
err = fmt.Errorf("%v cannot be empty", field)
func (raw *Config) Process(worldState common.WorldState) (remote RemoteConnConfig, auth AuthInfo, err error) {
if raw.ServerName == "" {
err = fmt.Errorf("ServerName cannot be empty")
return
}
if raw.ProxyMethod == "" {
err = fmt.Errorf("ProxyMethod cannot be empty")
return
}
if len(raw.UID) == 0 {
err = fmt.Errorf("UID cannot be empty")
return
}
if len(raw.PublicKey) == 0 {
err = fmt.Errorf("PublicKey cannot be empty")
return
}
if raw.RemoteHost == "" {
err = fmt.Errorf("RemoteHost cannot be empty")
return
}
auth.UID = raw.UID
auth.Unordered = raw.UDP
if raw.ServerName == "" {
return nullErr("ServerName")
}
auth.MockDomain = raw.ServerName
if raw.ProxyMethod == "" {
return nullErr("ProxyMethod")
}
auth.ProxyMethod = raw.ProxyMethod
if len(raw.UID) == 0 {
return nullErr("UID")
}
auth.WorldState = worldState
// static public key
if len(raw.PublicKey) == 0 {
return nullErr("PublicKey")
}
pub, ok := ecdh.Unmarshal(raw.PublicKey)
if !ok {
err = fmt.Errorf("failed to unmarshal Public key")
return
}
auth.ServerPubKey = pub
auth.WorldState = worldState
// Encryption method
switch strings.ToLower(raw.EncryptionMethod) {
case "plain":
auth.EncryptionMethod = mux.EncryptionMethodPlain
case "aes-gcm", "aes-256-gcm":
case "aes-gcm", "aes-256-gcm", "":
auth.EncryptionMethod = mux.EncryptionMethodAES256GCM
case "aes-128-gcm":
auth.EncryptionMethod = mux.EncryptionMethodAES128GCM
case "chacha20-poly1305":
auth.EncryptionMethod = mux.EncryptionMethodChaha20Poly1305
case "":
auth.EncryptionMethod = mux.EncryptionMethodAES256GCM
default:
err = fmt.Errorf("unknown encryption method %v", raw.EncryptionMethod)
return
}
if raw.RemoteHost == "" {
return nullErr("RemoteHost")
}
var remotePort string
if raw.RemotePort == "" {
remotePort = "443"
@ -175,8 +171,6 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (remote Rem
}
}
case "direct":
fallthrough
default:
var browser browser
switch strings.ToLower(raw.BrowserSig) {
case "firefox":
@ -193,6 +187,9 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (remote Rem
Browser: browser,
}
}
default:
err = fmt.Errorf("unknown transport %v", raw.Transport)
return
}
// KeepAlive

@ -0,0 +1,73 @@
package client
import (
"github.com/cbeuw/Cloak/internal/common"
mux "github.com/cbeuw/Cloak/internal/multiplex"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)
var baseConfig = Config{
ServerName: "www.bing.com",
ProxyMethod: "ssh",
UID: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf},
PublicKey: make([]byte, 32),
RemoteHost: "12.34.56.78",
}
func TestDefault(t *testing.T) {
remote, auth, err := baseConfig.Process(common.RealWorldState)
assert.NoError(t, err)
assert.EqualValues(t, 4, remote.NumConn)
assert.EqualValues(t, mux.EncryptionMethodAES256GCM, auth.EncryptionMethod)
assert.EqualValues(t, -1, remote.KeepAlive)
assert.False(t, auth.Unordered)
}
func TestValidation(t *testing.T) {
_, _, err := baseConfig.Process(common.RealWorldState)
assert.NoError(t, err)
type test struct {
fieldToChange string
newValue any
errPattern string
}
tests := []test{
{
fieldToChange: "ServerName",
newValue: "",
errPattern: "empty",
},
{
fieldToChange: "UID",
newValue: []byte{},
errPattern: "empty",
},
{
fieldToChange: "PublicKey",
newValue: []byte{0x1},
errPattern: "unmarshal",
},
{
fieldToChange: "RemoteHost",
newValue: "",
errPattern: "empty",
},
{
fieldToChange: "BrowserSig",
newValue: "not-a-browser",
errPattern: "unknown",
},
}
for _, test := range tests {
config := baseConfig
reflect.ValueOf(&config).Elem().FieldByName(test.fieldToChange).Set(reflect.ValueOf(test.newValue))
_, _, err := config.Process(common.RealWorldState)
assert.ErrorContains(t, err, test.errPattern)
}
}
Loading…
Cancel
Save