general: use builtin dns when it enabled. (#184)

This commit is contained in:
nadoo 2020-09-23 22:14:18 +08:00
parent 89114e678b
commit 84b00d6db6
10 changed files with 88 additions and 74 deletions

View File

@ -10,7 +10,6 @@ import (
"github.com/nadoo/glider/dns"
"github.com/nadoo/glider/rule"
"github.com/nadoo/glider/strategy"
)
var flag = conflag.New()
@ -21,7 +20,7 @@ var conf struct {
Listen []string
Forward []string
StrategyConfig strategy.Config
StrategyConfig rule.StrategyConfig
RuleFile []string
RulesDir string

4
go.mod
View File

@ -10,8 +10,8 @@ require (
github.com/xtaci/kcp-go/v5 v5.5.15
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect
golang.org/x/tools v0.0.0-20200913032122-97363e29fc9b // indirect
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 // indirect
golang.org/x/tools v0.0.0-20200923053713-ba800b16d873 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)

8
go.sum
View File

@ -120,15 +120,15 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 h1:YEu4SMq7D0cmT7CBbXfcH0NZeuChAXwsHe/9XueUO6o=
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c h1:iHhCR0b26amDCiiO+kBguKZom9aMF+NrFxh9zeKR/XU=
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200913032122-97363e29fc9b h1:3/5GThpuWHBq2GFcurHBWuWlzdbln+Er+cyzGqQAPOs=
golang.org/x/tools v0.0.0-20200913032122-97363e29fc9b/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200923053713-ba800b16d873 h1:Q5Sq7Lt0bkn6Ax1NAraQhKRN7xxxy1LV4guxsyFHZx4=
golang.org/x/tools v0.0.0-20200923053713-ba800b16d873/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

17
main.go
View File

@ -1,18 +1,20 @@
package main
import (
"context"
"fmt"
stdlog "log"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/dns"
"github.com/nadoo/glider/ipset"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/rule"
"github.com/nadoo/glider/strategy"
// comment out the protocol you don't need to make the compiled binary smaller.
_ "github.com/nadoo/glider/proxy/http"
@ -34,7 +36,7 @@ import (
_ "github.com/nadoo/glider/proxy/ws"
)
var version = "0.10.4"
var version = "0.11.0"
func main() {
// read configs
@ -48,7 +50,7 @@ func main() {
}
// global rule proxy
p := rule.NewProxy(conf.rules, strategy.NewProxy("default", conf.Forward, &conf.StrategyConfig))
p := rule.NewProxy(conf.Forward, &conf.StrategyConfig, conf.rules)
// ipset manager
ipsetM, _ := ipset.NewManager(conf.rules)
@ -69,6 +71,15 @@ func main() {
}
}
// custom resolver
net.DefaultResolver = &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{Timeout: time.Second * 3}
return d.DialContext(ctx, "udp", conf.DNS)
},
}
// add a handler to update proxy rules when a domain resolved
d.AddHandler(p.AddDomainIP)
if ipsetM != nil {

View File

@ -37,12 +37,12 @@ type UDPDialer interface {
type DialerCreator func(s string, dialer Dialer) (Dialer, error)
var (
dialerMap = make(map[string]DialerCreator)
dialerCreators = make(map[string]DialerCreator)
)
// RegisterDialer is used to register a dialer.
func RegisterDialer(name string, c DialerCreator) {
dialerMap[name] = c
dialerCreators[name] = c
}
// DialerFromURL calls the registered creator to create dialers.
@ -58,7 +58,7 @@ func DialerFromURL(s string, dialer Dialer) (Dialer, error) {
return nil, err
}
c, ok := dialerMap[strings.ToLower(u.Scheme)]
c, ok := dialerCreators[strings.ToLower(u.Scheme)]
if ok {
return c(s, dialer)
}

View File

@ -22,12 +22,12 @@ type Server interface {
type ServerCreator func(s string, proxy Proxy) (Server, error)
var (
serverMap = make(map[string]ServerCreator)
serverCreators = make(map[string]ServerCreator)
)
// RegisterServer is used to register a proxy server
func RegisterServer(name string, c ServerCreator) {
serverMap[name] = c
serverCreators[name] = c
}
// ServerFromURL calls the registered creator to create proxy servers
@ -47,7 +47,7 @@ func ServerFromURL(s string, p Proxy) (Server, error) {
return nil, err
}
c, ok := serverMap[strings.ToLower(u.Scheme)]
c, ok := serverCreators[strings.ToLower(u.Scheme)]
if ok {
return c(s, p)
}

View File

@ -7,8 +7,6 @@ import (
"strings"
"github.com/nadoo/conflag"
"github.com/nadoo/glider/strategy"
)
// Config of rule dialer.
@ -16,7 +14,7 @@ type Config struct {
Name string
Forward []string
StrategyConfig strategy.Config
StrategyConfig StrategyConfig
DNSServers []string
IPSet string

View File

@ -1,4 +1,4 @@
package strategy
package rule
import (
"net"

View File

@ -7,77 +7,83 @@ import (
"github.com/nadoo/glider/common/log"
"github.com/nadoo/glider/proxy"
"github.com/nadoo/glider/strategy"
)
// Proxy struct.
type Proxy struct {
proxy *strategy.Proxy
proxies []*strategy.Proxy
main *FwdrGroup
all []*FwdrGroup
domainMap sync.Map
ipMap sync.Map
cidrMap sync.Map
}
// NewProxy returns a new rule proxy.
func NewProxy(rules []*Config, proxy *strategy.Proxy) *Proxy {
rd := &Proxy{proxy: proxy}
func NewProxy(mainForwarders []string, mainStrategy *StrategyConfig, rules []*Config) *Proxy {
rd := &Proxy{main: NewFwdrGroup("main", mainForwarders, mainStrategy)}
for _, r := range rules {
sd := strategy.NewProxy(r.Name, r.Forward, &r.StrategyConfig)
rd.proxies = append(rd.proxies, sd)
group := NewFwdrGroup(r.Name, r.Forward, &r.StrategyConfig)
rd.all = append(rd.all, group)
for _, domain := range r.Domain {
rd.domainMap.Store(strings.ToLower(domain), sd)
rd.domainMap.Store(strings.ToLower(domain), group)
}
for _, ip := range r.IP {
rd.ipMap.Store(ip, sd)
rd.ipMap.Store(ip, group)
}
for _, s := range r.CIDR {
if _, cidr, err := net.ParseCIDR(s); err == nil {
rd.cidrMap.Store(cidr, sd)
rd.cidrMap.Store(cidr, group)
}
}
}
if len(mainForwarders) > 0 {
direct := NewFwdrGroup("backup", nil, mainStrategy)
for _, f := range rd.main.fwdrs {
// Note: the addr maybe ip address, but no matter here.
rd.domainMap.Store(strings.ToLower(strings.Split(f.addr, ":")[0]), direct)
}
}
return rd
}
// Dial dials to targer addr and return a conn.
func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) {
return p.nextProxy(addr).Dial(network, addr)
return p.chooseProxy(addr).Dial(network, addr)
}
// DialUDP connects to the given address via the proxy.
func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
return p.nextProxy(addr).DialUDP(network, addr)
return p.chooseProxy(addr).DialUDP(network, addr)
}
// nextProxy return next proxy according to rule.
func (p *Proxy) nextProxy(dstAddr string) *strategy.Proxy {
// chooseProxy returns a proxy according to rule.
func (p *Proxy) chooseProxy(dstAddr string) *FwdrGroup {
host, _, err := net.SplitHostPort(dstAddr)
if err != nil {
// TODO: check here
// logf("[rule] SplitHostPort ERROR: %s", err)
return p.proxy
return p.main
}
// find ip
if ip := net.ParseIP(host); ip != nil {
// check ip
if proxy, ok := p.ipMap.Load(ip.String()); ok {
return proxy.(*strategy.Proxy)
return proxy.(*FwdrGroup)
}
var ret *strategy.Proxy
var ret *FwdrGroup
// check cidr
p.cidrMap.Range(func(key, value interface{}) bool {
cidr := key.(*net.IPNet)
if cidr.Contains(ip) {
ret = value.(*strategy.Proxy)
ret = value.(*FwdrGroup)
return false
}
@ -94,21 +100,21 @@ func (p *Proxy) nextProxy(dstAddr string) *strategy.Proxy {
for i := len(host); i != -1; {
i = strings.LastIndexByte(host[:i], '.')
if proxy, ok := p.domainMap.Load(host[i+1:]); ok {
return proxy.(*strategy.Proxy)
return proxy.(*FwdrGroup)
}
}
return p.proxy
return p.main
}
// NextDialer return next dialer according to rule.
// NextDialer returns next dialer according to rule.
func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer {
return p.nextProxy(dstAddr).NextDialer(dstAddr)
return p.chooseProxy(dstAddr).NextDialer(dstAddr)
}
// Record records result while using the dialer from proxy.
func (p *Proxy) Record(dialer proxy.Dialer, success bool) {
strategy.OnRecord(dialer, success)
OnRecord(dialer, success)
}
// AddDomainIP used to update ipMap rules according to domainMap rule.
@ -128,9 +134,9 @@ func (p *Proxy) AddDomainIP(domain, ip string) error {
// Check .
func (p *Proxy) Check() {
p.proxy.Check()
p.main.Check()
for _, d := range p.proxies {
d.Check()
for _, fwdr := range p.all {
fwdr.Check()
}
}

View File

@ -1,4 +1,4 @@
package strategy
package rule
import (
"bytes"
@ -15,8 +15,8 @@ import (
"github.com/nadoo/glider/proxy"
)
// Config is strategy config struct.
type Config struct {
// StrategyConfig is strategy config struct.
type StrategyConfig struct {
Strategy string
CheckWebSite string
CheckInterval int
@ -35,9 +35,9 @@ func (p priSlice) Len() int { return len(p) }
func (p priSlice) Less(i, j int) bool { return p[i].Priority() > p[j].Priority() }
func (p priSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Proxy is base proxy struct.
type Proxy struct {
config *Config
// FwdrGroup is a forwarder group.
type FwdrGroup struct {
config *StrategyConfig
fwdrs priSlice
avail []*Forwarder // available forwarders
mu sync.RWMutex
@ -46,8 +46,8 @@ type Proxy struct {
next func(addr string) *Forwarder
}
// NewProxy returns a new strategy proxy.
func NewProxy(name string, s []string, c *Config) *Proxy {
// NewFwdrGroup returns a new forward group.
func NewFwdrGroup(name string, s []string, c *StrategyConfig) *FwdrGroup {
var fwdrs []*Forwarder
for _, chain := range s {
fwdr, err := ForwarderFromURL(chain, c.IntFace,
@ -66,12 +66,12 @@ func NewProxy(name string, s []string, c *Config) *Proxy {
c.Strategy = "rr"
}
return newProxy(name, fwdrs, c)
return newFwdrGroup(name, fwdrs, c)
}
// newProxy returns a new Proxy.
func newProxy(name string, fwdrs []*Forwarder, c *Config) *Proxy {
p := &Proxy{fwdrs: fwdrs, config: c}
// newFwdrGroup returns a new Proxy.
func newFwdrGroup(name string, fwdrs []*Forwarder, c *StrategyConfig) *FwdrGroup {
p := &FwdrGroup{fwdrs: fwdrs, config: c}
sort.Sort(p.fwdrs)
p.init()
@ -106,19 +106,19 @@ func newProxy(name string, fwdrs []*Forwarder, c *Config) *Proxy {
}
// Dial connects to the address addr on the network net.
func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) {
func (p *FwdrGroup) Dial(network, addr string) (net.Conn, proxy.Dialer, error) {
nd := p.NextDialer(addr)
c, err := nd.Dial(network, addr)
return c, nd, err
}
// DialUDP connects to the given address.
func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
func (p *FwdrGroup) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
return p.NextDialer(addr).DialUDP(network, addr)
}
// NextDialer returns the next dialer.
func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer {
func (p *FwdrGroup) NextDialer(dstAddr string) proxy.Dialer {
p.mu.RLock()
defer p.mu.RUnlock()
@ -130,7 +130,7 @@ func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer {
}
// Record records result while using the dialer from proxy.
func (p *Proxy) Record(dialer proxy.Dialer, success bool) {
func (p *FwdrGroup) Record(dialer proxy.Dialer, success bool) {
OnRecord(dialer, success)
}
@ -146,13 +146,13 @@ func OnRecord(dialer proxy.Dialer, success bool) {
}
// Priority returns the active priority of dialer.
func (p *Proxy) Priority() uint32 { return atomic.LoadUint32(&p.priority) }
func (p *FwdrGroup) Priority() uint32 { return atomic.LoadUint32(&p.priority) }
// SetPriority sets the active priority of daler.
func (p *Proxy) SetPriority(pri uint32) { atomic.StoreUint32(&p.priority, pri) }
func (p *FwdrGroup) SetPriority(pri uint32) { atomic.StoreUint32(&p.priority, pri) }
// init traverse d.fwdrs and init the available forwarder slice.
func (p *Proxy) init() {
func (p *FwdrGroup) init() {
for _, f := range p.fwdrs {
if f.Enabled() {
p.SetPriority(f.Priority())
@ -175,7 +175,7 @@ func (p *Proxy) init() {
}
// onStatusChanged will be called when fwdr's status changed.
func (p *Proxy) onStatusChanged(fwdr *Forwarder) {
func (p *FwdrGroup) onStatusChanged(fwdr *Forwarder) {
p.mu.Lock()
defer p.mu.Unlock()
@ -202,7 +202,7 @@ func (p *Proxy) onStatusChanged(fwdr *Forwarder) {
}
// Check implements the Checker interface.
func (p *Proxy) Check() {
func (p *FwdrGroup) Check() {
// no need to check when there's only 1 forwarder
if len(p.fwdrs) > 1 {
for i := 0; i < len(p.fwdrs); i++ {
@ -211,7 +211,7 @@ func (p *Proxy) Check() {
}
}
func (p *Proxy) check(f *Forwarder) {
func (p *FwdrGroup) check(f *Forwarder) {
wait := uint8(0)
buf := make([]byte, 4)
intval := time.Duration(p.config.CheckInterval) * time.Second
@ -301,17 +301,17 @@ func checkWebSite(fwdr *Forwarder, website string, timeout time.Duration, buf []
}
// Round Robin
func (p *Proxy) scheduleRR(dstAddr string) *Forwarder {
func (p *FwdrGroup) scheduleRR(dstAddr string) *Forwarder {
return p.avail[atomic.AddUint32(&p.index, 1)%uint32(len(p.avail))]
}
// High Availability
func (p *Proxy) scheduleHA(dstAddr string) *Forwarder {
func (p *FwdrGroup) scheduleHA(dstAddr string) *Forwarder {
return p.avail[0]
}
// Latency based High Availability
func (p *Proxy) scheduleLHA(dstAddr string) *Forwarder {
func (p *FwdrGroup) scheduleLHA(dstAddr string) *Forwarder {
fwdr := p.avail[0]
lowest := fwdr.Latency()
for _, f := range p.avail {
@ -324,7 +324,7 @@ func (p *Proxy) scheduleLHA(dstAddr string) *Forwarder {
}
// Destination Hashing
func (p *Proxy) scheduleDH(dstAddr string) *Forwarder {
func (p *FwdrGroup) scheduleDH(dstAddr string) *Forwarder {
fnv1a := fnv.New32a()
fnv1a.Write([]byte(dstAddr))
return p.avail[fnv1a.Sum32()%uint32(len(p.avail))]