From 063dc1bc012533f4c5ef115fb5440167e58e376a Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Wed, 18 Sep 2019 12:53:04 +0800 Subject: [PATCH] proxy: added the ability to log forwarder --- .github/workflows/release.yml | 5 -- README.md | 4 +- dns/client.go | 2 +- proxy/dialer.go | 2 +- proxy/direct.go | 4 +- proxy/http/http.go | 24 ++++----- proxy/kcp/kcp.go | 6 +-- proxy/obfs/obfs.go | 9 ++-- proxy/redir/redir_linux.go | 6 +-- proxy/reject/reject.go | 4 +- proxy/socks5/socks5.go | 20 ++++---- proxy/ss/ss.go | 18 +++---- proxy/ssr/ssr.go | 20 ++++---- proxy/tcptun/tcptun.go | 6 +-- proxy/tls/tls.go | 8 +-- proxy/unix/unix.go | 6 +-- proxy/uottun/uottun.go | 4 +- proxy/vmess/vmess.go | 9 ++-- proxy/ws/ws.go | 9 ++-- rule/rule.go | 24 +++------ proxy/forwarder.go => strategy/forward.go | 28 +++++++---- strategy/strategy.go | 61 +++++++++++------------ 22 files changed, 138 insertions(+), 141 deletions(-) rename proxy/forwarder.go => strategy/forward.go (86%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cde770..93904e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,11 +12,6 @@ jobs: - name: Check out code uses: actions/checkout@v1 - - name: Validates GO releaser config - uses: docker://goreleaser/goreleaser:latest - with: - args: check - - name: Create release on GitHub uses: docker://goreleaser/goreleaser:latest env: diff --git a/README.md b/README.md index 4205188..b8201a4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ # [glider](https://github.com/nadoo/glider) -[![Build Status](https://img.shields.io/travis/nadoo/glider.svg?style=flat-square)](https://travis-ci.org/nadoo/glider) [![Go Report Card](https://goreportcard.com/badge/github.com/nadoo/glider?style=flat-square)](https://goreportcard.com/report/github.com/nadoo/glider) -[![GitHub tag](https://img.shields.io/github/tag/nadoo/glider.svg?style=flat-square)](https://github.com/nadoo/glider/releases) -[![GitHub release](https://img.shields.io/github/release/nadoo/glider.svg?style=flat-square)](https://github.com/nadoo/glider/releases) +[![GitHub release](https://img.shields.io/github/v/release/nadoo/glider.svg?include_prereleases&style=flat-square)](https://github.com/nadoo/glider/releases) glider is a forward proxy with multiple protocols support, and also a dns forwarding server with ipset management features(like dnsmasq). diff --git a/dns/client.go b/dns/client.go index b7c1b4e..f12351c 100644 --- a/dns/client.go +++ b/dns/client.go @@ -143,7 +143,7 @@ func (c *Client) exchange(qname string, reqBytes []byte, preferTCP bool) (server servers := c.GetServers(qname) for _, server = range servers { var rc net.Conn - rc, err = dialer.Dial(network, server) + rc, _, err = dialer.Dial(network, server) if err != nil { log.F("[dns] failed to connect to server %v: %v", server, err) continue diff --git a/proxy/dialer.go b/proxy/dialer.go index 9c10c9e..08d4171 100644 --- a/proxy/dialer.go +++ b/proxy/dialer.go @@ -15,7 +15,7 @@ type Dialer interface { Addr() string // Dial connects to the given address via the proxy. - Dial(network, addr string) (c net.Conn, err error) + Dial(network, addr string) (c net.Conn, proxy string, err error) // DialUDP connects to the given address via the proxy. DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) diff --git a/proxy/direct.go b/proxy/direct.go index 38e11e4..e553ccf 100644 --- a/proxy/direct.go +++ b/proxy/direct.go @@ -39,7 +39,7 @@ func NewDirect(intface string) (*Direct, error) { func (d *Direct) Addr() string { return "DIRECT" } // Dial connects to the address addr on the network net -func (d *Direct) Dial(network, addr string) (c net.Conn, err error) { +func (d *Direct) Dial(network, addr string) (c net.Conn, p string, err error) { if d.iface == nil || d.ip != nil { c, err = dial(network, addr, d.ip) if err == nil { @@ -60,7 +60,7 @@ func (d *Direct) Dial(network, addr string) (c net.Conn, err error) { err = errors.New("dial failed, maybe the interface link is down, please check it") } - return + return c, "DIRECT", err } func dial(network, addr string, localIP net.IP) (net.Conn, error) { diff --git a/proxy/http/http.go b/proxy/http/http.go index 5f6f26a..ab29634 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -142,10 +142,10 @@ func (s *HTTP) Serve(c net.Conn) { tgt += ":80" } - rc, err := s.dialer.Dial("tcp", tgt) + rc, p, err := s.dialer.Dial("tcp", tgt) if err != nil { fmt.Fprintf(c, "%s 502 ERROR\r\n\r\n", proto) - log.F("[http] %s <-> %s, error in dial: %v", c.RemoteAddr(), tgt, err) + log.F("[http] %s <-> %s, %s, error in dial: %v", c.RemoteAddr(), tgt, err, p) return } defer rc.Close() @@ -192,7 +192,7 @@ func (s *HTTP) Serve(c net.Conn) { writeFirstLine(&respBuf, proto, code, status) writeHeaders(&respBuf, respHeader) - log.F("[http] %s <-> %s", c.RemoteAddr(), tgt) + log.F("[http] %s <-> %s, %s", c.RemoteAddr(), tgt, p) c.Write(respBuf.Bytes()) io.Copy(c, respR) @@ -200,7 +200,7 @@ func (s *HTTP) Serve(c net.Conn) { } func (s *HTTP) servHTTPS(method, requestURI, proto string, c net.Conn) { - rc, err := s.dialer.Dial("tcp", requestURI) + rc, p, err := s.dialer.Dial("tcp", requestURI) if err != nil { c.Write([]byte(proto)) c.Write([]byte(" 502 ERROR\r\n\r\n")) @@ -210,7 +210,7 @@ func (s *HTTP) servHTTPS(method, requestURI, proto string, c net.Conn) { c.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")) - log.F("[http] %s <-> %s [c]", c.RemoteAddr(), requestURI) + log.F("[http] %s <-> %s [c], %s", c.RemoteAddr(), requestURI, p) _, _, err = conn.Relay(c, rc) if err != nil { @@ -233,11 +233,11 @@ func (s *HTTP) Addr() string { func (s *HTTP) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy -func (s *HTTP) Dial(network, addr string) (net.Conn, error) { - rc, err := s.dialer.Dial(network, s.addr) +func (s *HTTP) Dial(network, addr string) (net.Conn, string, error) { + rc, p, err := s.dialer.Dial(network, s.addr) if err != nil { log.F("[http] dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } var buf bytes.Buffer @@ -254,7 +254,7 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) { buf.Write([]byte("\r\n")) _, err = rc.Write(buf.Bytes()) if err != nil { - return nil, err + return nil, p, err } c := conn.NewConn(rc) @@ -262,7 +262,7 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) { _, code, _, ok := parseFirstLine(tpr) if ok && code == "200" { tpr.ReadMIMEHeader() - return c, err + return c, p, err } if code == "407" { @@ -271,7 +271,7 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) { log.F("[http] 'CONNECT' method not allowed by proxy %s", s.addr) } - return nil, errors.New("[http] can not connect remote address: " + addr + ". error code: " + code) + return nil, p, errors.New("[http] can not connect remote address: " + addr + ". error code: " + code) } // DialUDP connects to the given address via the proxy @@ -282,9 +282,7 @@ func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Add // parseFirstLine parses "GET /foo HTTP/1.1" OR "HTTP/1.1 200 OK" into its three parts func parseFirstLine(tp *textproto.Reader) (r1, r2, r3 string, ok bool) { line, err := tp.ReadLine() - // log.F("first line: %s", line) if err != nil { - // log.F("[http] read first line error:%s", err) return } diff --git a/proxy/kcp/kcp.go b/proxy/kcp/kcp.go index 1123f74..48a4342 100644 --- a/proxy/kcp/kcp.go +++ b/proxy/kcp/kcp.go @@ -197,12 +197,12 @@ func (s *KCP) Addr() string { return s.addr } func (s *KCP) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy -func (s *KCP) Dial(network, addr string) (net.Conn, error) { +func (s *KCP) Dial(network, addr string) (net.Conn, string, error) { // NOTE: kcp uses udp, we should dial remote server directly here c, err := kcp.DialWithOptions(s.addr, s.block, s.dataShards, s.parityShards) if err != nil { log.F("[tls] dial to %s error: %s", s.addr, err) - return nil, err + return nil, "", err } // TODO: change them to customizable later? @@ -217,7 +217,7 @@ func (s *KCP) Dial(network, addr string) (net.Conn, error) { c.SetReadBuffer(4194304) c.SetWriteBuffer(4194304) - return c, err + return c, "", err } // DialUDP connects to the given address via the proxy diff --git a/proxy/obfs/obfs.go b/proxy/obfs/obfs.go index 73a9cfa..cd4d7b0 100644 --- a/proxy/obfs/obfs.go +++ b/proxy/obfs/obfs.go @@ -93,14 +93,15 @@ func (s *Obfs) Addr() string { return s.addr } func (s *Obfs) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy -func (s *Obfs) Dial(network, addr string) (net.Conn, error) { - c, err := s.dialer.Dial("tcp", s.addr) +func (s *Obfs) Dial(network, addr string) (net.Conn, string, error) { + c, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[obfs] dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } - return s.obfsConn(c) + cc, e := s.obfsConn(c) + return cc, p, e } // DialUDP connects to the given address via the proxy diff --git a/proxy/redir/redir_linux.go b/proxy/redir/redir_linux.go index 0ad21ae..ea7706e 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, err := s.dialer.Dial("tcp", tgt.String()) + rc, p, err := s.dialer.Dial("tcp", tgt.String()) if err != nil { - log.F("[redir] %s <-> %s, error in dial: %v", c.RemoteAddr(), tgt, err) + log.F("[redir] %s <-> %s, %s, error in dial: %v", c.RemoteAddr(), tgt, err, p) return } defer rc.Close() - log.F("[redir] %s <-> %s", c.RemoteAddr(), tgt) + log.F("[redir] %s <-> %s, %s", c.RemoteAddr(), tgt, p) _, _, err = conn.Relay(c, rc) if err != nil { diff --git a/proxy/reject/reject.go b/proxy/reject/reject.go index c511138..9dc704e 100644 --- a/proxy/reject/reject.go +++ b/proxy/reject/reject.go @@ -32,7 +32,9 @@ func (s *Reject) Addr() string { return "REJECT" } func (s *Reject) NextDialer(dstAddr string) proxy.Dialer { return s } // Dial connects to the address addr on the network net via the proxy. -func (s *Reject) Dial(network, addr string) (net.Conn, error) { return nil, errors.New("REJECT") } +func (s *Reject) Dial(network, addr string) (net.Conn, string, error) { + return nil, "REJECT", errors.New("REJECT") +} // DialUDP connects to the given address via the proxy. func (s *Reject) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { diff --git a/proxy/socks5/socks5.go b/proxy/socks5/socks5.go index 2c3ef3d..ad845ed 100644 --- a/proxy/socks5/socks5.go +++ b/proxy/socks5/socks5.go @@ -131,14 +131,14 @@ func (s *SOCKS5) Serve(c net.Conn) { return } - rc, err := s.dialer.Dial("tcp", tgt.String()) + rc, p, err := s.dialer.Dial("tcp", tgt.String()) if err != nil { - log.F("[socks5] %s <-> %s, error in dial: %v", c.RemoteAddr(), tgt, err) + log.F("[socks5] %s <-> %s, %s, error in dial: %v", c.RemoteAddr(), tgt, err, p) return } defer rc.Close() - log.F("[socks5] %s <-> %s", c.RemoteAddr(), tgt) + log.F("[socks5] %s <-> %s, %s", c.RemoteAddr(), tgt, p) _, _, err = conn.Relay(c, rc) if err != nil { @@ -224,30 +224,30 @@ func (s *SOCKS5) Addr() string { 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. -func (s *SOCKS5) Dial(network, addr string) (net.Conn, error) { +func (s *SOCKS5) Dial(network, addr string) (net.Conn, string, error) { switch network { case "tcp", "tcp6", "tcp4": default: - return nil, errors.New("[socks5]: no support for connection type " + network) + return nil, "", errors.New("[socks5]: no support for connection type " + network) } - c, err := s.dialer.Dial(network, s.addr) + c, p, err := s.dialer.Dial(network, s.addr) if err != nil { log.F("[socks5]: dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } if err := s.connect(c, addr); err != nil { c.Close() - return nil, err + return nil, p, err } - return c, nil + return c, p, nil } // 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) + c, _, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[socks5] dialudp dial tcp to %s error: %s", s.addr, err) return nil, nil, err diff --git a/proxy/ss/ss.go b/proxy/ss/ss.go index e5222b9..3e9505b 100644 --- a/proxy/ss/ss.go +++ b/proxy/ss/ss.go @@ -147,14 +147,14 @@ func (s *SS) Serve(c net.Conn) { network = "udp" } - rc, err := dialer.Dial(network, tgt.String()) + rc, p, err := dialer.Dial(network, tgt.String()) if err != nil { - log.F("[ss] %s <-> %s, error in dial: %v", c.RemoteAddr(), tgt, err) + log.F("[ss] %s <-> %s, %s, error in dial: %v", c.RemoteAddr(), tgt, err, p) return } defer rc.Close() - log.F("[ss] %s <-> %s", c.RemoteAddr(), tgt) + log.F("[ss] %s <-> %s, %s", c.RemoteAddr(), tgt, p) _, _, err = conn.Relay(c, rc) if err != nil { @@ -242,29 +242,29 @@ func (s *SS) Addr() string { 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. -func (s *SS) Dial(network, addr string) (net.Conn, error) { +func (s *SS) Dial(network, addr string) (net.Conn, string, error) { target := socks.ParseAddr(addr) if target == nil { - return nil, errors.New("[ss] unable to parse address: " + addr) + return nil, "", errors.New("[ss] unable to parse address: " + addr) } if network == "uot" { target[0] = target[0] | 0x8 } - c, err := s.dialer.Dial("tcp", s.addr) + c, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[ss] dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } c = s.StreamConn(c) if _, err = c.Write(target); err != nil { c.Close() - return nil, err + return nil, p, err } - return c, err + return c, p, err } diff --git a/proxy/ssr/ssr.go b/proxy/ssr/ssr.go index 216cae0..32bb5a9 100644 --- a/proxy/ssr/ssr.go +++ b/proxy/ssr/ssr.go @@ -81,26 +81,26 @@ func (s *SSR) Addr() string { func (s *SSR) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy. -func (s *SSR) Dial(network, addr string) (net.Conn, error) { +func (s *SSR) Dial(network, addr string) (net.Conn, string, error) { target := socks.ParseAddr(addr) if target == nil { - return nil, errors.New("[ssr] unable to parse address: " + addr) + return nil, "", errors.New("[ssr] unable to parse address: " + addr) } cipher, err := shadowsocksr.NewStreamCipher(s.EncryptMethod, s.EncryptPassword) if err != nil { - return nil, err + return nil, "", err } - c, err := s.dialer.Dial("tcp", s.addr) + c, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[ssr] dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } ssrconn := shadowsocksr.NewSSTCPConn(c, cipher) if ssrconn.Conn == nil || ssrconn.RemoteAddr() == nil { - return nil, errors.New("[ssr] nil connection") + return nil, p, errors.New("[ssr] nil connection") } // should initialize obfs/protocol now @@ -109,7 +109,7 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) { ssrconn.IObfs = obfs.NewObfs(s.Obfs) if ssrconn.IObfs == nil { - return nil, errors.New("[ssr] unsupported obfs type: " + s.Obfs) + return nil, p, errors.New("[ssr] unsupported obfs type: " + s.Obfs) } obfsServerInfo := &ssr.ServerInfoForObfs{ @@ -122,7 +122,7 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) { ssrconn.IProtocol = protocol.NewProtocol(s.Protocol) if ssrconn.IProtocol == nil { - return nil, errors.New("[ssr] unsupported protocol type: " + s.Protocol) + return nil, p, errors.New("[ssr] unsupported protocol type: " + s.Protocol) } protocolServerInfo := &ssr.ServerInfoForObfs{ @@ -145,10 +145,10 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) { if _, err := ssrconn.Write(target); err != nil { ssrconn.Close() - return nil, err + return nil, p, err } - return ssrconn, err + return ssrconn, p, err } // DialUDP connects to the given address via the proxy. diff --git a/proxy/tcptun/tcptun.go b/proxy/tcptun/tcptun.go index b57aa3f..f6f1807 100644 --- a/proxy/tcptun/tcptun.go +++ b/proxy/tcptun/tcptun.go @@ -76,14 +76,14 @@ func (s *TCPTun) Serve(c net.Conn) { c.SetKeepAlive(true) } - rc, err := s.dialer.Dial("tcp", s.raddr) + rc, p, err := s.dialer.Dial("tcp", s.raddr) if err != nil { - log.F("[tcptun] %s <-> %s, error in dial: %v", c.RemoteAddr(), s.addr, err) + log.F("[tcptun] %s <-> %s, %s, error in dial: %v", c.RemoteAddr(), s.addr, err, p) return } defer rc.Close() - log.F("[tcptun] %s <-> %s", c.RemoteAddr(), s.raddr) + log.F("[tcptun] %s <-> %s, %s", c.RemoteAddr(), s.raddr, p) _, _, err = conn.Relay(c, rc) if err != nil { diff --git a/proxy/tls/tls.go b/proxy/tls/tls.go index e795e27..0e2c471 100644 --- a/proxy/tls/tls.go +++ b/proxy/tls/tls.go @@ -160,16 +160,16 @@ func (s *TLS) Addr() string { return s.addr } func (s *TLS) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy -func (s *TLS) Dial(network, addr string) (net.Conn, error) { - cc, err := s.dialer.Dial("tcp", s.addr) +func (s *TLS) Dial(network, addr string) (net.Conn, string, error) { + cc, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { log.F("[tls] dial to %s error: %s", s.addr, err) - return nil, err + return nil, p, err } c := stdtls.Client(cc, s.tlsConfig) err = c.Handshake() - return c, err + return c, p, err } // DialUDP connects to the given address via the proxy diff --git a/proxy/unix/unix.go b/proxy/unix/unix.go index 0a43e62..308220b 100644 --- a/proxy/unix/unix.go +++ b/proxy/unix/unix.go @@ -113,14 +113,14 @@ func (s *Unix) Addr() string { func (s *Unix) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy. -func (s *Unix) Dial(network, addr string) (net.Conn, error) { +func (s *Unix) Dial(network, addr string) (net.Conn, string, error) { // NOTE: must be the first dialer in a chain rc, err := net.Dial("unix", s.addr) if err != nil { - return nil, err + return nil, "", err } - return rc, err + return rc, "", err } // DialUDP connects to the given address via the proxy diff --git a/proxy/uottun/uottun.go b/proxy/uottun/uottun.go index 5cdbbfd..4499633 100644 --- a/proxy/uottun/uottun.go +++ b/proxy/uottun/uottun.go @@ -69,7 +69,7 @@ func (s *UoTTun) ListenAndServe() { continue } - rc, err := s.dialer.Dial("uot", s.raddr) + rc, p, err := s.dialer.Dial("uot", s.raddr) if err != nil { log.F("[uottun] failed to connect to server %v: %v", s.raddr, err) continue @@ -99,7 +99,7 @@ func (s *UoTTun) ListenAndServe() { continue } - log.F("[uottun] %s <-> %s", clientAddr, s.raddr) + log.F("[uottun] %s <-> %s, %s", clientAddr, s.raddr, p) } } diff --git a/proxy/vmess/vmess.go b/proxy/vmess/vmess.go index 6e46481..b9747a4 100644 --- a/proxy/vmess/vmess.go +++ b/proxy/vmess/vmess.go @@ -90,13 +90,14 @@ func (s *VMess) Addr() string { func (s *VMess) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy. -func (s *VMess) Dial(network, addr string) (net.Conn, error) { - rc, err := s.dialer.Dial("tcp", s.addr) +func (s *VMess) Dial(network, addr string) (net.Conn, string, error) { + rc, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { - return nil, err + return nil, p, err } - return s.client.NewConn(rc, addr) + cc, e := s.client.NewConn(rc, addr) + return cc, p, e } // DialUDP connects to the given address via the proxy. diff --git a/proxy/ws/ws.go b/proxy/ws/ws.go index aa380b2..7da2379 100644 --- a/proxy/ws/ws.go +++ b/proxy/ws/ws.go @@ -76,13 +76,14 @@ func (s *WS) Addr() string { func (s *WS) NextDialer(dstAddr string) proxy.Dialer { return s.dialer.NextDialer(dstAddr) } // Dial connects to the address addr on the network net via the proxy. -func (s *WS) Dial(network, addr string) (net.Conn, error) { - rc, err := s.dialer.Dial("tcp", s.addr) +func (s *WS) Dial(network, addr string) (net.Conn, string, error) { + rc, p, err := s.dialer.Dial("tcp", s.addr) if err != nil { - return nil, err + return nil, p, err } - return s.client.NewConn(rc, addr) + cc, e := s.client.NewConn(rc, addr) + return cc, p, e } // DialUDP connects to the given address via the proxy. diff --git a/rule/rule.go b/rule/rule.go index 582c0ca..edc171f 100644 --- a/rule/rule.go +++ b/rule/rule.go @@ -12,8 +12,8 @@ import ( // Dialer struct type Dialer struct { - gDialer proxy.Dialer - dialers []proxy.Dialer + gDialer *strategy.Dialer + dialers []*strategy.Dialer domainMap sync.Map ipMap sync.Map @@ -21,7 +21,7 @@ type Dialer struct { } // NewDialer returns a new rule dialer -func NewDialer(rules []*Config, gDialer proxy.Dialer) *Dialer { +func NewDialer(rules []*Config, gDialer *strategy.Dialer) *Dialer { rd := &Dialer{gDialer: gDialer} for _, r := range rules { @@ -98,17 +98,13 @@ func (rd *Dialer) NextDialer(dstAddr string) proxy.Dialer { } // Dial dials to targer addr and return a conn -func (rd *Dialer) Dial(network, addr string) (net.Conn, error) { - d := rd.NextDialer(addr) - log.F("[dial] %s => %s", addr, d.Addr()) - return d.Dial(network, addr) +func (rd *Dialer) Dial(network, addr string) (net.Conn, string, error) { + return rd.NextDialer(addr).Dial(network, addr) } // DialUDP connects to the given address via the proxy func (rd *Dialer) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { - d := rd.NextDialer(addr) - log.F("[dial-udp] %s => %s", addr, d.Addr()) - return d.DialUDP(network, addr) + return rd.NextDialer(addr).DialUDP(network, addr) } // AddDomainIP used to update ipMap rules according to domainMap rule @@ -131,13 +127,9 @@ func (rd *Dialer) AddDomainIP(domain, ip string) error { // Check . func (rd *Dialer) Check() { - if checker, ok := rd.gDialer.(strategy.Checker); ok { - checker.Check() - } + rd.gDialer.Check() for _, d := range rd.dialers { - if checker, ok := d.(strategy.Checker); ok { - checker.Check() - } + d.Check() } } diff --git a/proxy/forwarder.go b/strategy/forward.go similarity index 86% rename from proxy/forwarder.go rename to strategy/forward.go index 366b9ea..9a34475 100644 --- a/proxy/forwarder.go +++ b/strategy/forward.go @@ -1,4 +1,4 @@ -package proxy +package strategy import ( "net" @@ -8,6 +8,7 @@ import ( "sync/atomic" "github.com/nadoo/glider/common/log" + "github.com/nadoo/glider/proxy" ) // StatusHandler function will be called when the forwarder's status changed @@ -15,7 +16,7 @@ type StatusHandler func(*Forwarder) // Forwarder is a forwarder type Forwarder struct { - Dialer + proxy.Dialer addr string priority uint32 maxFailures uint32 // maxfailures to set to Disabled @@ -40,14 +41,14 @@ func ForwarderFromURL(s, intface string) (f *Forwarder, err error) { iface = f.intface } - var d Dialer - d, err = NewDirect(iface) + var d proxy.Dialer + d, err = proxy.NewDirect(iface) if err != nil { return nil, err } for _, url := range strings.Split(ss[0], ",") { - d, err = DialerFromURL(url, d) + d, err = proxy.DialerFromURL(url, d) if err != nil { return nil, err } @@ -57,12 +58,21 @@ func ForwarderFromURL(s, intface string) (f *Forwarder, err error) { f.addr = d.Addr() // set forwarder to disabled by default - // TODO: check here f.Disable() return f, err } +// DirectForwarder returns a direct forwarder +func DirectForwarder(intface string) *Forwarder { + d, err := proxy.NewDirect(intface) + if err != nil { + return nil + } + + return &Forwarder{Dialer: d, addr: d.Addr()} +} + func (f *Forwarder) parseOption(option string) error { query, err := url.ParseQuery(option) if err != nil { @@ -87,8 +97,8 @@ func (f *Forwarder) Addr() string { } // Dial . -func (f *Forwarder) Dial(network, addr string) (c net.Conn, err error) { - c, err = f.Dialer.Dial(network, addr) +func (f *Forwarder) Dial(network, addr string) (c net.Conn, p string, err error) { + c, p, err = f.Dialer.Dial(network, addr) if err != nil { f.IncFailures() if f.Failures() >= f.MaxFailures() && f.Enabled() { @@ -97,7 +107,7 @@ func (f *Forwarder) Dial(network, addr string) (c net.Conn, err error) { } } - return c, err + return c, p, err } // Failures returns the failuer count of forwarder diff --git a/strategy/strategy.go b/strategy/strategy.go index 87ebef8..f3384fe 100644 --- a/strategy/strategy.go +++ b/strategy/strategy.go @@ -31,7 +31,7 @@ type Config struct { } // forwarder slice orderd by priority -type priSlice []*proxy.Forwarder +type priSlice []*Forwarder func (p priSlice) Len() int { return len(p) } func (p priSlice) Less(i, j int) bool { return p[i].Priority() > p[j].Priority() } @@ -41,19 +41,19 @@ func (p priSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } type Dialer struct { config *Config fwdrs priSlice - available []*proxy.Forwarder + available []*Forwarder mu sync.RWMutex index uint32 priority uint32 - nextForwarder func(addr string) *proxy.Forwarder + nextForwarder func(addr string) *Forwarder } // NewDialer returns a new strategy dialer. -func NewDialer(s []string, c *Config) proxy.Dialer { - var fwdrs []*proxy.Forwarder +func NewDialer(s []string, c *Config) *Dialer { + var fwdrs []*Forwarder for _, chain := range s { - fwdr, err := proxy.ForwarderFromURL(chain, c.IntFace) + fwdr, err := ForwarderFromURL(chain, c.IntFace) if err != nil { log.Fatal(err) } @@ -62,22 +62,16 @@ func NewDialer(s []string, c *Config) proxy.Dialer { } if len(fwdrs) == 0 { - d, err := proxy.NewDirect(c.IntFace) - if err != nil { - log.Fatal(err) - } - return d - } - - if len(fwdrs) == 1 { - return fwdrs[0] + // direct forwarder + fwdrs = append(fwdrs, DirectForwarder(c.IntFace)) + c.Strategy = "rr" } return newDialer(fwdrs, c) } // newDialer returns a new rrDialer -func newDialer(fwdrs []*proxy.Forwarder, c *Config) *Dialer { +func newDialer(fwdrs []*Forwarder, c *Config) *Dialer { d := &Dialer{fwdrs: fwdrs, config: c} sort.Sort(d.fwdrs) @@ -90,19 +84,19 @@ func newDialer(fwdrs []*proxy.Forwarder, c *Config) *Dialer { switch c.Strategy { case "rr": d.nextForwarder = d.scheduleRR - log.F("forward to remote servers in round robin mode.") + log.F("[strategy] forward to remote servers in round robin mode.") case "ha": d.nextForwarder = d.scheduleHA - log.F("forward to remote servers in high availability mode.") + log.F("[strategy] forward to remote servers in high availability mode.") case "lha": d.nextForwarder = d.scheduleLHA - log.F("forward to remote servers in latency based high availability mode.") + log.F("[strategy] forward to remote servers in latency based high availability mode.") case "dh": d.nextForwarder = d.scheduleDH - log.F("forward to remote servers in destination hashing mode.") + log.F("[strategy] forward to remote servers in destination hashing mode.") default: d.nextForwarder = d.scheduleRR - log.F("not supported forward mode '%s', use round robin mode.", c.Strategy) + log.F("[strategy] not supported forward mode '%s', use round robin mode.", c.Strategy) } for _, f := range fwdrs { @@ -116,8 +110,10 @@ func newDialer(fwdrs []*proxy.Forwarder, c *Config) *Dialer { func (d *Dialer) Addr() string { return "STRATEGY" } // 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) +func (d *Dialer) Dial(network, addr string) (net.Conn, string, error) { + nd := d.NextDialer(addr) + c, _, err := nd.Dial(network, addr) + return c, nd.Addr(), err } // DialUDP connects to the given address. @@ -164,7 +160,7 @@ func (d *Dialer) initAvailable() { } // onStatusChanged will be called when fwdr's status changed. -func (d *Dialer) onStatusChanged(fwdr *proxy.Forwarder) { +func (d *Dialer) onStatusChanged(fwdr *Forwarder) { d.mu.Lock() defer d.mu.Unlock() @@ -192,8 +188,11 @@ func (d *Dialer) onStatusChanged(fwdr *proxy.Forwarder) { // Check implements the Checker interface. func (d *Dialer) Check() { - for i := 0; i < len(d.fwdrs); i++ { - go d.check(i) + // no need to check when there's only 1 forwarder + if len(d.fwdrs) > 1 { + for i := 0; i < len(d.fwdrs); i++ { + go d.check(i) + } } } @@ -216,7 +215,7 @@ func (d *Dialer) check(i int) { } startTime := time.Now() - rc, err := f.Dial("tcp", d.config.CheckWebSite) + rc, _, err := f.Dial("tcp", d.config.CheckWebSite) if err != nil { f.Disable() log.F("[check] %s(%d) -> %s, DISABLED. error in dial: %s", f.Addr(), f.Priority(), d.config.CheckWebSite, err) @@ -253,17 +252,17 @@ func (d *Dialer) check(i int) { } // Round Robin -func (d *Dialer) scheduleRR(dstAddr string) *proxy.Forwarder { +func (d *Dialer) scheduleRR(dstAddr string) *Forwarder { return d.available[atomic.AddUint32(&d.index, 1)%uint32(len(d.available))] } // High Availability -func (d *Dialer) scheduleHA(dstAddr string) *proxy.Forwarder { +func (d *Dialer) scheduleHA(dstAddr string) *Forwarder { return d.available[0] } // Latency based High Availability -func (d *Dialer) scheduleLHA(dstAddr string) *proxy.Forwarder { +func (d *Dialer) scheduleLHA(dstAddr string) *Forwarder { fwdr := d.available[0] lowest := fwdr.Latency() for _, f := range d.available { @@ -276,7 +275,7 @@ func (d *Dialer) scheduleLHA(dstAddr string) *proxy.Forwarder { } // Destination Hashing -func (d *Dialer) scheduleDH(dstAddr string) *proxy.Forwarder { +func (d *Dialer) scheduleDH(dstAddr string) *Forwarder { fnv1a := fnv.New32a() fnv1a.Write([]byte(dstAddr)) return d.available[fnv1a.Sum32()%uint32(len(d.available))]