From e732ba62a699240620d177ee994ac0ac24c3874b Mon Sep 17 00:00:00 2001 From: v2ray Date: Fri, 10 Jun 2016 22:26:39 +0200 Subject: [PATCH] unified config loader --- common/loader/json_conf.go | 61 ++++++++++++++++ common/loader/loader.go | 47 +++++++++++++ proxy/blackhole/blackhole.go | 9 +-- proxy/blackhole/config.go | 30 ++++++++ proxy/blackhole/config_json.go | 13 ++-- proxy/dokodemo/config_json.go | 42 +++++------ proxy/freedom/config_json.go | 11 +-- proxy/http/config_json.go | 9 +-- proxy/internal/config/config_cache.go | 53 -------------- proxy/internal/config/config_cache_test.go | 49 ------------- proxy/internal/config_cache.go | 24 +++++++ proxy/internal/config_cache_json.go | 12 ++++ proxy/internal/handler_cache.go | 5 +- proxy/shadowsocks/config_json.go | 7 +- proxy/socks/config_json.go | 81 +++++++++++----------- proxy/socks/config_json_test.go | 4 +- proxy/vmess/inbound/config_json.go | 9 +-- proxy/vmess/outbound/config_json.go | 10 +-- 18 files changed, 259 insertions(+), 217 deletions(-) create mode 100644 common/loader/json_conf.go create mode 100644 common/loader/loader.go delete mode 100644 proxy/internal/config/config_cache.go delete mode 100644 proxy/internal/config/config_cache_test.go create mode 100644 proxy/internal/config_cache.go create mode 100644 proxy/internal/config_cache_json.go diff --git a/common/loader/json_conf.go b/common/loader/json_conf.go new file mode 100644 index 000000000..1865ab610 --- /dev/null +++ b/common/loader/json_conf.go @@ -0,0 +1,61 @@ +// +build json + +package loader + +import ( + "encoding/json" + + "github.com/v2ray/v2ray-core/common/log" +) + +type JSONConfigLoader struct { + *BaseConfigLoader + idKey string + configKey string +} + +func NewJSONConfigLoader(idKey string, configKey string) *JSONConfigLoader { + return &JSONConfigLoader{ + idKey: idKey, + configKey: configKey, + BaseConfigLoader: NewBaseConfigLoader(), + } +} + +func (this *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) { + config, err := this.CreateConfig(id) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(raw, config); err != nil { + return nil, err + } + return config, nil +} + +func (this *JSONConfigLoader) Load(raw []byte) (interface{}, error) { + obj := make(map[string]json.RawMessage) + if err := json.Unmarshal(raw, obj); err != nil { + return nil, err + } + rawID, found := obj[this.idKey] + if !found { + log.Error(this.idKey, " not found in JSON content.") + return nil, ErrConfigIDKeyNotFound + } + var id string + if err := json.Unmarshal(rawID, id); err != nil { + return nil, err + } + rawConfig := json.RawMessage(raw) + if len(this.configKey) > 0 { + configValue, found := obj[this.configKey] + if !found { + log.Error(this.configKey, " not found in JSON content.") + return nil, ErrConfigIDKeyNotFound + } + rawConfig = configValue + } + return this.LoadWithID([]byte(rawConfig), id) +} diff --git a/common/loader/loader.go b/common/loader/loader.go new file mode 100644 index 000000000..e580ce748 --- /dev/null +++ b/common/loader/loader.go @@ -0,0 +1,47 @@ +package loader + +import ( + "errors" +) + +var ( + ErrConfigIDKeyNotFound = errors.New("Config ID key is not found.") + ErrConfigIDExists = errors.New("Config ID already exists.") + ErrUnknownConfigID = errors.New("Unknown config ID.") +) + +type ConfigCreator func() interface{} + +type ConfigLoader interface { + RegisterCreator(string, ConfigCreator) error + CreateConfig(string) (interface{}, error) + Load([]byte) (interface{}, error) + LoadWithID([]byte, string) (interface{}, error) +} + +type BaseConfigLoader struct { + creators map[string]ConfigCreator +} + +func NewBaseConfigLoader() *BaseConfigLoader { + return &BaseConfigLoader{ + creators: make(map[string]ConfigCreator), + } +} + +func (this *BaseConfigLoader) RegisterCreator(id string, creator ConfigCreator) error { + if _, found := this.creators[id]; found { + return ErrConfigIDExists + } + + this.creators[id] = creator + return nil +} + +func (this *BaseConfigLoader) CreateConfig(id string) (interface{}, error) { + creator, found := this.creators[id] + if !found { + return nil, ErrUnknownConfigID + } + return creator(), nil +} diff --git a/proxy/blackhole/blackhole.go b/proxy/blackhole/blackhole.go index 1aa013775..02202962e 100644 --- a/proxy/blackhole/blackhole.go +++ b/proxy/blackhole/blackhole.go @@ -11,22 +11,23 @@ import ( // BlackHole is an outbound connection that sliently swallow the entire payload. type BlackHole struct { - meta *proxy.OutboundHandlerMeta + meta *proxy.OutboundHandlerMeta + response Response } func NewBlackHole(space app.Space, config *Config, meta *proxy.OutboundHandlerMeta) *BlackHole { return &BlackHole{ - meta: meta, + meta: meta, + response: config.Response, } } func (this *BlackHole) Dispatch(destination v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { payload.Release() + this.response.WriteTo(ray.OutboundOutput()) ray.OutboundOutput().Close() - ray.OutboundOutput().Release() - ray.OutboundInput().Close() ray.OutboundInput().Release() return nil diff --git a/proxy/blackhole/config.go b/proxy/blackhole/config.go index e16ce9b4d..e24529124 100644 --- a/proxy/blackhole/config.go +++ b/proxy/blackhole/config.go @@ -1,4 +1,34 @@ package blackhole +import ( + "github.com/v2ray/v2ray-core/common/alloc" + v2io "github.com/v2ray/v2ray-core/common/io" +) + type Config struct { + Response Response +} + +type Response interface { + WriteTo(v2io.Writer) +} + +type NoneResponse struct{} + +func (this *NoneResponse) WriteTo(writer v2io.Writer) {} + +type HTTPResponse struct { +} + +const ( + http403response = `HTTP/1.1 403 Forbidden +Connection: close +Cache-Control: max-age=3600, public +Content-Length: 0 + +` +) + +func (this *HTTPResponse) WriteTo(writer v2io.Writer) { + writer.Write(alloc.NewSmallBuffer().Clear().AppendString(http403response)) } diff --git a/proxy/blackhole/config_json.go b/proxy/blackhole/config_json.go index 45a0a29c4..adbe642f1 100644 --- a/proxy/blackhole/config_json.go +++ b/proxy/blackhole/config_json.go @@ -3,12 +3,13 @@ package blackhole import ( - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" ) -func init() { - config.RegisterOutboundConfig("blackhole", - func(data []byte) (interface{}, error) { - return new(Config), nil - }) +func (this *Config) UnmarshalJSON(data []byte) error { + return nil +} + +func init() { + internal.RegisterOutboundConfig("blackhole", func() interface{} { return new(Config) }) } diff --git a/proxy/dokodemo/config_json.go b/proxy/dokodemo/config_json.go index eb7f0f5fb..d395a5842 100644 --- a/proxy/dokodemo/config_json.go +++ b/proxy/dokodemo/config_json.go @@ -6,27 +6,27 @@ import ( "encoding/json" v2net "github.com/v2ray/v2ray-core/common/net" - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" ) -func init() { - config.RegisterInboundConfig("dokodemo-door", - func(data []byte) (interface{}, error) { - type DokodemoConfig struct { - Host *v2net.AddressJson `json:"address"` - PortValue v2net.Port `json:"port"` - NetworkList *v2net.NetworkList `json:"network"` - TimeoutValue int `json:"timeout"` - } - rawConfig := new(DokodemoConfig) - if err := json.Unmarshal(data, rawConfig); err != nil { - return nil, err - } - return &Config{ - Address: rawConfig.Host.Address, - Port: rawConfig.PortValue, - Network: rawConfig.NetworkList, - Timeout: rawConfig.TimeoutValue, - }, nil - }) +func (this *Config) UnmarshalJSON(data []byte) error { + type DokodemoConfig struct { + Host *v2net.AddressJson `json:"address"` + PortValue v2net.Port `json:"port"` + NetworkList *v2net.NetworkList `json:"network"` + TimeoutValue int `json:"timeout"` + } + rawConfig := new(DokodemoConfig) + if err := json.Unmarshal(data, rawConfig); err != nil { + return err + } + this.Address = rawConfig.Host.Address + this.Port = rawConfig.PortValue + this.Network = rawConfig.NetworkList + this.Timeout = rawConfig.TimeoutValue + return nil +} + +func init() { + internal.RegisterInboundConfig("dokodemo-door", func() interface{} { return new(Config) }) } diff --git a/proxy/freedom/config_json.go b/proxy/freedom/config_json.go index f1d41b1c5..da8e589c1 100644 --- a/proxy/freedom/config_json.go +++ b/proxy/freedom/config_json.go @@ -6,7 +6,7 @@ import ( "encoding/json" "strings" - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" ) func (this *Config) UnmarshalJSON(data []byte) error { @@ -28,12 +28,5 @@ func (this *Config) UnmarshalJSON(data []byte) error { } func init() { - config.RegisterOutboundConfig("freedom", - func(data []byte) (interface{}, error) { - c := new(Config) - if err := json.Unmarshal(data, c); err != nil { - return nil, err - } - return c, nil - }) + internal.RegisterOutboundConfig("freedom", func() interface{} { return new(Config) }) } diff --git a/proxy/http/config_json.go b/proxy/http/config_json.go index 442373356..a77e9973d 100644 --- a/proxy/http/config_json.go +++ b/proxy/http/config_json.go @@ -6,7 +6,7 @@ import ( "crypto/tls" "encoding/json" - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" ) // UnmarshalJSON implements json.Unmarshaler @@ -62,10 +62,5 @@ func (this *Config) UnmarshalJSON(data []byte) error { } func init() { - config.RegisterInboundConfig("http", - func(data []byte) (interface{}, error) { - rawConfig := new(Config) - err := json.Unmarshal(data, rawConfig) - return rawConfig, err - }) + internal.RegisterInboundConfig("http", func() interface{} { return new(Config) }) } diff --git a/proxy/internal/config/config_cache.go b/proxy/internal/config/config_cache.go deleted file mode 100644 index bc35b5747..000000000 --- a/proxy/internal/config/config_cache.go +++ /dev/null @@ -1,53 +0,0 @@ -package config - -import ( - "errors" -) - -type ConfigObjectCreator func(data []byte) (interface{}, error) - -var ( - configCache map[string]ConfigObjectCreator -) - -func getConfigKey(protocol string, proxyType string) string { - return protocol + "_" + proxyType -} - -func registerConfigType(protocol string, proxyType string, creator ConfigObjectCreator) error { - // TODO: check name - configCache[getConfigKey(protocol, proxyType)] = creator - return nil -} - -func RegisterInboundConfig(protocol string, creator ConfigObjectCreator) error { - return registerConfigType(protocol, "inbound", creator) -} - -func RegisterOutboundConfig(protocol string, creator ConfigObjectCreator) error { - return registerConfigType(protocol, "outbound", creator) -} - -func CreateInboundConfig(protocol string, data []byte) (interface{}, error) { - creator, found := configCache[getConfigKey(protocol, "inbound")] - if !found { - return nil, errors.New(protocol + " not found.") - } - return creator(data) -} - -func CreateOutboundConfig(protocol string, data []byte) (interface{}, error) { - creator, found := configCache[getConfigKey(protocol, "outbound")] - if !found { - return nil, errors.New(protocol + " not found.") - } - return creator(data) -} - -func initializeConfigCache() { - configCache = make(map[string]ConfigObjectCreator) -} - -func init() { - initializeConfigCache() -} diff --git a/proxy/internal/config/config_cache_test.go b/proxy/internal/config/config_cache_test.go deleted file mode 100644 index 1c5066845..000000000 --- a/proxy/internal/config/config_cache_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package config - -import ( - "testing" - - "github.com/v2ray/v2ray-core/testing/assert" -) - -func TestRegisterInboundConfig(t *testing.T) { - assert := assert.On(t) - initializeConfigCache() - - protocol := "test_protocol" - creator := func([]byte) (interface{}, error) { - return true, nil - } - - err := RegisterInboundConfig(protocol, creator) - assert.Error(err).IsNil() - - configObj, err := CreateInboundConfig(protocol, nil) - assert.Bool(configObj.(bool)).IsTrue() - assert.Error(err).IsNil() - - configObj, err = CreateOutboundConfig(protocol, nil) - assert.Error(err).IsNotNil() - assert.Pointer(configObj).IsNil() -} - -func TestRegisterOutboundConfig(t *testing.T) { - assert := assert.On(t) - initializeConfigCache() - - protocol := "test_protocol" - creator := func([]byte) (interface{}, error) { - return true, nil - } - - err := RegisterOutboundConfig(protocol, creator) - assert.Error(err).IsNil() - - configObj, err := CreateOutboundConfig(protocol, nil) - assert.Bool(configObj.(bool)).IsTrue() - assert.Error(err).IsNil() - - configObj, err = CreateInboundConfig(protocol, nil) - assert.Error(err).IsNotNil() - assert.Pointer(configObj).IsNil() -} diff --git a/proxy/internal/config_cache.go b/proxy/internal/config_cache.go new file mode 100644 index 000000000..129a8bc91 --- /dev/null +++ b/proxy/internal/config_cache.go @@ -0,0 +1,24 @@ +package internal + +import "github.com/v2ray/v2ray-core/common/loader" + +var ( + inboundConfigCache loader.ConfigLoader + outboundConfigCache loader.ConfigLoader +) + +func RegisterInboundConfig(protocol string, creator loader.ConfigCreator) error { + return inboundConfigCache.RegisterCreator(protocol, creator) +} + +func RegisterOutboundConfig(protocol string, creator loader.ConfigCreator) error { + return outboundConfigCache.RegisterCreator(protocol, creator) +} + +func CreateInboundConfig(protocol string, data []byte) (interface{}, error) { + return inboundConfigCache.LoadWithID(data, protocol) +} + +func CreateOutboundConfig(protocol string, data []byte) (interface{}, error) { + return outboundConfigCache.LoadWithID(data, protocol) +} diff --git a/proxy/internal/config_cache_json.go b/proxy/internal/config_cache_json.go new file mode 100644 index 000000000..17c0e2652 --- /dev/null +++ b/proxy/internal/config_cache_json.go @@ -0,0 +1,12 @@ +// +build json + +package internal + +import ( + "github.com/v2ray/v2ray-core/common/loader" +) + +func init() { + inboundConfigCache = loader.NewJSONConfigLoader("protocol", "settings") + outboundConfigCache = loader.NewJSONConfigLoader("protocol", "settings") +} diff --git a/proxy/internal/handler_cache.go b/proxy/internal/handler_cache.go index 2eae3322c..b016a1ffc 100644 --- a/proxy/internal/handler_cache.go +++ b/proxy/internal/handler_cache.go @@ -5,7 +5,6 @@ import ( "github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/proxy" - "github.com/v2ray/v2ray-core/proxy/internal/config" ) var ( @@ -51,7 +50,7 @@ func CreateInboundHandler(name string, space app.Space, rawConfig []byte, meta * return nil, ErrorProxyNotFound } if len(rawConfig) > 0 { - proxyConfig, err := config.CreateInboundConfig(name, rawConfig) + proxyConfig, err := CreateInboundConfig(name, rawConfig) if err != nil { return nil, err } @@ -67,7 +66,7 @@ func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, meta } if len(rawConfig) > 0 { - proxyConfig, err := config.CreateOutboundConfig(name, rawConfig) + proxyConfig, err := CreateOutboundConfig(name, rawConfig) if err != nil { return nil, err } diff --git a/proxy/shadowsocks/config_json.go b/proxy/shadowsocks/config_json.go index 865fa3a20..a62451e94 100644 --- a/proxy/shadowsocks/config_json.go +++ b/proxy/shadowsocks/config_json.go @@ -9,7 +9,6 @@ import ( "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/protocol" "github.com/v2ray/v2ray-core/proxy/internal" - "github.com/v2ray/v2ray-core/proxy/internal/config" ) func (this *Config) UnmarshalJSON(data []byte) error { @@ -62,9 +61,5 @@ func (this *Config) UnmarshalJSON(data []byte) error { } func init() { - config.RegisterInboundConfig("shadowsocks", func(data []byte) (interface{}, error) { - rawConfig := new(Config) - err := json.Unmarshal(data, rawConfig) - return rawConfig, err - }) + internal.RegisterInboundConfig("shadowsocks", func() interface{} { return new(Config) }) } diff --git a/proxy/socks/config_json.go b/proxy/socks/config_json.go index bcbcf5ed7..e2dbeba87 100644 --- a/proxy/socks/config_json.go +++ b/proxy/socks/config_json.go @@ -8,7 +8,6 @@ import ( "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" "github.com/v2ray/v2ray-core/proxy/internal" - "github.com/v2ray/v2ray-core/proxy/internal/config" ) const ( @@ -16,48 +15,48 @@ const ( AuthMethodUserPass = "password" ) -func init() { - config.RegisterInboundConfig("socks", - func(data []byte) (interface{}, error) { - type SocksAccount struct { - Username string `json:"user"` - Password string `json:"pass"` - } +func (this *Config) UnmarshalJSON(data []byte) error { + type SocksAccount struct { + Username string `json:"user"` + Password string `json:"pass"` + } - type SocksConfig struct { - AuthMethod string `json:"auth"` - Accounts []*SocksAccount `json:"accounts"` - UDP bool `json:"udp"` - Host *v2net.AddressJson `json:"ip"` - } + type SocksConfig struct { + AuthMethod string `json:"auth"` + Accounts []*SocksAccount `json:"accounts"` + UDP bool `json:"udp"` + Host *v2net.AddressJson `json:"ip"` + } - rawConfig := new(SocksConfig) - if err := json.Unmarshal(data, rawConfig); err != nil { - return nil, err - } - socksConfig := new(Config) - if rawConfig.AuthMethod == AuthMethodNoAuth { - socksConfig.AuthType = AuthTypeNoAuth - } else if rawConfig.AuthMethod == AuthMethodUserPass { - socksConfig.AuthType = AuthTypePassword - } else { - log.Error("Socks: Unknown auth method: ", rawConfig.AuthMethod) - return nil, internal.ErrorBadConfiguration - } + rawConfig := new(SocksConfig) + if err := json.Unmarshal(data, rawConfig); err != nil { + return err + } + if rawConfig.AuthMethod == AuthMethodNoAuth { + this.AuthType = AuthTypeNoAuth + } else if rawConfig.AuthMethod == AuthMethodUserPass { + this.AuthType = AuthTypePassword + } else { + log.Error("Socks: Unknown auth method: ", rawConfig.AuthMethod) + return internal.ErrorBadConfiguration + } - if len(rawConfig.Accounts) > 0 { - socksConfig.Accounts = make(map[string]string, len(rawConfig.Accounts)) - for _, account := range rawConfig.Accounts { - socksConfig.Accounts[account.Username] = account.Password - } - } + if len(rawConfig.Accounts) > 0 { + this.Accounts = make(map[string]string, len(rawConfig.Accounts)) + for _, account := range rawConfig.Accounts { + this.Accounts[account.Username] = account.Password + } + } - socksConfig.UDPEnabled = rawConfig.UDP - if rawConfig.Host != nil { - socksConfig.Address = rawConfig.Host.Address - } else { - socksConfig.Address = v2net.LocalHostIP - } - return socksConfig, nil - }) + this.UDPEnabled = rawConfig.UDP + if rawConfig.Host != nil { + this.Address = rawConfig.Host.Address + } else { + this.Address = v2net.LocalHostIP + } + return nil +} + +func init() { + internal.RegisterInboundConfig("socks", func() interface{} { return new(Config) }) } diff --git a/proxy/socks/config_json_test.go b/proxy/socks/config_json_test.go index c392f0ef8..0b13126a4 100644 --- a/proxy/socks/config_json_test.go +++ b/proxy/socks/config_json_test.go @@ -5,7 +5,7 @@ package socks_test import ( "testing" - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" "github.com/v2ray/v2ray-core/proxy/socks" "github.com/v2ray/v2ray-core/testing/assert" ) @@ -13,7 +13,7 @@ import ( func TestDefaultIPAddress(t *testing.T) { assert := assert.On(t) - socksConfig, err := config.CreateInboundConfig("socks", []byte(`{ + socksConfig, err := internal.CreateInboundConfig("socks", []byte(`{ "auth": "noauth" }`)) assert.Error(err).IsNil() diff --git a/proxy/vmess/inbound/config_json.go b/proxy/vmess/inbound/config_json.go index 03f78adbf..79af526cd 100644 --- a/proxy/vmess/inbound/config_json.go +++ b/proxy/vmess/inbound/config_json.go @@ -6,7 +6,7 @@ import ( "encoding/json" "github.com/v2ray/v2ray-core/common/protocol" - "github.com/v2ray/v2ray-core/proxy/internal/config" + "github.com/v2ray/v2ray-core/proxy/internal" ) func (this *DetourConfig) UnmarshalJSON(data []byte) error { @@ -79,10 +79,5 @@ func (this *Config) UnmarshalJSON(data []byte) error { } func init() { - config.RegisterInboundConfig("vmess", - func(data []byte) (interface{}, error) { - config := new(Config) - err := json.Unmarshal(data, config) - return config, err - }) + internal.RegisterInboundConfig("vmess", func() interface{} { return new(Config) }) } diff --git a/proxy/vmess/outbound/config_json.go b/proxy/vmess/outbound/config_json.go index fa697e2e3..06f23d7ef 100644 --- a/proxy/vmess/outbound/config_json.go +++ b/proxy/vmess/outbound/config_json.go @@ -7,7 +7,6 @@ import ( "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/proxy/internal" - proxyconfig "github.com/v2ray/v2ray-core/proxy/internal/config" ) func (this *Config) UnmarshalJSON(data []byte) error { @@ -28,12 +27,5 @@ func (this *Config) UnmarshalJSON(data []byte) error { } func init() { - proxyconfig.RegisterOutboundConfig("vmess", - func(data []byte) (interface{}, error) { - rawConfig := new(Config) - if err := json.Unmarshal(data, rawConfig); err != nil { - return nil, err - } - return rawConfig, nil - }) + internal.RegisterOutboundConfig("vmess", func() interface{} { return new(Config) }) }