add ping for ssh client

This commit is contained in:
rui.zheng 2017-02-26 18:31:07 +08:00
parent 2ca2bf7187
commit d5e4e24e83
7 changed files with 123 additions and 48 deletions

View File

@ -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)

View File

@ -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 downloadhttps://github.com/ginuerzh/gost/releases
@ -64,6 +65,8 @@ transport: data transmission mode (ws, wss, tls, http2, quic, kcp, pht), may be
> redirect - transparent proxyredirect://: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

View File

@ -7,6 +7,7 @@ import (
"github.com/golang/glog"
"golang.org/x/crypto/ssh"
"net"
"strconv"
"time"
)
@ -459,8 +460,41 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN
return err
}
client := ssh.NewClient(c, chans, reqs)
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 {
glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", laddr, raddr, err)
@ -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)
}
}

View File

@ -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())
}
}

View File

@ -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=",

View File

@ -7,6 +7,7 @@ import (
"github.com/golang/glog"
"golang.org/x/crypto/ssh"
"net"
"strconv"
"time"
)
@ -459,8 +460,41 @@ func (s *RTcpForwardServer) connectRTcpForwardSSH(conn net.Conn, sshNode *ProxyN
return err
}
client := ssh.NewClient(c, chans, reqs)
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 {
glog.V(LWARNING).Infof("[rtcp] %s -> %s : %s", laddr, raddr, err)
@ -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)
}
}

35
ssh.go
View File

@ -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())
}
}