From 88dda17725da78aac177d209f096f59fe419f61e Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Sat, 29 Jul 2017 21:31:01 +0800 Subject: [PATCH] 1. optimized strategy proxy code. 2. changed config name "checkhost" -> "checkwebsite" 3. optimized proxy check function. --- dnstun.go | 4 +-- glider.conf.example | 3 +- http.go | 5 ++- main.go | 11 ++++--- mixed.go | 6 ++-- proxy.go | 63 +++++++++++++++++-------------------- socks5.go | 4 +-- ss.go | 7 +++-- strategy.go | 76 +++++++++++++++++++++++++-------------------- tcptun.go | 4 +-- 10 files changed, 93 insertions(+), 90 deletions(-) diff --git a/dnstun.go b/dnstun.go index 625bf82..886a54c 100644 --- a/dnstun.go +++ b/dnstun.go @@ -24,7 +24,7 @@ const TCPDNSHEADERLen = 2 + UDPDNSHeaderLen const MaxUDPDNSLen = 512 type dnstun struct { - Proxy + *proxy addr string raddr string } @@ -32,7 +32,7 @@ type dnstun struct { // DNSTunProxy returns a dns forwarder. client -> dns.udp -> glider -> forwarder -> remote dns addr func DNSTunProxy(addr, raddr string, upProxy Proxy) (Proxy, error) { s := &dnstun{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), addr: addr, raddr: raddr, } diff --git a/glider.conf.example b/glider.conf.example index e7bcb96..3d38c53 100644 --- a/glider.conf.example +++ b/glider.conf.example @@ -89,7 +89,8 @@ strategy=rr # Used to connect via forwarders, if the host is unreachable, the forwarder # will be set to disabled. -checkhost=www.apple.com:443 +# MUST BE A HTTP or HTTPS WEBSITE HOST ADDRESS +checkwebsite=www.apple.com:443 # check duration(seconds) checkduration=30 diff --git a/http.go b/http.go index 205ea40..65d6a86 100644 --- a/http.go +++ b/http.go @@ -18,14 +18,14 @@ import ( // httpproxy type httpproxy struct { - Proxy + *proxy addr string } // HTTPProxy returns a http proxy. func HTTPProxy(addr string, upProxy Proxy) (Proxy, error) { s := &httpproxy{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), addr: addr, } @@ -56,7 +56,6 @@ func (s *httpproxy) ListenAndServe() { // Serve . func (s *httpproxy) Serve(c net.Conn) { - defer c.Close() if c, ok := c.(*net.TCPConn); ok { diff --git a/main.go b/main.go index 0bc02b2..eb2fb7b 100644 --- a/main.go +++ b/main.go @@ -12,12 +12,12 @@ import ( ) // VERSION . -const VERSION = "0.2.1" +const VERSION = "0.3" var conf struct { Verbose bool Strategy string - CheckHost string + CheckWebSite string CheckDuration int Listen arrFlags Forward arrFlags @@ -121,7 +121,7 @@ func main() { flag.BoolVar(&conf.Verbose, "verbose", false, "verbose mode") flag.StringVar(&conf.Strategy, "strategy", "rr", "forward strategy, default: rr") - flag.StringVar(&conf.CheckHost, "checkhost", "www.apple.com:443", "proxy check address") + flag.StringVar(&conf.CheckWebSite, "checkwebsite", "www.apple.com:443", "proxy check WEBSITE address") flag.IntVar(&conf.CheckDuration, "checkduration", 30, "proxy check duration(seconds)") flag.Var(&conf.Listen, "listen", "listen url, format: SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT") flag.Var(&conf.Forward, "forward", "forward url, format: SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT[,SCHEMA://[USER|METHOD:PASSWORD@][HOST]:PORT]") @@ -152,8 +152,9 @@ func main() { forwarders = append(forwarders, forward) } + forwarder := newStrategyForwarder(conf.Strategy, forwarders) for _, listen := range conf.Listen { - local, err := ProxyFromURL(listen, forwarders...) + local, err := ProxyFromURL(listen, forwarder) if err != nil { log.Fatal(err) } @@ -163,7 +164,7 @@ func main() { if len(forwarders) > 1 { for _, forward := range forwarders { - go check(forward, conf.CheckHost, conf.CheckDuration) + go check(forward, conf.CheckWebSite, conf.CheckDuration) } } diff --git a/mixed.go b/mixed.go index e063cba..684ed37 100644 --- a/mixed.go +++ b/mixed.go @@ -19,7 +19,7 @@ var httpMethods = [][]byte{ // mixedproxy type mixedproxy struct { - Proxy + *proxy http Proxy socks5 Proxy ss Proxy @@ -28,14 +28,14 @@ type mixedproxy struct { // MixedProxy returns a mixed proxy. func MixedProxy(network, addr, user, pass string, upProxy Proxy) (Proxy, error) { p := &mixedproxy{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), } p.http, _ = HTTPProxy(addr, upProxy) p.socks5, _ = SOCKS5Proxy(network, addr, user, pass, upProxy) if user != "" && pass != "" { - p.ss, _ = SSProxy(user, pass, upProxy) + p.ss, _ = SSProxy(addr, user, pass, upProxy) } return p, nil diff --git a/proxy.go b/proxy.go index b955ab3..e3ca974 100644 --- a/proxy.go +++ b/proxy.go @@ -2,6 +2,7 @@ package main import ( "errors" + "io" "net" "net/url" "strings" @@ -46,12 +47,12 @@ type proxy struct { } // newProxy . -func newProxy(addr string, forward Proxy) Proxy { +func newProxy(addr string, forward Proxy) *proxy { if forward == nil { forward = Direct } - return &proxy{addr: addr, forward: forward, enabled: false} + return &proxy{addr: addr, forward: forward, enabled: true} } func (p *proxy) ListenAndServe() { logf("base proxy ListenAndServe") } @@ -69,7 +70,7 @@ func (p *proxy) Dial(network, addr string) (net.Conn, error) { // ProxyFromURL parses url and get a Proxy // TODO: table -func ProxyFromURL(s string, forwarders ...Proxy) (Proxy, error) { +func ProxyFromURL(s string, forwarder Proxy) (Proxy, error) { if !strings.Contains(s, "://") { s = "mixed://" + s } @@ -87,43 +88,24 @@ func ProxyFromURL(s string, forwarders ...Proxy) (Proxy, error) { pass, _ = u.User.Password() } - var proxy Proxy - if len(forwarders) == 0 { - proxy = newProxy(addr, Direct) - } else if len(forwarders) == 1 { - proxy = newProxy(addr, forwarders[0]) - } else if len(forwarders) > 1 { - switch conf.Strategy { - case "rr": - proxy = newRRProxy(addr, forwarders) - logf("forward to remote servers in round robin mode.") - case "ha": - proxy = newHAProxy(addr, forwarders) - logf("forward to remote servers in high availability mode.") - default: - logf("not supported forward mode '%s', just use the first forward server.", conf.Strategy) - proxy = newProxy(addr, forwarders[0]) - } - } - switch u.Scheme { case "ss": - p, err := SSProxy(user, pass, proxy) + p, err := SSProxy(addr, user, pass, forwarder) return p, err case "socks5": - return SOCKS5Proxy("tcp", addr, user, pass, proxy) + return SOCKS5Proxy("tcp", addr, user, pass, forwarder) case "redir": - return RedirProxy(addr, proxy) + return RedirProxy(addr, forwarder) case "tcptun": d := strings.Split(addr, "=") - return TCPTunProxy(d[0], d[1], proxy) + return TCPTunProxy(d[0], d[1], forwarder) case "dnstun": d := strings.Split(addr, "=") - return DNSTunProxy(d[0], d[1], proxy) + return DNSTunProxy(d[0], d[1], forwarder) case "http": - return HTTPProxy(addr, proxy) + return HTTPProxy(addr, forwarder) case "mixed": - return MixedProxy("tcp", addr, user, pass, proxy) + return MixedProxy("tcp", addr, user, pass, forwarder) } return nil, errors.New("unknown schema '" + u.Scheme + "'") @@ -132,6 +114,8 @@ func ProxyFromURL(s string, forwarders ...Proxy) (Proxy, error) { // Check proxy func check(p Proxy, target string, duration int) { firstTime := true + buf := make([]byte, 8) + for { if !firstTime { time.Sleep(time.Duration(duration) * time.Second) @@ -141,15 +125,24 @@ func check(p Proxy, target string, duration int) { startTime := time.Now() c, err := p.Dial("tcp", target) if err != nil { - logf("proxy-check %s -> %s, set to DISABLED. error: %s", p.Addr(), conf.CheckHost, err) p.SetEnable(false) + logf("proxy-check %s -> %s, set to DISABLED. error: %s", p.Addr(), target, err) continue } - c.Close() - p.SetEnable(true) - // TODO: choose the fastest proxy. - dialTime := time.Since(startTime) - logf("proxy-check: %s -> %s, connect time: %s", p.Addr(), conf.CheckHost, dialTime.String()) + c.Write([]byte("GET / HTTP/1.0")) + c.Write([]byte("\r\n\r\n")) + + _, err = c.Read(buf) + if err != nil && err != io.EOF { + p.SetEnable(false) + logf("proxy-check %s -> %s, set to DISABLED. error: %s", p.Addr(), target, err) + } else { + p.SetEnable(true) + dialTime := time.Since(startTime) + logf("proxy-check: %s -> %s, connect time: %s", p.Addr(), target, dialTime.String()) + } + + c.Close() } } diff --git a/socks5.go b/socks5.go index 6043b43..aca2365 100644 --- a/socks5.go +++ b/socks5.go @@ -56,7 +56,7 @@ var socks5Errors = []string{ } type socks5 struct { - Proxy + *proxy network, addr string user, password string } @@ -65,7 +65,7 @@ type socks5 struct { // with an optional username and password. See RFC 1928. func SOCKS5Proxy(network, addr, user, pass string, upProxy Proxy) (Proxy, error) { s := &socks5{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), addr: addr, user: user, password: pass, diff --git a/ss.go b/ss.go index ba1c92a..e3a2ed6 100644 --- a/ss.go +++ b/ss.go @@ -11,19 +11,19 @@ import ( // ss type ss struct { - Proxy + *proxy core.StreamConnCipher } // SSProxy returns a shadowsocks proxy. -func SSProxy(method, pass string, upProxy Proxy) (Proxy, error) { +func SSProxy(addr, method, pass string, upProxy Proxy) (Proxy, error) { ciph, err := core.PickCipher(method, nil, pass) if err != nil { log.Fatal(err) } s := &ss{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), StreamConnCipher: ciph, } @@ -86,6 +86,7 @@ func (s *ss) Serve(c net.Conn) { // Dial connects to the address addr on the network net via the proxy. func (s *ss) Dial(network, addr string) (net.Conn, error) { + target := ParseAddr(addr) if target == nil { return nil, errors.New("Unable to parse address: " + addr) diff --git a/strategy.go b/strategy.go index 08c2f9b..4d61580 100644 --- a/strategy.go +++ b/strategy.go @@ -5,32 +5,53 @@ import ( "time" ) -// strategyProxy -type strategyProxy struct { - addr string +// newStrategyForwarder . +func newStrategyForwarder(strategy string, forwarders []Proxy) Proxy { + var proxy Proxy + if len(forwarders) == 0 { + proxy = Direct + } else if len(forwarders) == 1 { + proxy = forwarders[0] + } else if len(forwarders) > 1 { + switch strategy { + case "rr": + proxy = newRRProxy("", forwarders) + logf("forward to remote servers in round robin mode.") + case "ha": + proxy = newHAProxy("", forwarders) + logf("forward to remote servers in high availability mode.") + default: + logf("not supported forward mode '%s', just use the first forward server.", conf.Strategy) + proxy = forwarders[0] + } + } + + return proxy +} + +// rrProxy +type rrProxy struct { forwarders []Proxy idx int } -// newStrategyProxy . -func newStrategyProxy(addr string, forwarders []Proxy) Proxy { +// newRRProxy . +func newRRProxy(addr string, forwarders []Proxy) Proxy { if len(forwarders) == 0 { return Direct } else if len(forwarders) == 1 { return newProxy(addr, forwarders[0]) } - - - return &strategyProxy{addr: addr, forwarders: forwarders} + return &rrProxy{forwarders: forwarders} } -func (p *strategyProxy) ListenAndServe() {} -func (p *strategyProxy) Serve(c net.Conn) {} -func (p *strategyProxy) CurrentProxy() Proxy { return p.forwarders[p.idx] } -func (p *strategyProxy) GetProxy() Proxy { return p.NextProxy() } +func (p *rrProxy) ListenAndServe() {} +func (p *rrProxy) Serve(c net.Conn) {} +func (p *rrProxy) CurrentProxy() Proxy { return p.forwarders[p.idx] } +func (p *rrProxy) GetProxy() Proxy { return p.NextProxy() } -func (p *strategyProxy) NextProxy() Proxy { +func (p *rrProxy) NextProxy() Proxy { n := len(p.forwarders) if n == 1 { return p.forwarders[0] @@ -52,38 +73,25 @@ func (p *strategyProxy) NextProxy() Proxy { return p.forwarders[p.idx] } -func (p *strategyProxy) Enabled() bool { return true } -func (p *strategyProxy) SetEnable(enable bool) {} - -func (p *strategyProxy) Check(proxy Proxy, target string, duration time.Duration) {} - -func (p *strategyProxy) Addr() string { return p.addr } - -func (p *strategyProxy) Dial(network, addr string) (net.Conn, error) { +func (p *rrProxy) Enabled() bool { return true } +func (p *rrProxy) SetEnable(enable bool) {} +func (p *rrProxy) Check(proxy Proxy, target string, duration time.Duration) {} +func (p *rrProxy) Addr() string { return "" } +func (p *rrProxy) Dial(network, addr string) (net.Conn, error) { return p.NextProxy().Dial(network, addr) } -// round robin proxy -type rrproxy struct { - Proxy -} - -// newRRProxy . -func newRRProxy(addr string, forwarders []Proxy) Proxy { - return newStrategyProxy(addr, forwarders) -} - // high availability proxy -type haproxy struct { +type haProxy struct { Proxy } // newHAProxy . func newHAProxy(addr string, forwarders []Proxy) Proxy { - return &haproxy{Proxy: newStrategyProxy(addr, forwarders)} + return &haProxy{Proxy: newRRProxy(addr, forwarders)} } -func (p *haproxy) GetProxy() Proxy { +func (p *haProxy) GetProxy() Proxy { proxy := p.CurrentProxy() if proxy.Enabled() == false { return p.NextProxy() diff --git a/tcptun.go b/tcptun.go index 7b6abd4..f933aaa 100644 --- a/tcptun.go +++ b/tcptun.go @@ -3,7 +3,7 @@ package main import "net" type tcptun struct { - Proxy + *proxy addr string raddr string } @@ -11,7 +11,7 @@ type tcptun struct { // TCPTunProxy returns a redirect proxy. func TCPTunProxy(addr, raddr string, upProxy Proxy) (Proxy, error) { s := &tcptun{ - Proxy: upProxy, + proxy: newProxy(addr, upProxy), addr: addr, raddr: raddr, }