2017-07-30 01:54:19 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2017-08-23 16:35:39 +08:00
|
|
|
"net"
|
2017-07-30 01:54:19 +08:00
|
|
|
"strings"
|
2017-08-23 18:58:24 +08:00
|
|
|
"sync"
|
2017-07-30 01:54:19 +08:00
|
|
|
)
|
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// RuleDialer struct
|
2017-08-23 16:35:39 +08:00
|
|
|
type RuleDialer struct {
|
|
|
|
gDialer Dialer
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-08-23 18:58:24 +08:00
|
|
|
domainMap sync.Map
|
|
|
|
ipMap sync.Map
|
|
|
|
cidrMap sync.Map
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-08-16 13:20:12 +08:00
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// NewRuleDialer returns a new rule dialer
|
2017-08-23 18:58:24 +08:00
|
|
|
func NewRuleDialer(rules []*RuleConf, gDialer Dialer) *RuleDialer {
|
2017-08-23 16:35:39 +08:00
|
|
|
rd := &RuleDialer{gDialer: gDialer}
|
|
|
|
|
|
|
|
for _, r := range rules {
|
|
|
|
var forwarders []Dialer
|
|
|
|
for _, chain := range r.Forward {
|
|
|
|
var forward Dialer
|
|
|
|
var err error
|
|
|
|
for _, url := range strings.Split(chain, ",") {
|
|
|
|
forward, err = DialerFromURL(url, forward)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
forwarders = append(forwarders, forward)
|
|
|
|
}
|
|
|
|
|
|
|
|
sd := NewStrategyDialer(r.Strategy, forwarders, r.CheckWebSite, r.CheckDuration)
|
|
|
|
|
|
|
|
for _, domain := range r.Domain {
|
2017-08-23 18:58:24 +08:00
|
|
|
rd.domainMap.Store(domain, sd)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, ip := range r.IP {
|
2017-08-23 18:58:24 +08:00
|
|
|
rd.ipMap.Store(ip, sd)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-08-23 21:11:08 +08:00
|
|
|
for _, s := range r.CIDR {
|
|
|
|
if _, cidr, err := net.ParseCIDR(s); err == nil {
|
|
|
|
rd.cidrMap.Store(cidr, sd)
|
|
|
|
}
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-08-23 21:11:08 +08:00
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
return rd
|
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// Addr returns RuleDialer's address, always be "RULES"
|
2017-08-23 16:35:39 +08:00
|
|
|
func (rd *RuleDialer) Addr() string { return "RULES" }
|
2017-08-16 13:20:12 +08:00
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// NextDialer return next dialer according to rule
|
2017-09-21 23:07:04 +08:00
|
|
|
func (rd *RuleDialer) NextDialer(dstAddr string) Dialer {
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
// TODO: change to index finders
|
|
|
|
host, _, err := net.SplitHostPort(dstAddr)
|
2017-07-30 01:54:19 +08:00
|
|
|
if err != nil {
|
2017-08-23 16:35:39 +08:00
|
|
|
// TODO: check here
|
2017-09-08 15:25:10 +08:00
|
|
|
// logf("proxy-rule SplitHostPort ERROR: %s", err)
|
2017-09-21 23:07:04 +08:00
|
|
|
return rd.gDialer
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
// find ip
|
|
|
|
if ip := net.ParseIP(host); ip != nil {
|
|
|
|
// check ip
|
2017-09-21 23:07:04 +08:00
|
|
|
if d, ok := rd.ipMap.Load(ip.String()); ok {
|
2017-08-23 18:58:24 +08:00
|
|
|
return d.(Dialer)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
|
2017-08-23 18:58:24 +08:00
|
|
|
var ret Dialer
|
2017-08-23 16:35:39 +08:00
|
|
|
// check cidr
|
2017-09-21 23:07:04 +08:00
|
|
|
rd.cidrMap.Range(func(key, value interface{}) bool {
|
2017-08-23 21:11:08 +08:00
|
|
|
cidr := key.(*net.IPNet)
|
|
|
|
if cidr.Contains(ip) {
|
|
|
|
ret = value.(Dialer)
|
|
|
|
return false
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
2017-08-23 18:58:24 +08:00
|
|
|
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
|
|
|
|
if ret != nil {
|
|
|
|
return ret
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
2017-08-23 18:58:24 +08:00
|
|
|
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
domainParts := strings.Split(host, ".")
|
|
|
|
length := len(domainParts)
|
|
|
|
for i := length - 2; i >= 0; i-- {
|
|
|
|
domain := strings.Join(domainParts[i:length], ".")
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
// find in domainMap
|
2017-09-21 23:07:04 +08:00
|
|
|
if d, ok := rd.domainMap.Load(domain); ok {
|
2017-08-23 18:58:24 +08:00
|
|
|
return d.(Dialer)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
|
|
|
|
2017-09-21 23:07:04 +08:00
|
|
|
return rd.gDialer
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2017-09-10 20:33:35 +08:00
|
|
|
// Dial dials to targer addr and return a conn
|
2017-08-23 16:35:39 +08:00
|
|
|
func (rd *RuleDialer) Dial(network, addr string) (net.Conn, error) {
|
2017-08-23 17:45:57 +08:00
|
|
|
return rd.NextDialer(addr).Dial(network, addr)
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
2017-08-23 18:58:24 +08:00
|
|
|
|
|
|
|
// AddDomainIP used to update ipMap rules according to domainMap rule
|
|
|
|
func (rd *RuleDialer) AddDomainIP(domain, ip string) error {
|
|
|
|
if ip != "" {
|
|
|
|
domainParts := strings.Split(domain, ".")
|
|
|
|
length := len(domainParts)
|
|
|
|
for i := length - 2; i >= 0; i-- {
|
|
|
|
domain := strings.Join(domainParts[i:length], ".")
|
|
|
|
|
|
|
|
// find in domainMap
|
|
|
|
if d, ok := rd.domainMap.Load(domain); ok {
|
|
|
|
rd.ipMap.Store(ip, d)
|
2017-08-28 23:14:02 +08:00
|
|
|
logf("rule: add domain: %s, ip: %s\n", domain, ip)
|
2017-08-23 18:58:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|