mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 17:35:40 +08:00
ssh: added timeout parameter (optimize #289 @299)
This commit is contained in:
parent
ff09c45fb6
commit
5cbfcf815f
@ -100,7 +100,7 @@ glider -h
|
|||||||
<summary>click to see details</summary>
|
<summary>click to see details</summary>
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
glider 0.15.0 usage:
|
glider 0.15.1 usage:
|
||||||
-check string
|
-check string
|
||||||
check=tcp[://HOST:PORT]: tcp port connect check
|
check=tcp[://HOST:PORT]: tcp port connect check
|
||||||
check=http://HOST[:PORT][/URI][#expect=STRING_IN_RESP_LINE]
|
check=http://HOST[:PORT][/URI][#expect=STRING_IN_RESP_LINE]
|
||||||
@ -205,7 +205,8 @@ SSR scheme:
|
|||||||
ssr://method:pass@host:port?protocol=xxx&protocol_param=yyy&obfs=zzz&obfs_param=xyz
|
ssr://method:pass@host:port?protocol=xxx&protocol_param=yyy&obfs=zzz&obfs_param=xyz
|
||||||
|
|
||||||
SSH scheme:
|
SSH scheme:
|
||||||
ssh://user[:pass]@host:port[?key=keypath]
|
ssh://user[:pass]@host:port[?key=keypath&timeout=SECONDS]
|
||||||
|
timeout: timeout of ssh handshake and channel operation, default: 5
|
||||||
|
|
||||||
VMess scheme:
|
VMess scheme:
|
||||||
vmess://[security:]uuid@host:port[?alterID=num]
|
vmess://[security:]uuid@host:port[?alterID=num]
|
||||||
|
@ -177,7 +177,8 @@ func usage() {
|
|||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "SSH scheme:\n")
|
fmt.Fprintf(w, "SSH scheme:\n")
|
||||||
fmt.Fprintf(w, " ssh://user[:pass]@host:port[?key=keypath]\n")
|
fmt.Fprintf(w, " ssh://user[:pass]@host:port[?key=keypath&timeout=SECONDS]\n")
|
||||||
|
fmt.Fprintf(w, " timeout: timeout of ssh handshake and channel operation, default: 5\n")
|
||||||
fmt.Fprintf(w, "\n")
|
fmt.Fprintf(w, "\n")
|
||||||
|
|
||||||
fmt.Fprintf(w, "VMess scheme:\n")
|
fmt.Fprintf(w, "VMess scheme:\n")
|
||||||
|
@ -109,9 +109,10 @@ listen=socks5://:1080
|
|||||||
# forward=ssr://method:pass@1.1.1.1:8443?protocol=auth_aes128_md5&protocol_param=xxx&obfs=tls1.2_ticket_auth&obfs_param=yyy
|
# forward=ssr://method:pass@1.1.1.1:8443?protocol=auth_aes128_md5&protocol_param=xxx&obfs=tls1.2_ticket_auth&obfs_param=yyy
|
||||||
|
|
||||||
# ssh forwarder
|
# ssh forwarder
|
||||||
# forward=ssh://user[:pass]@host:port[?key=keypath]
|
# forward=ssh://user[:pass]@host:port[?key=keypath&timeout=SECONDS]
|
||||||
# forward=ssh://root:pass@host:port
|
# forward=ssh://root:pass@host:port
|
||||||
# forward=ssh://root@host:port?key=/path/to/keyfile
|
# forward=ssh://root@host:port?key=/path/to/keyfile
|
||||||
|
# forward=ssh://root@host:port?key=/path/to/keyfile&timeout=5
|
||||||
|
|
||||||
# http proxy as forwarder
|
# http proxy as forwarder
|
||||||
# forward=http://1.1.1.1:8080
|
# forward=http://1.1.1.1:8080
|
||||||
|
2
go.mod
2
go.mod
@ -26,7 +26,7 @@ require (
|
|||||||
github.com/templexxx/xorsimd v0.4.1 // indirect
|
github.com/templexxx/xorsimd v0.4.1 // indirect
|
||||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
|
github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect
|
||||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c // indirect
|
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// Replace dependency modules with local developing copy
|
// Replace dependency modules with local developing copy
|
||||||
|
4
go.sum
4
go.sum
@ -130,8 +130,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c h1:7SfqwP5fxEtl/P02w5IhKc86ziJ+A25yFrkVgoy2FT8=
|
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b h1:MWaHNqZy3KTpuTMAGvv+Kw+ylsEpmyJZizz1dqxnu28=
|
||||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
2
main.go
2
main.go
@ -18,7 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "0.15.0"
|
version = "0.15.1"
|
||||||
config = parseConfig()
|
config = parseConfig()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -20,8 +21,9 @@ type SSH struct {
|
|||||||
addr string
|
addr string
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
sshCfg *ssh.ClientConfig
|
conn net.Conn
|
||||||
sshClient *ssh.Client
|
client *ssh.Client
|
||||||
|
config *ssh.ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -43,17 +45,15 @@ func NewSSH(s string, d proxy.Dialer, p proxy.Proxy) (*SSH, error) {
|
|||||||
|
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
User: user,
|
User: user,
|
||||||
Timeout: time.Second * 3,
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pass, _ := u.User.Password(); pass != "" {
|
if pass, _ := u.User.Password(); pass != "" {
|
||||||
config.Auth = []ssh.AuthMethod{ssh.Password(pass)}
|
config.Auth = []ssh.AuthMethod{ssh.Password(pass)}
|
||||||
}
|
}
|
||||||
|
|
||||||
if key := u.Query().Get("key"); key != "" {
|
query := u.Query()
|
||||||
|
if key := query.Get("key"); key != "" {
|
||||||
keyAuth, err := privateKeyAuth(key)
|
keyAuth, err := privateKeyAuth(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ssh] read key file error: %s", err)
|
log.F("[ssh] read key file error: %s", err)
|
||||||
@ -62,11 +62,23 @@ func NewSSH(s string, d proxy.Dialer, p proxy.Proxy) (*SSH, error) {
|
|||||||
config.Auth = append(config.Auth, keyAuth)
|
config.Auth = append(config.Auth, keyAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// timeout of ssh handshake and channel operation
|
||||||
|
qtimeout := query.Get("timeout")
|
||||||
|
if qtimeout == "" {
|
||||||
|
qtimeout = "5" // default timeout
|
||||||
|
}
|
||||||
|
timeout, err := strconv.ParseUint(qtimeout, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.F("[ssh] parse timeout err: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.Timeout = time.Second * time.Duration(timeout)
|
||||||
|
|
||||||
t := &SSH{
|
t := &SSH{
|
||||||
dialer: d,
|
dialer: d,
|
||||||
proxy: p,
|
proxy: p,
|
||||||
addr: u.Host,
|
addr: u.Host,
|
||||||
sshCfg: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, port, _ := net.SplitHostPort(t.addr); port == "" {
|
if _, port, _ := net.SplitHostPort(t.addr); port == "" {
|
||||||
@ -89,6 +101,32 @@ func (s *SSH) Addr() string {
|
|||||||
return s.addr
|
return s.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dial connects to the address addr on the network net via the proxy.
|
||||||
|
func (s *SSH) Dial(network, addr string) (net.Conn, error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
if s.client != nil {
|
||||||
|
if c, err := s.dial(network, addr); err == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
s.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.initConn(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.dial(network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SSH) dial(network, addr string) (net.Conn, error) {
|
||||||
|
s.conn.SetDeadline(time.Now().Add(s.config.Timeout))
|
||||||
|
c, err := s.client.Dial(network, addr)
|
||||||
|
s.conn.SetDeadline(time.Time{})
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SSH) initConn() error {
|
func (s *SSH) initConn() error {
|
||||||
c, err := s.dialer.Dial("tcp", s.addr)
|
c, err := s.dialer.Dial("tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -96,32 +134,20 @@ func (s *SSH) initConn() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sshConn, sshChan, sshReq, err := ssh.NewClientConn(c, s.addr, s.sshCfg)
|
c.SetDeadline(time.Now().Add(s.config.Timeout))
|
||||||
|
sshConn, sshChan, sshReq, err := ssh.NewClientConn(c, s.addr, s.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ssh]: initial connection to %s error: %s", s.addr, err)
|
log.F("[ssh]: initial connection to %s error: %s", s.addr, err)
|
||||||
|
c.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.sshClient = ssh.NewClient(sshConn, sshChan, sshReq)
|
c.SetDeadline(time.Time{})
|
||||||
|
|
||||||
|
s.conn = c
|
||||||
|
s.client = ssh.NewClient(sshConn, sshChan, sshReq)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dial connects to the address addr on the network net via the proxy.
|
|
||||||
func (s *SSH) Dial(network, addr string) (net.Conn, error) {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
|
|
||||||
if s.sshClient != nil {
|
|
||||||
if c, err := s.sshClient.Dial(network, addr); err == nil {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
s.sshClient.Conn.Close()
|
|
||||||
}
|
|
||||||
if err := s.initConn(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return s.sshClient.Dial(network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
|
func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, nil, proxy.ErrNotSupported
|
||||||
|
Loading…
Reference in New Issue
Block a user