mirror of https://github.com/v2ray/v2ray-core
				
				
				
			field domain and ip accepts list of strings
							parent
							
								
									d4dcbbc734
								
							
						
					
					
						commit
						759efb0cfa
					
				| 
						 | 
				
			
			@ -10,24 +10,73 @@ import (
 | 
			
		|||
	v2netjson "github.com/v2ray/v2ray-core/common/net/json"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type StringList []string
 | 
			
		||||
 | 
			
		||||
func NewStringList(str ...string) *StringList {
 | 
			
		||||
	list := StringList(str)
 | 
			
		||||
	return &list
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *StringList) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	var strList []string
 | 
			
		||||
	err := json.Unmarshal(data, &strList)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		*this = make([]string, len(strList))
 | 
			
		||||
		copy(*this, strList)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var str string
 | 
			
		||||
	err = json.Unmarshal(data, &str)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		*this = make([]string, 0, 1)
 | 
			
		||||
		*this = append(*this, str)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errors.New("Failed to unmarshal string list: " + string(data))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *StringList) Len() int {
 | 
			
		||||
	return len([]string(*this))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FieldRule struct {
 | 
			
		||||
	Rule
 | 
			
		||||
	Domain  string
 | 
			
		||||
	IP      *net.IPNet
 | 
			
		||||
	Domain  *StringList
 | 
			
		||||
	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() || !strings.Contains(address.Domain(), this.Domain) {
 | 
			
		||||
	if this.Domain != nil && this.Domain.Len() > 0 {
 | 
			
		||||
		if !address.IsDomain() {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		foundMatch := false
 | 
			
		||||
		for _, domain := range *this.Domain {
 | 
			
		||||
			if strings.Contains(address.Domain(), domain) {
 | 
			
		||||
				foundMatch = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !foundMatch {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if this.IP != nil {
 | 
			
		||||
		if !(address.IsIPv4() || address.IsIPv6()) || !this.IP.Contains(address.IP()) {
 | 
			
		||||
	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
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !foundMatch {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,8 +100,8 @@ func (this *FieldRule) Apply(dest v2net.Destination) bool {
 | 
			
		|||
func (this *FieldRule) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	type RawFieldRule struct {
 | 
			
		||||
		Rule
 | 
			
		||||
		Domain  string                 `json:"domain"`
 | 
			
		||||
		IP      string                 `json:"ip"`
 | 
			
		||||
		Domain  *StringList            `json:"domain"`
 | 
			
		||||
		IP      *StringList            `json:"ip"`
 | 
			
		||||
		Port    *v2netjson.PortRange   `json:"port"`
 | 
			
		||||
		Network *v2netjson.NetworkList `json:"network"`
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -65,17 +114,20 @@ func (this *FieldRule) UnmarshalJSON(data []byte) error {
 | 
			
		|||
	this.OutboundTag = rawFieldRule.OutboundTag
 | 
			
		||||
 | 
			
		||||
	hasField := false
 | 
			
		||||
	if len(rawFieldRule.Domain) > 0 {
 | 
			
		||||
	if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 {
 | 
			
		||||
		this.Domain = rawFieldRule.Domain
 | 
			
		||||
		hasField = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(rawFieldRule.IP) > 0 {
 | 
			
		||||
		_, ipNet, err := net.ParseCIDR(rawFieldRule.IP)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.New("Invalid IP range in router rule: " + err.Error())
 | 
			
		||||
	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)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.New("Invalid IP range in router rule: " + err.Error())
 | 
			
		||||
			}
 | 
			
		||||
			this.IP = append(this.IP, ipNet)
 | 
			
		||||
		}
 | 
			
		||||
		this.IP = ipNet
 | 
			
		||||
		hasField = true
 | 
			
		||||
	}
 | 
			
		||||
	if rawFieldRule.Port != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
package json
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	v2net "github.com/v2ray/v2ray-core/common/net"
 | 
			
		||||
| 
						 | 
				
			
			@ -8,11 +9,31 @@ import (
 | 
			
		|||
	"github.com/v2ray/v2ray-core/testing/unit"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestStringListParsingList(t *testing.T) {
 | 
			
		||||
	assert := unit.Assert(t)
 | 
			
		||||
 | 
			
		||||
	rawJson := `["a", "b", "c", "d"]`
 | 
			
		||||
	var strList StringList
 | 
			
		||||
	err := json.Unmarshal([]byte(rawJson), &strList)
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Int(strList.Len()).Equals(4)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestStringListParsingString(t *testing.T) {
 | 
			
		||||
	assert := unit.Assert(t)
 | 
			
		||||
 | 
			
		||||
	rawJson := `"abcd"`
 | 
			
		||||
	var strList StringList
 | 
			
		||||
	err := json.Unmarshal([]byte(rawJson), &strList)
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Int(strList.Len()).Equals(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDomainMatching(t *testing.T) {
 | 
			
		||||
	assert := unit.Assert(t)
 | 
			
		||||
 | 
			
		||||
	rule := &FieldRule{
 | 
			
		||||
		Domain: "v2ray.com",
 | 
			
		||||
		Domain: NewStringList("v2ray.com"),
 | 
			
		||||
	}
 | 
			
		||||
	dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80))
 | 
			
		||||
	assert.Bool(rule.Apply(dest)).IsTrue()
 | 
			
		||||
| 
						 | 
				
			
			@ -62,10 +83,23 @@ func TestDomainNotMatching(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	rawJson := `{
 | 
			
		||||
    "type": "field",
 | 
			
		||||
    "domain": "google.com",
 | 
			
		||||
    "domain": ["google.com", "v2ray.com"],
 | 
			
		||||
    "tag": "test"
 | 
			
		||||
  }`
 | 
			
		||||
	rule := parseRule([]byte(rawJson))
 | 
			
		||||
	dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}, 79))
 | 
			
		||||
	dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}, 80))
 | 
			
		||||
	assert.Bool(rule.Apply(dest)).IsFalse()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDomainNotMatchingDomain(t *testing.T) {
 | 
			
		||||
	assert := unit.Assert(t)
 | 
			
		||||
 | 
			
		||||
	rawJson := `{
 | 
			
		||||
    "type": "field",
 | 
			
		||||
    "domain": ["google.com", "v2ray.com"],
 | 
			
		||||
    "tag": "test"
 | 
			
		||||
  }`
 | 
			
		||||
	rule := parseRule([]byte(rawJson))
 | 
			
		||||
	dest := v2net.NewTCPDestination(v2net.DomainAddress("baidu.com", 80))
 | 
			
		||||
	assert.Bool(rule.Apply(dest)).IsFalse()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,77 +39,23 @@
 | 
			
		|||
      "rules": [
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "0.0.0.0/8",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "10.0.0.0/8",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "100.64.0.0/10",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "127.0.0.0/8",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "169.254.0.0/16",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "172.16.0.0/12",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "192.0.0.0/24",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "192.0.2.0/24",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "192.168.0.0/16",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "198.18.0.0/15",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "198.51.100.0/24",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "203.0.113.0/24",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "::1/128",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "fc00::/7",
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "field",
 | 
			
		||||
          "ip": "fe80::/10",
 | 
			
		||||
          "ip": [
 | 
			
		||||
            "0.0.0.0/8",
 | 
			
		||||
            "10.0.0.0/8",
 | 
			
		||||
            "100.64.0.0/10",
 | 
			
		||||
            "127.0.0.0/8",
 | 
			
		||||
            "169.254.0.0/16",
 | 
			
		||||
            "172.16.0.0/12",
 | 
			
		||||
            "192.0.0.0/24",
 | 
			
		||||
            "192.0.2.0/24",
 | 
			
		||||
            "192.168.0.0/16",
 | 
			
		||||
            "198.18.0.0/15",
 | 
			
		||||
            "198.51.100.0/24",
 | 
			
		||||
            "203.0.113.0/24",
 | 
			
		||||
            "::1/128",
 | 
			
		||||
            "fc00::/7",
 | 
			
		||||
            "fe80::/10"
 | 
			
		||||
          ],
 | 
			
		||||
          "outboundTag": "direct"
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue