diff --git a/README.md b/README.md index bf46682..223959b 100644 --- a/README.md +++ b/README.md @@ -290,7 +290,7 @@ Examples: -listen on :1080 as a socks5 proxy server, in verbose mode. glider -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose - -listen on :443 as a https proxy server. + -listen on :443 as a https(http over tls) proxy server. glider -listen http://:8080 -forward socks5://127.0.0.1:1080 -listen on :8080 as a http proxy server, forward all requests via socks5 server. @@ -338,6 +338,40 @@ Examples: - [transparent proxy with dnsmasq](config/examples/8.transparent_proxy_with_dnsmasq) - [transparent proxy without dnsmasq](config/examples/9.transparent_proxy_without_dnsmasq) +### Forwarder Chain +In glider, you can easily chain several proxy servers or protocols together, e.g: + +- Chain proxy servers: + +```bash +forward=http://1.1.1.1:80,socks5://2.2.2.2:1080,ss://method:pass@3.3.3.3:8443@ +``` + +- Chain protocols: https proxy (http over tls) + +```bash +forward=tls://1.1.1.1:443,http:// +``` + +- Chain protocols: vmess over ws over tls + +```bash +forward=tls://1.1.1.1:443,ws://,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 +``` + +- Chain protocols and servers: + +``` bash +forward=socks5://1.1.1.1:1080,tls://2.2.2.2:443,ws://,vmess://5a146038-0b56-4e95-b1dc-5c6f5a32cd98@?alterID=2 +``` + +- Chain protocols in listener: https proxy server + +``` bash +listen=tls://:443?cert=crtFilePath&key=keyFilePath,http:// +``` + + ## Service - systemd: [https://github.com/nadoo/glider/blob/master/systemd/](https://github.com/nadoo/glider/blob/master/systemd/) diff --git a/common/conn/conn.go b/common/conn/conn.go index 3c10721..4e952d0 100644 --- a/common/conn/conn.go +++ b/common/conn/conn.go @@ -17,25 +17,30 @@ type Conn struct { } // NewConn . -func NewConn(c net.Conn) Conn { - return Conn{bufio.NewReader(c), c} +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} +func NewConnSize(c net.Conn, n int) *Conn { + return &Conn{bufio.NewReaderSize(c, n), c} } // Peek . -func (c Conn) Peek(n int) ([]byte, error) { +func (c *Conn) Peek(n int) ([]byte, error) { return c.r.Peek(n) } // Read . -func (c Conn) Read(p []byte) (int, error) { +func (c *Conn) Read(p []byte) (int, error) { return c.r.Read(p) } +// Reader returns the internal bufio.Reader +func (c *Conn) Reader() *bufio.Reader { + return c.r +} + // Relay . func Relay(left, right net.Conn) (int64, int64, error) { type res struct { diff --git a/conf.go b/conf.go index d78da2b..df1ebc1 100644 --- a/conf.go +++ b/conf.go @@ -266,7 +266,7 @@ func usage() { fmt.Fprintf(os.Stderr, " -listen on :1080 as a socks5 proxy server, in verbose mode.\n") fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, " "+app+" -listen tls://:443?cert=crtFilePath&key=keyFilePath,http:// -verbose\n") - fmt.Fprintf(os.Stderr, " -listen on :443 as a https proxy server.\n") + fmt.Fprintf(os.Stderr, " -listen on :443 as a https(http over tls) proxy server.\n") fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, " "+app+" -listen http://:8080 -forward socks5://127.0.0.1:1080\n") fmt.Fprintf(os.Stderr, " -listen on :8080 as a http proxy server, forward all requests via socks5 server.\n") diff --git a/proxy/http/http.go b/proxy/http/http.go index 21582d1..af4e919 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -249,19 +249,22 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) { buf.Write([]byte("Proxy-Authorization: Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) + "\r\n")) } - //header ended + // header ended buf.Write([]byte("\r\n")) - rc.Write(buf.Bytes()) + _, err = rc.Write(buf.Bytes()) + if err != nil { + return nil, err + } - respR := bufio.NewReader(rc) - respTP := textproto.NewReader(respR) - - _, code, _, ok := parseFirstLine(respTP) + c := conn.NewConn(rc) + tpr := textproto.NewReader(c.Reader()) + _, code, _, ok := parseFirstLine(tpr) if ok && code == "200" { - // TODO: check here - respTP.ReadMIMEHeader() - return rc, err - } else if code == "407" { + tpr.ReadMIMEHeader() + return c, err + } + + if code == "407" { log.F("[http] authencation needed by proxy %s", s.addr) } else if code == "405" { log.F("[http] 'CONNECT' method not allowed by proxy %s", s.addr) @@ -280,7 +283,7 @@ 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) + // log.F("[http] read first line error:%s", err) return } diff --git a/proxy/kcp/kcp.go b/proxy/kcp/kcp.go index e404cde..1123f74 100644 --- a/proxy/kcp/kcp.go +++ b/proxy/kcp/kcp.go @@ -168,6 +168,7 @@ func (s *KCP) ListenAndServe() { continue } + // TODO: change them to customizable later? c.SetStreamMode(true) c.SetWriteDelay(false) c.SetNoDelay(0, 30, 2, 1) @@ -204,6 +205,7 @@ func (s *KCP) Dial(network, addr string) (net.Conn, error) { return nil, err } + // TODO: change them to customizable later? c.SetStreamMode(true) c.SetWriteDelay(false) c.SetNoDelay(0, 30, 2, 1)