Explorar el Código

remove json packages in app folder

Darien Raymond hace 9 años
padre
commit
ae8121e633

+ 3 - 3
app/router/config.go

@@ -1,6 +1,6 @@
 package router
 
-type Config interface {
-	Strategy() string
-	Settings() interface{}
+type Config struct {
+	Strategy string
+	Settings interface{}
 }

+ 11 - 5
app/router/json/cache.go → 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() {

+ 28 - 0
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
+}

+ 0 - 26
app/router/json/json.go

@@ -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
-}

+ 2 - 2
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)

+ 16 - 14
app/router/rules/json/chinaip.go → 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
-	}
-	if address.IsIPv6() {
-		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
 	}
-	ip := address.IP()
-	return chinaIPNet.Contains(ip)
+	return &Rule{
+		Tag:       rawRule.OutboundTag,
+		Condition: NewIPv4Matcher(chinaIPNet),
+	}, nil
 }
 
 var (

+ 2 - 2
app/router/rules/json/chinaip_test.go → 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

+ 26 - 18
app/router/rules/json/chinasites.go → app/router/rules/chinasites.go

@@ -1,29 +1,38 @@
-package json
+// +build json
 
-import (
-	"strings"
+package rules
 
+import (
+	"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
 	}
 }

+ 4 - 2
app/router/rules/json/chinasites_test.go → 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()

+ 144 - 0
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()))
+}

+ 24 - 5
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
 }

+ 0 - 166
app/router/rules/json/fieldrule.go

@@ -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
-}

+ 0 - 103
app/router/rules/json/fieldrule_test.go

@@ -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()
-}

+ 0 - 63
app/router/rules/json/router.go

@@ -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)
-	})
-}

+ 0 - 18
app/router/rules/json/rules.go

@@ -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
-}

+ 5 - 5
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 {

+ 129 - 0
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
+	})
+}

+ 3 - 6
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))

+ 0 - 17
app/router/rules/testing/router.go

@@ -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
-}

+ 0 - 18
app/router/rules/testing/rule.go

@@ -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
-}

+ 0 - 14
app/router/testing/config.go

@@ -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
-}

+ 5 - 0
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 {

+ 4 - 0
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
+}

+ 4 - 0
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)
 }

+ 0 - 2
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"

+ 1 - 1
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

+ 8 - 9
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
 	}

+ 1 - 0
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"

+ 1 - 1
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

+ 2 - 3
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
 	}

+ 0 - 2
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"