Browse Source

regexp support in domain matching

Darien Raymond 10 years ago
parent
commit
96aa94002a

+ 49 - 5
app/router/rules/config/json/fieldrule.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"errors"
 	"net"
+	"regexp"
 	"strings"
 
 	v2net "github.com/v2ray/v2ray-core/common/net"
@@ -41,9 +42,39 @@ func (this *StringList) Len() int {
 	return len([]string(*this))
 }
 
+type DomainMatcher interface {
+	Match(domain string) bool
+}
+
+type PlainDomainMatcher struct {
+	pattern string
+}
+
+func (this *PlainDomainMatcher) Match(domain string) bool {
+	return strings.Contains(this.pattern, domain)
+}
+
+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(domain)
+}
+
 type FieldRule struct {
 	Rule
-	Domain  *StringList
+	Domain  []DomainMatcher
 	IP      []*net.IPNet
 	Port    v2net.PortRange
 	Network v2net.NetworkList
@@ -51,13 +82,13 @@ type FieldRule struct {
 
 func (this *FieldRule) Apply(dest v2net.Destination) bool {
 	address := dest.Address()
-	if this.Domain != nil && this.Domain.Len() > 0 {
+	if len(this.Domain) > 0 {
 		if !address.IsDomain() {
 			return false
 		}
 		foundMatch := false
-		for _, domain := range *this.Domain {
-			if strings.Contains(address.Domain(), domain) {
+		for _, domain := range this.Domain {
+			if domain.Match(address.Domain()) {
 				foundMatch = true
 				break
 			}
@@ -117,7 +148,20 @@ func (this *FieldRule) UnmarshalJSON(data []byte) error {
 
 	hasField := false
 	if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 {
-		this.Domain = rawFieldRule.Domain
+		this.Domain = make([]DomainMatcher, rawFieldRule.Domain.Len())
+		for idx, rawDomain := range *(rawFieldRule.Domain) {
+			var matcher DomainMatcher
+			if strings.HasPrefix(rawDomain, "regexp:") {
+				rawMatcher, err := NewRegexpDomainMatcher(rawDomain[7:])
+				if err != nil {
+					return err
+				}
+				matcher = rawMatcher
+			} else {
+				matcher = &PlainDomainMatcher{pattern: rawDomain}
+			}
+			this.Domain[idx] = matcher
+		}
 		hasField = true
 	}
 

+ 6 - 3
app/router/rules/config/json/fieldrule_test.go

@@ -33,9 +33,12 @@ func TestStringListParsingString(t *testing.T) {
 func TestDomainMatching(t *testing.T) {
 	v2testing.Current(t)
 
-	rule := &FieldRule{
-		Domain: NewStringList("v2ray.com"),
-	}
+	rawJson := `{
+    "type": "field",
+    "domain": ["google.com", "regexp:v2ray.com$"],
+    "tag": "test"
+  }`
+	rule := parseRule([]byte(rawJson))
 	dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80))
 	assert.Bool(rule.Apply(dest)).IsTrue()
 }