| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- package config
-
- import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "math"
- "net"
-
- "github.com/alecthomas/units"
- statsd "github.com/smira/go-statsd"
- "go.uber.org/zap"
- )
-
- type SecretMode uint8
-
- func (s SecretMode) String() string {
- switch s {
- case SecretModeSimple:
- return "simple"
- case SecretModeSecured:
- return "secured"
- case SecretModeTLS:
- return "tls"
- }
-
- return "tls"
- }
-
- const (
- SecretModeSimple SecretMode = iota
- SecretModeSecured
- SecretModeTLS
- )
-
- type PreferIP uint8
-
- const (
- PreferIPv4 PreferIP = iota
- PreferIPv6
- )
-
- const SimpleSecretLength = 16
-
- type OptionType uint8
-
- const (
- OptionTypeDebug OptionType = iota
- OptionTypeVerbose
-
- OptionTypePreferIP
-
- OptionTypeBind
- OptionTypePublicIPv4
- OptionTypePublicIPv6
-
- OptionTypeStatsBind
- OptionTypeStatsNamespace
- OptionTypeStatsdAddress
- OptionTypeStatsdTagsFormat
- OptionTypeStatsdTags
-
- OptionTypeWriteBufferSize
- OptionTypeReadBufferSize
-
- OptionTypeCloakPort
-
- OptionTypeAntiReplayMaxSize
-
- OptionTypeMultiplexPerConnection
-
- OptionTypeNTPServers
-
- OptionTypeSecret
- OptionTypeAdtag
- )
-
- type Config struct {
- Bind *net.TCPAddr `json:"bind"`
- PublicIPv4 *net.TCPAddr `json:"public_ipv4"` // nolint: tagliatelle
- PublicIPv6 *net.TCPAddr `json:"public_ipv6"` // nolint: tagliatelle
- StatsBind *net.TCPAddr `json:"stats_bind"` // nolint: tagliatelle
- StatsdAddr *net.TCPAddr `json:"stats_addr"` // nolint: tagliatelle
- StatsdTagsFormat *statsd.TagFormat `json:"statsd_tags_format"` // nolint: tagliatelle
-
- StatsNamespace string `json:"stats_namespace"` // nolint: tagliatelle
- CloakHost string `json:"cloak_host"` // nolint: tagliatelle
- StatsdTags map[string]string `json:"statsd_tags"` // nolint: tagliatelle
-
- WriteBuffer int `json:"write_buffer"` // nolint: tagliatelle
- ReadBuffer int `json:"read_buffer"` // nolint: tagliatelle
- CloakPort int `json:"cloak_port"` // nolint: tagliatelle
-
- AntiReplayMaxSize int `json:"anti_replay_max_size"` // nolint: tagliatelle
-
- MultiplexPerConnection int `json:"multiplex_per_connection"` // nolint: tagliatelle
-
- Debug bool `json:"debug"`
- Verbose bool `json:"verbose"`
- SecretMode SecretMode `json:"secret_mode"` // nolint: tagliatelle
- PreferIP PreferIP `json:"prefer_ip"` // nolint: tagliatelle
- NTPServers []string `json:"ntp_servers"` // nolint: tagliatelle
-
- Secret []byte `json:"secret"`
- AdTag []byte `json:"adtag"`
- }
-
- func (c *Config) ClientReadBuffer() int {
- return c.ReadBuffer
- }
-
- func (c *Config) ClientWriteBuffer() int {
- return c.WriteBuffer
- }
-
- func (c *Config) MiddleProxyMode() bool {
- return len(c.AdTag) > 0
- }
-
- func (c *Config) ProxyReadBuffer() int {
- value := c.ReadBuffer
-
- if c.MiddleProxyMode() {
- value = c.adjustProxyValue(value)
- }
-
- return value
- }
-
- func (c *Config) ProxyWriteBuffer() int {
- value := c.WriteBuffer
-
- if c.MiddleProxyMode() {
- value = c.adjustProxyValue(value)
- }
-
- return value
- }
-
- func (c *Config) adjustProxyValue(value int) int {
- if c.MultiplexPerConnection == 0 {
- return value
- }
-
- fvalue := float64(value)
-
- newValue := fvalue * 2 * math.Log(float64(c.MultiplexPerConnection)) // nolint: gomnd
- newValue = math.Ceil(newValue)
- newValue = math.Max(fvalue, newValue)
-
- return int(newValue)
- }
-
- type Opt struct {
- Option OptionType
- Value interface{}
- }
-
- var C = Config{}
-
- func Init(options ...Opt) error { // nolint: gocyclo, funlen, cyclop
- for _, opt := range options {
- switch opt.Option {
- case OptionTypeDebug:
- C.Debug = opt.Value.(bool) // nolint: forcetypeassert
- case OptionTypeVerbose:
- C.Verbose = opt.Value.(bool) // nolint: forcetypeassert
- case OptionTypePreferIP:
- value := opt.Value.(string) // nolint: forcetypeassert
- switch value {
- case "ipv4":
- C.PreferIP = PreferIPv4
- case "ipv6":
- C.PreferIP = PreferIPv6
- default:
- return fmt.Errorf("incorrect direct IP mode %s", value)
- }
- case OptionTypeBind:
- C.Bind = opt.Value.(*net.TCPAddr) // nolint: forcetypeassert
- case OptionTypePublicIPv4:
- C.PublicIPv4 = opt.Value.(*net.TCPAddr) // nolint: forcetypeassert
- if C.PublicIPv4 == nil {
- C.PublicIPv4 = &net.TCPAddr{}
- }
- case OptionTypePublicIPv6:
- C.PublicIPv6 = opt.Value.(*net.TCPAddr) // nolint: forcetypeassert
- if C.PublicIPv6 == nil {
- C.PublicIPv6 = &net.TCPAddr{}
- }
- case OptionTypeStatsBind:
- C.StatsBind = opt.Value.(*net.TCPAddr) // nolint: forcetypeassert
- case OptionTypeStatsNamespace:
- C.StatsNamespace = opt.Value.(string) // nolint: forcetypeassert
- case OptionTypeStatsdAddress:
- C.StatsdAddr = opt.Value.(*net.TCPAddr) // nolint: forcetypeassert
- case OptionTypeStatsdTagsFormat:
- value := opt.Value.(string) // nolint: forcetypeassert
- switch value {
- case "datadog":
- C.StatsdTagsFormat = statsd.TagFormatDatadog
- case "influxdb":
- C.StatsdTagsFormat = statsd.TagFormatInfluxDB
- default:
- return fmt.Errorf("incorrect statsd tag %s", value)
- }
- case OptionTypeStatsdTags:
- C.StatsdTags = opt.Value.(map[string]string) // nolint: forcetypeassert
- case OptionTypeWriteBufferSize:
- C.WriteBuffer = int(opt.Value.(units.Base2Bytes)) // nolint: forcetypeassert
- case OptionTypeReadBufferSize:
- C.ReadBuffer = int(opt.Value.(units.Base2Bytes)) // nolint: forcetypeassert
- case OptionTypeCloakPort:
- C.CloakPort = int(opt.Value.(uint16)) // nolint: forcetypeassert
- case OptionTypeAntiReplayMaxSize:
- C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes)) // nolint: forcetypeassert
- case OptionTypeMultiplexPerConnection:
- C.MultiplexPerConnection = int(opt.Value.(uint)) // nolint: forcetypeassert
- case OptionTypeNTPServers:
- C.NTPServers = opt.Value.([]string) // nolint: forcetypeassert
- if len(C.NTPServers) == 0 {
- return errors.New("ntp server list is empty")
- }
- case OptionTypeSecret:
- C.Secret = opt.Value.([]byte) // nolint: forcetypeassert
- case OptionTypeAdtag:
- C.AdTag = opt.Value.([]byte) // nolint: forcetypeassert
- default:
- return fmt.Errorf("unknown tag %v", opt.Option)
- }
- }
-
- switch {
- case len(C.Secret) == 1+SimpleSecretLength && bytes.HasPrefix(C.Secret, []byte{0xdd}):
- C.SecretMode = SecretModeSecured
- C.Secret = bytes.TrimPrefix(C.Secret, []byte{0xdd})
- case len(C.Secret) > SimpleSecretLength && bytes.HasPrefix(C.Secret, []byte{0xee}):
- C.SecretMode = SecretModeTLS
- secret := bytes.TrimPrefix(C.Secret, []byte{0xee})
- C.Secret = secret[:SimpleSecretLength]
- C.CloakHost = string(secret[SimpleSecretLength:])
- case len(C.Secret) == SimpleSecretLength:
- C.SecretMode = SecretModeSimple
- default:
- return errors.New("incorrect secret")
- }
-
- if C.MultiplexPerConnection == 0 {
- return errors.New("cannot use 0 clients per connection for multiplexing")
- }
-
- if C.CloakHost != "" {
- if _, err := net.LookupHost(C.CloakHost); err != nil {
- zap.S().Warnw("Cannot resolve address of host", "hostname", C.CloakHost, "error", err)
- }
- }
-
- return nil
- }
-
- func InitPublicAddress(ctx context.Context) error {
- if C.PublicIPv4.Port == 0 {
- C.PublicIPv4.Port = C.Bind.Port
- }
-
- if C.PublicIPv6.Port == 0 {
- C.PublicIPv6.Port = C.Bind.Port
- }
-
- foundAddress := C.PublicIPv4.IP != nil || C.PublicIPv6.IP != nil
-
- if C.PublicIPv4.IP == nil {
- ip, err := getGlobalIPv4(ctx)
- if err != nil {
- zap.S().Warnw("Cannot resolve public address", "error", err)
- } else {
- C.PublicIPv4.IP = ip
- foundAddress = true
- }
- }
-
- if C.PublicIPv6.IP == nil {
- ip, err := getGlobalIPv6(ctx)
- if err != nil {
- zap.S().Warnw("Cannot resolve public address", "error", err)
- } else {
- C.PublicIPv6.IP = ip
- foundAddress = true
- }
- }
-
- if !foundAddress {
- return errors.New("cannot resolve any public address")
- }
-
- return nil
- }
-
- func Printable() interface{} {
- data, err := json.Marshal(C)
- if err != nil {
- panic(err)
- }
-
- rv := map[string]interface{}{}
- if err := json.Unmarshal(data, &rv); err != nil {
- panic(err)
- }
-
- return rv
- }
|