2018-08-12 22:24:49 +08:00
|
|
|
package rule
|
2017-07-30 01:54:19 +08:00
|
|
|
|
|
|
|
import (
|
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"
|
2018-06-26 16:15:48 +08:00
|
|
|
|
2020-10-01 22:49:14 +08:00
|
|
|
"github.com/nadoo/glider/log"
|
2018-06-26 16:15:48 +08:00
|
|
|
"github.com/nadoo/glider/proxy"
|
2017-07-30 01:54:19 +08:00
|
|
|
)
|
|
|
|
|
2020-09-24 18:50:04 +08:00
|
|
|
// Proxy implements the proxy.Proxy interface with rule support.
|
2019-09-18 19:40:14 +08:00
|
|
|
type Proxy struct {
|
2020-09-23 22:14:18 +08:00
|
|
|
main *FwdrGroup
|
|
|
|
all []*FwdrGroup
|
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
|
|
|
|
2020-05-01 20:54:23 +08:00
|
|
|
// NewProxy returns a new rule proxy.
|
2020-11-20 18:11:25 +08:00
|
|
|
func NewProxy(mainForwarders []string, mainStrategy *Strategy, rules []*Config) *Proxy {
|
2020-09-23 22:14:18 +08:00
|
|
|
rd := &Proxy{main: NewFwdrGroup("main", mainForwarders, mainStrategy)}
|
2017-08-23 16:35:39 +08:00
|
|
|
|
|
|
|
for _, r := range rules {
|
2020-11-20 18:11:25 +08:00
|
|
|
group := NewFwdrGroup(r.Name, r.Forward, &r.Strategy)
|
2020-09-23 22:14:18 +08:00
|
|
|
rd.all = append(rd.all, group)
|
2017-08-23 16:35:39 +08:00
|
|
|
|
|
|
|
for _, domain := range r.Domain {
|
2020-09-23 22:14:18 +08:00
|
|
|
rd.domainMap.Store(strings.ToLower(domain), group)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, ip := range r.IP {
|
2020-09-23 22:14:18 +08:00
|
|
|
rd.ipMap.Store(ip, group)
|
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 {
|
2020-09-23 22:14:18 +08:00
|
|
|
rd.cidrMap.Store(cidr, group)
|
2017-08-23 21:11:08 +08:00
|
|
|
}
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2020-09-24 18:50:04 +08:00
|
|
|
// if there's any forwarder defined in main config, make sure they will be accessed directly.
|
2020-09-23 22:14:18 +08:00
|
|
|
if len(mainForwarders) > 0 {
|
2020-09-24 18:50:04 +08:00
|
|
|
direct := NewFwdrGroup("", nil, mainStrategy)
|
2020-09-23 22:14:18 +08:00
|
|
|
for _, f := range rd.main.fwdrs {
|
2020-11-26 19:21:27 +08:00
|
|
|
host, _, _ := net.SplitHostPort(f.addr)
|
2020-09-24 18:50:04 +08:00
|
|
|
if ip := net.ParseIP(host); ip == nil {
|
|
|
|
rd.domainMap.Store(strings.ToLower(host), direct)
|
|
|
|
}
|
2020-09-23 22:14:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-23 16:35:39 +08:00
|
|
|
return rd
|
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2020-05-01 20:54:23 +08:00
|
|
|
// Dial dials to targer addr and return a conn.
|
2020-04-28 15:18:19 +08:00
|
|
|
func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) {
|
2020-09-24 18:50:04 +08:00
|
|
|
return p.findDialer(addr).Dial(network, addr)
|
2019-09-18 19:40:14 +08:00
|
|
|
}
|
2017-08-16 13:20:12 +08:00
|
|
|
|
2020-05-01 20:54:23 +08:00
|
|
|
// DialUDP connects to the given address via the proxy.
|
2020-11-29 15:09:44 +08:00
|
|
|
func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, writeTo net.Addr, err error) {
|
2020-09-24 18:50:04 +08:00
|
|
|
return p.findDialer(addr).DialUDP(network, addr)
|
2019-09-18 19:40:14 +08:00
|
|
|
}
|
|
|
|
|
2020-09-24 18:50:04 +08:00
|
|
|
// findDialer returns a dialer by dstAddr according to rule.
|
|
|
|
func (p *Proxy) findDialer(dstAddr string) *FwdrGroup {
|
2017-08-23 16:35:39 +08:00
|
|
|
host, _, err := net.SplitHostPort(dstAddr)
|
2017-07-30 01:54:19 +08:00
|
|
|
if err != nil {
|
2020-09-23 22:14:18 +08:00
|
|
|
return p.main
|
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
|
2019-09-18 19:40:14 +08:00
|
|
|
if proxy, ok := p.ipMap.Load(ip.String()); ok {
|
2020-09-23 22:14:18 +08:00
|
|
|
return proxy.(*FwdrGroup)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
|
|
|
|
2020-09-23 22:14:18 +08:00
|
|
|
var ret *FwdrGroup
|
2017-08-23 16:35:39 +08:00
|
|
|
// check cidr
|
2019-09-18 19:40:14 +08:00
|
|
|
p.cidrMap.Range(func(key, value interface{}) bool {
|
2017-08-23 21:11:08 +08:00
|
|
|
cidr := key.(*net.IPNet)
|
|
|
|
if cidr.Contains(ip) {
|
2020-09-23 22:14:18 +08:00
|
|
|
ret = value.(*FwdrGroup)
|
2017-08-23 21:11:08 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-08-16 12:00:46 +08:00
|
|
|
host = strings.ToLower(host)
|
|
|
|
for i := len(host); i != -1; {
|
|
|
|
i = strings.LastIndexByte(host[:i], '.')
|
|
|
|
if proxy, ok := p.domainMap.Load(host[i+1:]); ok {
|
2020-09-23 22:14:18 +08:00
|
|
|
return proxy.(*FwdrGroup)
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
}
|
|
|
|
|
2020-09-23 22:14:18 +08:00
|
|
|
return p.main
|
2017-08-23 16:35:39 +08:00
|
|
|
}
|
2017-07-30 01:54:19 +08:00
|
|
|
|
2020-09-23 22:14:18 +08:00
|
|
|
// NextDialer returns next dialer according to rule.
|
2019-09-18 19:40:14 +08:00
|
|
|
func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer {
|
2020-09-24 18:50:04 +08:00
|
|
|
return p.findDialer(dstAddr).NextDialer(dstAddr)
|
2018-01-17 00:26:38 +08:00
|
|
|
}
|
|
|
|
|
2020-04-28 15:18:19 +08:00
|
|
|
// Record records result while using the dialer from proxy.
|
|
|
|
func (p *Proxy) Record(dialer proxy.Dialer, success bool) {
|
2020-09-24 18:50:04 +08:00
|
|
|
if fwdr, ok := dialer.(*Forwarder); ok {
|
|
|
|
if !success {
|
|
|
|
fwdr.IncFailures()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fwdr.Enable()
|
|
|
|
}
|
2020-04-28 15:18:19 +08:00
|
|
|
}
|
|
|
|
|
2020-05-01 20:54:23 +08:00
|
|
|
// AddDomainIP used to update ipMap rules according to domainMap rule.
|
2019-09-18 19:40:14 +08:00
|
|
|
func (p *Proxy) AddDomainIP(domain, ip string) error {
|
2017-08-23 18:58:24 +08:00
|
|
|
if ip != "" {
|
2020-08-16 12:00:46 +08:00
|
|
|
domain = strings.ToLower(domain)
|
|
|
|
for i := len(domain); i != -1; {
|
|
|
|
i = strings.LastIndexByte(domain[:i], '.')
|
|
|
|
if dialer, ok := p.domainMap.Load(domain[i+1:]); ok {
|
2019-09-18 19:40:14 +08:00
|
|
|
p.ipMap.Store(ip, dialer)
|
2020-09-24 18:50:04 +08:00
|
|
|
log.F("[rule] add ip=%s, based on rule: domain=%s & domain/ip: %s/%s\n",
|
|
|
|
ip, domain[i+1:], domain, ip)
|
2017-08-23 18:58:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2018-08-14 19:33:18 +08:00
|
|
|
|
2020-09-24 18:50:04 +08:00
|
|
|
// Check checks availability of forwarders inside proxy.
|
2019-09-18 19:40:14 +08:00
|
|
|
func (p *Proxy) Check() {
|
2020-09-23 22:14:18 +08:00
|
|
|
p.main.Check()
|
2018-08-14 19:33:18 +08:00
|
|
|
|
2020-09-24 18:50:04 +08:00
|
|
|
for _, fwdrGroup := range p.all {
|
|
|
|
fwdrGroup.Check()
|
2018-08-14 19:33:18 +08:00
|
|
|
}
|
|
|
|
}
|