diff --git a/cmd/gost/vendor/github.com/ginuerzh/gost/README.md b/cmd/gost/vendor/github.com/ginuerzh/gost/README.md index fc8e813..3b8eb53 100644 --- a/cmd/gost/vendor/github.com/ginuerzh/gost/README.md +++ b/cmd/gost/vendor/github.com/ginuerzh/gost/README.md @@ -18,6 +18,7 @@ gost - GO Simple Tunnel * 实验性支持QUIC (2.3+) * 支持KCP协议 (2.3+) * 透明代理 (2.3+) +* SSH隧道 (2.4+) 二进制文件下载:https://github.com/ginuerzh/gost/releases @@ -64,6 +65,8 @@ protocol: 代理协议类型(http, socks4(a), socks5, shadowsocks), transport: > redirect - 透明代理,redirect://:12345 +> ssh - SSH转发隧道,ssh://admin:123456@:2222 + #### 端口转发 适用于-L参数 @@ -165,8 +168,7 @@ gost按照-F设置的顺序通过代理链将请求最终转发给a.b.c.d:NNNN ```bash gost -L=tcp://:2222/192.168.1.1:22 -F=... ``` -将本地TCP端口2222上的数据(通过代理链)转发到192.168.1.1:22上。 - +将本地TCP端口2222上的数据(通过代理链)转发到192.168.1.1:22上。当代理链末端(最后一个-F参数)为SSH类型时,gost会直接使用SSH的本地端口转发功能。 #### 本地端口转发(UDP) ```bash @@ -182,7 +184,7 @@ gost -L=udp://:5353/192.168.1.1:53?ttl=60 -F=... ```bash gost -L=rtcp://:2222/192.168.1.1:22 -F=... -F=socks://172.24.10.1:1080 ``` -将172.24.10.1:2222上的数据(通过代理链)转发到192.168.1.1:22上。 +将172.24.10.1:2222上的数据(通过代理链)转发到192.168.1.1:22上。当代理链末端(最后一个-F参数)为SSH类型时,gost会直接使用SSH的远程端口转发功能。 #### 远程端口转发(UDP) diff --git a/cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md b/cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md index 7a37a3f..6c8e7e3 100644 --- a/cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md +++ b/cmd/gost/vendor/github.com/ginuerzh/gost/README_en.md @@ -16,6 +16,7 @@ Features * Experimental QUIC support (2.3+) * KCP protocol support (2.3+) * Transparent proxy (2.3+) +* SSH tunnel (2.4+) Binary file download:https://github.com/ginuerzh/gost/releases @@ -64,6 +65,8 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp, pht), may be > redirect - transparent proxy,redirect://:12345 +> ssh - SSH tunnel, ssh://admin:123456@:2222 + #### Port forwarding Effective for the -L parameter @@ -165,7 +168,7 @@ each forward proxy can be any HTTP/HTTPS/HTTP2/SOCKS5/Shadowsocks type. ```bash gost -L=tcp://:2222/192.168.1.1:22 -F=... ``` -The data on the local TCP port 2222 is forwarded to 192.168.1.1:22 (through the proxy chain). +The data on the local TCP port 2222 is forwarded to 192.168.1.1:22 (through the proxy chain). If the last node of the chain (the last -F parameter) is a SSH tunnel, then gost will use the local port forwarding function of SSH directly. #### Local UDP port forwarding @@ -182,7 +185,7 @@ Each forwarding channel has a timeout period. When this time is exceeded and the ```bash gost -L=rtcp://:2222/192.168.1.1:22 -F=... -F=socks://172.24.10.1:1080 ``` -The data on 172.24.10.1:2222 is forwarded to 192.168.1.1:22 (through the proxy chain). +The data on 172.24.10.1:2222 is forwarded to 192.168.1.1:22 (through the proxy chain). If the last node of the chain (the last -F parameter) is a SSH tunnel, then gost will use the remote port forwarding function of SSH directly. #### Remote UDP port forwarding diff --git a/cmd/gost/vendor/github.com/ginuerzh/gost/forward.go b/cmd/gost/vendor/github.com/ginuerzh/gost/forward.go index eb3ac98..cc1fbf5 100644 --- a/cmd/gost/vendor/github.com/ginuerzh/gost/forward.go +++ b/cmd/gost/vendor/github.com/ginuerzh/gost/forward.go @@ -7,6 +7,7 @@ import ( "github.com/golang/glog" "golang.org/x/crypto/ssh" "net" + "strconv" "time" ) @@ -459,7 +460,40 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN return err } client := ssh.NewClient(c, chans, reqs) - defer client.Close() + + quit := make(chan interface{}) + defer close(quit) + + go func() { + defer client.Close() + + var c <-chan time.Time + + ping, _ := strconv.Atoi(sshNode.Get("ping")) + if ping > 0 { + d := time.Second * time.Duration(ping) + glog.V(LINFO).Infoln("[rtcp] ping is enabled:", d) + t := time.NewTicker(d) + defer t.Stop() + c = t.C + } + + for { + select { + case <-c: + _, _, err := client.SendRequest("ping", true, nil) + if err != nil { + glog.V(LWARNING).Infoln("[rtcp] ping", err) + return + } + glog.V(LDEBUG).Infoln("[rtcp] heartbeat OK") + + case <-quit: + glog.V(LWARNING).Infoln("[rtcp] ssh connection closed") + return + } + } + }() ln, err := client.Listen("tcp", laddr.String()) if err != nil { @@ -484,9 +518,9 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN } defer tc.Close() - glog.V(3).Infof("[rtcp] %s <-> %s", c.RemoteAddr(), c.LocalAddr()) + glog.V(LINFO).Infof("[rtcp] %s <-> %s", c.RemoteAddr(), c.LocalAddr()) Transport(c, tc) - glog.V(3).Infof("[rtcp] %s >-< %s", c.RemoteAddr(), c.LocalAddr()) + glog.V(LINFO).Infof("[rtcp] %s >-< %s", c.RemoteAddr(), c.LocalAddr()) }(rc) } } diff --git a/cmd/gost/vendor/github.com/ginuerzh/gost/ssh.go b/cmd/gost/vendor/github.com/ginuerzh/gost/ssh.go index c2c7514..4a838ef 100644 --- a/cmd/gost/vendor/github.com/ginuerzh/gost/ssh.go +++ b/cmd/gost/vendor/github.com/ginuerzh/gost/ssh.go @@ -30,7 +30,7 @@ type SSHServer struct { func (s *SSHServer) ListenAndServe() error { ln, err := net.Listen("tcp", s.Addr) if err != nil { - glog.V(1).Infoln("[ssh] Listen:", err) + glog.V(LWARNING).Infoln("[ssh] Listen:", err) return err } defer ln.Close() @@ -38,14 +38,14 @@ func (s *SSHServer) ListenAndServe() error { for { conn, err := ln.Accept() if err != nil { - glog.V(1).Infoln("[ssh] Accept:", err) + glog.V(LWARNING).Infoln("[ssh] Accept:", err) return err } go func(conn net.Conn) { sshConn, chans, reqs, err := ssh.NewServerConn(conn, s.Config) if err != nil { - glog.V(1).Infof("[ssh] %s -> %s : %s", conn.RemoteAddr(), s.Addr, err) + glog.V(LWARNING).Infof("[ssh] %s -> %s : %s", conn.RemoteAddr(), s.Addr, err) return } defer sshConn.Close() @@ -54,9 +54,9 @@ func (s *SSHServer) ListenAndServe() error { s.Handler = s.handleSSHConn } - glog.V(3).Infof("[ssh] %s <-> %s", conn.RemoteAddr(), s.Addr) + glog.V(LINFO).Infof("[ssh] %s <-> %s", conn.RemoteAddr(), s.Addr) s.Handler(sshConn, chans, reqs) - glog.V(3).Infof("[ssh] %s >-< %s", conn.RemoteAddr(), s.Addr) + glog.V(LINFO).Infof("[ssh] %s >-< %s", conn.RemoteAddr(), s.Addr) }(conn) } } @@ -69,6 +69,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re case RemoteForwardRequest: go s.tcpipForwardRequest(conn, req, quit) default: + // glog.V(LWARNING).Infoln("unknown channel type:", req.Type) if req.WantReply { req.Reply(false, nil) } @@ -84,7 +85,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re case DirectForwardRequest: channel, requests, err := newChannel.Accept() if err != nil { - glog.V(3).Infoln("[ssh] Could not accept channel:", err) + glog.V(LINFO).Infoln("[ssh] Could not accept channel:", err) continue } p := directForward{} @@ -93,7 +94,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re go ssh.DiscardRequests(requests) go s.directPortForwardChannel(channel, fmt.Sprintf("%s:%d", p.Host1, p.Port1)) default: - glog.V(3).Infoln("[ssh] Unknown channel type:", t) + glog.V(LWARNING).Infoln("[ssh] Unknown channel type:", t) newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) } } @@ -118,18 +119,18 @@ func (p directForward) String() string { func (s *SSHServer) directPortForwardChannel(channel ssh.Channel, raddr string) { defer channel.Close() - glog.V(3).Infof("[ssh-tcp] %s - %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s - %s", s.Addr, raddr) conn, err := s.Base.Chain.Dial(raddr) if err != nil { - glog.V(3).Infof("[ssh-tcp] %s - %s : %s", s.Addr, raddr, err) + glog.V(LINFO).Infof("[ssh-tcp] %s - %s : %s", s.Addr, raddr, err) return } defer conn.Close() - glog.V(3).Infof("[ssh-tcp] %s <-> %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s <-> %s", s.Addr, raddr) Transport(conn, channel) - glog.V(3).Infof("[ssh-tcp] %s >-< %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s >-< %s", s.Addr, raddr) } // tcpipForward is structure for RFC 4254 7.1 "tcpip-forward" request @@ -142,10 +143,10 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit t := tcpipForward{} ssh.Unmarshal(req.Payload, &t) addr := fmt.Sprintf("%s:%d", t.Host, t.Port) - glog.V(3).Infoln("[ssh-rtcp] listening tcp", addr) + glog.V(LINFO).Infoln("[ssh-rtcp] listening tcp", addr) ln, err := net.Listen("tcp", addr) //tie to the client connection if err != nil { - glog.V(1).Infoln("[ssh-rtcp]", err) + glog.V(LWARNING).Infoln("[ssh-rtcp]", err) req.Reply(false, nil) return } @@ -165,7 +166,7 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit return req.Reply(true, nil) } if err := replyFunc(); err != nil { - glog.V(1).Infoln("[ssh-rtcp]", err) + glog.V(LWARNING).Infoln("[ssh-rtcp]", err) return } @@ -199,9 +200,9 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit defer ch.Close() go ssh.DiscardRequests(reqs) - glog.V(3).Infof("[ssh-rtcp] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) + glog.V(LINFO).Infof("[ssh-rtcp] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) Transport(ch, conn) - glog.V(3).Infof("[ssh-rtcp] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr()) + glog.V(LINFO).Infof("[ssh-rtcp] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr()) }(conn) } }() @@ -229,7 +230,7 @@ func DefaultPasswordCallback(users []*url.Userinfo) PasswordCallbackFunc { return nil, nil } } - glog.V(3).Infof("[ssh] %s -> %s : password rejected for %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User()) + glog.V(LINFO).Infof("[ssh] %s -> %s : password rejected for %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User()) return nil, fmt.Errorf("password rejected for %s", conn.User()) } } diff --git a/cmd/gost/vendor/vendor.json b/cmd/gost/vendor/vendor.json index 599d34a..bb6e514 100644 --- a/cmd/gost/vendor/vendor.json +++ b/cmd/gost/vendor/vendor.json @@ -21,10 +21,10 @@ "revisionTime": "2017-01-19T05:34:58Z" }, { - "checksumSHA1": "lSL+LZe/WK67zmkONjox+zr66qI=", + "checksumSHA1": "8JlPLyEAjSN5tknRlRClQIVD5XA=", "path": "github.com/ginuerzh/gost", - "revision": "f31949d1ed0ddf2ea3c930f2859528c3f146d48c", - "revisionTime": "2017-02-11T13:17:58Z" + "revision": "2ca2bf71871e271ad2b69f7b26e14983c99efc5d", + "revisionTime": "2017-02-25T14:51:33Z" }, { "checksumSHA1": "+XIOnTW0rv8Kr/amkXgMraNeUr4=", diff --git a/forward.go b/forward.go index eb3ac98..cc1fbf5 100644 --- a/forward.go +++ b/forward.go @@ -7,6 +7,7 @@ import ( "github.com/golang/glog" "golang.org/x/crypto/ssh" "net" + "strconv" "time" ) @@ -459,7 +460,40 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN return err } client := ssh.NewClient(c, chans, reqs) - defer client.Close() + + quit := make(chan interface{}) + defer close(quit) + + go func() { + defer client.Close() + + var c <-chan time.Time + + ping, _ := strconv.Atoi(sshNode.Get("ping")) + if ping > 0 { + d := time.Second * time.Duration(ping) + glog.V(LINFO).Infoln("[rtcp] ping is enabled:", d) + t := time.NewTicker(d) + defer t.Stop() + c = t.C + } + + for { + select { + case <-c: + _, _, err := client.SendRequest("ping", true, nil) + if err != nil { + glog.V(LWARNING).Infoln("[rtcp] ping", err) + return + } + glog.V(LDEBUG).Infoln("[rtcp] heartbeat OK") + + case <-quit: + glog.V(LWARNING).Infoln("[rtcp] ssh connection closed") + return + } + } + }() ln, err := client.Listen("tcp", laddr.String()) if err != nil { @@ -484,9 +518,9 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN } defer tc.Close() - glog.V(3).Infof("[rtcp] %s <-> %s", c.RemoteAddr(), c.LocalAddr()) + glog.V(LINFO).Infof("[rtcp] %s <-> %s", c.RemoteAddr(), c.LocalAddr()) Transport(c, tc) - glog.V(3).Infof("[rtcp] %s >-< %s", c.RemoteAddr(), c.LocalAddr()) + glog.V(LINFO).Infof("[rtcp] %s >-< %s", c.RemoteAddr(), c.LocalAddr()) }(rc) } } diff --git a/ssh.go b/ssh.go index c2c7514..4a838ef 100644 --- a/ssh.go +++ b/ssh.go @@ -30,7 +30,7 @@ type SSHServer struct { func (s *SSHServer) ListenAndServe() error { ln, err := net.Listen("tcp", s.Addr) if err != nil { - glog.V(1).Infoln("[ssh] Listen:", err) + glog.V(LWARNING).Infoln("[ssh] Listen:", err) return err } defer ln.Close() @@ -38,14 +38,14 @@ func (s *SSHServer) ListenAndServe() error { for { conn, err := ln.Accept() if err != nil { - glog.V(1).Infoln("[ssh] Accept:", err) + glog.V(LWARNING).Infoln("[ssh] Accept:", err) return err } go func(conn net.Conn) { sshConn, chans, reqs, err := ssh.NewServerConn(conn, s.Config) if err != nil { - glog.V(1).Infof("[ssh] %s -> %s : %s", conn.RemoteAddr(), s.Addr, err) + glog.V(LWARNING).Infof("[ssh] %s -> %s : %s", conn.RemoteAddr(), s.Addr, err) return } defer sshConn.Close() @@ -54,9 +54,9 @@ func (s *SSHServer) ListenAndServe() error { s.Handler = s.handleSSHConn } - glog.V(3).Infof("[ssh] %s <-> %s", conn.RemoteAddr(), s.Addr) + glog.V(LINFO).Infof("[ssh] %s <-> %s", conn.RemoteAddr(), s.Addr) s.Handler(sshConn, chans, reqs) - glog.V(3).Infof("[ssh] %s >-< %s", conn.RemoteAddr(), s.Addr) + glog.V(LINFO).Infof("[ssh] %s >-< %s", conn.RemoteAddr(), s.Addr) }(conn) } } @@ -69,6 +69,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re case RemoteForwardRequest: go s.tcpipForwardRequest(conn, req, quit) default: + // glog.V(LWARNING).Infoln("unknown channel type:", req.Type) if req.WantReply { req.Reply(false, nil) } @@ -84,7 +85,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re case DirectForwardRequest: channel, requests, err := newChannel.Accept() if err != nil { - glog.V(3).Infoln("[ssh] Could not accept channel:", err) + glog.V(LINFO).Infoln("[ssh] Could not accept channel:", err) continue } p := directForward{} @@ -93,7 +94,7 @@ func (s *SSHServer) handleSSHConn(conn ssh.Conn, chans <-chan ssh.NewChannel, re go ssh.DiscardRequests(requests) go s.directPortForwardChannel(channel, fmt.Sprintf("%s:%d", p.Host1, p.Port1)) default: - glog.V(3).Infoln("[ssh] Unknown channel type:", t) + glog.V(LWARNING).Infoln("[ssh] Unknown channel type:", t) newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) } } @@ -118,18 +119,18 @@ func (p directForward) String() string { func (s *SSHServer) directPortForwardChannel(channel ssh.Channel, raddr string) { defer channel.Close() - glog.V(3).Infof("[ssh-tcp] %s - %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s - %s", s.Addr, raddr) conn, err := s.Base.Chain.Dial(raddr) if err != nil { - glog.V(3).Infof("[ssh-tcp] %s - %s : %s", s.Addr, raddr, err) + glog.V(LINFO).Infof("[ssh-tcp] %s - %s : %s", s.Addr, raddr, err) return } defer conn.Close() - glog.V(3).Infof("[ssh-tcp] %s <-> %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s <-> %s", s.Addr, raddr) Transport(conn, channel) - glog.V(3).Infof("[ssh-tcp] %s >-< %s", s.Addr, raddr) + glog.V(LINFO).Infof("[ssh-tcp] %s >-< %s", s.Addr, raddr) } // tcpipForward is structure for RFC 4254 7.1 "tcpip-forward" request @@ -142,10 +143,10 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit t := tcpipForward{} ssh.Unmarshal(req.Payload, &t) addr := fmt.Sprintf("%s:%d", t.Host, t.Port) - glog.V(3).Infoln("[ssh-rtcp] listening tcp", addr) + glog.V(LINFO).Infoln("[ssh-rtcp] listening tcp", addr) ln, err := net.Listen("tcp", addr) //tie to the client connection if err != nil { - glog.V(1).Infoln("[ssh-rtcp]", err) + glog.V(LWARNING).Infoln("[ssh-rtcp]", err) req.Reply(false, nil) return } @@ -165,7 +166,7 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit return req.Reply(true, nil) } if err := replyFunc(); err != nil { - glog.V(1).Infoln("[ssh-rtcp]", err) + glog.V(LWARNING).Infoln("[ssh-rtcp]", err) return } @@ -199,9 +200,9 @@ func (s *SSHServer) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Request, quit defer ch.Close() go ssh.DiscardRequests(reqs) - glog.V(3).Infof("[ssh-rtcp] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) + glog.V(LINFO).Infof("[ssh-rtcp] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) Transport(ch, conn) - glog.V(3).Infof("[ssh-rtcp] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr()) + glog.V(LINFO).Infof("[ssh-rtcp] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr()) }(conn) } }() @@ -229,7 +230,7 @@ func DefaultPasswordCallback(users []*url.Userinfo) PasswordCallbackFunc { return nil, nil } } - glog.V(3).Infof("[ssh] %s -> %s : password rejected for %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User()) + glog.V(LINFO).Infof("[ssh] %s -> %s : password rejected for %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User()) return nil, fmt.Errorf("password rejected for %s", conn.User()) } }