| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 | package jsonimport (	"encoding/json"	"errors"	"net"	"regexp"	"strings"	v2net "github.com/v2ray/v2ray-core/common/net"	v2netjson "github.com/v2ray/v2ray-core/common/net/json")type StringList []stringfunc 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 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(this.pattern, strings.ToLower(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(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 := address.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  *StringList            `json:"domain"`		IP      *StringList            `json:"ip"`		Port    *v2netjson.PortRange   `json:"port"`		Network *v2netjson.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, "regexp:") {				rawMatcher, err := NewRegexpDomainMatcher(rawDomain[7:])				if err != nil {					return err				}				matcher = rawMatcher			} else {				matcher = NewPlainDomainMatcher(rawDomain)			}			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)			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}
 |