From a22b1d9c861005f0b2d16702508deb2337bd155a Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Mon, 18 Mar 2019 23:37:01 +0800 Subject: [PATCH] strategy: add checktimeout config. (#89) --- README.md | 6 +++++- common/conn/conn.go | 24 +++++++++------------- conf.go | 1 + config/glider.conf.example | 2 ++ go.mod | 6 +++--- go.sum | 6 ++++++ proxy/socks5/socks5.go | 30 ++++++++++++++-------------- proxy/ss/ss.go | 26 ++++++++++++------------ proxy/udptun/udptun.go | 10 +++++----- proxy/uottun/uottun.go | 12 +++++------ rule/config.go | 1 + strategy/strategy.go | 41 +++++++++++++++++++++++--------------- 12 files changed, 91 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index a79a3c6..5d4d794 100644 --- a/README.md +++ b/README.md @@ -116,9 +116,11 @@ glider -config CONFIGPATH -listen :8080 -verbose ## Usage ```bash -glider v0.6.10 usage: +glider v0.7.0 usage: -checkinterval int proxy check interval(seconds) (default 30) + -checktimeout int + proxy check timeout(seconds) (default 10) -checkwebsite string proxy check HTTP(NOT HTTPS) website address, format: HOST[:PORT], default port: 80 (default "www.apple.com") -config string @@ -139,6 +141,8 @@ glider v0.6.10 usage: timeout value used in multiple dnsservers switch(seconds) (default 3) -forward value forward url, format: SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS[,SCHEME://[USER|METHOD:PASSWORD@][HOST]:PORT?PARAMS] + -include value + include file -interface string source ip or source interface -listen value diff --git a/common/conn/conn.go b/common/conn/conn.go index 4e952d0..aca363b 100644 --- a/common/conn/conn.go +++ b/common/conn/conn.go @@ -7,41 +7,35 @@ import ( "time" ) -// UDPBufSize is the size of udp buffer +// UDPBufSize is the size of udp buffer. const UDPBufSize = 65536 -// Conn struct +// Conn is a base conn struct. type Conn struct { r *bufio.Reader net.Conn } -// NewConn . +// NewConn returns a new conn. func NewConn(c net.Conn) *Conn { return &Conn{bufio.NewReader(c), c} } -// NewConnSize . -func NewConnSize(c net.Conn, n int) *Conn { - return &Conn{bufio.NewReaderSize(c, n), c} -} - -// Peek . +// Peek returns the next n bytes without advancing the reader. func (c *Conn) Peek(n int) ([]byte, error) { return c.r.Peek(n) } -// Read . func (c *Conn) Read(p []byte) (int, error) { return c.r.Read(p) } -// Reader returns the internal bufio.Reader +// Reader returns the internal bufio.Reader. func (c *Conn) Reader() *bufio.Reader { return c.r } -// Relay . +// Relay relays between left and right. func Relay(left, right net.Conn) (int64, int64, error) { type res struct { N int64 @@ -67,8 +61,8 @@ func Relay(left, right net.Conn) (int64, int64, error) { return n, rs.N, err } -// TimedCopy copy from src to dst at target with read timeout -func TimedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration) error { +// RelayUDP copys from src to dst at target with read timeout. +func RelayUDP(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout time.Duration) error { buf := make([]byte, UDPBufSize) for { src.SetReadDeadline(time.Now().Add(timeout)) @@ -84,7 +78,7 @@ func TimedCopy(dst net.PacketConn, target net.Addr, src net.PacketConn, timeout } } -// OutboundIP returns preferred outbound ip of this machine +// OutboundIP returns preferred outbound ip of this machine. func OutboundIP() string { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { diff --git a/conf.go b/conf.go index c2d7a32..5c2e972 100644 --- a/conf.go +++ b/conf.go @@ -40,6 +40,7 @@ func confInit() { flag.StringVar(&conf.StrategyConfig.Strategy, "strategy", "rr", "forward strategy, default: rr") flag.StringVar(&conf.StrategyConfig.CheckWebSite, "checkwebsite", "www.apple.com", "proxy check HTTP(NOT HTTPS) website address, format: HOST[:PORT], default port: 80") flag.IntVar(&conf.StrategyConfig.CheckInterval, "checkinterval", 30, "proxy check interval(seconds)") + flag.IntVar(&conf.StrategyConfig.CheckTimeout, "checktimeout", 10, "proxy check timeout(seconds)") flag.IntVar(&conf.StrategyConfig.MaxFailures, "maxfailures", 3, "max failures to change forwarder status to disabled") flag.StringVar(&conf.StrategyConfig.IntFace, "interface", "", "source ip or source interface") diff --git a/config/glider.conf.example b/config/glider.conf.example index 5926a23..794bb73 100644 --- a/config/glider.conf.example +++ b/config/glider.conf.example @@ -155,6 +155,8 @@ checkwebsite=www.apple.com # check interval(seconds) checkinterval=30 +# check timeout(seconds) +checktimeout=10 # DNS FORWARDING SERVER # ---------------- diff --git a/go.mod b/go.mod index d5f321d..161a993 100644 --- a/go.mod +++ b/go.mod @@ -19,9 +19,9 @@ require ( github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect github.com/tjfoc/gmsm v1.0.1 // indirect github.com/xtaci/kcp-go v5.0.7+incompatible - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 - golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect - golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect + golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a + golang.org/x/net v0.0.0-20190313220215-9f648a60d977 // indirect + golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f // indirect ) // Replace dependency modules with local developing copy diff --git a/go.sum b/go.sum index aa60bf7..01c4203 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28 golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95 h1:fY7Dsw114eJN4boqzVSbpVHO6rTdhq6/GnXeu+PKnzU= golang.org/x/net v0.0.0-20190301231341-16b79f2e4e95/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190310074541-c10a0554eabf h1:J7RqX9u0J9ZB37CGaFc2VC+QZZT6E6jnDbrboEFVo0U= @@ -46,6 +48,8 @@ golang.org/x/net v0.0.0-20190311031020-56fb01167e7d h1:vQJbQvu6+H699vOmHa20TEBI9 golang.org/x/net v0.0.0-20190311031020-56fb01167e7d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190302025703-b6889370fb10 h1:xQJI9OEiErEQ++DoXOHqEpzsGMrAv2Q2jyCpi7DmfpQ= golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -69,4 +73,6 @@ golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1 h1:FQNj2xvjQ1lgFyzbSybGZr792 golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f h1:yCrMx/EeIue0+Qca57bWZS7VX6ymEoypmhWyPhz0NHM= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/proxy/socks5/socks5.go b/proxy/socks5/socks5.go index c714560..351ad5e 100644 --- a/proxy/socks5/socks5.go +++ b/proxy/socks5/socks5.go @@ -26,10 +26,10 @@ import ( "github.com/nadoo/glider/proxy" ) -// Version is socks5 version number +// Version is socks5 version number. const Version = 5 -// SOCKS5 struct +// SOCKS5 is a base socks5 struct. type SOCKS5 struct { dialer proxy.Dialer addr string @@ -43,7 +43,7 @@ func init() { } // NewSOCKS5 returns a Proxy that makes SOCKS v5 connections to the given address -// with an optional username and password. See RFC 1928 +// with an optional username and password. (RFC 1928) func NewSOCKS5(s string, dialer proxy.Dialer) (*SOCKS5, error) { u, err := url.Parse(s) if err != nil { @@ -65,23 +65,23 @@ func NewSOCKS5(s string, dialer proxy.Dialer) (*SOCKS5, error) { return h, nil } -// NewSocks5Dialer returns a socks5 proxy dialer +// NewSocks5Dialer returns a socks5 proxy dialer. func NewSocks5Dialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) { return NewSOCKS5(s, dialer) } -// NewSocks5Server returns a socks5 proxy server +// NewSocks5Server returns a socks5 proxy server. func NewSocks5Server(s string, dialer proxy.Dialer) (proxy.Server, error) { return NewSOCKS5(s, dialer) } -// ListenAndServe serves socks5 requests +// ListenAndServe serves socks5 requests. func (s *SOCKS5) ListenAndServe() { go s.ListenAndServeUDP() s.ListenAndServeTCP() } -// ListenAndServeTCP . +// ListenAndServeTCP listen and serve on tcp port. func (s *SOCKS5) ListenAndServeTCP() { l, err := net.Listen("tcp", s.addr) if err != nil { @@ -102,7 +102,7 @@ func (s *SOCKS5) ListenAndServeTCP() { } } -// Serve . +// Serve serves a connection. func (s *SOCKS5) Serve(c net.Conn) { defer c.Close() @@ -148,7 +148,7 @@ func (s *SOCKS5) Serve(c net.Conn) { } } -// ListenAndServeUDP serves udp requests +// ListenAndServeUDP serves udp requests. func (s *SOCKS5) ListenAndServeUDP() { lc, err := net.ListenPacket("udp", s.addr) if err != nil { @@ -189,7 +189,7 @@ func (s *SOCKS5) ListenAndServeUDP() { nm.Store(raddr.String(), pc) go func() { - conn.TimedCopy(c, raddr, pc, 2*time.Minute) + conn.RelayUDP(c, raddr, pc, 2*time.Minute) pc.Close() nm.Delete(raddr.String()) }() @@ -211,7 +211,7 @@ func (s *SOCKS5) ListenAndServeUDP() { } -// Addr returns forwarder's address +// Addr returns forwarder's address. func (s *SOCKS5) Addr() string { if s.addr == "" { return s.dialer.Addr() @@ -219,7 +219,7 @@ func (s *SOCKS5) Addr() string { return s.addr } -// NextDialer returns the next dialer +// NextDialer returns the next dialer. func (s *SOCKS5) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the SOCKS5 proxy. @@ -244,7 +244,7 @@ func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) { return c, nil } -// DialUDP connects to the given address via the proxy +// DialUDP connects to the given address via the proxy. func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { c, err := s.dialer.Dial("tcp", s.addr) if err != nil { @@ -293,7 +293,7 @@ func (s *SOCKS5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A // connect takes an existing connection to a socks5 proxy server, // and commands the server to extend that connection to target, -// which must be a canonical address with a host and port +// which must be a canonical address with a host and port. func (s *SOCKS5) connect(conn net.Conn, target string) error { host, portStr, err := net.SplitHostPort(target) if err != nil { @@ -424,7 +424,7 @@ func (s *SOCKS5) connect(conn net.Conn, target string) error { return nil } -// Handshake fast-tracks SOCKS initialization to get target address to connect +// Handshake fast-tracks SOCKS initialization to get target address to connect. func (s *SOCKS5) handshake(rw io.ReadWriter) (socks.Addr, error) { // Read RFC 1928 for request and reply structure and sizes buf := make([]byte, socks.MaxAddrLen) diff --git a/proxy/ss/ss.go b/proxy/ss/ss.go index 34a4a10..e5222b9 100644 --- a/proxy/ss/ss.go +++ b/proxy/ss/ss.go @@ -16,7 +16,7 @@ import ( "github.com/nadoo/glider/proxy" ) -// SS . +// SS is a base ss struct. type SS struct { dialer proxy.Dialer addr string @@ -29,7 +29,7 @@ func init() { proxy.RegisterServer("ss", NewSSServer) } -// NewSS returns a shadowsocks proxy +// NewSS returns a ss proxy. func NewSS(s string, dialer proxy.Dialer) (*SS, error) { u, err := url.Parse(s) if err != nil { @@ -55,23 +55,23 @@ func NewSS(s string, dialer proxy.Dialer) (*SS, error) { return p, nil } -// NewSSDialer returns a ss proxy dialer +// NewSSDialer returns a ss proxy dialer. func NewSSDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) { return NewSS(s, dialer) } -// NewSSServer returns a ss proxy server +// NewSSServer returns a ss proxy server. func NewSSServer(s string, dialer proxy.Dialer) (proxy.Server, error) { return NewSS(s, dialer) } -// ListenAndServe serves ss requests +// ListenAndServe serves ss requests. func (s *SS) ListenAndServe() { go s.ListenAndServeUDP() s.ListenAndServeTCP() } -// ListenAndServeTCP serves tcp ss requests +// ListenAndServeTCP serves tcp ss requests. func (s *SS) ListenAndServeTCP() { l, err := net.Listen("tcp", s.addr) if err != nil { @@ -92,7 +92,7 @@ func (s *SS) ListenAndServeTCP() { } -// Serve serves tcp ss requests +// Serve serves a connection. func (s *SS) Serve(c net.Conn) { defer c.Close() @@ -166,7 +166,7 @@ func (s *SS) Serve(c net.Conn) { } -// ListenAndServeUDP serves udp ss requests +// ListenAndServeUDP serves udp ss requests. func (s *SS) ListenAndServeUDP() { lc, err := net.ListenPacket("udp", s.addr) if err != nil { @@ -204,7 +204,7 @@ func (s *SS) ListenAndServeUDP() { nm.Store(raddr.String(), pc) go func() { - conn.TimedCopy(c, raddr, pc, 2*time.Minute) + conn.RelayUDP(c, raddr, pc, 2*time.Minute) pc.Close() nm.Delete(raddr.String()) }() @@ -225,12 +225,12 @@ func (s *SS) ListenAndServeUDP() { } } -// ListCipher . +// ListCipher returns all the ciphers supported. func ListCipher() string { return strings.Join(core.ListCipher(), " ") } -// Addr returns forwarder's address +// Addr returns forwarder's address. func (s *SS) Addr() string { if s.addr == "" { return s.dialer.Addr() @@ -238,7 +238,7 @@ func (s *SS) Addr() string { return s.addr } -// NextDialer returns the next dialer +// NextDialer returns the next dialer. func (s *SS) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy. @@ -268,7 +268,7 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) { } -// DialUDP connects to the given address via the proxy +// DialUDP connects to the given address via the proxy. func (s *SS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { pc, nextHop, err := s.dialer.DialUDP(network, s.addr) if err != nil { diff --git a/proxy/udptun/udptun.go b/proxy/udptun/udptun.go index 31976a1..f170dc6 100644 --- a/proxy/udptun/udptun.go +++ b/proxy/udptun/udptun.go @@ -16,8 +16,8 @@ import ( type UDPTun struct { dialer proxy.Dialer addr string - taddr string // tunnel addr - uaddr *net.UDPAddr // tunnel addr + taddr string // tunnel addr string + tuaddr *net.UDPAddr // tunnel addr } func init() { @@ -41,7 +41,7 @@ func NewUDPTun(s string, dialer proxy.Dialer) (*UDPTun, error) { taddr: d[1], } - p.uaddr, err = net.ResolveUDPAddr("udp", p.taddr) + p.tuaddr, err = net.ResolveUDPAddr("udp", p.taddr) return p, err } @@ -85,7 +85,7 @@ func (s *UDPTun) ListenAndServe() { nm.Store(raddr.String(), pc) go func() { - conn.TimedCopy(c, raddr, pc, 2*time.Minute) + conn.RelayUDP(c, raddr, pc, 2*time.Minute) pc.Close() nm.Delete(raddr.String()) }() @@ -94,7 +94,7 @@ func (s *UDPTun) ListenAndServe() { pc = v.(net.PacketConn) } - _, err = pc.WriteTo(buf[:n], s.uaddr) + _, err = pc.WriteTo(buf[:n], s.tuaddr) if err != nil { log.F("[udptun] remote write error: %v", err) continue diff --git a/proxy/uottun/uottun.go b/proxy/uottun/uottun.go index 445c9b7..5cdbbfd 100644 --- a/proxy/uottun/uottun.go +++ b/proxy/uottun/uottun.go @@ -12,7 +12,7 @@ import ( "github.com/nadoo/glider/proxy" ) -// UoTTun udp over tcp tunnel +// UoTTun is a base udp over tcp tunnel struct. type UoTTun struct { dialer proxy.Dialer addr string @@ -24,7 +24,7 @@ func init() { proxy.RegisterServer("uottun", NewUoTTunServer) } -// NewUoTTun returns a UoTTun proxy +// NewUoTTun returns a UoTTun proxy. func NewUoTTun(s string, dialer proxy.Dialer) (*UoTTun, error) { u, err := url.Parse(s) if err != nil { @@ -44,12 +44,12 @@ func NewUoTTun(s string, dialer proxy.Dialer) (*UoTTun, error) { return p, nil } -// NewUoTTunServer returns a uot tunnel server +// NewUoTTunServer returns a uot tunnel server. func NewUoTTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) { return NewUoTTun(s, dialer) } -// ListenAndServe . +// ListenAndServe listen and serve on tcp. func (s *UoTTun) ListenAndServe() { c, err := net.ListenPacket("udp", s.addr) if err != nil { @@ -78,7 +78,7 @@ func (s *UoTTun) ListenAndServe() { go func() { // no remote forwarder, just a local udp forwarder if urc, ok := rc.(*net.UDPConn); ok { - conn.TimedCopy(c, clientAddr, urc, 2*time.Minute) + conn.RelayUDP(c, clientAddr, urc, 2*time.Minute) urc.Close() return } @@ -103,7 +103,7 @@ func (s *UoTTun) ListenAndServe() { } } -// Serve . +// Serve is not allowed to be called directly. func (s *UoTTun) Serve(c net.Conn) { // TODO log.F("[uottun] func Serve: can not be called directly") diff --git a/rule/config.go b/rule/config.go index 113d015..0862d4d 100644 --- a/rule/config.go +++ b/rule/config.go @@ -35,6 +35,7 @@ func NewConfFromFile(ruleFile string) (*Config, error) { f.StringVar(&p.StrategyConfig.Strategy, "strategy", "rr", "forward strategy, default: rr") f.StringVar(&p.StrategyConfig.CheckWebSite, "checkwebsite", "www.apple.com", "proxy check HTTP(NOT HTTPS) website address, format: HOST[:PORT], default port: 80") f.IntVar(&p.StrategyConfig.CheckInterval, "checkinterval", 30, "proxy check interval(seconds)") + f.IntVar(&p.StrategyConfig.CheckTimeout, "checktimeout", 10, "proxy check timeout(seconds)") f.StringVar(&p.StrategyConfig.IntFace, "interface", "", "source ip or source interface") f.StringSliceUniqVar(&p.DNSServers, "dnsserver", nil, "remote dns server") diff --git a/strategy/strategy.go b/strategy/strategy.go index 2583b27..31cde0c 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -15,16 +15,17 @@ import ( "github.com/nadoo/glider/proxy" ) -// Checker is an interface of forwarder checker +// Checker is an interface of forwarder checker. type Checker interface { Check() } -// Config of strategy +// Config is strategy config struct. type Config struct { Strategy string CheckWebSite string CheckInterval int + CheckTimeout int MaxFailures int IntFace string } @@ -36,7 +37,7 @@ 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] } -// Dialer . +// Dialer is base dialer struct. type Dialer struct { config *Config fwdrs priSlice @@ -48,7 +49,7 @@ type Dialer struct { nextForwarder func(addr string) *proxy.Forwarder } -// NewDialer returns a new strategy dialer +// NewDialer returns a new strategy dialer. func NewDialer(s []string, c *Config) proxy.Dialer { var fwdrs []*proxy.Forwarder for _, chain := range s { @@ -111,20 +112,20 @@ func newDialer(fwdrs []*proxy.Forwarder, c *Config) *Dialer { return d } -// Addr returns forwarder's address +// Addr returns forwarder's address. func (d *Dialer) Addr() string { return "STRATEGY" } -// Dial connects to the address addr on the network net +// Dial connects to the address addr on the network net. func (d *Dialer) Dial(network, addr string) (net.Conn, error) { return d.NextDialer(addr).Dial(network, addr) } -// DialUDP connects to the given address +// DialUDP connects to the given address. func (d *Dialer) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { return d.NextDialer(addr).DialUDP(network, addr) } -// NextDialer returns the next dialer +// NextDialer returns the next dialer. func (d *Dialer) NextDialer(dstAddr string) proxy.Dialer { d.mu.RLock() defer d.mu.RUnlock() @@ -132,13 +133,13 @@ func (d *Dialer) NextDialer(dstAddr string) proxy.Dialer { return d.nextForwarder(dstAddr) } -// Priority returns the active priority of dialer +// Priority returns the active priority of dialer. func (d *Dialer) Priority() uint32 { return atomic.LoadUint32(&d.priority) } -// SetPriority sets the active priority of daler +// SetPriority sets the active priority of daler. func (d *Dialer) SetPriority(p uint32) { atomic.StoreUint32(&d.priority, p) } -// initAvailable traverse d.fwdrs and init the available forwarder slice +// initAvailable traverse d.fwdrs and init the available forwarder slice. func (d *Dialer) initAvailable() { for _, f := range d.fwdrs { if f.Enabled() { @@ -162,7 +163,7 @@ func (d *Dialer) initAvailable() { } } -// onStatusChanged will be called when fwdr's status changed +// onStatusChanged will be called when fwdr's status changed. func (d *Dialer) onStatusChanged(fwdr *proxy.Forwarder) { d.mu.Lock() defer d.mu.Unlock() @@ -189,7 +190,7 @@ func (d *Dialer) onStatusChanged(fwdr *proxy.Forwarder) { } } -// Check implements the Checker interface +// Check implements the Checker interface. func (d *Dialer) Check() { for i := 0; i < len(d.fwdrs); i++ { go d.check(i) @@ -229,11 +230,19 @@ func (d *Dialer) check(i int) { f.Disable() log.F("[check] %s(%d) -> %s, DISABLED. error in read: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, err) } else if bytes.Equal([]byte("HTTP"), buf) { - f.Enable() - retry = 2 + readTime := time.Since(startTime) f.SetLatency(int64(readTime)) - log.F("[check] %s(%d) -> %s, ENABLED. connect time: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, readTime.String()) + + if readTime > time.Duration(d.config.CheckTimeout)*time.Second { + f.Disable() + log.F("[check] %s(%d) -> %s, DISABLED. connect timeout: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, readTime) + } else { + retry = 2 + f.Enable() + log.F("[check] %s(%d) -> %s, ENABLED. connect time: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, readTime) + } + } else { f.Disable() log.F("[check] %s(%d) -> %s, DISABLED. server response: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, buf)