diff --git a/go.mod b/go.mod index ae39f75..2329787 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/tjfoc/gmsm v1.3.0 // indirect github.com/xtaci/kcp-go/v5 v5.5.12 - golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc - golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect - golang.org/x/sys v0.0.0-20200428200454-593003d681fa // indirect + golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 + golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 // indirect + golang.org/x/sys v0.0.0-20200501052902-10377860bb8e // indirect ) // Replace dependency modules with local developing copy diff --git a/go.sum b/go.sum index a8c83ea..606d2c1 100644 --- a/go.sum +++ b/go.sum @@ -60,13 +60,13 @@ golang.org/x/crypto v0.0.0-20191010185427-af544f31c8ac/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc h1:ZGI/fILM2+ueot/UixBSoj9188jCAxVHEZEGhqq67I4= -golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= +golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U= -golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -75,8 +75,8 @@ golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA= -golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e h1:hq86ru83GdWTlfQFZGO4nZJTU4Bs2wfHl8oFHRaXsfc= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/proxy/http/server.go b/proxy/http/server.go index efb1441..1a9f2e1 100644 --- a/proxy/http/server.go +++ b/proxy/http/server.go @@ -108,6 +108,7 @@ func (s *HTTP) servHTTPS(r *request, c net.Conn) { return // ignore i/o timeout } log.F("[http] relay error: %v", err) + s.proxy.Record(dialer, false) } } diff --git a/proxy/socks5/socks5.go b/proxy/socks5/socks5.go index dbc0641..8a3ec9d 100644 --- a/proxy/socks5/socks5.go +++ b/proxy/socks5/socks5.go @@ -147,6 +147,7 @@ func (s *Socks5) Serve(c net.Conn) { return // ignore i/o timeout } log.F("[socks5] relay error: %v", err) + s.proxy.Record(dialer, false) } } diff --git a/proxy/ss/ss.go b/proxy/ss/ss.go index 14fbeff..9fbd83e 100644 --- a/proxy/ss/ss.go +++ b/proxy/ss/ss.go @@ -166,8 +166,8 @@ func (s *SS) Serve(c net.Conn) { return // ignore i/o timeout } log.F("[ss] relay error: %v", err) + s.proxy.Record(dialer, false) } - } // ListenAndServeUDP serves udp ss requests. diff --git a/proxy/tcptun/tcptun.go b/proxy/tcptun/tcptun.go index 413fb4a..3c87a64 100644 --- a/proxy/tcptun/tcptun.go +++ b/proxy/tcptun/tcptun.go @@ -83,6 +83,7 @@ func (s *TCPTun) Serve(c net.Conn) { rc, dialer, err := s.proxy.Dial("tcp", s.raddr) if err != nil { log.F("[tcptun] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), s.addr, dialer.Addr(), err) + s.proxy.Record(dialer, false) return } defer rc.Close() @@ -95,5 +96,6 @@ func (s *TCPTun) Serve(c net.Conn) { return // ignore i/o timeout } log.F("relay error: %v", err) + s.proxy.Record(dialer, false) } } diff --git a/rule/rule.go b/rule/rule.go index c5f011e..dfe9eea 100644 --- a/rule/rule.go +++ b/rule/rule.go @@ -20,7 +20,7 @@ type Proxy struct { cidrMap sync.Map } -// NewProxy returns a new rule proxy +// NewProxy returns a new rule proxy. func NewProxy(rules []*Config, proxy *strategy.Proxy) *Proxy { rd := &Proxy{proxy: proxy} @@ -46,17 +46,17 @@ func NewProxy(rules []*Config, proxy *strategy.Proxy) *Proxy { return rd } -// 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) { return p.nextProxy(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, writeTo net.Addr, err error) { return p.nextProxy(addr).DialUDP(network, addr) } -// nextProxy return next proxy according to rule +// nextProxy return next proxy according to rule. func (p *Proxy) nextProxy(dstAddr string) *strategy.Proxy { host, _, err := net.SplitHostPort(dstAddr) if err != nil { @@ -104,17 +104,17 @@ func (p *Proxy) nextProxy(dstAddr string) *strategy.Proxy { return p.proxy } -// NextDialer return next dialer according to rule +// NextDialer return next dialer according to rule. 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) + strategy.OnRecord(dialer, success) } -// AddDomainIP used to update ipMap rules according to domainMap rule +// AddDomainIP used to update ipMap rules according to domainMap rule. func (p *Proxy) AddDomainIP(domain, ip string) error { if ip != "" { domainParts := strings.Split(domain, ".") diff --git a/strategy/forward.go b/strategy/forward.go index 7f5315a..c70f524 100644 --- a/strategy/forward.go +++ b/strategy/forward.go @@ -115,6 +115,7 @@ func (f *Forwarder) Failures() uint32 { func (f *Forwarder) IncFailures() { 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() diff --git a/strategy/strategy.go b/strategy/strategy.go index b51a7e1..4715138 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -65,7 +65,7 @@ func NewProxy(s []string, c *Config) *Proxy { return newProxy(fwdrs, c) } -// newProxy returns a new rrProxy +// newProxy returns a new Proxy. func newProxy(fwdrs []*Forwarder, c *Config) *Proxy { p := &Proxy{fwdrs: fwdrs, config: c} sort.Sort(p.fwdrs) @@ -127,12 +127,16 @@ 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) { - if success { - return - } - forwarder, ok := dialer.(*Forwarder) - if ok { - forwarder.IncFailures() + OnRecord(dialer, success) +} + +func OnRecord(dialer proxy.Dialer, success bool) { + if fwdr, ok := dialer.(*Forwarder); ok { + if success { + fwdr.Enable() + } else { + fwdr.IncFailures() + } } }