From ae8121e63338aadb88ec7c49fb1bf54bc23f6116 Mon Sep 17 00:00:00 2001 From: Darien Raymond Date: Sun, 17 Jan 2016 15:20:49 +0000 Subject: [PATCH] remove json packages in app folder --- app/router/config.go | 6 +- app/router/{json/cache.go => config_cache.go} | 16 +- app/router/config_json.go | 28 +++ app/router/json/json.go | 26 --- app/router/router_test.go | 4 +- app/router/rules/{json => }/chinaip.go | 30 ++-- app/router/rules/{json => }/chinaip_test.go | 4 +- app/router/rules/{json => }/chinasites.go | 44 +++-- .../rules/{json => }/chinasites_test.go | 6 +- app/router/rules/condition.go | 144 +++++++++++++++ app/router/rules/config.go | 29 ++- app/router/rules/json/fieldrule.go | 166 ------------------ app/router/rules/json/fieldrule_test.go | 103 ----------- app/router/rules/json/router.go | 63 ------- app/router/rules/json/rules.go | 18 -- app/router/rules/router.go | 10 +- app/router/rules/router_config.go | 129 ++++++++++++++ app/router/rules/router_test.go | 9 +- app/router/rules/testing/router.go | 17 -- app/router/rules/testing/rule.go | 18 -- app/router/testing/config.go | 14 -- common/net/network.go | 5 + common/net/port.go | 4 + common/serial/string.go | 4 + release/server/main.go | 2 - shell/point/config.go | 2 +- shell/point/json/json.go | 17 +- shell/point/json/json_test.go | 1 + shell/point/point.go | 2 +- shell/point/testing/mocks/config.go | 5 +- testing/scenarios/server_env.go | 2 - 31 files changed, 423 insertions(+), 505 deletions(-) rename app/router/{json/cache.go => config_cache.go} (54%) create mode 100644 app/router/config_json.go delete mode 100644 app/router/json/json.go rename app/router/rules/{json => }/chinaip.go (99%) rename app/router/rules/{json => }/chinaip_test.go (93%) rename app/router/rules/{json => }/chinasites.go (94%) rename app/router/rules/{json => }/chinasites_test.go (91%) create mode 100644 app/router/rules/condition.go delete mode 100644 app/router/rules/json/fieldrule.go delete mode 100644 app/router/rules/json/fieldrule_test.go delete mode 100644 app/router/rules/json/router.go delete mode 100644 app/router/rules/json/rules.go create mode 100644 app/router/rules/router_config.go delete mode 100644 app/router/rules/testing/router.go delete mode 100644 app/router/rules/testing/rule.go delete mode 100644 app/router/testing/config.go diff --git a/app/router/config.go b/app/router/config.go index 1bcebbc1f..bddd358a5 100644 --- a/app/router/config.go +++ b/app/router/config.go @@ -1,6 +1,6 @@ package router -type Config interface { - Strategy() string - Settings() interface{} +type Config struct { + Strategy string + Settings interface{} } diff --git a/app/router/json/cache.go b/app/router/config_cache.go similarity index 54% rename from app/router/json/cache.go rename to app/router/config_cache.go index dda786052..012ad0d5e 100644 --- a/app/router/json/cache.go +++ b/app/router/config_cache.go @@ -1,9 +1,15 @@ -package json +package router -type ConfigObjectCreator func() interface{} +import ( + "errors" +) + +type ConfigObjectCreator func([]byte) (interface{}, error) var ( configCache map[string]ConfigObjectCreator + + ErrorRouterNotFound = errors.New("Router not found.") ) func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error { @@ -12,12 +18,12 @@ func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error { return nil } -func CreateRouterConfig(strategy string) interface{} { +func CreateRouterConfig(strategy string, data []byte) (interface{}, error) { creator, found := configCache[strategy] if !found { - return nil + return nil, ErrorRouterNotFound } - return creator() + return creator(data) } func init() { diff --git a/app/router/config_json.go b/app/router/config_json.go new file mode 100644 index 000000000..79a9ababd --- /dev/null +++ b/app/router/config_json.go @@ -0,0 +1,28 @@ +// +build json + +package router + +import ( + "encoding/json" + + "github.com/v2ray/v2ray-core/common/log" +) + +func (this *Config) UnmarshalJSON(data []byte) error { + type JsonConfig struct { + Strategy string `json:"strategy"` + Settings json.RawMessage `json:"settings"` + } + jsonConfig := new(JsonConfig) + if err := json.Unmarshal(data, jsonConfig); err != nil { + return err + } + settings, err := CreateRouterConfig(jsonConfig.Strategy, []byte(jsonConfig.Settings)) + if err != nil { + log.Error("Router: Failed to load router settings: %v", err) + return err + } + this.Strategy = jsonConfig.Strategy + this.Settings = settings + return nil +} diff --git a/app/router/json/json.go b/app/router/json/json.go deleted file mode 100644 index 2ce911b4c..000000000 --- a/app/router/json/json.go +++ /dev/null @@ -1,26 +0,0 @@ -package json - -import ( - "encoding/json" - - "github.com/v2ray/v2ray-core/common/log" -) - -type RouterConfig struct { - StrategyValue string `json:"strategy"` - SettingsValue json.RawMessage `json:"settings"` -} - -func (this *RouterConfig) Strategy() string { - return this.StrategyValue -} - -func (this *RouterConfig) Settings() interface{} { - settings := CreateRouterConfig(this.Strategy()) - err := json.Unmarshal(this.SettingsValue, settings) - if err != nil { - log.Error("Failed to load router settings: %v", err) - return nil - } - return settings -} diff --git a/app/router/router_test.go b/app/router/router_test.go index 8723d949f..e55cc8b3b 100644 --- a/app/router/router_test.go +++ b/app/router/router_test.go @@ -6,7 +6,7 @@ import ( "testing" . "github.com/v2ray/v2ray-core/app/router" - _ "github.com/v2ray/v2ray-core/app/router/rules/json" + _ "github.com/v2ray/v2ray-core/app/router/rules" v2net "github.com/v2ray/v2ray-core/common/net" "github.com/v2ray/v2ray-core/shell/point/json" v2testing "github.com/v2ray/v2ray-core/testing" @@ -21,7 +21,7 @@ func TestRouter(t *testing.T) { pointConfig, err := json.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json")) assert.Error(err).IsNil() - router, err := CreateRouter(pointConfig.RouterConfig().Strategy(), pointConfig.RouterConfig().Settings()) + router, err := CreateRouter(pointConfig.RouterConfig().Strategy, pointConfig.RouterConfig().Settings) assert.Error(err).IsNil() dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80) diff --git a/app/router/rules/json/chinaip.go b/app/router/rules/chinaip.go similarity index 99% rename from app/router/rules/json/chinaip.go rename to app/router/rules/chinaip.go index 399fbf172..e3a2fd171 100644 --- a/app/router/rules/json/chinaip.go +++ b/app/router/rules/chinaip.go @@ -1,23 +1,25 @@ -package json +// +build json + +package rules import ( + "encoding/json" + + "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" ) -type ChinaIPRule struct { - Rule -} - -func (this *ChinaIPRule) Apply(dest v2net.Destination) bool { - address := dest.Address() - if address.IsDomain() { - return false +func parseChinaIPRule(data []byte) (*Rule, error) { + rawRule := new(JsonRule) + err := json.Unmarshal(data, rawRule) + if err != nil { + log.Error("Router: Invalid router rule: %v", err) + return nil, err } - if address.IsIPv6() { - return false - } - ip := address.IP() - return chinaIPNet.Contains(ip) + return &Rule{ + Tag: rawRule.OutboundTag, + Condition: NewIPv4Matcher(chinaIPNet), + }, nil } var ( diff --git a/app/router/rules/json/chinaip_test.go b/app/router/rules/chinaip_test.go similarity index 93% rename from app/router/rules/json/chinaip_test.go rename to app/router/rules/chinaip_test.go index 19ac0efe6..9848d564d 100644 --- a/app/router/rules/json/chinaip_test.go +++ b/app/router/rules/chinaip_test.go @@ -1,4 +1,4 @@ -package json +package rules import ( "net" @@ -16,7 +16,7 @@ func makeDestination(ip string) v2net.Destination { func TestChinaIP(t *testing.T) { v2testing.Current(t) - rule := &ChinaIPRule{} + rule := NewIPv4Matcher(chinaIPNet) assert.Bool(rule.Apply(makeDestination("121.14.1.189"))).IsTrue() // sina.com.cn assert.Bool(rule.Apply(makeDestination("101.226.103.106"))).IsTrue() // qq.com assert.Bool(rule.Apply(makeDestination("115.239.210.36"))).IsTrue() // image.baidu.com diff --git a/app/router/rules/json/chinasites.go b/app/router/rules/chinasites.go similarity index 94% rename from app/router/rules/json/chinasites.go rename to app/router/rules/chinasites.go index afaf599b0..66015b953 100644 --- a/app/router/rules/json/chinasites.go +++ b/app/router/rules/chinasites.go @@ -1,29 +1,38 @@ -package json +// +build json + +package rules import ( - "strings" - + "encoding/json" + "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" ) -type ChinaSitesRule struct { - Rule +type ChinaSitesCondition struct { } -func (this *ChinaSitesRule) Apply(dest v2net.Destination) bool { - address := dest.Address() - if !address.IsDomain() { - return false - } - domain := strings.ToLower(address.Domain()) - for _, matcher := range compiledMatchers { - if matcher.Match(domain) { +func (this *ChinaSitesCondition) Apply(dest v2net.Destination) bool { + for _, cond := range chinaSitesConds { + if cond.Apply(dest) { return true } } return false } +func parseChinaSitesRule(data []byte) (*Rule, error) { + rawRule := new(JsonRule) + err := json.Unmarshal(data, rawRule) + if err != nil { + log.Error("Router: Invalid router rule: %v", err) + return nil, err + } + return &Rule{ + Tag: rawRule.OutboundTag, + Condition: &ChinaSitesCondition{}, + }, nil +} + const ( anySubDomain = "^(.*\\.)?" dotAm = "\\.am$" @@ -39,12 +48,10 @@ const ( ) var ( - compiledMatchers []*RegexpDomainMatcher + chinaSitesConds []Condition ) func init() { - compiledMatchers = make([]*RegexpDomainMatcher, 0, 1024) - regexpDomains := []string{ dotCn, "\\.xn--fiqs8s$", /* .中国 */ @@ -353,11 +360,12 @@ func init() { anySubDomain + "zhubajie" + dotCom, } - for _, pattern := range regexpDomains { + chinaSitesConds = make([]Condition, len(regexpDomains)) + for idx, pattern := range regexpDomains { matcher, err := NewRegexpDomainMatcher(pattern) if err != nil { panic(err) } - compiledMatchers = append(compiledMatchers, matcher) + chinaSitesConds[idx] = matcher } } diff --git a/app/router/rules/json/chinasites_test.go b/app/router/rules/chinasites_test.go similarity index 91% rename from app/router/rules/json/chinasites_test.go rename to app/router/rules/chinasites_test.go index e4fdeffb4..10bbab768 100644 --- a/app/router/rules/json/chinasites_test.go +++ b/app/router/rules/chinasites_test.go @@ -1,4 +1,6 @@ -package json +// +build json + +package rules import ( "testing" @@ -15,7 +17,7 @@ func makeDomainDestination(domain string) v2net.Destination { func TestChinaSites(t *testing.T) { v2testing.Current(t) - rule := &ChinaSitesRule{} + rule := new(ChinaSitesCondition) assert.Bool(rule.Apply(makeDomainDestination("v.qq.com"))).IsTrue() assert.Bool(rule.Apply(makeDomainDestination("www.163.com"))).IsTrue() assert.Bool(rule.Apply(makeDomainDestination("ngacn.cc"))).IsTrue() diff --git a/app/router/rules/condition.go b/app/router/rules/condition.go new file mode 100644 index 000000000..390352f64 --- /dev/null +++ b/app/router/rules/condition.go @@ -0,0 +1,144 @@ +package rules + +import ( + "net" + "regexp" + + v2net "github.com/v2ray/v2ray-core/common/net" + "github.com/v2ray/v2ray-core/common/serial" +) + +type Condition interface { + Apply(dest v2net.Destination) bool +} + +type ConditionChan []Condition + +func NewConditionChan() *ConditionChan { + var condChan ConditionChan = make([]Condition, 0, 8) + return &condChan +} + +func (this *ConditionChan) Add(cond Condition) *ConditionChan { + *this = append(*this, cond) + return this +} + +func (this *ConditionChan) Apply(dest v2net.Destination) bool { + for _, cond := range *this { + if !cond.Apply(dest) { + return false + } + } + return true +} + +func (this *ConditionChan) Len() int { + return len(*this) +} + +type PlainDomainMatcher struct { + pattern serial.StringLiteral +} + +func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher { + return &PlainDomainMatcher{ + pattern: serial.StringLiteral(pattern), + } +} + +func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool { + if !dest.Address().IsDomain() { + return false + } + domain := serial.StringLiteral(dest.Address().Domain()) + return domain.Contains(this.pattern) +} + +type RegexpDomainMatcher struct { + pattern *regexp.Regexp +} + +func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) { + r, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + return &RegexpDomainMatcher{ + pattern: r, + }, nil +} + +func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool { + if !dest.Address().IsDomain() { + return false + } + domain := serial.StringLiteral(dest.Address().Domain()) + return this.pattern.MatchString(domain.ToLower().String()) +} + +type CIDRMatcher struct { + cidr *net.IPNet +} + +func NewCIDRMatcher(ipnet string) (*CIDRMatcher, error) { + _, cidr, err := net.ParseCIDR(ipnet) + if err != nil { + return nil, err + } + return &CIDRMatcher{ + cidr: cidr, + }, nil +} + +func (this *CIDRMatcher) Apply(dest v2net.Destination) bool { + if !dest.Address().IsIPv4() && !dest.Address().IsIPv6() { + return false + } + return this.cidr.Contains(dest.Address().IP()) +} + +type IPv4Matcher struct { + ipv4net *v2net.IPNet +} + +func NewIPv4Matcher(ipnet *v2net.IPNet) *IPv4Matcher { + return &IPv4Matcher{ + ipv4net: ipnet, + } +} + +func (this *IPv4Matcher) Apply(dest v2net.Destination) bool { + if !dest.Address().IsIPv4() { + return false + } + return this.ipv4net.Contains(dest.Address().IP()) +} + +type PortMatcher struct { + port v2net.PortRange +} + +func NewPortMatcher(portRange v2net.PortRange) *PortMatcher { + return &PortMatcher{ + port: portRange, + } +} + +func (this *PortMatcher) Apply(dest v2net.Destination) bool { + return this.port.Contains(dest.Port()) +} + +type NetworkMatcher struct { + network *v2net.NetworkList +} + +func NewNetworkMatcher(network *v2net.NetworkList) *NetworkMatcher { + return &NetworkMatcher{ + network: network, + } +} + +func (this *NetworkMatcher) Apply(dest v2net.Destination) bool { + return this.network.HasNetwork(v2net.Network(dest.Network())) +} diff --git a/app/router/rules/config.go b/app/router/rules/config.go index 52bfd4bbc..0e6c91dbe 100644 --- a/app/router/rules/config.go +++ b/app/router/rules/config.go @@ -4,11 +4,30 @@ import ( v2net "github.com/v2ray/v2ray-core/common/net" ) -type Rule interface { - Tag() string - Apply(dest v2net.Destination) bool +type Rule struct { + Tag string + Condition Condition } -type RouterRuleConfig interface { - Rules() []Rule +func (this *Rule) Apply(dest v2net.Destination) bool { + return this.Condition.Apply(dest) +} + +type RouterRuleConfig struct { + rules []*Rule +} + +func NewRouterRuleConfig() *RouterRuleConfig { + return &RouterRuleConfig{ + rules: make([]*Rule, 0, 16), + } +} + +func (this *RouterRuleConfig) Add(rule *Rule) *RouterRuleConfig { + this.rules = append(this.rules, rule) + return this +} + +func (this *RouterRuleConfig) Rules() []*Rule { + return this.rules } diff --git a/app/router/rules/json/fieldrule.go b/app/router/rules/json/fieldrule.go deleted file mode 100644 index 93f9494fb..000000000 --- a/app/router/rules/json/fieldrule.go +++ /dev/null @@ -1,166 +0,0 @@ -package json - -import ( - "encoding/json" - "errors" - "net" - "regexp" - "strings" - - v2net "github.com/v2ray/v2ray-core/common/net" - "github.com/v2ray/v2ray-core/common/serial" -) - -type DomainMatcher interface { - Match(domain string) bool -} - -type PlainDomainMatcher struct { - pattern string -} - -func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher { - return &PlainDomainMatcher{ - pattern: strings.ToLower(pattern), - } -} - -func (this *PlainDomainMatcher) Match(domain string) bool { - return strings.Contains(strings.ToLower(domain), this.pattern) -} - -type RegexpDomainMatcher struct { - pattern *regexp.Regexp -} - -func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) { - r, err := regexp.Compile(pattern) - if err != nil { - return nil, err - } - return &RegexpDomainMatcher{ - pattern: r, - }, nil -} - -func (this *RegexpDomainMatcher) Match(domain string) bool { - return this.pattern.MatchString(strings.ToLower(domain)) -} - -type FieldRule struct { - Rule - Domain []DomainMatcher - IP []*net.IPNet - Port *v2net.PortRange - Network *v2net.NetworkList -} - -func (this *FieldRule) Apply(dest v2net.Destination) bool { - address := dest.Address() - if len(this.Domain) > 0 { - if !address.IsDomain() { - return false - } - foundMatch := false - for _, domain := range this.Domain { - if domain.Match(address.Domain()) { - foundMatch = true - break - } - } - if !foundMatch { - return false - } - } - - if this.IP != nil && len(this.IP) > 0 { - if !(address.IsIPv4() || address.IsIPv6()) { - return false - } - foundMatch := false - for _, ipnet := range this.IP { - if ipnet.Contains(address.IP()) { - foundMatch = true - break - } - } - if !foundMatch { - return false - } - } - - if this.Port != nil { - port := dest.Port() - if port.Value() < this.Port.From.Value() || port.Value() > this.Port.To.Value() { - return false - } - } - - if this.Network != nil { - if !this.Network.HasNetwork(v2net.Network(dest.Network())) { - return false - } - } - - return true -} - -func (this *FieldRule) UnmarshalJSON(data []byte) error { - type RawFieldRule struct { - Rule - Domain *serial.StringLiteralList `json:"domain"` - IP *serial.StringLiteralList `json:"ip"` - Port *v2net.PortRange `json:"port"` - Network *v2net.NetworkList `json:"network"` - } - rawFieldRule := RawFieldRule{} - err := json.Unmarshal(data, &rawFieldRule) - if err != nil { - return err - } - this.Type = rawFieldRule.Type - this.OutboundTag = rawFieldRule.OutboundTag - - hasField := false - if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 { - this.Domain = make([]DomainMatcher, rawFieldRule.Domain.Len()) - for idx, rawDomain := range *(rawFieldRule.Domain) { - var matcher DomainMatcher - if strings.HasPrefix(rawDomain.String(), "regexp:") { - rawMatcher, err := NewRegexpDomainMatcher(rawDomain.String()[7:]) - if err != nil { - return err - } - matcher = rawMatcher - } else { - matcher = NewPlainDomainMatcher(rawDomain.String()) - } - this.Domain[idx] = matcher - } - hasField = true - } - - if rawFieldRule.IP != nil && rawFieldRule.IP.Len() > 0 { - this.IP = make([]*net.IPNet, 0, rawFieldRule.IP.Len()) - for _, ipStr := range *(rawFieldRule.IP) { - _, ipNet, err := net.ParseCIDR(ipStr.String()) - if err != nil { - return errors.New("Invalid IP range in router rule: " + err.Error()) - } - this.IP = append(this.IP, ipNet) - } - hasField = true - } - if rawFieldRule.Port != nil { - this.Port = rawFieldRule.Port - hasField = true - } - if rawFieldRule.Network != nil { - this.Network = rawFieldRule.Network - hasField = true - } - if !hasField { - return errors.New("This rule has no effective fields.") - } - return nil -} diff --git a/app/router/rules/json/fieldrule_test.go b/app/router/rules/json/fieldrule_test.go deleted file mode 100644 index 5926ce24b..000000000 --- a/app/router/rules/json/fieldrule_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package json - -import ( - "testing" - - v2net "github.com/v2ray/v2ray-core/common/net" - v2testing "github.com/v2ray/v2ray-core/testing" - "github.com/v2ray/v2ray-core/testing/assert" -) - -func TestDomainMatching(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "domain": ["google.com", "regexp:v2ray.com$"], - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.DomainAddress("www.v2ray.com"), 80) - assert.Bool(rule.Apply(dest)).IsTrue() -} - -func TestPortMatching(t *testing.T) { - v2testing.Current(t) - - rule := &FieldRule{ - Port: &v2net.PortRange{ - From: 0, - To: 100, - }, - } - dest := v2net.TCPDestination(v2net.DomainAddress("www.v2ray.com"), 80) - assert.Bool(rule.Apply(dest)).IsTrue() -} - -func TestIPMatching(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "ip": "10.0.0.0/8", - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80) - assert.Bool(rule.Apply(dest)).IsTrue() -} - -func TestIPListMatching(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "ip": ["10.0.0.0/8", "192.168.0.0/16"], - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.IPAddress([]byte{192, 168, 1, 1}), 80) - assert.Bool(rule.Apply(dest)).IsTrue() -} - -func TestPortNotMatching(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "port": "80-100", - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 79) - assert.Bool(rule.Apply(dest)).IsFalse() -} - -func TestDomainNotMatching(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "domain": ["google.com", "v2ray.com"], - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80) - assert.Bool(rule.Apply(dest)).IsFalse() -} - -func TestDomainNotMatchingDomain(t *testing.T) { - v2testing.Current(t) - - rawJson := `{ - "type": "field", - "domain": ["google.com", "v2ray.com"], - "tag": "test" - }` - rule := parseRule([]byte(rawJson)) - dest := v2net.TCPDestination(v2net.DomainAddress("baidu.com"), 80) - assert.Bool(rule.Apply(dest)).IsFalse() - - dest = v2net.TCPDestination(v2net.DomainAddress("www.google.com"), 80) - assert.Bool(rule.Apply(dest)).IsTrue() -} diff --git a/app/router/rules/json/router.go b/app/router/rules/json/router.go deleted file mode 100644 index 45809edc7..000000000 --- a/app/router/rules/json/router.go +++ /dev/null @@ -1,63 +0,0 @@ -package json - -import ( - "encoding/json" - - v2routerjson "github.com/v2ray/v2ray-core/app/router/json" - "github.com/v2ray/v2ray-core/app/router/rules" - "github.com/v2ray/v2ray-core/common/log" -) - -type RouterRuleConfig struct { - RuleList []json.RawMessage `json:"rules"` -} - -func parseRule(msg json.RawMessage) rules.Rule { - rule := new(Rule) - err := json.Unmarshal(msg, rule) - if err != nil { - log.Error("Invalid router rule: %v", err) - return nil - } - if rule.Type == "field" { - fieldrule := new(FieldRule) - err = json.Unmarshal(msg, fieldrule) - if err != nil { - log.Error("Invalid field rule: %v", err) - return nil - } - return fieldrule - } - if rule.Type == "chinaip" { - chinaiprule := new(ChinaIPRule) - if err := json.Unmarshal(msg, chinaiprule); err != nil { - log.Error("Invalid chinaip rule: %v", err) - return nil - } - return chinaiprule - } - if rule.Type == "chinasites" { - chinasitesrule := new(ChinaSitesRule) - if err := json.Unmarshal(msg, chinasitesrule); err != nil { - log.Error("Invalid chinasites rule: %v", err) - return nil - } - return chinasitesrule - } - log.Error("Unknown router rule type: %s", rule.Type) - return nil -} - -func (this *RouterRuleConfig) Rules() []rules.Rule { - rules := make([]rules.Rule, len(this.RuleList)) - for idx, rawRule := range this.RuleList { - rules[idx] = parseRule(rawRule) - } - return rules -} - -func init() { - v2routerjson.RegisterRouterConfig("rules", func() interface{} { - return new(RouterRuleConfig) - }) -} diff --git a/app/router/rules/json/rules.go b/app/router/rules/json/rules.go deleted file mode 100644 index 8dbc15b49..000000000 --- a/app/router/rules/json/rules.go +++ /dev/null @@ -1,18 +0,0 @@ -package json - -import ( - v2net "github.com/v2ray/v2ray-core/common/net" -) - -type Rule struct { - Type string `json:"type"` - OutboundTag string `json:"outboundTag"` -} - -func (this *Rule) Tag() string { - return this.OutboundTag -} - -func (this *Rule) Apply(dest v2net.Destination) bool { - return false -} diff --git a/app/router/rules/router.go b/app/router/rules/router.go index 41b5bbebb..f1d46acf9 100644 --- a/app/router/rules/router.go +++ b/app/router/rules/router.go @@ -38,18 +38,18 @@ func (this *cacheEntry) Extend() { } type Router struct { - rules []Rule + rules []*Rule cache *collect.ValidityMap } func NewRouter() *Router { return &Router{ - rules: make([]Rule, 0, 16), + rules: make([]*Rule, 0, 16), cache: collect.NewValidityMap(3600), } } -func (this *Router) AddRule(rule Rule) *Router { +func (this *Router) AddRule(rule *Rule) *Router { this.rules = append(this.rules, rule) return this } @@ -57,7 +57,7 @@ func (this *Router) AddRule(rule Rule) *Router { func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) { for _, rule := range this.rules { if rule.Apply(dest) { - return rule.Tag(), nil + return rule.Tag, nil } } return "", NoRuleApplicable @@ -78,7 +78,7 @@ type RouterFactory struct { } func (this *RouterFactory) Create(rawConfig interface{}) (router.Router, error) { - config := rawConfig.(RouterRuleConfig) + config := rawConfig.(*RouterRuleConfig) rules := config.Rules() router := NewRouter() for _, rule := range rules { diff --git a/app/router/rules/router_config.go b/app/router/rules/router_config.go new file mode 100644 index 000000000..0eed6d24b --- /dev/null +++ b/app/router/rules/router_config.go @@ -0,0 +1,129 @@ +// +build json + +package rules + +import ( + "encoding/json" + "errors" + "strings" + + router "github.com/v2ray/v2ray-core/app/router" + "github.com/v2ray/v2ray-core/common/log" + v2net "github.com/v2ray/v2ray-core/common/net" + "github.com/v2ray/v2ray-core/common/serial" +) + +type JsonRule struct { + Type string `json:"type"` + OutboundTag string `json:"outboundTag"` +} + +func parseFieldRule(msg json.RawMessage) (*Rule, error) { + type RawFieldRule struct { + JsonRule + Domain *serial.StringLiteralList `json:"domain"` + IP *serial.StringLiteralList `json:"ip"` + Port *v2net.PortRange `json:"port"` + Network *v2net.NetworkList `json:"network"` + } + rawFieldRule := new(RawFieldRule) + err := json.Unmarshal(msg, rawFieldRule) + if err != nil { + return nil, err + } + conds := NewConditionChan() + + if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 { + for _, rawDomain := range *(rawFieldRule.Domain) { + var matcher Condition + if strings.HasPrefix(rawDomain.String(), "regexp:") { + rawMatcher, err := NewRegexpDomainMatcher(rawDomain.String()[7:]) + if err != nil { + return nil, err + } + matcher = rawMatcher + } else { + matcher = NewPlainDomainMatcher(rawDomain.String()) + } + conds.Add(matcher) + } + } + + if rawFieldRule.IP != nil && rawFieldRule.IP.Len() > 0 { + for _, ipStr := range *(rawFieldRule.IP) { + cidrMatcher, err := NewCIDRMatcher(ipStr.String()) + if err != nil { + log.Error("Router: Invalid IP range in router rule: %v", err) + return nil, err + } + conds.Add(cidrMatcher) + } + } + if rawFieldRule.Port != nil { + conds.Add(NewPortMatcher(*rawFieldRule.Port)) + } + if rawFieldRule.Network != nil { + conds.Add(NewNetworkMatcher(rawFieldRule.Network)) + } + if conds.Len() == 0 { + return nil, errors.New("Router: This rule has no effective fields.") + } + return &Rule{ + Tag: rawFieldRule.OutboundTag, + Condition: conds, + }, nil +} + +func parseRule(msg json.RawMessage) *Rule { + rawRule := new(JsonRule) + err := json.Unmarshal(msg, rawRule) + if err != nil { + log.Error("Router: Invalid router rule: %v", err) + return nil + } + if rawRule.Type == "field" { + + fieldrule, err := parseFieldRule(msg) + if err != nil { + log.Error("Invalid field rule: %v", err) + return nil + } + return fieldrule + } + if rawRule.Type == "chinaip" { + chinaiprule, err := parseChinaIPRule(msg) + if err != nil { + log.Error("Router: Invalid chinaip rule: %v", err) + return nil + } + return chinaiprule + } + if rawRule.Type == "chinasites" { + chinasitesrule, err := parseChinaSitesRule(msg) + if err != nil { + log.Error("Invalid chinasites rule: %v", err) + return nil + } + return chinasitesrule + } + log.Error("Unknown router rule type: %s", rawRule.Type) + return nil +} + +func init() { + router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) { + type JsonConfig struct { + RuleList []json.RawMessage `json:"rules"` + } + jsonConfig := new(JsonConfig) + if err := json.Unmarshal(data, jsonConfig); err != nil { + return nil, err + } + config := NewRouterRuleConfig() + for _, rawRule := range jsonConfig.RuleList { + rule := parseRule(rawRule) + config.Add(rule) + } + return config, nil + }) +} diff --git a/app/router/rules/router_test.go b/app/router/rules/router_test.go index 93473e589..214770138 100644 --- a/app/router/rules/router_test.go +++ b/app/router/rules/router_test.go @@ -4,7 +4,6 @@ import ( "testing" . "github.com/v2ray/v2ray-core/app/router/rules" - testinconfig "github.com/v2ray/v2ray-core/app/router/rules/testing" v2net "github.com/v2ray/v2ray-core/common/net" v2testing "github.com/v2ray/v2ray-core/testing" "github.com/v2ray/v2ray-core/testing/assert" @@ -14,11 +13,9 @@ func TestSimpleRouter(t *testing.T) { v2testing.Current(t) router := NewRouter().AddRule( - &testinconfig.TestRule{ - TagValue: "test", - Function: func(dest v2net.Destination) bool { - return dest.IsTCP() - }, + &Rule{ + Tag: "test", + Condition: NewNetworkMatcher(v2net.Network("tcp").AsList()), }) tag, err := router.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80)) diff --git a/app/router/rules/testing/router.go b/app/router/rules/testing/router.go deleted file mode 100644 index a2b2f90e3..000000000 --- a/app/router/rules/testing/router.go +++ /dev/null @@ -1,17 +0,0 @@ -package testing - -import ( - "github.com/v2ray/v2ray-core/app/router/rules" -) - -type RouterRuleConfig struct { - RuleList []*TestRule -} - -func (this *RouterRuleConfig) Rules() []rules.Rule { - rules := make([]rules.Rule, len(this.RuleList)) - for idx, rule := range this.RuleList { - rules[idx] = rule - } - return rules -} diff --git a/app/router/rules/testing/rule.go b/app/router/rules/testing/rule.go deleted file mode 100644 index 775003337..000000000 --- a/app/router/rules/testing/rule.go +++ /dev/null @@ -1,18 +0,0 @@ -package testing - -import ( - v2net "github.com/v2ray/v2ray-core/common/net" -) - -type TestRule struct { - Function func(v2net.Destination) bool - TagValue string -} - -func (this *TestRule) Apply(dest v2net.Destination) bool { - return this.Function(dest) -} - -func (this *TestRule) Tag() string { - return this.TagValue -} diff --git a/app/router/testing/config.go b/app/router/testing/config.go deleted file mode 100644 index bd1d314bb..000000000 --- a/app/router/testing/config.go +++ /dev/null @@ -1,14 +0,0 @@ -package testing - -type RouterConfig struct { - StrategyValue string - SettingsValue interface{} -} - -func (this *RouterConfig) Strategy() string { - return this.StrategyValue -} - -func (this *RouterConfig) Settings() interface{} { - return this.SettingsValue -} diff --git a/common/net/network.go b/common/net/network.go index 91ab1a99d..64efe110c 100644 --- a/common/net/network.go +++ b/common/net/network.go @@ -11,6 +11,11 @@ const ( type Network serial.StringLiteral +func (this Network) AsList() *NetworkList { + list := NetworkList([]Network{this}) + return &list +} + type NetworkList []Network func NewNetworkList(networks serial.StringLiteralList) NetworkList { diff --git a/common/net/port.go b/common/net/port.go index 5efb191dc..e22d58df5 100644 --- a/common/net/port.go +++ b/common/net/port.go @@ -26,3 +26,7 @@ type PortRange struct { From Port To Port } + +func (this PortRange) Contains(port Port) bool { + return this.From <= port && port <= this.To +} diff --git a/common/serial/string.go b/common/serial/string.go index 1c5bbd1e9..68ddd54ac 100644 --- a/common/serial/string.go +++ b/common/serial/string.go @@ -15,6 +15,10 @@ func NewStringLiteral(str String) StringLiteral { return StringLiteral(str.String()) } +func (this StringLiteral) Contains(str String) bool { + return strings.Contains(this.String(), str.String()) +} + func (this StringLiteral) String() string { return string(this) } diff --git a/release/server/main.go b/release/server/main.go index 3646b7e41..516511982 100644 --- a/release/server/main.go +++ b/release/server/main.go @@ -7,9 +7,7 @@ import ( "path/filepath" "github.com/v2ray/v2ray-core" - _ "github.com/v2ray/v2ray-core/app/router/json" _ "github.com/v2ray/v2ray-core/app/router/rules" - _ "github.com/v2ray/v2ray-core/app/router/rules/json" "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/shell/point" pointjson "github.com/v2ray/v2ray-core/shell/point/json" diff --git a/shell/point/config.go b/shell/point/config.go index e291e0234..7f367752b 100644 --- a/shell/point/config.go +++ b/shell/point/config.go @@ -52,7 +52,7 @@ type OutboundDetourConfig interface { type PointConfig interface { Port() v2net.Port LogConfig() LogConfig - RouterConfig() router.Config + RouterConfig() *router.Config InboundConfig() ConnectionConfig OutboundConfig() ConnectionConfig InboundDetours() []InboundDetourConfig diff --git a/shell/point/json/json.go b/shell/point/json/json.go index 516155480..b5999159c 100644 --- a/shell/point/json/json.go +++ b/shell/point/json/json.go @@ -6,7 +6,6 @@ import ( "os" "github.com/v2ray/v2ray-core/app/router" - routerjson "github.com/v2ray/v2ray-core/app/router/json" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" "github.com/v2ray/v2ray-core/shell/point" @@ -14,13 +13,13 @@ import ( // Config is the config for Point server. type Config struct { - PortValue v2net.Port `json:"port"` // Port of this Point server. - LogConfigValue *LogConfig `json:"log"` - RouterConfigValue *routerjson.RouterConfig `json:"routing"` - InboundConfigValue *ConnectionConfig `json:"inbound"` - OutboundConfigValue *ConnectionConfig `json:"outbound"` - InboundDetoursValue []*InboundDetourConfig `json:"inboundDetour"` - OutboundDetoursValue []*OutboundDetourConfig `json:"outboundDetour"` + PortValue v2net.Port `json:"port"` // Port of this Point server. + LogConfigValue *LogConfig `json:"log"` + RouterConfigValue *router.Config `json:"routing"` + InboundConfigValue *ConnectionConfig `json:"inbound"` + OutboundConfigValue *ConnectionConfig `json:"outbound"` + InboundDetoursValue []*InboundDetourConfig `json:"inboundDetour"` + OutboundDetoursValue []*OutboundDetourConfig `json:"outboundDetour"` } func (config *Config) Port() v2net.Port { @@ -34,7 +33,7 @@ func (config *Config) LogConfig() point.LogConfig { return config.LogConfigValue } -func (this *Config) RouterConfig() router.Config { +func (this *Config) RouterConfig() *router.Config { if this.RouterConfigValue == nil { return nil } diff --git a/shell/point/json/json_test.go b/shell/point/json/json_test.go index 341b4d976..c6de1b335 100644 --- a/shell/point/json/json_test.go +++ b/shell/point/json/json_test.go @@ -4,6 +4,7 @@ import ( "path/filepath" "testing" + _ "github.com/v2ray/v2ray-core/app/router/rules" netassert "github.com/v2ray/v2ray-core/common/net/testing/assert" _ "github.com/v2ray/v2ray-core/proxy/dokodemo" _ "github.com/v2ray/v2ray-core/proxy/freedom" diff --git a/shell/point/point.go b/shell/point/point.go index 300f8c039..48b829da0 100644 --- a/shell/point/point.go +++ b/shell/point/point.go @@ -102,7 +102,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) { routerConfig := pConfig.RouterConfig() if routerConfig != nil { - r, err := router.CreateRouter(routerConfig.Strategy(), routerConfig.Settings()) + r, err := router.CreateRouter(routerConfig.Strategy, routerConfig.Settings) if err != nil { log.Error("Failed to create router: %v", err) return nil, BadConfiguration diff --git a/shell/point/testing/mocks/config.go b/shell/point/testing/mocks/config.go index 0b76e416d..399506e47 100644 --- a/shell/point/testing/mocks/config.go +++ b/shell/point/testing/mocks/config.go @@ -2,7 +2,6 @@ package mocks import ( "github.com/v2ray/v2ray-core/app/router" - routertesting "github.com/v2ray/v2ray-core/app/router/testing" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" "github.com/v2ray/v2ray-core/shell/point" @@ -88,7 +87,7 @@ func (this *OutboundDetourConfig) Tag() string { type Config struct { PortValue v2net.Port LogConfigValue *LogConfig - RouterConfigValue *routertesting.RouterConfig + RouterConfigValue *router.Config InboundConfigValue *ConnectionConfig OutboundConfigValue *ConnectionConfig InboundDetoursValue []*InboundDetourConfig @@ -106,7 +105,7 @@ func (config *Config) LogConfig() point.LogConfig { return config.LogConfigValue } -func (this *Config) RouterConfig() router.Config { +func (this *Config) RouterConfig() *router.Config { if this.RouterConfigValue == nil { return nil } diff --git a/testing/scenarios/server_env.go b/testing/scenarios/server_env.go index a8c0263f2..29567c629 100644 --- a/testing/scenarios/server_env.go +++ b/testing/scenarios/server_env.go @@ -4,9 +4,7 @@ import ( "os" "path/filepath" - _ "github.com/v2ray/v2ray-core/app/router/json" _ "github.com/v2ray/v2ray-core/app/router/rules" - _ "github.com/v2ray/v2ray-core/app/router/rules/json" "github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/shell/point" pointjson "github.com/v2ray/v2ray-core/shell/point/json"