mirror of
				https://github.com/nadoo/glider.git
				synced 2025-10-26 11:25:53 +08:00 
			
		
		
		
	feat: support routingA
This commit is contained in:
		
							parent
							
								
									10b7f2d5e6
								
							
						
					
					
						commit
						05559703a3
					
				
							
								
								
									
										12
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								config.go
									
									
									
									
									
								
							| @ -25,6 +25,7 @@ type Config struct { | |||||||
| 
 | 
 | ||||||
| 	RuleFiles    []string | 	RuleFiles    []string | ||||||
| 	RulesDir     string | 	RulesDir     string | ||||||
|  | 	RoutingAFile string | ||||||
| 
 | 
 | ||||||
| 	DNS       string | 	DNS       string | ||||||
| 	DNSConfig dns.Config | 	DNSConfig dns.Config | ||||||
| @ -56,6 +57,7 @@ func parseConfig() *Config { | |||||||
| 
 | 
 | ||||||
| 	flag.StringSliceUniqVar(&conf.RuleFiles, "rulefile", nil, "rule file path") | 	flag.StringSliceUniqVar(&conf.RuleFiles, "rulefile", nil, "rule file path") | ||||||
| 	flag.StringVar(&conf.RulesDir, "rules-dir", "", "rule file folder") | 	flag.StringVar(&conf.RulesDir, "rules-dir", "", "rule file folder") | ||||||
|  | 	flag.StringVar(&conf.RoutingAFile, "routingA", "", "routingA file path") | ||||||
| 
 | 
 | ||||||
| 	// dns configs
 | 	// dns configs
 | ||||||
| 	flag.StringVar(&conf.DNS, "dns", "", "local dns server listen address") | 	flag.StringVar(&conf.DNS, "dns", "", "local dns server listen address") | ||||||
| @ -118,6 +120,16 @@ func parseConfig() *Config { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if conf.RoutingAFile != "" { | ||||||
|  | 		if !path.IsAbs(conf.RoutingAFile) { | ||||||
|  | 			conf.RoutingAFile = path.Join(flag.ConfDir(), conf.RoutingAFile) | ||||||
|  | 		} | ||||||
|  | 		conf.Strategy.RoutingA, err = rule.ParseRoutingA(conf.RoutingAFile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return conf | 	return conf | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -148,7 +148,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) ( | |||||||
| 
 | 
 | ||||||
| 	// use tcp to connect upstream server default
 | 	// use tcp to connect upstream server default
 | ||||||
| 	network = "tcp" | 	network = "tcp" | ||||||
| 	dialer := c.proxy.NextDialer(qname + ":53") | 	dialer := c.proxy.NextDialer(network, qname+":53") | ||||||
| 
 | 
 | ||||||
| 	// if we are resolving the dialer's domain, then use Direct to avoid denpency loop
 | 	// if we are resolving the dialer's domain, then use Direct to avoid denpency loop
 | ||||||
| 	// TODO: dialer.Addr() == "REJECT", tricky
 | 	// TODO: dialer.Addr() == "REJECT", tricky
 | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @ -13,6 +13,7 @@ require ( | |||||||
| 	github.com/nadoo/conflag v0.2.3 | 	github.com/nadoo/conflag v0.2.3 | ||||||
| 	github.com/nadoo/ipset v0.3.0 | 	github.com/nadoo/ipset v0.3.0 | ||||||
| 	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect | 	github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect | ||||||
|  | 	github.com/v2rayA/routingA v0.0.0-20201204065601-aef348ea7aa1 | ||||||
| 	github.com/xtaci/kcp-go/v5 v5.6.1 | 	github.com/xtaci/kcp-go/v5 v5.6.1 | ||||||
| 	golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 | 	golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 | ||||||
| 	golang.org/x/mod v0.4.0 // indirect | 	golang.org/x/mod v0.4.0 // indirect | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @ -11,6 +11,8 @@ github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152/go.mod h1:I9fhc/EvS | |||||||
| github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521 h1:fBHFH+Y/GPGFGo7LIrErQc3p2MeAhoIQNgaxPWYsSxk= | github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521 h1:fBHFH+Y/GPGFGo7LIrErQc3p2MeAhoIQNgaxPWYsSxk= | ||||||
| github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:ucvhdsUCE3TH0LoLRb6ShHiJl8e39dGlx6A4g/ujlow= | github.com/ebfe/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:ucvhdsUCE3TH0LoLRb6ShHiJl8e39dGlx6A4g/ujlow= | ||||||
| github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= | github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= | ||||||
|  | github.com/gocarina/gocsv v0.0.0-20201103164230-b291445e0dd2 h1:DTpqi8htDqlk4dGMxZ3+7BVX2OoMki9akiCHWQpSXfA= | ||||||
|  | github.com/gocarina/gocsv v0.0.0-20201103164230-b291445e0dd2/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= | ||||||
| github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
| github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
| @ -73,6 +75,8 @@ github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= | |||||||
| github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= | github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= | ||||||
| github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= | github.com/u-root/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= | ||||||
| github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= | github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= | ||||||
|  | github.com/v2rayA/routingA v0.0.0-20201204065601-aef348ea7aa1 h1:PITT+h0KRoBQwifYJr9vLqkhPH0UyJTonP+sIa5yGa4= | ||||||
|  | github.com/v2rayA/routingA v0.0.0-20201204065601-aef348ea7aa1/go.mod h1:V86dy1jY9VJKMrEinUjUQTclZaQQv+nIXBuFCSf67A4= | ||||||
| github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI= | github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI= | ||||||
| github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo= | github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo= | ||||||
| github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= | github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ type Proxy interface { | |||||||
| 	DialUDP(network, addr string) (pc net.PacketConn, dialer UDPDialer, writeTo net.Addr, err error) | 	DialUDP(network, addr string) (pc net.PacketConn, dialer UDPDialer, writeTo net.Addr, err error) | ||||||
| 
 | 
 | ||||||
| 	// Get the dialer by dstAddr.
 | 	// Get the dialer by dstAddr.
 | ||||||
| 	NextDialer(dstAddr string) Dialer | 	NextDialer(network, dstAddr string) Dialer | ||||||
| 
 | 
 | ||||||
| 	// Record records result while using the dialer from proxy.
 | 	// Record records result while using the dialer from proxy.
 | ||||||
| 	Record(dialer Dialer, success bool) | 	Record(dialer Dialer, success bool) | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ func (s *SS) Serve(c net.Conn) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	network := "tcp" | 	network := "tcp" | ||||||
| 	dialer := s.proxy.NextDialer(tgt.String()) | 	dialer := s.proxy.NextDialer(network, tgt.String()) | ||||||
| 
 | 
 | ||||||
| 	rc, err := dialer.Dial(network, tgt.String()) | 	rc, err := dialer.Dial(network, tgt.String()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | |||||||
| @ -106,7 +106,7 @@ func (s *Trojan) Serve(c net.Conn) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	network := "tcp" | 	network := "tcp" | ||||||
| 	dialer := s.proxy.NextDialer(target.String()) | 	dialer := s.proxy.NextDialer(network, target.String()) | ||||||
| 
 | 
 | ||||||
| 	if cmd == socks.CmdUDPAssociate { | 	if cmd == socks.CmdUDPAssociate { | ||||||
| 		// there is no upstream proxy, just serve it
 | 		// there is no upstream proxy, just serve it
 | ||||||
| @ -137,7 +137,7 @@ func (s *Trojan) Serve(c net.Conn) { | |||||||
| 
 | 
 | ||||||
| func (s *Trojan) serveFallback(c net.Conn, tgt string, headBuf *bytes.Buffer) { | func (s *Trojan) serveFallback(c net.Conn, tgt string, headBuf *bytes.Buffer) { | ||||||
| 	// TODO: should we access fallback directly or via proxy?
 | 	// TODO: should we access fallback directly or via proxy?
 | ||||||
| 	dialer := s.proxy.NextDialer(tgt) | 	dialer := s.proxy.NextDialer("tcp", tgt) | ||||||
| 	rc, err := dialer.Dial("tcp", tgt) | 	rc, err := dialer.Dial("tcp", tgt) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.F("[trojan-fallback] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) | 		log.F("[trojan-fallback] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) | ||||||
|  | |||||||
| @ -63,7 +63,7 @@ func (s *VLess) Serve(c net.Conn) { | |||||||
| 	c = NewServerConn(c) | 	c = NewServerConn(c) | ||||||
| 
 | 
 | ||||||
| 	network := "tcp" | 	network := "tcp" | ||||||
| 	dialer := s.proxy.NextDialer(target) | 	dialer := s.proxy.NextDialer(network, target) | ||||||
| 
 | 
 | ||||||
| 	if cmd == CmdUDP { | 	if cmd == CmdUDP { | ||||||
| 		// there is no upstream proxy, just serve it
 | 		// there is no upstream proxy, just serve it
 | ||||||
| @ -94,7 +94,7 @@ func (s *VLess) Serve(c net.Conn) { | |||||||
| 
 | 
 | ||||||
| func (s *VLess) serveFallback(c net.Conn, tgt string, headBuf *bytes.Buffer) { | func (s *VLess) serveFallback(c net.Conn, tgt string, headBuf *bytes.Buffer) { | ||||||
| 	// TODO: should we access fallback directly or via proxy?
 | 	// TODO: should we access fallback directly or via proxy?
 | ||||||
| 	dialer := s.proxy.NextDialer(tgt) | 	dialer := s.proxy.NextDialer("tcp", tgt) | ||||||
| 	rc, err := dialer.Dial("tcp", tgt) | 	rc, err := dialer.Dial("tcp", tgt) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.F("[vless-fallback] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) | 		log.F("[vless-fallback] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) | ||||||
|  | |||||||
| @ -1,8 +1,10 @@ | |||||||
| package rule | package rule | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"github.com/v2rayA/routingA" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/nadoo/conflag" | 	"github.com/nadoo/conflag" | ||||||
| @ -35,11 +37,12 @@ type Strategy struct { | |||||||
| 	DialTimeout       int | 	DialTimeout       int | ||||||
| 	RelayTimeout      int | 	RelayTimeout      int | ||||||
| 	IntFace           string | 	IntFace           string | ||||||
|  | 	RoutingA          *RoutingA | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewConfFromFile returns a new config from file.
 | // NewConfFromFile returns a new config from file.
 | ||||||
| func NewConfFromFile(ruleFile string) (*Config, error) { | func NewConfFromFile(ruleFile string) (*Config, error) { | ||||||
| 	p := &Config{Name: ruleFile} | 	p := &Config{Name: getFilename(ruleFile)} | ||||||
| 
 | 
 | ||||||
| 	f := conflag.NewFromFile("rule", ruleFile) | 	f := conflag.NewFromFile("rule", ruleFile) | ||||||
| 	f.StringSliceUniqVar(&p.Forward, "forward", nil, "forward url, format: SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS[,SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS]") | 	f.StringSliceUniqVar(&p.Forward, "forward", nil, "forward url, format: SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS[,SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS]") | ||||||
| @ -65,7 +68,6 @@ func NewConfFromFile(ruleFile string) (*Config, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	return p, err | 	return p, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -88,3 +90,19 @@ func ListDir(dirPth string, suffix string) (files []string, err error) { | |||||||
| 	} | 	} | ||||||
| 	return files, nil | 	return files, nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func getFilename(ruleFile string) string { | ||||||
|  | 	return strings.TrimSuffix(filepath.Base(ruleFile), filepath.Ext(ruleFile)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ParseRoutingA(filename string) (*RoutingA, error) { | ||||||
|  | 	b, err := ioutil.ReadFile(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	ra, err := routingA.Parse(string(b)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return NewRoutingA(ra) | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										38
									
								
								rule/internal/matcher/cidrMatcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								rule/internal/matcher/cidrMatcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"github.com/nadoo/glider/rule/internal/trie" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type CIDRMatcher trie.Trie | ||||||
|  | 
 | ||||||
|  | // TODO: ipv6
 | ||||||
|  | func NewCIDRMatcher(CIDRs []string) *CIDRMatcher { | ||||||
|  | 	dict := make([]string, 0, len(CIDRs)) | ||||||
|  | 	for _, CIDR := range CIDRs { | ||||||
|  | 		grp := strings.SplitN(CIDR, "/", 2) | ||||||
|  | 		if len(grp) == 1 { | ||||||
|  | 			grp = append(grp, "32") | ||||||
|  | 		} | ||||||
|  | 		l, _ := strconv.Atoi(grp[1]) | ||||||
|  | 		arr := strings.Split(grp[0], ".") | ||||||
|  | 		var builder strings.Builder | ||||||
|  | 		for _, sec := range arr { | ||||||
|  | 			itg, _ := strconv.Atoi(sec) | ||||||
|  | 			tmp := strconv.FormatInt(int64(itg), 2) | ||||||
|  | 			builder.WriteString(strings.Repeat("0", 8-len(tmp))) | ||||||
|  | 			builder.WriteString(tmp) | ||||||
|  | 			if builder.Len() >= l { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		dict = append(dict, builder.String()[:l]) | ||||||
|  | 	} | ||||||
|  | 	return (*CIDRMatcher)(trie.New(dict)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m CIDRMatcher) Match(t interface{}) bool { | ||||||
|  | 	return (*trie.Trie)(&m).Match(t.(string)) != "" | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								rule/internal/matcher/domainMatcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								rule/internal/matcher/domainMatcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | import "strings" | ||||||
|  | 
 | ||||||
|  | type SuffixDomainTree map[string]interface{} | ||||||
|  | 
 | ||||||
|  | func NewSuffixDomainTree(domains []string) *SuffixDomainTree { | ||||||
|  | 	var ( | ||||||
|  | 		tree = make(map[string]interface{}) | ||||||
|  | 		m    = tree | ||||||
|  | 		ok   bool | ||||||
|  | 	) | ||||||
|  | 	for _, d := range domains { | ||||||
|  | 		m = tree | ||||||
|  | 		fields := strings.Split(d, ".") | ||||||
|  | 		for i := len(fields) - 1; i >= 0; i-- { | ||||||
|  | 			var t interface{} | ||||||
|  | 			if t, ok = m[fields[i]]; ok { | ||||||
|  | 				m = t.(map[string]interface{}) | ||||||
|  | 			} else { | ||||||
|  | 				m[fields[i]] = make(map[string]interface{}) | ||||||
|  | 				m = m[fields[i]].(map[string]interface{}) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		m[".end"] = struct{}{} | ||||||
|  | 	} | ||||||
|  | 	return (*SuffixDomainTree)(&tree) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m SuffixDomainTree) Match(t interface{}) bool { | ||||||
|  | 	fields := strings.Split(t.(string), ".") | ||||||
|  | 	mm := m | ||||||
|  | 	for i := len(fields) - 1; i >= 0; i-- { | ||||||
|  | 		var tt interface{} | ||||||
|  | 		var ok bool | ||||||
|  | 		if tt, ok = mm[fields[i]]; ok { | ||||||
|  | 			mm = tt.(map[string]interface{}) | ||||||
|  | 			if _, ok := mm[".end"]; ok { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								rule/internal/matcher/integerMatcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								rule/internal/matcher/integerMatcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"github.com/nadoo/glider/log" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type IntegerMatcher map[int]struct{} | ||||||
|  | 
 | ||||||
|  | func NewIntegerMatcher(ports []string) *IntegerMatcher { | ||||||
|  | 	m := make(map[int]struct{}) | ||||||
|  | 	for _, port := range ports { | ||||||
|  | 		p, err := strconv.Atoi(port) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.F("invalid port: ", port) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		m[p] = struct{}{} | ||||||
|  | 	} | ||||||
|  | 	if len(m) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return (*IntegerMatcher)(&m) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m IntegerMatcher) Match(t interface{}) bool { | ||||||
|  | 	_, ok := m[t.(int)] | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								rule/internal/matcher/matcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								rule/internal/matcher/matcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | type Matcher interface { | ||||||
|  | 	Match(t interface{}) bool | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								rule/internal/matcher/networkMatcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								rule/internal/matcher/networkMatcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | import "github.com/nadoo/glider/log" | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	TCP = iota | ||||||
|  | 	UDP | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type NetworkMatcher [2]bool | ||||||
|  | 
 | ||||||
|  | func NewNetworkMatcher(networks []string) *NetworkMatcher { | ||||||
|  | 	var bucket [2]bool | ||||||
|  | 	for _, n := range networks { | ||||||
|  | 		if n == "tcp" { | ||||||
|  | 			bucket[TCP] = true | ||||||
|  | 		} else if n == "udp" { | ||||||
|  | 			bucket[UDP] = true | ||||||
|  | 		} else { | ||||||
|  | 			log.F("invalid network: ", n) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (*NetworkMatcher)(&bucket) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m NetworkMatcher) Match(t interface{}) bool { | ||||||
|  | 	return m[t.(int)] | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								rule/internal/matcher/stringMatcher.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								rule/internal/matcher/stringMatcher.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | package matcher | ||||||
|  | 
 | ||||||
|  | type StringMatcher map[string]struct{} | ||||||
|  | 
 | ||||||
|  | func NewStringMatcher(app []string) *StringMatcher { | ||||||
|  | 	m := make(map[string]struct{}) | ||||||
|  | 	for _, name := range app { | ||||||
|  | 		m[name] = struct{}{} | ||||||
|  | 	} | ||||||
|  | 	if len(m) == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return (*StringMatcher)(&m) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m StringMatcher) Match(t interface{}) bool { | ||||||
|  | 	_, ok := m[t.(string)] | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								rule/internal/trie/trie.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								rule/internal/trie/trie.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | // Static trie
 | ||||||
|  | package trie | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type cast map[rune]*next | ||||||
|  | 
 | ||||||
|  | type next struct { | ||||||
|  | 	*node | ||||||
|  | 	str *string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type node struct { | ||||||
|  | 	c   cast | ||||||
|  | 	end bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Trie struct { | ||||||
|  | 	root *node | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newNode() *node { | ||||||
|  | 	return &node{ | ||||||
|  | 		c:   cast{}, | ||||||
|  | 		end: false, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func New(dict []string) (trie *Trie) { | ||||||
|  | 	var t Trie | ||||||
|  | 	var ok bool | ||||||
|  | 	var p *node | ||||||
|  | 	t.root = newNode() | ||||||
|  | 	for _, d := range dict { | ||||||
|  | 		p = t.root | ||||||
|  | 		for i, r := range d { | ||||||
|  | 			_, ok = p.c[r] | ||||||
|  | 			if !ok { | ||||||
|  | 				n := next{ | ||||||
|  | 					node: newNode(), | ||||||
|  | 					str:  nil, | ||||||
|  | 				} | ||||||
|  | 				p.c[r] = &n | ||||||
|  | 			} | ||||||
|  | 			p = p.c[r].node | ||||||
|  | 			if i == len(d)-1 { | ||||||
|  | 				p.end = true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	//make jump
 | ||||||
|  | 	makeJump(t.root) | ||||||
|  | 	return &t | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func fastJump(from *next, to *next, str *string) { | ||||||
|  | 	from.str = str | ||||||
|  | 	from.node = to.node | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func _makeJump(cur *next, from *next, builder *strings.Builder) { | ||||||
|  | 	var fork bool | ||||||
|  | 	if cur.node.end || len(cur.node.c) > 1 { | ||||||
|  | 		if builder.Len() > 1 { | ||||||
|  | 			s := builder.String() | ||||||
|  | 			fastJump(from, cur, &s) | ||||||
|  | 		} | ||||||
|  | 		fork = true | ||||||
|  | 	} | ||||||
|  | 	for k := range cur.node.c { | ||||||
|  | 		child := cur.node.c[k] | ||||||
|  | 		if fork { | ||||||
|  | 			from = child | ||||||
|  | 			builder = new(strings.Builder) | ||||||
|  | 		} | ||||||
|  | 		builder.WriteRune(k) | ||||||
|  | 		_makeJump(child, from, builder) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func makeJump(root *node) { | ||||||
|  | 	//DFS
 | ||||||
|  | 	for k := range root.c { | ||||||
|  | 		builder := new(strings.Builder) | ||||||
|  | 		builder.WriteRune(k) | ||||||
|  | 		_makeJump(root.c[k], root.c[k], builder) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (t *Trie) Match(str string) (prefix string) { | ||||||
|  | 	var builder strings.Builder | ||||||
|  | 	var runes = []rune(str) | ||||||
|  | 	var length = len(runes) | ||||||
|  | 	p := t.root | ||||||
|  | 	for i := 0; i < length; i++ { | ||||||
|  | 		r := runes[i] | ||||||
|  | 		tmp, ok := p.c[r] | ||||||
|  | 		if !ok { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if tmp.str == nil { | ||||||
|  | 			builder.WriteRune(r) | ||||||
|  | 		} else { | ||||||
|  | 			if lenTmp := len(*tmp.str); builder.Len()+lenTmp <= length { | ||||||
|  | 				if string(runes[i:lenTmp+i]) == *tmp.str { | ||||||
|  | 					builder.WriteString(*tmp.str) | ||||||
|  | 					i += len(*tmp.str) - 1 | ||||||
|  | 				} else { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if tmp.node.end { | ||||||
|  | 			if builder.Len() <= length { | ||||||
|  | 				prefix = builder.String() | ||||||
|  | 				if len(prefix) == length { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		p = tmp.node | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								rule/internal/trie/trie_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								rule/internal/trie/trie_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | package trie | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestTrie_Match(t *testing.T) { | ||||||
|  | 	trie := New([]string{ | ||||||
|  | 		"12", | ||||||
|  | 		"12345", | ||||||
|  | 		"1234567", | ||||||
|  | 		"2222", | ||||||
|  | 		"1", | ||||||
|  | 	}) | ||||||
|  | 	test := [][2]string{ | ||||||
|  | 		{"1", "1"}, | ||||||
|  | 		{"123", "12"}, | ||||||
|  | 		{"1233", "12"}, | ||||||
|  | 		{"12345", "12345"}, | ||||||
|  | 		{"123456", "12345"}, | ||||||
|  | 		{"1234567", "1234567"}, | ||||||
|  | 		{"123456789", "1234567"}, | ||||||
|  | 		{"222", ""}, | ||||||
|  | 		{"2222", "2222"}, | ||||||
|  | 		{"22222", "2222"}, | ||||||
|  | 		{"122", "12"}, | ||||||
|  | 	} | ||||||
|  | 	for _, tt := range test { | ||||||
|  | 		if p := trie.Match(tt[0]); p == tt[1] { | ||||||
|  | 			t.Log(tt[0], "match prefix", p) | ||||||
|  | 		} else { | ||||||
|  | 			t.Error(tt[0], "expect", tt[1], "wrong prefix", p) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| package rule | package rule | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"github.com/nadoo/glider/rule/internal/matcher" | ||||||
| 	"net" | 	"net" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| @ -13,18 +14,29 @@ import ( | |||||||
| type Proxy struct { | type Proxy struct { | ||||||
| 	main       *FwdrGroup | 	main       *FwdrGroup | ||||||
| 	all        []*FwdrGroup | 	all        []*FwdrGroup | ||||||
|  | 	name2Group map[string]*FwdrGroup | ||||||
| 	domainMap  sync.Map | 	domainMap  sync.Map | ||||||
| 	ipMap      sync.Map | 	ipMap      sync.Map | ||||||
| 	cidrMap    sync.Map | 	cidrMap    sync.Map | ||||||
|  | 	routingA   *RoutingA | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewProxy returns a new rule proxy.
 | // NewProxy returns a new rule proxy.
 | ||||||
| func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) *Proxy { | func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) *Proxy { | ||||||
| 	rd := &Proxy{main: NewFwdrGroup("main", mainForwarders, mainStrategy)} | 	rd := &Proxy{ | ||||||
|  | 		main:       NewFwdrGroup("main", mainForwarders, mainStrategy), | ||||||
|  | 		name2Group: make(map[string]*FwdrGroup), | ||||||
|  | 		routingA:   mainStrategy.RoutingA, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	rd.name2Group[OutProxy] = rd.main | ||||||
|  | 	rd.name2Group[OutDirect] = NewFwdrGroup("", nil, mainStrategy) | ||||||
|  | 	rd.name2Group[OutReject] = NewFwdrGroup("", []string{"reject://"}, mainStrategy) | ||||||
| 
 | 
 | ||||||
| 	for _, r := range rules { | 	for _, r := range rules { | ||||||
| 		group := NewFwdrGroup(r.Name, r.Forward, &r.Strategy) | 		group := NewFwdrGroup(r.Name, r.Forward, &r.Strategy) | ||||||
| 		rd.all = append(rd.all, group) | 		rd.all = append(rd.all, group) | ||||||
|  | 		rd.name2Group[r.Name] = group | ||||||
| 
 | 
 | ||||||
| 		for _, domain := range r.Domain { | 		for _, domain := range r.Domain { | ||||||
| 			rd.domainMap.Store(strings.ToLower(domain), group) | 			rd.domainMap.Store(strings.ToLower(domain), group) | ||||||
| @ -40,14 +52,18 @@ func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if rd.routingA != nil { | ||||||
|  | 		rd.name2Group[OutDefault] = rd.name2Group[rd.routingA.DefaultOut] | ||||||
|  | 	} else { | ||||||
|  | 		rd.name2Group[OutDefault] = rd.main | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// if there's any forwarder defined in main config, make sure they will be accessed directly.
 | 	// if there's any forwarder defined in main config, make sure they will be accessed directly.
 | ||||||
| 	if len(mainForwarders) > 0 { | 	if len(mainForwarders) > 0 { | ||||||
| 		direct := NewFwdrGroup("", nil, mainStrategy) |  | ||||||
| 		for _, f := range rd.main.fwdrs { | 		for _, f := range rd.main.fwdrs { | ||||||
| 			host, _, _ := net.SplitHostPort(f.addr) | 			host, _, _ := net.SplitHostPort(f.addr) | ||||||
| 			if ip := net.ParseIP(host); ip == nil { | 			if ip := net.ParseIP(host); ip == nil { | ||||||
| 				rd.domainMap.Store(strings.ToLower(host), direct) | 				rd.domainMap.Store(strings.ToLower(host), rd.name2Group[OutDirect]) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -57,23 +73,24 @@ func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) | |||||||
| 
 | 
 | ||||||
| // Dial dials to targer addr and return a conn.
 | // Dial dials to targer addr and return a conn.
 | ||||||
| func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { | func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { | ||||||
| 	return p.findDialer(addr).Dial(network, addr) | 	return p.findDialer(network, addr).Dial(network, addr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DialUDP connects to the given address via the proxy.
 | // DialUDP connects to the given address via the proxy.
 | ||||||
| func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, writeTo net.Addr, err error) { | func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, writeTo net.Addr, err error) { | ||||||
| 	return p.findDialer(addr).DialUDP(network, addr) | 	return p.findDialer(network, addr).DialUDP(network, addr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // findDialer returns a dialer by dstAddr according to rule.
 | // findDialer returns a dialer by dstAddr according to rule.
 | ||||||
| func (p *Proxy) findDialer(dstAddr string) *FwdrGroup { | func (p *Proxy) findDialer(network string, dstAddr string) *FwdrGroup { | ||||||
| 	host, _, err := net.SplitHostPort(dstAddr) | 	host, port, err := net.SplitHostPort(dstAddr) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return p.main | 		return p.main | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// find ip
 | 	// find ip
 | ||||||
| 	if ip := net.ParseIP(host); ip != nil { | 	var ip net.IP | ||||||
|  | 	if ip = net.ParseIP(host); ip != nil { | ||||||
| 		// check ip
 | 		// check ip
 | ||||||
| 		if proxy, ok := p.ipMap.Load(ip.String()); ok { | 		if proxy, ok := p.ipMap.Load(ip.String()); ok { | ||||||
| 			return proxy.(*FwdrGroup) | 			return proxy.(*FwdrGroup) | ||||||
| @ -93,7 +110,6 @@ func (p *Proxy) findDialer(dstAddr string) *FwdrGroup { | |||||||
| 		if ret != nil { | 		if ret != nil { | ||||||
| 			return ret | 			return ret | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	host = strings.ToLower(host) | 	host = strings.ToLower(host) | ||||||
| @ -104,12 +120,52 @@ func (p *Proxy) findDialer(dstAddr string) *FwdrGroup { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// check routingA
 | ||||||
|  | 	if p.routingA != nil { | ||||||
|  | 		for _, r := range p.routingA.Rules { | ||||||
|  | 			matched := false | ||||||
|  | 			for _, m := range r.Matchers { | ||||||
|  | 				switch m.RuleType { | ||||||
|  | 				case "domain": | ||||||
|  | 					matched = m.Matcher.Match(host) | ||||||
|  | 				case "tip": | ||||||
|  | 					if ip != nil { | ||||||
|  | 						matched = m.Matcher.Match(ip.String()) | ||||||
|  | 					} | ||||||
|  | 				case "tport": | ||||||
|  | 					matched = m.Matcher.Match(port) | ||||||
|  | 				case "network": | ||||||
|  | 					if network == "tcp" { | ||||||
|  | 						matched = m.Matcher.Match(matcher.TCP) | ||||||
|  | 					} else if network == "udp" { | ||||||
|  | 						matched = m.Matcher.Match(matcher.UDP) | ||||||
|  | 					} | ||||||
|  | 				case "sport", "sip": | ||||||
|  | 					// TODO: UNSUPPORTED
 | ||||||
|  | 				case "app": | ||||||
|  | 					// TODO: UNSUPPORTED
 | ||||||
|  | 				} | ||||||
|  | 				if matched { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			if matched { | ||||||
|  | 				if g, ok := p.name2Group[r.Out]; ok { | ||||||
|  | 					return g | ||||||
|  | 				} else { | ||||||
|  | 					log.F("invalid out rule: ", r.Out) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return p.name2Group[OutDefault] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return p.main | 	return p.main | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NextDialer returns next dialer according to rule.
 | // NextDialer returns next dialer according to rule.
 | ||||||
| func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer { | func (p *Proxy) NextDialer(network, dstAddr string) proxy.Dialer { | ||||||
| 	return p.findDialer(dstAddr).NextDialer(dstAddr) | 	return p.findDialer(network, dstAddr).NextDialer(dstAddr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Record records result while using the dialer from proxy.
 | // Record records result while using the dialer from proxy.
 | ||||||
|  | |||||||
							
								
								
									
										92
									
								
								rule/routingA.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								rule/routingA.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | package rule | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/nadoo/glider/rule/internal/matcher" | ||||||
|  | 	"github.com/v2rayA/routingA" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type OutType int | ||||||
|  | type DomainStrategy int | ||||||
|  | type Network int | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	OutDirect  = "direct" | ||||||
|  | 	OutProxy   = "proxy" | ||||||
|  | 	OutReject  = "reject" | ||||||
|  | 	OutDefault = "_default" //try not to conflict with user's definition
 | ||||||
|  | ) | ||||||
|  | const ( | ||||||
|  | 	DomainStrategyAsIs DomainStrategy = iota | ||||||
|  | 	DomainStrategyIPIfNonMatch | ||||||
|  | 	DomainStrategyIPOnDemand | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type RoutingA struct { | ||||||
|  | 	DefaultOut     string | ||||||
|  | 	DomainStrategy DomainStrategy // FIXME: not valid
 | ||||||
|  | 	Rules          []RoutingRule | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewRoutingA(routing routingA.RoutingA) (ra *RoutingA, err error) { | ||||||
|  | 	ra = &RoutingA{ | ||||||
|  | 		DefaultOut:     OutProxy, | ||||||
|  | 		DomainStrategy: DomainStrategyIPIfNonMatch, | ||||||
|  | 	} | ||||||
|  | 	rs, ds := routing.Unfold() | ||||||
|  | 	for _, d := range ds { | ||||||
|  | 		switch d.Name { | ||||||
|  | 		case "default": | ||||||
|  | 			ra.DefaultOut = d.Value.(string) | ||||||
|  | 		case "domainStrategy": | ||||||
|  | 			switch d.Value.(string) { | ||||||
|  | 			case "AsIs": | ||||||
|  | 				ra.DomainStrategy = DomainStrategyAsIs | ||||||
|  | 			case "IPIfNonMatch": | ||||||
|  | 				ra.DomainStrategy = DomainStrategyIPIfNonMatch | ||||||
|  | 			case "IPOnDemand": | ||||||
|  | 				ra.DomainStrategy = DomainStrategyIPOnDemand | ||||||
|  | 			default: | ||||||
|  | 				return nil, fmt.Errorf("unsupported domainStrategy: %v", d.Value) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for _, r := range rs { | ||||||
|  | 		var rr RoutingRule | ||||||
|  | 		rr.Out = r.Out | ||||||
|  | 		for _, cond := range r.And { | ||||||
|  | 			m := Matcher{ | ||||||
|  | 				RuleType: cond.Name, | ||||||
|  | 			} | ||||||
|  | 			switch cond.Name { | ||||||
|  | 			case "domain": | ||||||
|  | 				m.Matcher = matcher.NewSuffixDomainTree(cond.Params) | ||||||
|  | 			case "tip", "sip": | ||||||
|  | 				m.Matcher = matcher.NewCIDRMatcher(cond.Params) | ||||||
|  | 			case "network": | ||||||
|  | 				m.Matcher = matcher.NewNetworkMatcher(cond.Params) | ||||||
|  | 			case "app", "tport", "sport": | ||||||
|  | 				m.Matcher = matcher.NewStringMatcher(cond.Params) | ||||||
|  | 			default: | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			rr.Matchers = append(rr.Matchers, m) | ||||||
|  | 		} | ||||||
|  | 		ra.Rules = append(ra.Rules, rr) | ||||||
|  | 	} | ||||||
|  | 	return ra, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //TODO
 | ||||||
|  | //func (ra *RoutingA) MergeAdjacentRules() {
 | ||||||
|  | //}
 | ||||||
|  | 
 | ||||||
|  | type Matcher struct { | ||||||
|  | 	matcher.Matcher | ||||||
|  | 	RuleType string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type RoutingRule struct { | ||||||
|  | 	Out      string | ||||||
|  | 	Matchers []Matcher | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 mzz2017
						mzz2017