From 22e0576b53565f86422c2ca4abfc740011a26974 Mon Sep 17 00:00:00 2001 From: wuudjac Date: Tue, 28 Apr 2020 15:18:19 +0800 Subject: [PATCH] redir, dns: IncFailures on non-timeout errors (#133) --- dns/client.go | 3 +++ proxy/proxy.go | 5 ++++- proxy/redir/redir_linux.go | 7 ++++--- rule/rule.go | 9 ++++++++- strategy/forward.go | 11 ++++++----- strategy/strategy.go | 17 +++++++++++++++-- 6 files changed, 40 insertions(+), 12 deletions(-) diff --git a/dns/client.go b/dns/client.go index e85914f..9f3602a 100644 --- a/dns/client.go +++ b/dns/client.go @@ -175,6 +175,9 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) ( log.F("[dns] error in resolving %s, failed to exchange with server %v: %v", qname, server, err) } + if err != nil { + c.proxy.Record(dialer, false) + } return server, network, dialer.Addr(), respBytes, err } diff --git a/proxy/proxy.go b/proxy/proxy.go index da80bc1..7736631 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -5,11 +5,14 @@ import "net" // Proxy is a dialer manager type Proxy interface { // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, proxy string, err error) + Dial(network, addr string) (c net.Conn, dialer Dialer, err error) // DialUDP connects to the given address via the proxy. DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) // Get the dialer by dstAddr NextDialer(dstAddr string) Dialer + + // Record records result while using the dialer from proxy. + Record(dialer Dialer, success bool) } diff --git a/proxy/redir/redir_linux.go b/proxy/redir/redir_linux.go index f03e8db..227bf99 100644 --- a/proxy/redir/redir_linux.go +++ b/proxy/redir/redir_linux.go @@ -104,14 +104,14 @@ func (s *RedirProxy) Serve(c net.Conn) { return } - rc, p, err := s.proxy.Dial("tcp", tgt.String()) + rc, dialer, err := s.proxy.Dial("tcp", tgt.String()) if err != nil { - log.F("[redir] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, p, err) + log.F("[redir] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) return } defer rc.Close() - log.F("[redir] %s <-> %s via %s", c.RemoteAddr(), tgt, p) + log.F("[redir] %s <-> %s via %s", c.RemoteAddr(), tgt, dialer.Addr()) _, _, err = conn.Relay(c, rc) if err != nil { @@ -119,6 +119,7 @@ func (s *RedirProxy) Serve(c net.Conn) { return // ignore i/o timeout } log.F("[redir] relay error: %v", err) + s.proxy.Record(dialer, false) } } diff --git a/rule/rule.go b/rule/rule.go index b8474f9..7130555 100644 --- a/rule/rule.go +++ b/rule/rule.go @@ -10,6 +10,8 @@ import ( "github.com/nadoo/glider/strategy" ) +var _ proxy.Proxy = &Proxy{} + // Proxy struct type Proxy struct { proxy *strategy.Proxy @@ -47,7 +49,7 @@ func NewProxy(rules []*Config, proxy *strategy.Proxy) *Proxy { } // Dial dials to targer addr and return a conn -func (p *Proxy) Dial(network, addr string) (net.Conn, string, error) { +func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { return p.nextProxy(addr).Dial(network, addr) } @@ -109,6 +111,11 @@ func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer { return p.nextProxy(dstAddr).NextDialer(dstAddr) } +// Record records result while using the dialer from proxy. +func (p *Proxy) Record(dialer proxy.Dialer, success bool) { + p.proxy.Record(dialer, success) +} + // AddDomainIP used to update ipMap rules according to domainMap rule func (p *Proxy) AddDomainIP(domain, ip string) error { if ip != "" { diff --git a/strategy/forward.go b/strategy/forward.go index 81f4b32..7f5315a 100644 --- a/strategy/forward.go +++ b/strategy/forward.go @@ -101,10 +101,6 @@ func (f *Forwarder) Dial(network, addr string) (c net.Conn, err error) { c, err = f.Dialer.Dial(network, addr) if err != nil { f.IncFailures() - if f.Failures() >= f.MaxFailures() && f.Enabled() { - f.Disable() - log.F("[forwarder] %s reaches maxfailures.", f.addr) - } } return c, err @@ -117,7 +113,12 @@ func (f *Forwarder) Failures() uint32 { // IncFailures increase the failuer count by 1 func (f *Forwarder) IncFailures() { - atomic.AddUint32(&f.failures, 1) + failures := atomic.AddUint32(&f.failures, 1) + log.F("[forwarder] %s recorded %d failures", f.addr, failures) + if failures >= f.MaxFailures() && f.Enabled() { + log.F("[forwarder] %s reaches maxfailures.", f.addr) + f.Disable() + } } // AddHandler adds a custom handler to handle the status change event diff --git a/strategy/strategy.go b/strategy/strategy.go index 3ed71ba..8526030 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -15,6 +15,8 @@ import ( "github.com/nadoo/glider/proxy" ) +var _ proxy.Proxy = &Proxy{} + // Config is strategy config struct. type Config struct { Strategy string @@ -102,10 +104,10 @@ func newProxy(fwdrs []*Forwarder, c *Config) *Proxy { } // Dial connects to the address addr on the network net. -func (p *Proxy) Dial(network, addr string) (net.Conn, string, error) { +func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { nd := p.NextDialer(addr) c, err := nd.Dial(network, addr) - return c, nd.Addr(), err + return c, nd, err } // DialUDP connects to the given address. @@ -125,6 +127,17 @@ func (p *Proxy) NextDialer(dstAddr string) proxy.Dialer { return p.next(dstAddr) } +// Record records result while using the dialer from proxy. +func (p *Proxy) Record(dialer proxy.Dialer, success bool) { + if success { + return + } + forwarder, ok := dialer.(*Forwarder) + if ok { + forwarder.IncFailures() + } +} + // Priority returns the active priority of dialer. func (p *Proxy) Priority() uint32 { return atomic.LoadUint32(&p.priority) }