From 93fa95f27a491cd2e836b2e75e25f30faa89ed36 Mon Sep 17 00:00:00 2001 From: "rui.zheng" Date: Mon, 14 Aug 2017 22:13:11 +0800 Subject: [PATCH] add data forward support for tunnels --- cmd/gost/main.go | 15 ++++++++++++--- forward.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ node.go | 5 ++--- sni.go | 2 +- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/cmd/gost/main.go b/cmd/gost/main.go index 1ee4221..1cba6e7 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -129,7 +129,7 @@ func initChain() (*gost.Chain, error) { } tr = gost.KCPTransporter(config) case "ssh": - if node.Protocol == "direct" || node.Protocol == "remote" || node.Protocol == "forward" { + if node.Protocol == "direct" || node.Protocol == "remote" { tr = gost.SSHForwardTransporter() } else { tr = gost.SSHTunnelTransporter() @@ -187,10 +187,12 @@ func initChain() (*gost.Chain, error) { connector = gost.SOCKS4AConnector() case "ss": connector = gost.ShadowConnector(node.User) - case "direct", "forward": + case "direct": connector = gost.SSHDirectForwardConnector() case "remote": connector = gost.SSHRemoteForwardConnector() + case "forward": + connector = gost.ForwardConnector() case "http": fallthrough default: @@ -239,6 +241,7 @@ func serve(chain *gost.Chain) error { if err != nil && certFile != "" && keyFile != "" { return err } + var ln gost.Listener switch node.Transport { case "tls": @@ -364,8 +367,14 @@ func serve(chain *gost.Chain) error { case "sni": handler = gost.SNIHandler(handlerOptions...) default: - handler = gost.AutoHandler(handlerOptions...) + // start from 2.5, if remote is not empty, then we assume that it is a forward tunnel + if node.Remote != "" { + handler = gost.ForwardHandler(node.Remote, handlerOptions...) + } else { + handler = gost.AutoHandler(handlerOptions...) + } } + srv := &gost.Server{Listener: ln} go srv.Serve(handler) } diff --git a/forward.go b/forward.go index 5c5e9a6..b0f4bb0 100644 --- a/forward.go +++ b/forward.go @@ -12,6 +12,51 @@ import ( "github.com/go-log/log" ) +type forwardConnector struct { +} + +// ForwardConnector creates a Connector for data forward client. +func ForwardConnector() Connector { + return &forwardConnector{} +} + +func (c *forwardConnector) Connect(conn net.Conn, addr string) (net.Conn, error) { + return conn, nil +} + +type forwardHandler struct { + raddr string + options *HandlerOptions +} + +// ForwardHandler creates a server Handler for data forwarding server. +func ForwardHandler(raddr string, opts ...HandlerOption) Handler { + h := &forwardHandler{ + raddr: raddr, + options: &HandlerOptions{}, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *forwardHandler) Handle(conn net.Conn) { + defer conn.Close() + + log.Logf("[forward] %s - %s", conn.RemoteAddr(), h.raddr) + cc, err := h.options.Chain.Dial(h.raddr) + if err != nil { + log.Logf("[forward] %s -> %s : %s", conn.RemoteAddr(), h.raddr, err) + return + } + defer cc.Close() + + log.Logf("[forward] %s <-> %s", conn.RemoteAddr(), h.raddr) + transport(conn, cc) + log.Logf("[forward] %s >-< %s", conn.RemoteAddr(), h.raddr) +} + type tcpDirectForwardHandler struct { raddr string options *HandlerOptions diff --git a/node.go b/node.go index 8b1e943..629bec7 100644 --- a/node.go +++ b/node.go @@ -36,6 +36,7 @@ func ParseNode(s string) (node Node, err error) { node = Node{ Addr: u.Host, + Remote: strings.Trim(u.EscapedPath(), "/"), Values: u.Query(), User: u.User, } @@ -56,9 +57,7 @@ func ParseNode(s string) (node Node, err error) { node.Protocol = "http" node.Transport = "tls" case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding - node.Remote = strings.Trim(u.EscapedPath(), "/") case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding - node.Remote = strings.Trim(u.EscapedPath(), "/") default: node.Transport = "tcp" } @@ -68,7 +67,7 @@ func ParseNode(s string) (node Node, err error) { case "socks", "socks5": node.Protocol = "socks5" case "tcp", "udp", "rtcp", "rudp": // port forwarding - case "direct", "remote", "forward": // SSH port forwarding + case "direct", "remote", "forward": // forwarding case "redirect": // TCP transparent proxy default: node.Protocol = "" diff --git a/sni.go b/sni.go index 3d984c0..cc06d55 100644 --- a/sni.go +++ b/sni.go @@ -56,7 +56,7 @@ func (h *sniHandler) Handle(conn net.Conn) { return } - cc, err := options.Chain.Dial(sni) + cc, err := options.Chain.Dial(sni + ":443") if err != nil { log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), sni, err) return