forward http request directly when end of chain is http proxy

This commit is contained in:
rui.zheng 2016-09-21 17:36:02 +08:00
parent f7c8c40081
commit daf7c32cb8
3 changed files with 72 additions and 15 deletions

20
conn.go
View File

@ -77,10 +77,7 @@ func listenAndServe(arg Args) error {
continue continue
} }
if tc, ok := conn.(*net.TCPConn); ok { setKeepAlive(conn, keepAliveTime)
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(time.Second * 180)
}
go handleConn(conn, arg) go handleConn(conn, arg)
} }
@ -104,6 +101,8 @@ func listenAndServeTcpForward(arg Args) error {
glog.V(LWARNING).Infoln(err) glog.V(LWARNING).Infoln(err)
continue continue
} }
setKeepAlive(conn, keepAliveTime)
go handleTcpForward(conn, raddr) go handleTcpForward(conn, raddr)
} }
} }
@ -361,15 +360,19 @@ func (r *reqReader) Read(p []byte) (n int, err error) {
} }
func Connect(addr string) (conn net.Conn, err error) { func Connect(addr string) (conn net.Conn, err error) {
return connectWithChain(addr, forwardArgs...)
}
func connectWithChain(addr string, chain ...Args) (conn net.Conn, err error) {
if !strings.Contains(addr, ":") { if !strings.Contains(addr, ":") {
addr += ":80" addr += ":80"
} }
if len(forwardArgs) == 0 { if len(chain) == 0 {
return net.DialTimeout("tcp", addr, time.Second*90) return net.DialTimeout("tcp", addr, time.Second*90)
} }
var end Args var end Args
conn, end, err = forwardChain(forwardArgs...) conn, end, err = forwardChain(chain...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -394,9 +397,7 @@ func forwardChain(chain ...Args) (conn net.Conn, end Args, err error) {
return return
} }
tc := conn.(*net.TCPConn) setKeepAlive(conn, keepAliveTime)
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(time.Second * 180) // 3min
c, err := forward(conn, end) c, err := forward(conn, end)
if err != nil { if err != nil {
@ -453,6 +454,7 @@ func forward(conn net.Conn, arg Args) (net.Conn, error) {
case "tls": // tls connection case "tls": // tls connection
tlsUsed = true tlsUsed = true
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true}) conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
// conn = tls.Client(conn, &tls.Config{ServerName: "ice139.com"})
case "tcp": case "tcp":
fallthrough fallthrough
default: default:

41
http.go
View File

@ -42,7 +42,40 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) {
return return
} }
c, err := Connect(req.Host) var c net.Conn
var err error
if len(forwardArgs) > 0 {
last := forwardArgs[len(forwardArgs)-1]
if last.Protocol == "http" || last.Protocol == "" {
c, _, err = forwardChain(forwardArgs...)
if err != nil {
glog.V(LWARNING).Infof("[http] %s -> %s : %s", conn.RemoteAddr(), last.Addr, err)
b := []byte("HTTP/1.1 503 Service unavailable\r\n" +
"Proxy-Agent: gost/" + Version + "\r\n\r\n")
glog.V(LDEBUG).Infof("[http] %s <- %s\n%s", conn.RemoteAddr(), last.Addr, string(b))
conn.Write(b)
return
}
defer c.Close()
if last.User != nil {
req.Header.Set("Proxy-Authorization",
"Basic "+base64.StdEncoding.EncodeToString([]byte(last.User.String())))
}
if err = req.Write(c); err != nil {
glog.V(LWARNING).Infof("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err)
return
}
glog.V(LINFO).Infof("[http] %s <-> %s", conn.RemoteAddr(), req.Host)
Transport(conn, c)
glog.V(LINFO).Infof("[http] %s >-< %s", conn.RemoteAddr(), req.Host)
return
}
}
c, err = Connect(req.Host)
if err != nil { if err != nil {
glog.V(LWARNING).Infof("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err) glog.V(LWARNING).Infof("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err)
@ -58,11 +91,7 @@ func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) {
b := []byte("HTTP/1.1 200 Connection established\r\n" + b := []byte("HTTP/1.1 200 Connection established\r\n" +
"Proxy-Agent: gost/" + Version + "\r\n\r\n") "Proxy-Agent: gost/" + Version + "\r\n\r\n")
glog.V(LDEBUG).Infof("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(b)) glog.V(LDEBUG).Infof("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(b))
conn.Write(b)
if _, err := conn.Write(b); err != nil {
glog.V(LWARNING).Infof("[http] %s <- %s : %s", conn.RemoteAddr(), req.Host, err)
return
}
} else { } else {
req.Header.Del("Proxy-Connection") req.Header.Del("Proxy-Connection")
req.Header.Set("Connection", "Keep-Alive") req.Header.Set("Connection", "Keep-Alive")

26
util.go
View File

@ -2,12 +2,18 @@ package main
import ( import (
"crypto/tls" "crypto/tls"
"errors"
"fmt" "fmt"
"github.com/golang/glog" "github.com/golang/glog"
"io" "io"
"net" "net"
"net/url" "net/url"
"strings" "strings"
"time"
)
const (
keepAliveTime = 180 * time.Second
) )
type strSlice []string type strSlice []string
@ -69,12 +75,18 @@ func parseArgs(ss []string) (args []Args) {
switch arg.Protocol { switch arg.Protocol {
case "http", "socks", "socks5", "ss": case "http", "socks", "socks5", "ss":
case "https":
arg.Protocol = "http"
arg.Transport = "tls"
default: default:
arg.Protocol = "" arg.Protocol = ""
} }
switch arg.Transport { switch arg.Transport {
case "ws", "wss", "tls": case "ws", "wss", "tls":
case "https":
arg.Protocol = "http"
arg.Transport = "tls"
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
arg.Remote = strings.Trim(u.EscapedPath(), "/") arg.Remote = strings.Trim(u.EscapedPath(), "/")
case "rtcp", "rudp": // started from v2.1, rtcp and rudp are for remote port forwarding case "rtcp", "rudp": // started from v2.1, rtcp and rudp are for remote port forwarding
@ -147,3 +159,17 @@ func Transport(conn, conn2 net.Conn) (err error) {
return return
} }
func setKeepAlive(conn net.Conn, d time.Duration) error {
c, ok := conn.(*net.TCPConn)
if !ok {
return errors.New("Not a TCP connection")
}
if err := c.SetKeepAlive(true); err != nil {
return err
}
if err := c.SetKeepAlivePeriod(d); err != nil {
return err
}
return nil
}