You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Cloak/libcloak/client/config.go

207 lines
6.1 KiB
Go

package client
import (
"fmt"
"github.com/cbeuw/Cloak/internal/common"
"github.com/cbeuw/Cloak/libcloak/client/transports"
"net"
"strings"
"time"
"github.com/cbeuw/Cloak/internal/ecdh"
mux "github.com/cbeuw/Cloak/internal/multiplex"
)
// 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
ServerName string
// ProxyMethod is the name of the underlying proxy you wish
// to connect to, as determined by your server. The value can
// be any string whose UTF-8 ENCODED byte length is no greater than
// 12 bytes
ProxyMethod string
// UID is a 16-byte secret string unique to an authorised user
// The same UID can be used by the same user for multiple Cloak connections
UID []byte
// 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
// Optional Fields
// EncryptionMethod is the cryptographic algorithm used to
// encrypt data on the wire.
// Valid values are `aes-128-gcm`, `aes-256-gcm`, `chacha20-poly1305`, and `plain`
// Defaults to `aes-256-gcm`
EncryptionMethod string
// NumConn is the amount of underlying TLS connections to establish with Cloak server.
// Cloak multiplexes any number of incoming connections to a fixed number of underlying TLS connections.
// If set to 0, a special singleplex mode is enabled: each incoming connection will correspond to exactly one
// TLS connection
// Defaults to 4
NumConn *int
// UDP enables UDP semantics, where packets must fit into one unit of message (below 16000 bytes by default),
// and packets can be received out of order. Though reliable delivery is still guaranteed.
UDP bool
// BrowserSig is the browser signature to be used. Options are `chrome` and `firefox`
// Defaults to `chrome`
BrowserSig string
// Transport is either `direct` or `cdn`. Under `direct`, the client connects to a Cloak server directly.
// Under `cdn`, the client connects to a CDN provider such as Amazon Cloudfront, which in turn connects
// to a Cloak server.
// Defaults to `direct`
Transport string
// CDNOriginHost is the CDN Origin's (i.e. Cloak server) real hostname or IP address, which is encrypted between
// the client and the CDN server, and therefore hidden to ISP or firewalls. This only has effect when Transport
// is set to `cdn`
// Defaults to RemoteHost
CDNOriginHost string
// KeepAlive is the interval between TCP KeepAlive packets to be sent over the underlying TLS connections
// Defaults to -1, which means no TCP KeepAlive is ever sent
KeepAlive int
// RemotePort is the port Cloak server is listening to
// Defaults to 443
RemotePort string
// InactivityTimeout is the number of seconds the client keeps the underlying connections to the server
// after the last proxy connection is disconnected.
// Defaults to 30. Always set to 0 under Singleplex mode (NumConn == 0)
InactivityTimeout *int
}
type RemoteConnConfig struct {
NumConn int
KeepAlive time.Duration
RemoteAddr string
TransportMaker func() transports.Transport
InactivityTimeout time.Duration
}
type AuthInfo = transports.AuthInfo
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
auth.MockDomain = raw.ServerName
auth.ProxyMethod = raw.ProxyMethod
auth.WorldState = worldState
// static public key
pub, ok := ecdh.Unmarshal(raw.PublicKey)
if !ok {
err = fmt.Errorf("failed to unmarshal Public key")
return
}
auth.ServerPubKey = pub
// Encryption method
switch strings.ToLower(raw.EncryptionMethod) {
case "plain":
auth.EncryptionMethod = mux.EncryptionMethodPlain
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
default:
err = fmt.Errorf("unknown encryption method %v", raw.EncryptionMethod)
return
}
var remotePort string
if raw.RemotePort == "" {
remotePort = "443"
} else {
remotePort = raw.RemotePort
}
remote.RemoteAddr = net.JoinHostPort(raw.RemoteHost, remotePort)
if raw.InactivityTimeout == nil {
remote.InactivityTimeout = 30 * time.Second
} else {
remote.InactivityTimeout = time.Duration(*raw.InactivityTimeout) * time.Second
}
if raw.NumConn == nil {
remote.NumConn = 4
} else if *raw.NumConn <= 0 {
remote.NumConn = 1
remote.InactivityTimeout = 0
} else {
remote.NumConn = *raw.NumConn
}
// Transport and (if TLS mode), browser
switch strings.ToLower(raw.Transport) {
case "cdn":
cdnPort := raw.RemotePort
var cdnHost string
if raw.CDNOriginHost == "" {
cdnHost = raw.RemoteHost
} else {
cdnHost = raw.CDNOriginHost
}
remote.TransportMaker = func() transports.Transport {
return &transports.WSOverTLS{
CDNHost: cdnHost,
CDNPort: cdnPort,
}
}
case "direct", "":
var browser transports.Browser
switch strings.ToLower(raw.BrowserSig) {
case "firefox":
browser = transports.Firefox
case "safari":
browser = transports.Safari
case "chrome", "":
browser = transports.Chrome
default:
err = fmt.Errorf("unknown browser signature %v", raw.BrowserSig)
return
}
remote.TransportMaker = func() transports.Transport {
return &transports.DirectTLS{
Browser: browser,
}
}
default:
err = fmt.Errorf("unknown transport %v", raw.Transport)
return
}
// KeepAlive
if raw.KeepAlive <= 0 {
remote.KeepAlive = -1
} else {
remote.KeepAlive = remote.KeepAlive * time.Second
}
return
}