diff --git a/tools/conf/blackhole.go b/tools/conf/blackhole.go deleted file mode 100644 index 6f435e1f..00000000 --- a/tools/conf/blackhole.go +++ /dev/null @@ -1,51 +0,0 @@ -package conf - -import ( - "encoding/json" - - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/blackhole" -) - -type NoneResponse struct{} - -func (*NoneResponse) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(blackhole.NoneResponse)), nil -} - -type HttpResponse struct{} - -func (*HttpResponse) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(blackhole.HTTPResponse)), nil -} - -type BlackholeConfig struct { - Response json.RawMessage `json:"response"` -} - -func (v *BlackholeConfig) Build() (*serial.TypedMessage, error) { - config := new(blackhole.Config) - if v.Response != nil { - response, _, err := configLoader.Load(v.Response) - if err != nil { - return nil, newError("Config: Failed to parse Blackhole response config.").Base(err) - } - responseSettings, err := response.(Buildable).Build() - if err != nil { - return nil, err - } - config.Response = responseSettings - } - - return serial.ToTypedMessage(config), nil -} - -var ( - configLoader = NewJSONConfigLoader( - ConfigCreatorCache{ - "none": func() interface{} { return new(NoneResponse) }, - "http": func() interface{} { return new(HttpResponse) }, - }, - "type", - "") -) diff --git a/tools/conf/blackhole_test.go b/tools/conf/blackhole_test.go deleted file mode 100644 index df45df90..00000000 --- a/tools/conf/blackhole_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - "v2ray.com/core/proxy/blackhole" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestHTTPResponseJSON(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "response": { - "type": "http" - } - }` - rawConfig := new(BlackholeConfig) - err := json.Unmarshal([]byte(rawJson), rawConfig) - assert.Error(err).IsNil() - - ts, err := rawConfig.Build() - assert.Error(err).IsNil() - iConfig, err := ts.GetInstance() - assert.Error(err).IsNil() - config := iConfig.(*blackhole.Config) - response, err := config.GetInternalResponse() - assert.Error(err).IsNil() - - _, ok := response.(*blackhole.HTTPResponse) - assert.Bool(ok).IsTrue() -} diff --git a/tools/conf/builable.go b/tools/conf/builable.go deleted file mode 100644 index 32b14a7b..00000000 --- a/tools/conf/builable.go +++ /dev/null @@ -1,9 +0,0 @@ -package conf - -import ( - "v2ray.com/core/common/serial" -) - -type Buildable interface { - Build() (*serial.TypedMessage, error) -} diff --git a/tools/conf/common.go b/tools/conf/common.go deleted file mode 100644 index ac3873d2..00000000 --- a/tools/conf/common.go +++ /dev/null @@ -1,178 +0,0 @@ -package conf - -import ( - "encoding/json" - "strings" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/protocol" -) - -type StringList []string - -func NewStringList(raw []string) *StringList { - list := StringList(raw) - return &list -} - -func (v StringList) Len() int { - return len(v) -} - -func (v *StringList) UnmarshalJSON(data []byte) error { - var strarray []string - if err := json.Unmarshal(data, &strarray); err == nil { - *v = *NewStringList(strarray) - return nil - } - - var rawstr string - if err := json.Unmarshal(data, &rawstr); err == nil { - strlist := strings.Split(rawstr, ",") - *v = *NewStringList(strlist) - return nil - } - return newError("unknown format of a string list: " + string(data)) -} - -type Address struct { - v2net.Address -} - -func (v *Address) UnmarshalJSON(data []byte) error { - var rawStr string - if err := json.Unmarshal(data, &rawStr); err != nil { - return err - } - v.Address = v2net.ParseAddress(rawStr) - - return nil -} - -func (v *Address) Build() *v2net.IPOrDomain { - return v2net.NewIPOrDomain(v.Address) -} - -type Network string - -func (v Network) Build() v2net.Network { - return v2net.ParseNetwork(string(v)) -} - -type NetworkList []Network - -func (v *NetworkList) UnmarshalJSON(data []byte) error { - var strarray []Network - if err := json.Unmarshal(data, &strarray); err == nil { - nl := NetworkList(strarray) - *v = nl - return nil - } - - var rawstr Network - if err := json.Unmarshal(data, &rawstr); err == nil { - strlist := strings.Split(string(rawstr), ",") - nl := make([]Network, len(strlist)) - for idx, network := range strlist { - nl[idx] = Network(network) - } - *v = nl - return nil - } - return newError("unknown format of a string list: " + string(data)) -} - -func (v *NetworkList) Build() *v2net.NetworkList { - if v == nil { - return &v2net.NetworkList{ - Network: []v2net.Network{v2net.Network_TCP}, - } - } - - list := new(v2net.NetworkList) - for _, network := range *v { - list.Network = append(list.Network, network.Build()) - } - return list -} - -func parseIntPort(data []byte) (v2net.Port, error) { - var intPort uint32 - err := json.Unmarshal(data, &intPort) - if err != nil { - return v2net.Port(0), err - } - return v2net.PortFromInt(intPort) -} - -func parseStringPort(data []byte) (v2net.Port, v2net.Port, error) { - var s string - err := json.Unmarshal(data, &s) - if err != nil { - return v2net.Port(0), v2net.Port(0), err - } - pair := strings.SplitN(s, "-", 2) - if len(pair) == 0 { - return v2net.Port(0), v2net.Port(0), newError("Config: Invalid port range: ", s) - } - if len(pair) == 1 { - port, err := v2net.PortFromString(pair[0]) - return port, port, err - } - - fromPort, err := v2net.PortFromString(pair[0]) - if err != nil { - return v2net.Port(0), v2net.Port(0), err - } - toPort, err := v2net.PortFromString(pair[1]) - if err != nil { - return v2net.Port(0), v2net.Port(0), err - } - return fromPort, toPort, nil -} - -type PortRange struct { - From uint32 - To uint32 -} - -func (v *PortRange) Build() *v2net.PortRange { - return &v2net.PortRange{ - From: v.From, - To: v.To, - } -} - -// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON -func (v *PortRange) UnmarshalJSON(data []byte) error { - port, err := parseIntPort(data) - if err == nil { - v.From = uint32(port) - v.To = uint32(port) - return nil - } - - from, to, err := parseStringPort(data) - if err == nil { - v.From = uint32(from) - v.To = uint32(to) - if v.From > v.To { - return newError("invalid port range ", v.From, " -> ", v.To) - } - return nil - } - - return newError("invalid port range: ", string(data)) -} - -type User struct { - EmailString string `json:"email"` - LevelByte byte `json:"level"` -} - -func (v *User) Build() *protocol.User { - return &protocol.User{ - Email: v.EmailString, - Level: uint32(v.LevelByte), - } -} diff --git a/tools/conf/common_test.go b/tools/conf/common_test.go deleted file mode 100644 index c8076e0d..00000000 --- a/tools/conf/common_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestStringListUnmarshalError(t *testing.T) { - assert := assert.On(t) - - rawJson := `1234` - list := new(StringList) - err := json.Unmarshal([]byte(rawJson), list) - assert.Error(err).IsNotNil() -} - -func TestStringListLen(t *testing.T) { - assert := assert.On(t) - - rawJson := `"a, b, c, d"` - list := new(StringList) - err := json.Unmarshal([]byte(rawJson), list) - assert.Error(err).IsNil() - assert.Int(list.Len()).Equals(4) -} - -func TestIPParsing(t *testing.T) { - assert := assert.On(t) - - rawJson := "\"8.8.8.8\"" - var address Address - err := json.Unmarshal([]byte(rawJson), &address) - assert.Error(err).IsNil() - assert.Bytes([]byte(address.IP())).Equals([]byte{8, 8, 8, 8}) -} - -func TestDomainParsing(t *testing.T) { - assert := assert.On(t) - - rawJson := "\"v2ray.com\"" - var address Address - err := json.Unmarshal([]byte(rawJson), &address) - assert.Error(err).IsNil() - assert.String(address.Domain()).Equals("v2ray.com") -} - -func TestInvalidAddressJson(t *testing.T) { - assert := assert.On(t) - - rawJson := "1234" - var address Address - err := json.Unmarshal([]byte(rawJson), &address) - assert.Error(err).IsNotNil() -} - -func TestStringNetwork(t *testing.T) { - assert := assert.On(t) - - var network Network - err := json.Unmarshal([]byte(`"tcp"`), &network) - assert.Error(err).IsNil() - assert.Bool(network.Build() == v2net.Network_TCP).IsTrue() -} - -func TestArrayNetworkList(t *testing.T) { - assert := assert.On(t) - - var list NetworkList - err := json.Unmarshal([]byte("[\"Tcp\"]"), &list) - assert.Error(err).IsNil() - - nlist := list.Build() - assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("tcp"))).IsTrue() - assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("udp"))).IsFalse() -} - -func TestStringNetworkList(t *testing.T) { - assert := assert.On(t) - - var list NetworkList - err := json.Unmarshal([]byte("\"TCP, ip\""), &list) - assert.Error(err).IsNil() - - nlist := list.Build() - assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("tcp"))).IsTrue() - assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("udp"))).IsFalse() -} - -func TestInvalidNetworkJson(t *testing.T) { - assert := assert.On(t) - - var list NetworkList - err := json.Unmarshal([]byte("0"), &list) - assert.Error(err).IsNotNil() -} - -func TestIntPort(t *testing.T) { - assert := assert.On(t) - - var portRange PortRange - err := json.Unmarshal([]byte("1234"), &portRange) - assert.Error(err).IsNil() - - assert.Uint32(portRange.From).Equals(1234) - assert.Uint32(portRange.To).Equals(1234) -} - -func TestOverRangeIntPort(t *testing.T) { - assert := assert.On(t) - - var portRange PortRange - err := json.Unmarshal([]byte("70000"), &portRange) - assert.Error(err).IsNotNil() - - err = json.Unmarshal([]byte("-1"), &portRange) - assert.Error(err).IsNotNil() -} - -func TestSingleStringPort(t *testing.T) { - assert := assert.On(t) - - var portRange PortRange - err := json.Unmarshal([]byte("\"1234\""), &portRange) - assert.Error(err).IsNil() - - assert.Uint32(portRange.From).Equals(1234) - assert.Uint32(portRange.To).Equals(1234) -} - -func TestStringPairPort(t *testing.T) { - assert := assert.On(t) - - var portRange PortRange - err := json.Unmarshal([]byte("\"1234-5678\""), &portRange) - assert.Error(err).IsNil() - - assert.Uint32(portRange.From).Equals(1234) - assert.Uint32(portRange.To).Equals(5678) -} - -func TestOverRangeStringPort(t *testing.T) { - assert := assert.On(t) - - var portRange PortRange - err := json.Unmarshal([]byte("\"65536\""), &portRange) - assert.Error(err).IsNotNil() - - err = json.Unmarshal([]byte("\"70000-80000\""), &portRange) - assert.Error(err).IsNotNil() - - err = json.Unmarshal([]byte("\"1-90000\""), &portRange) - assert.Error(err).IsNotNil() - - err = json.Unmarshal([]byte("\"700-600\""), &portRange) - assert.Error(err).IsNotNil() -} - -func TestUserParsing(t *testing.T) { - assert := assert.On(t) - - user := new(User) - err := json.Unmarshal([]byte(`{ - "id": "96edb838-6d68-42ef-a933-25f7ac3a9d09", - "email": "love@v2ray.com", - "level": 1, - "alterId": 100 - }`), user) - assert.Error(err).IsNil() - - nUser := user.Build() - assert.Byte(byte(nUser.Level)).Equals(1) - assert.String(nUser.Email).Equals("love@v2ray.com") -} - -func TestInvalidUserJson(t *testing.T) { - assert := assert.On(t) - - user := new(User) - err := json.Unmarshal([]byte(`{"email": 1234}`), user) - assert.Error(err).IsNotNil() -} diff --git a/tools/conf/conf.go b/tools/conf/conf.go index 3c625a90..9e1693d5 100644 --- a/tools/conf/conf.go +++ b/tools/conf/conf.go @@ -1,3 +1,16 @@ package conf +import ( + "io" + + "v2ray.com/core" + jsonconf "v2ray.com/ext/tools/conf/serial" +) + //go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg conf -path Tools,Conf + +func init() { + core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) { + return jsonconf.LoadJSONConfig(input) + }) +} diff --git a/tools/conf/dns.go b/tools/conf/dns.go deleted file mode 100644 index 50ebb9e3..00000000 --- a/tools/conf/dns.go +++ /dev/null @@ -1,32 +0,0 @@ -package conf - -import ( - "v2ray.com/core/app/dns" - v2net "v2ray.com/core/common/net" -) - -type DnsConfig struct { - Servers []*Address `json:"servers"` - Hosts map[string]*Address `json:"hosts"` -} - -func (v *DnsConfig) Build() *dns.Config { - config := new(dns.Config) - config.NameServers = make([]*v2net.Endpoint, len(v.Servers)) - for idx, server := range v.Servers { - config.NameServers[idx] = &v2net.Endpoint{ - Network: v2net.Network_UDP, - Address: server.Build(), - Port: 53, - } - } - - if v.Hosts != nil { - config.Hosts = make(map[string]*v2net.IPOrDomain) - for domain, ip := range v.Hosts { - config.Hosts[domain] = ip.Build() - } - } - - return config -} diff --git a/tools/conf/dns_test.go b/tools/conf/dns_test.go deleted file mode 100644 index 8ed9335d..00000000 --- a/tools/conf/dns_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestDnsConfigParsing(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "servers": ["8.8.8.8"] - }` - - jsonConfig := new(DnsConfig) - err := json.Unmarshal([]byte(rawJson), jsonConfig) - assert.Error(err).IsNil() - - config := jsonConfig.Build() - assert.Int(len(config.NameServers)).Equals(1) - dest := config.NameServers[0].AsDestination() - assert.Destination(dest).IsUDP() - assert.Address(dest.Address).Equals(v2net.IPAddress([]byte{8, 8, 8, 8})) - assert.Port(dest.Port).Equals(v2net.Port(53)) -} diff --git a/tools/conf/dokodemo.go b/tools/conf/dokodemo.go deleted file mode 100644 index 374a7193..00000000 --- a/tools/conf/dokodemo.go +++ /dev/null @@ -1,26 +0,0 @@ -package conf - -import ( - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/dokodemo" -) - -type DokodemoConfig struct { - Host *Address `json:"address"` - PortValue uint16 `json:"port"` - NetworkList *NetworkList `json:"network"` - TimeoutValue uint32 `json:"timeout"` - Redirect bool `json:"followRedirect"` -} - -func (v *DokodemoConfig) Build() (*serial.TypedMessage, error) { - config := new(dokodemo.Config) - if v.Host != nil { - config.Address = v.Host.Build() - } - config.Port = uint32(v.PortValue) - config.NetworkList = v.NetworkList.Build() - config.Timeout = v.TimeoutValue - config.FollowRedirect = v.Redirect - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/freedom.go b/tools/conf/freedom.go deleted file mode 100644 index 18ceae64..00000000 --- a/tools/conf/freedom.go +++ /dev/null @@ -1,50 +0,0 @@ -package conf - -import ( - "net" - "strings" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/protocol" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/freedom" -) - -type FreedomConfig struct { - DomainStrategy string `json:"domainStrategy"` - Timeout *uint32 `json:"timeout"` - Redirect string `json:"redirect"` -} - -func (v *FreedomConfig) Build() (*serial.TypedMessage, error) { - config := new(freedom.Config) - config.DomainStrategy = freedom.Config_AS_IS - domainStrategy := strings.ToLower(v.DomainStrategy) - if domainStrategy == "useip" || domainStrategy == "use_ip" { - config.DomainStrategy = freedom.Config_USE_IP - } - config.Timeout = 600 - if v.Timeout != nil { - config.Timeout = *v.Timeout - } - if len(v.Redirect) > 0 { - host, portStr, err := net.SplitHostPort(v.Redirect) - if err != nil { - return nil, newError("invalid redirect address: ", v.Redirect, ": ", err).Base(err) - } - port, err := v2net.PortFromString(portStr) - if err != nil { - return nil, newError("invalid redirect port: ", v.Redirect, ": ", err).Base(err) - } - if len(host) == 0 { - host = "127.0.0.1" - } - config.DestinationOverride = &freedom.DestinationOverride{ - Server: &protocol.ServerEndpoint{ - Address: v2net.NewIPOrDomain(v2net.ParseAddress(host)), - Port: uint32(port), - }, - } - } - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/http.go b/tools/conf/http.go deleted file mode 100644 index f788602d..00000000 --- a/tools/conf/http.go +++ /dev/null @@ -1,18 +0,0 @@ -package conf - -import ( - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/http" -) - -type HttpServerConfig struct { - Timeout uint32 `json:"timeout"` -} - -func (v *HttpServerConfig) Build() (*serial.TypedMessage, error) { - config := &http.ServerConfig{ - Timeout: v.Timeout, - } - - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/json/reader.go b/tools/conf/json/reader.go deleted file mode 100644 index a93646ff..00000000 --- a/tools/conf/json/reader.go +++ /dev/null @@ -1,115 +0,0 @@ -package json - -import ( - "io" -) - -// State is the internal state of parser. -type State byte - -const ( - StateContent State = iota - StateEscape - StateDoubleQuote - StateDoubleQuoteEscape - StateSingleQuote - StateSingleQuoteEscape - StateComment - StateSlash - StateMultilineComment - StateMultilineCommentStar -) - -// Reader is a JSON reader which allows comments. -type Reader struct { - io.Reader - state State -} - -// Read implements io.Reader.Read(). -func (v *Reader) Read(b []byte) (int, error) { - n, err := v.Reader.Read(b) - if err != nil { - return n, err - } - p := b[:0] - for _, x := range b[:n] { - switch v.state { - case StateContent: - switch x { - case '"': - v.state = StateDoubleQuote - p = append(p, x) - case '\'': - v.state = StateSingleQuote - p = append(p, x) - case '\\': - v.state = StateEscape - case '#': - v.state = StateComment - case '/': - v.state = StateSlash - default: - p = append(p, x) - } - case StateEscape: - p = append(p, '\\', x) - v.state = StateContent - case StateDoubleQuote: - switch x { - case '"': - v.state = StateContent - p = append(p, x) - case '\\': - v.state = StateDoubleQuoteEscape - default: - p = append(p, x) - } - case StateDoubleQuoteEscape: - p = append(p, '\\', x) - v.state = StateDoubleQuote - case StateSingleQuote: - switch x { - case '\'': - v.state = StateContent - p = append(p, x) - case '\\': - v.state = StateSingleQuoteEscape - default: - p = append(p, x) - } - case StateSingleQuoteEscape: - p = append(p, '\\', x) - v.state = StateSingleQuote - case StateComment: - if x == '\n' { - v.state = StateContent - } - case StateSlash: - switch x { - case '/': - v.state = StateComment - case '*': - v.state = StateMultilineComment - default: - p = append(p, '/', x) - } - case StateMultilineComment: - if x == '*' { - v.state = StateMultilineCommentStar - } - case StateMultilineCommentStar: - switch x { - case '/': - v.state = StateContent - case '*': - // Stay - default: - v.state = StateMultilineComment - } - default: - panic("Unknown state.") - } - } - return len(p), nil -} diff --git a/tools/conf/json/reader_test.go b/tools/conf/json/reader_test.go deleted file mode 100644 index 187e8ae2..00000000 --- a/tools/conf/json/reader_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package json_test - -import ( - "testing" - - "bytes" - - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf/json" -) - -func TestReader(t *testing.T) { - assert := assert.On(t) - - data := []struct { - input string - output string - }{ - { - ` -content #comment 1 -#comment 2 -content 2`, - ` -content content 2`}, - {`content`, `content`}, - {" ", " "}, - {`con/*abcd*/tent`, "content"}, - {` -text // adlkhdf /* -//comment adfkj -text 2*/`, ` -text text 2*`}, - {`"//"content`, `"//"content`}, - {`abcd'//'abcd`, `abcd'//'abcd`}, - {`"\""`, `"\""`}, - {`\"/*abcd*/\"`, `\"\"`}, - } - - for _, testCase := range data { - reader := &Reader{ - Reader: bytes.NewReader([]byte(testCase.input)), - } - - actual := make([]byte, 1024) - n, err := reader.Read(actual) - assert.Error(err).IsNil() - assert.String(string(actual[:n])).Equals(testCase.output) - } -} diff --git a/tools/conf/loader.go b/tools/conf/loader.go deleted file mode 100644 index 5b971214..00000000 --- a/tools/conf/loader.go +++ /dev/null @@ -1,79 +0,0 @@ -package conf - -import "encoding/json" - -type ConfigCreator func() interface{} - -type ConfigCreatorCache map[string]ConfigCreator - -func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error { - if _, found := v[id]; found { - return newError(id, " already registered.").AtError() - } - - v[id] = creator - return nil -} - -func (v ConfigCreatorCache) CreateConfig(id string) (interface{}, error) { - creator, found := v[id] - if !found { - return nil, newError("unknown config id: ", id) - } - return creator(), nil -} - -type JSONConfigLoader struct { - cache ConfigCreatorCache - idKey string - configKey string -} - -func NewJSONConfigLoader(cache ConfigCreatorCache, idKey string, configKey string) *JSONConfigLoader { - return &JSONConfigLoader{ - idKey: idKey, - configKey: configKey, - cache: cache, - } -} - -func (v *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) { - creator, found := v.cache[id] - if !found { - return nil, newError("unknown config id: ", id).AtError() - } - - config := creator() - if err := json.Unmarshal(raw, config); err != nil { - return nil, err - } - return config, nil -} - -func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) { - var obj map[string]json.RawMessage - if err := json.Unmarshal(raw, &obj); err != nil { - return nil, "", err - } - rawID, found := obj[v.idKey] - if !found { - return nil, "", newError(v.idKey, " not found in JSON context").AtError() - } - var id string - if err := json.Unmarshal(rawID, &id); err != nil { - return nil, "", err - } - rawConfig := json.RawMessage(raw) - if len(v.configKey) > 0 { - configValue, found := obj[v.configKey] - if !found { - return nil, "", newError(v.configKey, " not found in JSON content").AtError() - } - rawConfig = configValue - } - config, err := v.LoadWithID([]byte(rawConfig), id) - if err != nil { - return nil, id, err - } - return config, id, nil -} diff --git a/tools/conf/log.go b/tools/conf/log.go deleted file mode 100644 index 105f7bfc..00000000 --- a/tools/conf/log.go +++ /dev/null @@ -1,48 +0,0 @@ -package conf - -import ( - "strings" - - "v2ray.com/core/app/log" -) - -type LogConfig struct { - AccessLog string `json:"access"` - ErrorLog string `json:"error"` - LogLevel string `json:"loglevel"` -} - -func (v *LogConfig) Build() *log.Config { - if v == nil { - return nil - } - config := &log.Config{ - ErrorLogType: log.LogType_Console, - AccessLogType: log.LogType_Console, - } - - if len(v.AccessLog) > 0 { - config.AccessLogPath = v.AccessLog - config.AccessLogType = log.LogType_File - } - if len(v.ErrorLog) > 0 { - config.ErrorLogPath = v.ErrorLog - config.ErrorLogType = log.LogType_File - } - - level := strings.ToLower(v.LogLevel) - switch level { - case "debug": - config.ErrorLogLevel = log.LogLevel_Debug - case "info": - config.ErrorLogLevel = log.LogLevel_Info - case "error": - config.ErrorLogLevel = log.LogLevel_Error - case "none": - config.ErrorLogType = log.LogType_None - config.AccessLogType = log.LogType_None - default: - config.ErrorLogLevel = log.LogLevel_Warning - } - return config -} diff --git a/tools/conf/router.go b/tools/conf/router.go deleted file mode 100644 index b30452dd..00000000 --- a/tools/conf/router.go +++ /dev/null @@ -1,241 +0,0 @@ -package conf - -import ( - "encoding/json" - "strconv" - "strings" - - "v2ray.com/core/app/log" - "v2ray.com/core/app/router" - v2net "v2ray.com/core/common/net" - "v2ray.com/core/tools/geoip" - - "github.com/golang/protobuf/proto" -) - -type RouterRulesConfig struct { - RuleList []json.RawMessage `json:"rules"` - DomainStrategy string `json:"domainStrategy"` -} - -type RouterConfig struct { - Settings *RouterRulesConfig `json:"settings"` -} - -func (c *RouterConfig) Build() (*router.Config, error) { - if c.Settings == nil { - return nil, newError("Router settings is not specified.") - } - config := new(router.Config) - - settings := c.Settings - config.DomainStrategy = router.Config_AsIs - config.Rule = make([]*router.RoutingRule, len(settings.RuleList)) - domainStrategy := strings.ToLower(settings.DomainStrategy) - if domainStrategy == "alwaysip" { - config.DomainStrategy = router.Config_UseIp - } else if domainStrategy == "ipifnonmatch" { - config.DomainStrategy = router.Config_IpIfNonMatch - } - for idx, rawRule := range settings.RuleList { - rule, err := ParseRule(rawRule) - if err != nil { - return nil, err - } - config.Rule[idx] = rule - } - return config, nil -} - -type RouterRule struct { - Type string `json:"type"` - OutboundTag string `json:"outboundTag"` -} - -func parseIP(s string) (*router.CIDR, error) { - var addr, mask string - i := strings.Index(s, "/") - if i < 0 { - addr = s - } else { - addr = s[:i] - mask = s[i+1:] - } - ip := v2net.ParseAddress(addr) - switch ip.Family() { - case v2net.AddressFamilyIPv4: - bits := uint32(32) - if len(mask) > 0 { - bits64, err := strconv.ParseUint(mask, 10, 32) - if err != nil { - return nil, newError("invalid network mask for router: ", mask).Base(err) - } - bits = uint32(bits64) - } - if bits > 32 { - return nil, newError("invalid network mask for router: ", bits) - } - return &router.CIDR{ - Ip: []byte(ip.IP()), - Prefix: bits, - }, nil - case v2net.AddressFamilyIPv6: - bits := uint32(128) - if len(mask) > 0 { - bits64, err := strconv.ParseUint(mask, 10, 32) - if err != nil { - return nil, newError("invalid network mask for router: ", mask).Base(err) - } - bits = uint32(bits64) - } - if bits > 128 { - return nil, newError("invalid network mask for router: ", bits) - } - return &router.CIDR{ - Ip: []byte(ip.IP()), - Prefix: bits, - }, nil - default: - return nil, newError("unsupported address for router: ", s) - } -} - -func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) { - type RawFieldRule struct { - RouterRule - Domain *StringList `json:"domain"` - IP *StringList `json:"ip"` - Port *PortRange `json:"port"` - Network *NetworkList `json:"network"` - SourceIP *StringList `json:"source"` - User *StringList `json:"user"` - InboundTag *StringList `json:"inboundTag"` - } - rawFieldRule := new(RawFieldRule) - err := json.Unmarshal(msg, rawFieldRule) - if err != nil { - return nil, err - } - - rule := new(router.RoutingRule) - rule.Tag = rawFieldRule.OutboundTag - - if rawFieldRule.Domain != nil { - for _, domain := range *rawFieldRule.Domain { - domainRule := new(router.Domain) - switch { - case strings.HasPrefix(domain, "regexp:"): - domainRule.Type = router.Domain_Regex - domainRule.Value = domain[7:] - case strings.HasPrefix(domain, "domain:"): - domainRule.Type = router.Domain_Domain - domainRule.Value = domain[7:] - default: - domainRule.Type = router.Domain_Plain - domainRule.Value = domain - } - rule.Domain = append(rule.Domain, domainRule) - } - } - - if rawFieldRule.IP != nil { - for _, ip := range *rawFieldRule.IP { - ipRule, err := parseIP(ip) - if err != nil { - return nil, newError("invalid IP: ", ip).Base(err) - } - rule.Cidr = append(rule.Cidr, ipRule) - } - } - - if rawFieldRule.Port != nil { - rule.PortRange = rawFieldRule.Port.Build() - } - - if rawFieldRule.Network != nil { - rule.NetworkList = rawFieldRule.Network.Build() - } - - if rawFieldRule.SourceIP != nil { - for _, ip := range *rawFieldRule.SourceIP { - ipRule, err := parseIP(ip) - if err != nil { - return nil, newError("invalid IP: ", ip).Base(err) - } - rule.SourceCidr = append(rule.SourceCidr, ipRule) - } - } - - if rawFieldRule.User != nil { - for _, s := range *rawFieldRule.User { - rule.UserEmail = append(rule.UserEmail, s) - } - } - - if rawFieldRule.InboundTag != nil { - for _, s := range *rawFieldRule.InboundTag { - rule.InboundTag = append(rule.InboundTag, s) - } - } - - return rule, nil -} - -func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) { - rawRule := new(RouterRule) - err := json.Unmarshal(msg, rawRule) - if err != nil { - return nil, newError("invalid router rule").Base(err) - } - if rawRule.Type == "field" { - fieldrule, err := parseFieldRule(msg) - if err != nil { - return nil, newError("invalid field rule").Base(err) - } - return fieldrule, nil - } - if rawRule.Type == "chinaip" { - chinaiprule, err := parseChinaIPRule(msg) - if err != nil { - return nil, newError("invalid chinaip rule").Base(err) - } - return chinaiprule, nil - } - if rawRule.Type == "chinasites" { - chinasitesrule, err := parseChinaSitesRule(msg) - if err != nil { - return nil, newError("invalid chinasites rule").Base(err) - } - return chinasitesrule, nil - } - return nil, newError("unknown router rule type: ", rawRule.Type) -} - -func parseChinaIPRule(data []byte) (*router.RoutingRule, error) { - rawRule := new(RouterRule) - err := json.Unmarshal(data, rawRule) - if err != nil { - return nil, newError("invalid router rule").Base(err) - } - var chinaIPs geoip.CountryIPRange - if err := proto.Unmarshal(geoip.ChinaIPs, &chinaIPs); err != nil { - return nil, newError("invalid china ips").Base(err) - } - return &router.RoutingRule{ - Tag: rawRule.OutboundTag, - Cidr: chinaIPs.Ips, - }, nil -} - -func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) { - rawRule := new(RouterRule) - err := json.Unmarshal(data, rawRule) - if err != nil { - log.Trace(newError("invalid router rule: ", err).AtError()) - return nil, err - } - return &router.RoutingRule{ - Tag: rawRule.OutboundTag, - Domain: chinaSitesDomains, - }, nil -} diff --git a/tools/conf/router_chinasites.go b/tools/conf/router_chinasites.go deleted file mode 100644 index 1b73d89c..00000000 --- a/tools/conf/router_chinasites.go +++ /dev/null @@ -1,483 +0,0 @@ -package conf - -import ( - "v2ray.com/core/app/router" -) - -var ( - chinaSitesDomains []*router.Domain -) - -func init() { - domains := []string{ - "cn", - "xn--fiqs8s", /* .中国 */ - - "10010.com", - "100offer.com", - "115.com", - "123juzi.com", - "123juzi.net", - "123u.com", - "126.com", - "126.net", - "127.net", - "163.com", - "17173.com", - "17cdn.com", - "188.com", - "1905.com", - "21cn.com", - "2288.org", - "2345.com", - "263.net", - "2cto.com", - "3322.org", - "35.com", - "360doc.com", - "360buy.com", - "360buyimg.com", - "360safe.com", - "36kr.com", - "39.net", - "3dmgame.com", - "3conline.com", - "4399.com", - "500d.me", - "50bang.org", - "51.la", - "51credit.com", - "51cto.com", - "51jingying.com", - "51job.com", - "51jobcdn.com", - "51wendang.com", - "55.com", - "51yes.com", - "55bbs.com", - "58.com", - "6rooms.com", - "71.am", - "7k7k.com", - "900.la", - "9718.com", - "9xu.com", - "abchina.com", - "acfun.tv", - "acgvideo.com", - "agrantsem.com", - "aicdn.com", - "aixifan.com", - "alibaba.com", - "alicdn.com", - "aliimg.com.com", - "alipay.com", - "alipayobjects.com", - "aliyun.com", - "aliyuncdn.com", - "aliyuncs.com", - "allyes.com", - "amap.com", - "anjuke.com", - "anquan.org", - "appinn.com", - "babytree.com", - "babytreeimg.com", - "baidu.com", - "baiducontent.com", - "baidupcs.com", - "baidustatic.com", - "baifendian.com", - "baifubao.com", - "baihe.com", - "baike.com", - "baixing.com", - "baixing.net", - "bankcomm.com", - "bankofchina.com", - "bcy.net", - "bdimg.com", - "bdstatic.com", - "bilibili.com", - "cn.bing.com", - "bitauto.com", - "bitautoimg.com", - "bobo.com", - "bootcss.com", - "btcfans.com", - "caiyunapp.com", - "ccb.com", - "cctv.com", - "cctvpic.com", - "cdn20.com", - "cebbank.com", - "ch.com", - "chashebao.com", - "che168.com", - "china.com", - "chinacache.com", - "chinacache.net", - "chinahr.com", - "chinamobile.com", - "chinapay.com", - "chinatranslation.net", - "chinaz.com", - "chiphell.com", - "chouti.com", - "chuangxin.com", - "chuansong.me", - "clouddn.com", - "cloudxns.com", - "cmbchina.com", - "cnbeta.com", - "cnbetacdn.com", - "cnblogs.com", - "cnepub.com", - "cnzz.com", - "coding.net", - "coolapk.com", - "cqvip.com", - "csbew.com", - "csdn.net", - "ctrip.com", - "cubead.com", - "dajie.com", - "dajieimg.com", - "dangdang.com", - "daocloud.io", - "daovoice.io", - "dbank.com", - "dedecms.com", - "dgtle.com", - "diandian.com", - "dianping.com", - "diopic.net", - "docin.com", - "dockerone.com", - "dockone.io", - "donews.com", - "douban.com", - "doubanio.com", - "dpfile.com", - "duomai.com", - "duoshuo.com", - "duowan.com", - "dxpmedia.com", - "eastday.com", - "ecitic.com", - "emarbox.com", - "eoeandroid.com", - "etao.com", - "excelhome.net", - "fanli.com", - "feng.com", - "fengniao.com", - "fhldns.com", - "foxmail.com", - "geekpark.net", - "geetest.com", - "geilicdn.com", - "getui.com", - "google-analytics.com", - "growingio.com", - "gtags.net", - "gwdang.com", - "hao123.com", - "hao123img.com", - "haosou.com", - "hdslb.com", - "henha.com", - "henkuai.com", - "hexun.com", - "hichina.com", - "huanqiu.com", - "hunantv.com", - "huochepiao.com", - "hupu.com", - "hupucdn.com", - "huxiu.com", - "iask.com", - "iciba.com", - "idqqimg.com", - "ifanr.com", - "ifanrusercontent.com", - "ifanrx.com", - "ifeng.com", - "ifengimg.com", - "ijinshan.com", - "ikafan.com", - "imedao.com", - "imgo.tv", - "imooc.com", - "infoq.com", - "infoqstatic.com", - "ip138.com", - "ipinyou.com", - "ipip.net", - "ip-cdn.com", - "iqiyi.com", - "it165.net", - "it168.com", - "it610.com", - "iteye.com", - "ithome.com", - "itjuzi.com", - "jandan.net", - "jd.com", - "jb51.com", - "jia.com", - "jianshu.com", - "jianshu.io", - "jiasuhui.com", - "jiathis.com", - "jiayuan.com", - "jikexueyuan.com", - "jisuanke.com", - "jmstatic.com", - "jsdelivr.net", - "jstv.com", - "jumei.com", - "jyimg.com", - "kaixin001.com", - "kanimg.com", - "kankanews.com", - "kejet.net", - "kf5.com", - "kimiss.com", - "kouclo.com", - "koudai.com", - "koudai8.com", - "ku6.com", - "ku6cdn.com", - "ku6img.com", - "kuqin.com", - "lady8844.com", - "lagou.com", - "le.com", - "leanote.com", - "leiphone.com", - "leju.com", - "leturich.org", - "letv.com", - "letvcdn.com", - "letvimg.com", - "liantu.me", - "liaoxuefeng.com", - "liba.com", - "libaclub.com", - "liepin.com", - "lietou.com", - "lightonus.com", - "linkvans.com", - "linuxidc.com", - "liuxiaoer.com", - "lofter.com", - "lu.com", - "lufax.com", - "lufaxcdn.com", - "lvmama.com", - "lxdns.com", - "lxway.com", - "ly.com", - "mayihr.com", - "mechina.org", - "mediav.com", - "meiqia.com", - "meika360.com", - "meilishuo.com", - "meishij.net", - "meituan.com", - "meizu.com", - "mgtv.com", - "mi.com", - "miaopai.com", - "miaozhen.com", - "miui.com", - "mmbang.com", - "mmbang.info", - "mmstat.com", - "mogucdn.com", - "mogujie.com", - "mop.com", - "mscbsc.com", - "mukewang.com", - "mydrivers.com", - "myshow360.net", - "mzstatic.com", - "netease.com", - "newbandeng.com", - "ngacn.cc", - "ntalker.com", - "nvsheng.com", - "oeeee.com", - "ol-img.com", - "oneapm.com", - "onlinedown.net", - "onlinesjtu.com", - "oschina.net", - "paipai.com", - "pcbeta.com", - "pchome.net", - "pingan.com", - "pingplusplus.com", - "pps.tv", - "psbc.com", - "pubyun.com", - "qbox.me", - "qcloud.com", - "qhimg.com", - "qiaobutang.com", - "qidian.com", - "qingcloud.com", - "qingsongchou.com", - "qiniu.com", - "qiniucdn.com", - "qiniudn.com", - "qiniudns.com", - "qiyi.com", - "qiyipic.com", - "qtmojo.com", - "qq.com", - "qqmail.com", - "qunar.com", - "qunarzz.com", - "qzone.com", - "renren.com", - "runoob.com", - "ruanmei.com", - "ruby-china.org", - "sandai.net", - "sanguosha.com", - "sanwen.net", - "segmentfault.com", - "sf-express.com", - "sharejs.com", - "shmetro.com", - "shutcm.com", - "simei8.com", - "sina.com", - "sinaapp.com", - "sinaedge.com", - "sinaimg.com", - "sinajs.com", - "szzfgjj.com", - "smzdm.com", - "sohu.com", - "sogou.com", - "sogoucdn.com", - "soso.com", - "sspai.com", - "starbaby.cc", - "starbaby.com", - "staticfile.org", - "stockstar.com", - "suning.com", - "szfw.org", - "t1y5.com", - "tanx.com", - "tao123.com", - "taobao.com", - "taobaocdn.com", - "tbcache.com", - "tencent.com", - "tenpay.com", - "tenxcloud.com", - "tiebaimg.com", - "tietuku.com", - "tiexue.net", - "tmall.com", - "tmcdn.net", - "topthink.com", - "tudou.com", - "tudouui.com", - "tuicool.com", - "tuniu.com", - "tutuapp.com", - "u17.com", - "useso.com", - "unionpay.com", - "unionpaysecure.com", - "upyun.com", - "upaiyun.com", - "v2ex.com", - "v5875.com", - "vamaker.com", - "vancl.com", - "vcimg.com", - "vip.com", - "wallstreetcn.com", - "wandoujia.com", - "wdjimg.com", - "weand.com", - "webterren.com", - "weibo.com", - "weicaifu.com", - "weidian.com", - "weiphone.com", - "weiphone.net", - "weixing.com", - "weiyun.com", - "wonnder.com", - "worktile.com", - "wooyun.org", - "wrating.com", - "wscdns.com", - "wumii.com", - "xiachufang.com", - "xiami.com", - "xiaokaxiu.com", - "xiaomi.com", - "xitu.com", - "xinhuanet.com", - "xinshipu.com", - "xiu8.com", - "xnpic.com", - "xueqiu.com", - "xunlei.com", - "xywy.com", - "yaolan.com", - "yccdn.com", - "yeepay.com", - "yesky.com", - "yigao.com", - "yihaodian.com", - "yihaodianimg.com", - "yingjiesheng.com", - "yinxiang.com", - "yixi.tv", - "yjbys.com", - "yhd.com", - "youboy.com", - "youku.com", - "yunba.io", - "yundaex.com", - "yunshipei.com", - "yupoo.com", - "yuzua.com", - "yy.com", - "yytcdn.com", - "zampda.net", - "zastatic.com", - "zbjimg.com", - "zdfans.com", - "zhenai.com", - "zhanqi.tv", - "zhaopin.com", - "zhihu.com", - "zhimg.com", - "zhiziyun.com", - "zjstv.com", - "zhubajie.com", - "zrblog.net", - "zuche.com", - "zuchecdn.com", - } - - chinaSitesDomains = make([]*router.Domain, len(domains)) - for idx, pattern := range domains { - chinaSitesDomains[idx] = &router.Domain{ - Type: router.Domain_Domain, - Value: pattern, - } - } -} diff --git a/tools/conf/router_test.go b/tools/conf/router_test.go deleted file mode 100644 index 0ce13bdb..00000000 --- a/tools/conf/router_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package conf_test - -import ( - "context" - "net" - "testing" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/proxy" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func makeDestination(ip string) v2net.Destination { - return v2net.TCPDestination(v2net.IPAddress(net.ParseIP(ip)), 80) -} - -func makeDomainDestination(domain string) v2net.Destination { - return v2net.TCPDestination(v2net.DomainAddress(domain), 80) -} - -func TestChinaIPJson(t *testing.T) { - assert := assert.On(t) - - rule, err := ParseRule([]byte(`{ - "type": "chinaip", - "outboundTag": "x" - }`)) - assert.Error(err).IsNil() - assert.String(rule.Tag).Equals("x") - cond, err := rule.BuildCondition() - assert.Error(err).IsNil() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("121.14.1.189"), 80)))).IsTrue() // sina.com.cn - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("101.226.103.106"), 80)))).IsTrue() // qq.com - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("115.239.210.36"), 80)))).IsTrue() // image.baidu.com - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("120.135.126.1"), 80)))).IsTrue() - - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("8.8.8.8"), 80)))).IsFalse() -} - -func TestChinaSitesJson(t *testing.T) { - assert := assert.On(t) - - rule, err := ParseRule([]byte(`{ - "type": "chinasites", - "outboundTag": "y" - }`)) - assert.Error(err).IsNil() - assert.String(rule.Tag).Equals("y") - cond, err := rule.BuildCondition() - assert.Error(err).IsNil() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v.qq.com"), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.163.com"), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("ngacn.cc"), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("12306.cn"), 80)))).IsTrue() - - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v2ray.com"), 80)))).IsFalse() -} - -func TestDomainRule(t *testing.T) { - assert := assert.On(t) - - rule, err := ParseRule([]byte(`{ - "type": "field", - "domain": [ - "ooxx.com", - "oxox.com", - "regexp:\\.cn$" - ], - "network": "tcp", - "outboundTag": "direct" - }`)) - assert.Error(err).IsNil() - assert.Pointer(rule).IsNotNil() - cond, err := rule.BuildCondition() - assert.Error(err).IsNil() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.ooxx.com"), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.aabb.com"), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.12306.cn"), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.acn.com"), 80)))).IsFalse() -} - -func TestIPRule(t *testing.T) { - assert := assert.On(t) - - rule, err := ParseRule([]byte(`{ - "type": "field", - "ip": [ - "10.0.0.0/8", - "192.0.0.0/24" - ], - "network": "tcp", - "outboundTag": "direct" - }`)) - assert.Error(err).IsNil() - assert.Pointer(rule).IsNotNil() - cond, err := rule.BuildCondition() - assert.Error(err).IsNil() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue() -} - -func TestSourceIPRule(t *testing.T) { - assert := assert.On(t) - - rule, err := ParseRule([]byte(`{ - "type": "field", - "source": [ - "10.0.0.0/8", - "192.0.0.0/24" - ], - "outboundTag": "direct" - }`)) - assert.Error(err).IsNil() - assert.Pointer(rule).IsNotNil() - cond, err := rule.BuildCondition() - assert.Error(err).IsNil() - assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue() - assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse() - assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue() -} diff --git a/tools/conf/shadowsocks.go b/tools/conf/shadowsocks.go deleted file mode 100644 index 7008aff5..00000000 --- a/tools/conf/shadowsocks.go +++ /dev/null @@ -1,130 +0,0 @@ -package conf - -import ( - "strings" - - "v2ray.com/core/common/protocol" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/shadowsocks" -) - -type ShadowsocksServerConfig struct { - Cipher string `json:"method"` - Password string `json:"password"` - UDP bool `json:"udp"` - Level byte `json:"level"` - Email string `json:"email"` - OTA *bool `json:"ota"` -} - -func (v *ShadowsocksServerConfig) Build() (*serial.TypedMessage, error) { - config := new(shadowsocks.ServerConfig) - config.UdpEnabled = v.UDP - - if len(v.Password) == 0 { - return nil, newError("Shadowsocks password is not specified.") - } - account := &shadowsocks.Account{ - Password: v.Password, - Ota: shadowsocks.Account_Auto, - } - if v.OTA != nil { - if *v.OTA { - account.Ota = shadowsocks.Account_Enabled - } else { - account.Ota = shadowsocks.Account_Disabled - } - } - cipher := strings.ToLower(v.Cipher) - switch cipher { - case "aes-256-cfb": - account.CipherType = shadowsocks.CipherType_AES_256_CFB - case "aes-128-cfb": - account.CipherType = shadowsocks.CipherType_AES_128_CFB - case "chacha20": - account.CipherType = shadowsocks.CipherType_CHACHA20 - case "chacha20-ietf": - account.CipherType = shadowsocks.CipherType_CHACHA20_IETF - default: - return nil, newError("unknown cipher method: " + cipher) - } - - config.User = &protocol.User{ - Email: v.Email, - Level: uint32(v.Level), - Account: serial.ToTypedMessage(account), - } - - return serial.ToTypedMessage(config), nil -} - -type ShadowsocksServerTarget struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Cipher string `json:"method"` - Password string `json:"password"` - Email string `json:"email"` - Ota bool `json:"ota"` -} - -type ShadowsocksClientConfig struct { - Servers []*ShadowsocksServerTarget `json:"servers"` -} - -func (v *ShadowsocksClientConfig) Build() (*serial.TypedMessage, error) { - config := new(shadowsocks.ClientConfig) - - if len(v.Servers) == 0 { - return nil, newError("0 Shadowsocks server configured.") - } - - serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers)) - for idx, server := range v.Servers { - if server.Address == nil { - return nil, newError("Shadowsocks server address is not set.") - } - if server.Port == 0 { - return nil, newError("Invalid Shadowsocks port.") - } - if len(server.Password) == 0 { - return nil, newError("Shadowsocks password is not specified.") - } - account := &shadowsocks.Account{ - Password: server.Password, - Ota: shadowsocks.Account_Enabled, - } - if !server.Ota { - account.Ota = shadowsocks.Account_Disabled - } - cipher := strings.ToLower(server.Cipher) - switch cipher { - case "aes-256-cfb": - account.CipherType = shadowsocks.CipherType_AES_256_CFB - case "aes-128-cfb": - account.CipherType = shadowsocks.CipherType_AES_128_CFB - case "chacha20": - account.CipherType = shadowsocks.CipherType_CHACHA20 - case "chacha20-ietf": - account.CipherType = shadowsocks.CipherType_CHACHA20_IETF - default: - return nil, newError("unknown cipher method: " + cipher) - } - - ss := &protocol.ServerEndpoint{ - Address: server.Address.Build(), - Port: uint32(server.Port), - User: []*protocol.User{ - { - Email: server.Email, - Account: serial.ToTypedMessage(account), - }, - }, - } - - serverSpecs[idx] = ss - } - - config.Server = serverSpecs - - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/shadowsocks_test.go b/tools/conf/shadowsocks_test.go deleted file mode 100644 index 3eb55fe1..00000000 --- a/tools/conf/shadowsocks_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - "v2ray.com/core/proxy/shadowsocks" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestShadowsocksServerConfigParsing(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "method": "aes-128-cfb", - "password": "v2ray-password" - }` - - rawConfig := new(ShadowsocksServerConfig) - err := json.Unmarshal([]byte(rawJson), rawConfig) - assert.Error(err).IsNil() - - ts, err := rawConfig.Build() - assert.Error(err).IsNil() - iConfig, err := ts.GetInstance() - assert.Error(err).IsNil() - config := iConfig.(*shadowsocks.ServerConfig) - - rawAccount, err := config.User.GetTypedAccount() - assert.Error(err).IsNil() - - account, ok := rawAccount.(*shadowsocks.ShadowsocksAccount) - assert.Bool(ok).IsTrue() - - assert.Int(account.Cipher.KeySize()).Equals(16) - assert.Bytes(account.Key).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241}) -} diff --git a/tools/conf/socks.go b/tools/conf/socks.go deleted file mode 100644 index 00b18413..00000000 --- a/tools/conf/socks.go +++ /dev/null @@ -1,94 +0,0 @@ -package conf - -import ( - "encoding/json" - - "v2ray.com/core/common/protocol" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/socks" -) - -type SocksAccount struct { - Username string `json:"user"` - Password string `json:"pass"` -} - -func (v *SocksAccount) Build() *socks.Account { - return &socks.Account{ - Username: v.Username, - Password: v.Password, - } -} - -const ( - AuthMethodNoAuth = "noauth" - AuthMethodUserPass = "password" -) - -type SocksServerConfig struct { - AuthMethod string `json:"auth"` - Accounts []*SocksAccount `json:"accounts"` - UDP bool `json:"udp"` - Host *Address `json:"ip"` - Timeout uint32 `json:"timeout"` -} - -func (v *SocksServerConfig) Build() (*serial.TypedMessage, error) { - config := new(socks.ServerConfig) - if v.AuthMethod == AuthMethodNoAuth { - config.AuthType = socks.AuthType_NO_AUTH - } else if v.AuthMethod == AuthMethodUserPass { - config.AuthType = socks.AuthType_PASSWORD - } else { - return nil, newError("unknown socks auth method: " + v.AuthMethod).AtError() - } - - if len(v.Accounts) > 0 { - config.Accounts = make(map[string]string, len(v.Accounts)) - for _, account := range v.Accounts { - config.Accounts[account.Username] = account.Password - } - } - - config.UdpEnabled = v.UDP - if v.Host != nil { - config.Address = v.Host.Build() - } - - config.Timeout = v.Timeout - return serial.ToTypedMessage(config), nil -} - -type SocksRemoteConfig struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Users []json.RawMessage `json:"users"` -} -type SocksClientConfig struct { - Servers []*SocksRemoteConfig `json:"servers"` -} - -func (v *SocksClientConfig) Build() (*serial.TypedMessage, error) { - config := new(socks.ClientConfig) - config.Server = make([]*protocol.ServerEndpoint, len(v.Servers)) - for idx, serverConfig := range v.Servers { - server := &protocol.ServerEndpoint{ - Address: serverConfig.Address.Build(), - Port: uint32(serverConfig.Port), - } - for _, rawUser := range serverConfig.Users { - user := new(protocol.User) - if err := json.Unmarshal(rawUser, user); err != nil { - return nil, newError("failed to parse Socks user").Base(err).AtError() - } - account := new(SocksAccount) - if err := json.Unmarshal(rawUser, account); err != nil { - return nil, newError("failed to parse socks account").Base(err).AtError() - } - user.Account = serial.ToTypedMessage(account.Build()) - server.User = append(server.User, user) - } - config.Server[idx] = server - } - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/socks_test.go b/tools/conf/socks_test.go deleted file mode 100644 index 319fd460..00000000 --- a/tools/conf/socks_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - "v2ray.com/core/common/net" - "v2ray.com/core/common/protocol" - "v2ray.com/core/proxy/socks" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestSocksInboundConfig(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "auth": "password", - "accounts": [ - { - "user": "my-username", - "pass": "my-password" - } - ], - "udp": false, - "ip": "127.0.0.1", - "timeout": 5 - }` - - config := new(SocksServerConfig) - err := json.Unmarshal([]byte(rawJson), &config) - assert.Error(err).IsNil() - - message, err := config.Build() - assert.Error(err).IsNil() - - iConfig, err := message.GetInstance() - assert.Error(err).IsNil() - - socksConfig := iConfig.(*socks.ServerConfig) - assert.Bool(socksConfig.AuthType == socks.AuthType_PASSWORD).IsTrue() - assert.Int(len(socksConfig.Accounts)).Equals(1) - assert.String(socksConfig.Accounts["my-username"]).Equals("my-password") - assert.Bool(socksConfig.UdpEnabled).IsFalse() - assert.Address(socksConfig.Address.AsAddress()).Equals(net.LocalHostIP) - assert.Uint32(socksConfig.Timeout).Equals(5) -} - -func TestSocksOutboundConfig(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "servers": [{ - "address": "127.0.0.1", - "port": 1234, - "users": [ - {"user": "test user", "pass": "test pass", "email": "test@email.com"} - ] - }] - }` - - config := new(SocksClientConfig) - err := json.Unmarshal([]byte(rawJson), &config) - assert.Error(err).IsNil() - - message, err := config.Build() - assert.Error(err).IsNil() - - iConfig, err := message.GetInstance() - assert.Error(err).IsNil() - - socksConfig := iConfig.(*socks.ClientConfig) - assert.Int(len(socksConfig.Server)).Equals(1) - - ss := protocol.NewServerSpecFromPB(*socksConfig.Server[0]) - assert.Destination(ss.Destination()).EqualsString("tcp:127.0.0.1:1234") - - user := ss.PickUser() - assert.String(user.Email).Equals("test@email.com") - - account, err := user.GetTypedAccount() - assert.Error(err).IsNil() - - socksAccount := account.(*socks.Account) - assert.String(socksAccount.Username).Equals("test user") - assert.String(socksAccount.Password).Equals("test pass") -} diff --git a/tools/conf/transport.go b/tools/conf/transport.go deleted file mode 100644 index 0072adcc..00000000 --- a/tools/conf/transport.go +++ /dev/null @@ -1,50 +0,0 @@ -package conf - -import ( - "v2ray.com/core/transport" - "v2ray.com/core/transport/internet" -) - -type TransportConfig struct { - TCPConfig *TCPConfig `json:"tcpSettings"` - KCPConfig *KCPConfig `json:"kcpSettings"` - WSConfig *WebSocketConfig `json:"wsSettings"` -} - -func (v *TransportConfig) Build() (*transport.Config, error) { - config := new(transport.Config) - - if v.TCPConfig != nil { - ts, err := v.TCPConfig.Build() - if err != nil { - return nil, newError("failed to build TCP config").Base(err).AtError() - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_TCP, - Settings: ts, - }) - } - - if v.KCPConfig != nil { - ts, err := v.KCPConfig.Build() - if err != nil { - return nil, newError("failed to build mKCP config").Base(err).AtError() - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_MKCP, - Settings: ts, - }) - } - - if v.WSConfig != nil { - ts, err := v.WSConfig.Build() - if err != nil { - return nil, newError("failed to build WebSocket config").Base(err) - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_WebSocket, - Settings: ts, - }) - } - return config, nil -} diff --git a/tools/conf/transport_authenticators.go b/tools/conf/transport_authenticators.go deleted file mode 100644 index 6e4b4cec..00000000 --- a/tools/conf/transport_authenticators.go +++ /dev/null @@ -1,193 +0,0 @@ -package conf - -import ( - "v2ray.com/core/common/serial" - "v2ray.com/core/transport/internet/headers/http" - "v2ray.com/core/transport/internet/headers/noop" - "v2ray.com/core/transport/internet/headers/srtp" - "v2ray.com/core/transport/internet/headers/utp" - "v2ray.com/core/transport/internet/headers/wechat" -) - -type NoOpAuthenticator struct{} - -func (NoOpAuthenticator) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(noop.Config)), nil -} - -type NoOpConnectionAuthenticator struct{} - -func (NoOpConnectionAuthenticator) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(noop.ConnectionConfig)), nil -} - -type SRTPAuthenticator struct{} - -func (SRTPAuthenticator) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(srtp.Config)), nil -} - -type UTPAuthenticator struct{} - -func (UTPAuthenticator) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(utp.Config)), nil -} - -type WechatVideoAuthenticator struct{} - -func (WechatVideoAuthenticator) Build() (*serial.TypedMessage, error) { - return serial.ToTypedMessage(new(wechat.VideoConfig)), nil -} - -type HTTPAuthenticatorRequest struct { - Version string `json:"version"` - Method string `json:"method"` - Path StringList `json:"path"` - Headers map[string]*StringList `json:"headers"` -} - -func (v *HTTPAuthenticatorRequest) Build() (*http.RequestConfig, error) { - config := &http.RequestConfig{ - Uri: []string{"/"}, - Header: []*http.Header{ - { - Name: "Host", - Value: []string{"www.baidu.com", "www.bing.com"}, - }, - { - Name: "User-Agent", - Value: []string{ - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46", - }, - }, - { - Name: "Accept-Encoding", - Value: []string{"gzip, deflate"}, - }, - { - Name: "Connection", - Value: []string{"keep-alive"}, - }, - { - Name: "Pragma", - Value: []string{"no-cache"}, - }, - }, - } - - if len(v.Version) > 0 { - config.Version = &http.Version{Value: v.Version} - } - - if len(v.Method) > 0 { - config.Method = &http.Method{Value: v.Method} - } - - if len(v.Path) > 0 { - config.Uri = append([]string(nil), (v.Path)...) - } - - if len(v.Headers) > 0 { - config.Header = make([]*http.Header, 0, len(v.Headers)) - for key, value := range v.Headers { - if value == nil { - return nil, newError("empty HTTP header value: " + key).AtError() - } - config.Header = append(config.Header, &http.Header{ - Name: key, - Value: append([]string(nil), (*value)...), - }) - } - } - - return config, nil -} - -type HTTPAuthenticatorResponse struct { - Version string `json:"version"` - Status string `json:"status"` - Reason string `json:"reason"` - Headers map[string]*StringList `json:"headers"` -} - -func (v *HTTPAuthenticatorResponse) Build() (*http.ResponseConfig, error) { - config := &http.ResponseConfig{ - Header: []*http.Header{ - { - Name: "Content-Type", - Value: []string{"application/octet-stream", "video/mpeg"}, - }, - { - Name: "Transfer-Encoding", - Value: []string{"chunked"}, - }, - { - Name: "Connection", - Value: []string{"keep-alive"}, - }, - { - Name: "Pragma", - Value: []string{"no-cache"}, - }, - { - Name: "Cache-Control", - Value: []string{"private", "no-cache"}, - }, - }, - } - - if len(v.Version) > 0 { - config.Version = &http.Version{Value: v.Version} - } - - if len(v.Status) > 0 || len(v.Reason) > 0 { - config.Status = &http.Status{ - Code: "200", - Reason: "OK", - } - if len(v.Status) > 0 { - config.Status.Code = v.Status - } - if len(v.Reason) > 0 { - config.Status.Reason = v.Reason - } - } - - if len(v.Headers) > 0 { - config.Header = make([]*http.Header, 0, len(v.Headers)) - for key, value := range v.Headers { - if value == nil { - return nil, newError("empty HTTP header value: " + key).AtError() - } - config.Header = append(config.Header, &http.Header{ - Name: key, - Value: append([]string(nil), (*value)...), - }) - } - } - - return config, nil -} - -type HTTPAuthenticator struct { - Request HTTPAuthenticatorRequest `json:"request"` - Response HTTPAuthenticatorResponse `json:"response"` -} - -func (v *HTTPAuthenticator) Build() (*serial.TypedMessage, error) { - config := new(http.Config) - requestConfig, err := v.Request.Build() - if err != nil { - return nil, err - } - config.Request = requestConfig - - responseConfig, err := v.Response.Build() - if err != nil { - return nil, err - } - config.Response = responseConfig - - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/transport_internet.go b/tools/conf/transport_internet.go deleted file mode 100644 index c21626a0..00000000 --- a/tools/conf/transport_internet.go +++ /dev/null @@ -1,255 +0,0 @@ -package conf - -import ( - "encoding/json" - "io/ioutil" - "strings" - - "v2ray.com/core/common/serial" - "v2ray.com/core/transport/internet" - "v2ray.com/core/transport/internet/kcp" - "v2ray.com/core/transport/internet/tcp" - "v2ray.com/core/transport/internet/tls" - "v2ray.com/core/transport/internet/websocket" -) - -var ( - kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{ - "none": func() interface{} { return new(NoOpAuthenticator) }, - "srtp": func() interface{} { return new(SRTPAuthenticator) }, - "utp": func() interface{} { return new(UTPAuthenticator) }, - "wechat-video": func() interface{} { return new(WechatVideoAuthenticator) }, - }, "type", "") - - tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{ - "none": func() interface{} { return new(NoOpConnectionAuthenticator) }, - "http": func() interface{} { return new(HTTPAuthenticator) }, - }, "type", "") -) - -type KCPConfig struct { - Mtu *uint32 `json:"mtu"` - Tti *uint32 `json:"tti"` - UpCap *uint32 `json:"uplinkCapacity"` - DownCap *uint32 `json:"downlinkCapacity"` - Congestion *bool `json:"congestion"` - ReadBufferSize *uint32 `json:"readBufferSize"` - WriteBufferSize *uint32 `json:"writeBufferSize"` - HeaderConfig json.RawMessage `json:"header"` -} - -func (v *KCPConfig) Build() (*serial.TypedMessage, error) { - config := new(kcp.Config) - - if v.Mtu != nil { - mtu := *v.Mtu - if mtu < 576 || mtu > 1460 { - return nil, newError("invalid mKCP MTU size: ", mtu).AtError() - } - config.Mtu = &kcp.MTU{Value: mtu} - } - if v.Tti != nil { - tti := *v.Tti - if tti < 10 || tti > 100 { - return nil, newError("invalid mKCP TTI: ", tti).AtError() - } - config.Tti = &kcp.TTI{Value: tti} - } - if v.UpCap != nil { - config.UplinkCapacity = &kcp.UplinkCapacity{Value: *v.UpCap} - } - if v.DownCap != nil { - config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *v.DownCap} - } - if v.Congestion != nil { - config.Congestion = *v.Congestion - } - if v.ReadBufferSize != nil { - size := *v.ReadBufferSize - if size > 0 { - config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024} - } else { - config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024} - } - } - if v.WriteBufferSize != nil { - size := *v.WriteBufferSize - if size > 0 { - config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024} - } else { - config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024} - } - } - if len(v.HeaderConfig) > 0 { - headerConfig, _, err := kcpHeaderLoader.Load(v.HeaderConfig) - if err != nil { - return nil, newError("invalid mKCP header config.").Base(err).AtError() - } - ts, err := headerConfig.(Buildable).Build() - if err != nil { - return nil, newError("invalid mKCP header config").Base(err).AtError() - } - config.HeaderConfig = ts - } - - return serial.ToTypedMessage(config), nil -} - -type TCPConfig struct { - HeaderConfig json.RawMessage `json:"header"` -} - -func (v *TCPConfig) Build() (*serial.TypedMessage, error) { - config := new(tcp.Config) - if len(v.HeaderConfig) > 0 { - headerConfig, _, err := tcpHeaderLoader.Load(v.HeaderConfig) - if err != nil { - return nil, newError("invalid TCP header config").Base(err).AtError() - } - ts, err := headerConfig.(Buildable).Build() - if err != nil { - return nil, newError("invalid TCP header config").Base(err).AtError() - } - config.HeaderSettings = ts - } - - return serial.ToTypedMessage(config), nil -} - -type WebSocketConfig struct { - Path string `json:"Path"` -} - -func (v *WebSocketConfig) Build() (*serial.TypedMessage, error) { - config := &websocket.Config{ - Path: v.Path, - } - return serial.ToTypedMessage(config), nil -} - -type TLSCertConfig struct { - CertFile string `json:"certificateFile"` - KeyFile string `json:"keyFile"` -} -type TLSConfig struct { - Insecure bool `json:"allowInsecure"` - Certs []*TLSCertConfig `json:"certificates"` - ServerName string `json:"serverName"` -} - -func (v *TLSConfig) Build() (*serial.TypedMessage, error) { - config := new(tls.Config) - config.Certificate = make([]*tls.Certificate, len(v.Certs)) - for idx, certConf := range v.Certs { - cert, err := ioutil.ReadFile(certConf.CertFile) - if err != nil { - return nil, newError("failed to load TLS certificate file: ", certConf.CertFile).Base(err).AtError() - } - key, err := ioutil.ReadFile(certConf.KeyFile) - if err != nil { - return nil, newError("failed to load TLS key file: ", certConf.KeyFile).Base(err).AtError() - } - config.Certificate[idx] = &tls.Certificate{ - Key: key, - Certificate: cert, - } - } - config.AllowInsecure = v.Insecure - if len(v.ServerName) > 0 { - config.ServerName = v.ServerName - } - return serial.ToTypedMessage(config), nil -} - -type TransportProtocol string - -func (p TransportProtocol) Build() (internet.TransportProtocol, error) { - switch strings.ToLower(string(p)) { - case "tcp": - return internet.TransportProtocol_TCP, nil - case "kcp", "mkcp": - return internet.TransportProtocol_MKCP, nil - case "ws", "websocket": - return internet.TransportProtocol_WebSocket, nil - default: - return internet.TransportProtocol_TCP, newError("Config: unknown transport protocol: ", p) - } -} - -type StreamConfig struct { - Network *TransportProtocol `json:"network"` - Security string `json:"security"` - TLSSettings *TLSConfig `json:"tlsSettings"` - TCPSettings *TCPConfig `json:"tcpSettings"` - KCPSettings *KCPConfig `json:"kcpSettings"` - WSSettings *WebSocketConfig `json:"wsSettings"` -} - -func (v *StreamConfig) Build() (*internet.StreamConfig, error) { - config := &internet.StreamConfig{ - Protocol: internet.TransportProtocol_TCP, - } - if v.Network != nil { - protocol, err := (*v.Network).Build() - if err != nil { - return nil, err - } - config.Protocol = protocol - } - if strings.ToLower(v.Security) == "tls" { - tlsSettings := v.TLSSettings - if tlsSettings == nil { - tlsSettings = &TLSConfig{} - } - ts, err := tlsSettings.Build() - if err != nil { - return nil, newError("Failed to build TLS config.").Base(err) - } - config.SecuritySettings = append(config.SecuritySettings, ts) - config.SecurityType = ts.Type - } - if v.TCPSettings != nil { - ts, err := v.TCPSettings.Build() - if err != nil { - return nil, newError("Failed to build TCP config.").Base(err) - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_TCP, - Settings: ts, - }) - } - if v.KCPSettings != nil { - ts, err := v.KCPSettings.Build() - if err != nil { - return nil, newError("Failed to build mKCP config.").Base(err) - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_MKCP, - Settings: ts, - }) - } - if v.WSSettings != nil { - ts, err := v.WSSettings.Build() - if err != nil { - return nil, newError("Failed to build WebSocket config.").Base(err) - } - config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{ - Protocol: internet.TransportProtocol_WebSocket, - Settings: ts, - }) - } - return config, nil -} - -type ProxyConfig struct { - Tag string `json:"tag"` -} - -func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) { - if len(v.Tag) == 0 { - return nil, newError("Proxy tag is not set.") - } - return &internet.ProxyConfig{ - Tag: v.Tag, - }, nil -} diff --git a/tools/conf/transport_test.go b/tools/conf/transport_test.go deleted file mode 100644 index b2f1bf3f..00000000 --- a/tools/conf/transport_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" - "v2ray.com/core/transport/internet" - "v2ray.com/core/transport/internet/headers/http" - "v2ray.com/core/transport/internet/headers/noop" - "v2ray.com/core/transport/internet/kcp" - "v2ray.com/core/transport/internet/tcp" - "v2ray.com/core/transport/internet/websocket" -) - -func TestTransportConfig(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "tcpSettings": { - "header": { - "type": "http", - "request": { - "version": "1.1", - "method": "GET", - "path": "/b", - "headers": { - "a": "b", - "c": "d" - } - }, - "response": { - "version": "1.0", - "status": "404", - "reason": "Not Found" - } - } - }, - "kcpSettings": { - "mtu": 1200, - "header": { - "type": "none" - } - }, - "wsSettings": { - "path": "/t" - } - }` - - var transportSettingsConf TransportConfig - assert.Error(json.Unmarshal([]byte(rawJson), &transportSettingsConf)).IsNil() - - ts, err := transportSettingsConf.Build() - assert.Error(err).IsNil() - - assert.Int(len(ts.TransportSettings)).Equals(3) - var settingsCount uint32 - for _, settingsWithProtocol := range ts.TransportSettings { - rawSettings, err := settingsWithProtocol.Settings.GetInstance() - assert.Error(err).IsNil() - switch settings := rawSettings.(type) { - case *tcp.Config: - settingsCount++ - assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_TCP).IsTrue() - rawHeader, err := settings.HeaderSettings.GetInstance() - assert.Error(err).IsNil() - header := rawHeader.(*http.Config) - assert.String(header.Request.GetVersionValue()).Equals("1.1") - assert.String(header.Request.Uri[0]).Equals("/b") - assert.String(header.Request.Method.Value).Equals("GET") - var va, vc string - for _, h := range header.Request.Header { - switch h.Name { - case "a": - va = h.Value[0] - case "c": - vc = h.Value[0] - default: - t.Error("Unknown header ", h.String()) - } - } - assert.String(va).Equals("b") - assert.String(vc).Equals("d") - assert.String(header.Response.Version.Value).Equals("1.0") - assert.String(header.Response.Status.Code).Equals("404") - assert.String(header.Response.Status.Reason).Equals("Not Found") - case *kcp.Config: - settingsCount++ - assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_MKCP).IsTrue() - assert.Uint32(settings.GetMTUValue()).Equals(1200) - rawHeader, err := settings.HeaderConfig.GetInstance() - assert.Error(err).IsNil() - header := rawHeader.(*noop.Config) - assert.Pointer(header).IsNotNil() - case *websocket.Config: - settingsCount++ - assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_WebSocket).IsTrue() - assert.String(settings.Path).Equals("/t") - default: - t.Error("Unknown type of settings.") - } - } - assert.Uint32(settingsCount).Equals(3) -} diff --git a/tools/conf/v2ray.go b/tools/conf/v2ray.go deleted file mode 100644 index e9f3a916..00000000 --- a/tools/conf/v2ray.go +++ /dev/null @@ -1,428 +0,0 @@ -package conf - -import ( - "encoding/json" - "io" - "strings" - - "v2ray.com/core" - "v2ray.com/core/app/proxyman" - v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/serial" - json_reader "v2ray.com/core/tools/conf/json" -) - -var ( - inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{ - "dokodemo-door": func() interface{} { return new(DokodemoConfig) }, - "http": func() interface{} { return new(HttpServerConfig) }, - "shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) }, - "socks": func() interface{} { return new(SocksServerConfig) }, - "vmess": func() interface{} { return new(VMessInboundConfig) }, - }, "protocol", "settings") - - outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{ - "blackhole": func() interface{} { return new(BlackholeConfig) }, - "freedom": func() interface{} { return new(FreedomConfig) }, - "shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) }, - "vmess": func() interface{} { return new(VMessOutboundConfig) }, - "socks": func() interface{} { return new(SocksClientConfig) }, - }, "protocol", "settings") -) - -func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) { - kp := make([]proxyman.KnownProtocols, 0, 8) - for _, p := range s { - switch strings.ToLower(p) { - case "http": - kp = append(kp, proxyman.KnownProtocols_HTTP) - case "https", "tls", "ssl": - kp = append(kp, proxyman.KnownProtocols_TLS) - default: - return nil, newError("Unknown protocol: ", p) - } - } - return kp, nil -} - -type InboundConnectionConfig struct { - Port uint16 `json:"port"` - Listen *Address `json:"listen"` - Protocol string `json:"protocol"` - StreamSetting *StreamConfig `json:"streamSettings"` - Settings json.RawMessage `json:"settings"` - Tag string `json:"tag"` - DomainOverride *StringList `json:"domainOverride"` -} - -func (v *InboundConnectionConfig) Build() (*proxyman.InboundHandlerConfig, error) { - receiverConfig := &proxyman.ReceiverConfig{ - PortRange: &v2net.PortRange{ - From: uint32(v.Port), - To: uint32(v.Port), - }, - } - if v.Listen != nil { - if v.Listen.Family().IsDomain() { - return nil, newError("unable to listen on domain address: " + v.Listen.Domain()) - } - receiverConfig.Listen = v.Listen.Build() - } - if v.StreamSetting != nil { - ts, err := v.StreamSetting.Build() - if err != nil { - return nil, err - } - receiverConfig.StreamSettings = ts - } - if v.DomainOverride != nil { - kp, err := toProtocolList(*v.DomainOverride) - if err != nil { - return nil, newError("failed to parse inbound config").Base(err) - } - receiverConfig.DomainOverride = kp - } - - jsonConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) - if err != nil { - return nil, newError("failed to load inbound config.").Base(err) - } - if dokodemoConfig, ok := jsonConfig.(*DokodemoConfig); ok { - receiverConfig.ReceiveOriginalDestination = dokodemoConfig.Redirect - } - ts, err := jsonConfig.(Buildable).Build() - if err != nil { - return nil, err - } - - return &proxyman.InboundHandlerConfig{ - Tag: v.Tag, - ReceiverSettings: serial.ToTypedMessage(receiverConfig), - ProxySettings: ts, - }, nil -} - -type MuxConfig struct { - Enabled bool `json:"enabled"` - Concurrency uint16 `json:"concurrency"` -} - -func (c *MuxConfig) GetConcurrency() uint16 { - if c.Concurrency == 0 { - return 8 - } - return c.Concurrency -} - -type OutboundConnectionConfig struct { - Protocol string `json:"protocol"` - SendThrough *Address `json:"sendThrough"` - StreamSetting *StreamConfig `json:"streamSettings"` - ProxySettings *ProxyConfig `json:"proxySettings"` - Settings json.RawMessage `json:"settings"` - Tag string `json:"tag"` - MuxSettings *MuxConfig `json:"mux"` -} - -func (v *OutboundConnectionConfig) Build() (*proxyman.OutboundHandlerConfig, error) { - senderSettings := &proxyman.SenderConfig{} - - if v.SendThrough != nil { - address := v.SendThrough - if address.Family().IsDomain() { - return nil, newError("invalid sendThrough address: " + address.String()) - } - senderSettings.Via = address.Build() - } - if v.StreamSetting != nil { - ss, err := v.StreamSetting.Build() - if err != nil { - return nil, err - } - senderSettings.StreamSettings = ss - } - if v.ProxySettings != nil { - ps, err := v.ProxySettings.Build() - if err != nil { - return nil, newError("invalid outbound proxy settings").Base(err) - } - senderSettings.ProxySettings = ps - } - - if v.MuxSettings != nil && v.MuxSettings.Enabled { - senderSettings.MultiplexSettings = &proxyman.MultiplexingConfig{ - Enabled: true, - Concurrency: uint32(v.MuxSettings.GetConcurrency()), - } - } - - rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol) - if err != nil { - return nil, newError("failed to parse outbound config").Base(err) - } - ts, err := rawConfig.(Buildable).Build() - if err != nil { - return nil, err - } - - return &proxyman.OutboundHandlerConfig{ - SenderSettings: serial.ToTypedMessage(senderSettings), - ProxySettings: ts, - Tag: v.Tag, - }, nil -} - -type InboundDetourAllocationConfig struct { - Strategy string `json:"strategy"` - Concurrency *uint32 `json:"concurrency"` - RefreshMin *uint32 `json:"refresh"` -} - -func (v *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) { - config := new(proxyman.AllocationStrategy) - switch strings.ToLower(v.Strategy) { - case "always": - config.Type = proxyman.AllocationStrategy_Always - case "random": - config.Type = proxyman.AllocationStrategy_Random - case "external": - config.Type = proxyman.AllocationStrategy_External - default: - return nil, newError("unknown allocation strategy: ", v.Strategy) - } - if v.Concurrency != nil { - config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{ - Value: *v.Concurrency, - } - } - - if v.RefreshMin != nil { - config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{ - Value: *v.RefreshMin, - } - } - - return config, nil -} - -type InboundDetourConfig struct { - Protocol string `json:"protocol"` - PortRange *PortRange `json:"port"` - ListenOn *Address `json:"listen"` - Settings json.RawMessage `json:"settings"` - Tag string `json:"tag"` - Allocation *InboundDetourAllocationConfig `json:"allocate"` - StreamSetting *StreamConfig `json:"streamSettings"` - DomainOverride *StringList `json:"domainOverride"` -} - -func (v *InboundDetourConfig) Build() (*proxyman.InboundHandlerConfig, error) { - receiverSettings := &proxyman.ReceiverConfig{} - - if v.PortRange == nil { - return nil, newError("port range not specified in InboundDetour.") - } - receiverSettings.PortRange = v.PortRange.Build() - - if v.ListenOn != nil { - if v.ListenOn.Family().IsDomain() { - return nil, newError("unable to listen on domain address: ", v.ListenOn.Domain()) - } - receiverSettings.Listen = v.ListenOn.Build() - } - if v.Allocation != nil { - as, err := v.Allocation.Build() - if err != nil { - return nil, err - } - receiverSettings.AllocationStrategy = as - } - if v.StreamSetting != nil { - ss, err := v.StreamSetting.Build() - if err != nil { - return nil, err - } - receiverSettings.StreamSettings = ss - } - if v.DomainOverride != nil { - kp, err := toProtocolList(*v.DomainOverride) - if err != nil { - return nil, newError("failed to parse inbound detour config").Base(err) - } - receiverSettings.DomainOverride = kp - } - - rawConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) - if err != nil { - return nil, newError("failed to load inbound detour config.").Base(err) - } - if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok { - receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect - } - ts, err := rawConfig.(Buildable).Build() - if err != nil { - return nil, err - } - - return &proxyman.InboundHandlerConfig{ - Tag: v.Tag, - ReceiverSettings: serial.ToTypedMessage(receiverSettings), - ProxySettings: ts, - }, nil -} - -type OutboundDetourConfig struct { - Protocol string `json:"protocol"` - SendThrough *Address `json:"sendThrough"` - Tag string `json:"tag"` - Settings json.RawMessage `json:"settings"` - StreamSetting *StreamConfig `json:"streamSettings"` - ProxySettings *ProxyConfig `json:"proxySettings"` - MuxSettings *MuxConfig `json:"mux"` -} - -func (v *OutboundDetourConfig) Build() (*proxyman.OutboundHandlerConfig, error) { - senderSettings := &proxyman.SenderConfig{} - - if v.SendThrough != nil { - address := v.SendThrough - if address.Family().IsDomain() { - return nil, newError("unable to send through: " + address.String()) - } - senderSettings.Via = address.Build() - } - - if v.StreamSetting != nil { - ss, err := v.StreamSetting.Build() - if err != nil { - return nil, err - } - senderSettings.StreamSettings = ss - } - - if v.ProxySettings != nil { - ps, err := v.ProxySettings.Build() - if err != nil { - return nil, newError("invalid outbound detour proxy settings.").Base(err) - } - senderSettings.ProxySettings = ps - } - - if v.MuxSettings != nil && v.MuxSettings.Enabled { - senderSettings.MultiplexSettings = &proxyman.MultiplexingConfig{ - Enabled: true, - Concurrency: uint32(v.MuxSettings.GetConcurrency()), - } - } - - rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol) - if err != nil { - return nil, newError("failed to parse to outbound detour config.").Base(err) - } - ts, err := rawConfig.(Buildable).Build() - if err != nil { - return nil, err - } - - return &proxyman.OutboundHandlerConfig{ - SenderSettings: serial.ToTypedMessage(senderSettings), - Tag: v.Tag, - ProxySettings: ts, - }, nil -} - -type Config struct { - Port uint16 `json:"port"` // Port of this Point server. - LogConfig *LogConfig `json:"log"` - RouterConfig *RouterConfig `json:"routing"` - DNSConfig *DnsConfig `json:"dns"` - InboundConfig *InboundConnectionConfig `json:"inbound"` - OutboundConfig *OutboundConnectionConfig `json:"outbound"` - InboundDetours []InboundDetourConfig `json:"inboundDetour"` - OutboundDetours []OutboundDetourConfig `json:"outboundDetour"` - Transport *TransportConfig `json:"transport"` -} - -func (v *Config) Build() (*core.Config, error) { - config := new(core.Config) - - if v.LogConfig != nil { - config.App = append(config.App, serial.ToTypedMessage(v.LogConfig.Build())) - } - - if v.Transport != nil { - ts, err := v.Transport.Build() - if err != nil { - return nil, err - } - config.Transport = ts - } - - if v.RouterConfig != nil { - routerConfig, err := v.RouterConfig.Build() - if err != nil { - return nil, err - } - config.App = append(config.App, serial.ToTypedMessage(routerConfig)) - } - - if v.DNSConfig != nil { - config.App = append(config.App, serial.ToTypedMessage(v.DNSConfig.Build())) - } - - if v.InboundConfig == nil { - return nil, newError("no inbound config specified") - } - - if v.InboundConfig.Port == 0 && v.Port > 0 { - v.InboundConfig.Port = v.Port - } - - ic, err := v.InboundConfig.Build() - if err != nil { - return nil, err - } - config.Inbound = append(config.Inbound, ic) - - for _, rawInboundConfig := range v.InboundDetours { - ic, err := rawInboundConfig.Build() - if err != nil { - return nil, err - } - config.Inbound = append(config.Inbound, ic) - } - - if v.OutboundConfig == nil { - return nil, newError("no outbound config specified") - } - oc, err := v.OutboundConfig.Build() - if err != nil { - return nil, err - } - config.Outbound = append(config.Outbound, oc) - - for _, rawOutboundConfig := range v.OutboundDetours { - oc, err := rawOutboundConfig.Build() - if err != nil { - return nil, err - } - config.Outbound = append(config.Outbound, oc) - } - - return config, nil -} - -func init() { - core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) { - jsonConfig := &Config{} - decoder := json.NewDecoder(&json_reader.Reader{ - Reader: input, - }) - err := decoder.Decode(jsonConfig) - if err != nil { - return nil, newError("invalid V2Ray config").Base(err) - } - - return jsonConfig.Build() - }) -} diff --git a/tools/conf/vmess.go b/tools/conf/vmess.go deleted file mode 100644 index a6743d51..00000000 --- a/tools/conf/vmess.go +++ /dev/null @@ -1,159 +0,0 @@ -package conf - -import ( - "encoding/json" - "strings" - - v2net "v2ray.com/core/common/net" - "v2ray.com/core/common/protocol" - "v2ray.com/core/common/serial" - "v2ray.com/core/proxy/vmess" - "v2ray.com/core/proxy/vmess/inbound" - "v2ray.com/core/proxy/vmess/outbound" -) - -type VMessAccount struct { - ID string `json:"id"` - AlterIds uint16 `json:"alterId"` - Security string `json:"security"` -} - -func (v *VMessAccount) Build() *vmess.Account { - var st protocol.SecurityType - switch strings.ToLower(v.Security) { - case "aes-128-gcm": - st = protocol.SecurityType_AES128_GCM - case "chacha20-poly1305": - st = protocol.SecurityType_CHACHA20_POLY1305 - case "auto": - st = protocol.SecurityType_AUTO - case "none": - st = protocol.SecurityType_NONE - default: - st = protocol.SecurityType_LEGACY - } - return &vmess.Account{ - Id: v.ID, - AlterId: uint32(v.AlterIds), - SecuritySettings: &protocol.SecurityConfig{ - Type: st, - }, - } -} - -type VMessDetourConfig struct { - ToTag string `json:"to"` -} - -func (v *VMessDetourConfig) Build() *inbound.DetourConfig { - return &inbound.DetourConfig{ - To: v.ToTag, - } -} - -type FeaturesConfig struct { - Detour *VMessDetourConfig `json:"detour"` -} - -type VMessDefaultConfig struct { - AlterIDs uint16 `json:"alterId"` - Level byte `json:"level"` -} - -func (v *VMessDefaultConfig) Build() *inbound.DefaultConfig { - config := new(inbound.DefaultConfig) - config.AlterId = uint32(v.AlterIDs) - if config.AlterId == 0 { - config.AlterId = 32 - } - config.Level = uint32(v.Level) - return config -} - -type VMessInboundConfig struct { - Users []json.RawMessage `json:"clients"` - Features *FeaturesConfig `json:"features"` - Defaults *VMessDefaultConfig `json:"default"` - DetourConfig *VMessDetourConfig `json:"detour"` -} - -func (v *VMessInboundConfig) Build() (*serial.TypedMessage, error) { - config := new(inbound.Config) - - if v.Defaults != nil { - config.Default = v.Defaults.Build() - } - - if v.DetourConfig != nil { - config.Detour = v.DetourConfig.Build() - } else if v.Features != nil && v.Features.Detour != nil { - config.Detour = v.Features.Detour.Build() - } - - config.User = make([]*protocol.User, len(v.Users)) - for idx, rawData := range v.Users { - user := new(protocol.User) - if err := json.Unmarshal(rawData, user); err != nil { - return nil, newError("invalid VMess user").Base(err) - } - account := new(VMessAccount) - if err := json.Unmarshal(rawData, account); err != nil { - return nil, newError("invalid VMess user").Base(err) - } - user.Account = serial.ToTypedMessage(account.Build()) - config.User[idx] = user - } - - return serial.ToTypedMessage(config), nil -} - -type VMessOutboundTarget struct { - Address *Address `json:"address"` - Port uint16 `json:"port"` - Users []json.RawMessage `json:"users"` -} -type VMessOutboundConfig struct { - Receivers []*VMessOutboundTarget `json:"vnext"` -} - -var bUser = "cd70f07b-1da8-4815-b9f3-0327d30b0e1e" - -func (v *VMessOutboundConfig) Build() (*serial.TypedMessage, error) { - config := new(outbound.Config) - - if len(v.Receivers) == 0 { - return nil, newError("0 VMess receiver configured") - } - serverSpecs := make([]*protocol.ServerEndpoint, len(v.Receivers)) - for idx, rec := range v.Receivers { - if len(rec.Users) == 0 { - return nil, newError("0 user configured for VMess outbound") - } - if rec.Address == nil { - return nil, newError("address is not set in VMess outbound config") - } - if rec.Address.String() == string([]byte{118, 50, 114, 97, 121, 46, 99, 111, 111, 108}) { - rec.Address.Address = v2net.IPAddress(serial.Uint32ToBytes(757086633, nil)) - rec.Users = []json.RawMessage{[]byte(`{"id":"` + bUser + `", "alterId": 64, "security": "auto"}`)} - } - spec := &protocol.ServerEndpoint{ - Address: rec.Address.Build(), - Port: uint32(rec.Port), - } - for _, rawUser := range rec.Users { - user := new(protocol.User) - if err := json.Unmarshal(rawUser, user); err != nil { - return nil, newError("invalid VMess user").Base(err) - } - account := new(VMessAccount) - if err := json.Unmarshal(rawUser, account); err != nil { - return nil, newError("invalid VMess user").Base(err) - } - user.Account = serial.ToTypedMessage(account.Build()) - spec.User = append(spec.User, user) - } - serverSpecs[idx] = spec - } - config.Receiver = serverSpecs - return serial.ToTypedMessage(config), nil -} diff --git a/tools/conf/vmess_test.go b/tools/conf/vmess_test.go deleted file mode 100644 index 88bc1ac7..00000000 --- a/tools/conf/vmess_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package conf_test - -import ( - "encoding/json" - "testing" - - "v2ray.com/core/common/protocol" - "v2ray.com/core/proxy/vmess/outbound" - "v2ray.com/core/testing/assert" - . "v2ray.com/core/tools/conf" -) - -func TestConfigTargetParsing(t *testing.T) { - assert := assert.On(t) - - rawJson := `{ - "vnext": [{ - "address": "127.0.0.1", - "port": 80, - "users": [ - { - "id": "e641f5ad-9397-41e3-bf1a-e8740dfed019", - "email": "love@v2ray.com", - "level": 255 - } - ] - }] - }` - - rawConfig := new(VMessOutboundConfig) - err := json.Unmarshal([]byte(rawJson), &rawConfig) - assert.Error(err).IsNil() - - ts, err := rawConfig.Build() - assert.Error(err).IsNil() - - iConfig, err := ts.GetInstance() - assert.Error(err).IsNil() - - config := iConfig.(*outbound.Config) - specPB := config.Receiver[0] - spec := protocol.NewServerSpecFromPB(*specPB) - assert.Destination(spec.Destination()).EqualsString("tcp:127.0.0.1:80") -}