From e6f2cf921226afc482f399862526f223072d5519 Mon Sep 17 00:00:00 2001 From: blacknon Date: Fri, 30 Aug 2024 00:44:18 +0900 Subject: [PATCH 1/5] update. Modification to run on TUI terminal (PoC). --- cmd.go | 43 ++++++++++++++++++++++++++++++------------- connect.go | 3 +++ shell.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 15 deletions(-) diff --git a/cmd.go b/cmd.go index 89e5a68..7018ca6 100644 --- a/cmd.go +++ b/cmd.go @@ -24,35 +24,52 @@ func (c *Connect) Command(command string) (err error) { } defer func() { c.Session = nil }() - // setup options - err = c.setOption(c.Session) - if err != nil { - return - } - - // Set Stdin, Stdout, Stderr... - if c.Stdin != nil { + // Set Stdin + switch { + case c.Stdin != nil: w, _ := c.Session.StdinPipe() go io.Copy(w, c.Stdin) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stdin = c.PtyRelayTty + + default: stdin := GetStdin() c.Session.Stdin = stdin } - if c.Stdout != nil { + // Set Stdout + switch { + case c.Stdout != nil: or, _ := c.Session.StdoutPipe() go io.Copy(c.Stdout, or) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stdout = c.PtyRelayTty + + default: c.Session.Stdout = os.Stdout } - if c.Stderr != nil { + // Set Stderr + switch { + case c.Stderr != nil: er, _ := c.Session.StderrPipe() go io.Copy(c.Stderr, er) - } else { + + case c.PtyRelayTty != nil: + c.Session.Stderr = c.PtyRelayTty + + default: c.Session.Stderr = os.Stderr } + // setup options + err = c.setOption(c.Session) + if err != nil { + return + } + // Run Command c.Session.Run(command) diff --git a/connect.go b/connect.go index d4affed..a397164 100644 --- a/connect.go +++ b/connect.go @@ -51,6 +51,9 @@ type Connect struct { // Set it before CraeteClient. ForwardAgent bool + // Set the TTY to be used as the input and output for the Session/Cmd. + PtyRelayTty *os.File + // CheckKnownHosts if true, check knownhosts. // Ignored if HostKeyCallback is set. // Set it before CraeteClient. diff --git a/shell.go b/shell.go index e9379a5..a185947 100644 --- a/shell.go +++ b/shell.go @@ -20,7 +20,13 @@ import ( // Shell connect login shell over ssh. func (c *Connect) Shell(session *ssh.Session) (err error) { // Input terminal Make raw - fd := int(os.Stdin.Fd()) + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdin.Fd()) + } + state, err := terminal.MakeRaw(fd) if err != nil { return @@ -33,6 +39,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { return } + // set tty + if c.PtyRelayTty != nil { + session.Stdin = c.PtyRelayTty + session.Stdout = c.PtyRelayTty + session.Stderr = c.PtyRelayTty + } + // Start shell err = session.Shell() if err != nil { @@ -42,6 +55,11 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { // keep alive packet go c.SendKeepAlive(session) + // if tty is set, get signal winch + if c.PtyRelayTty != nil { + go c.ChangeWinSize(session) + } + err = session.Wait() if err != nil { return @@ -54,7 +72,13 @@ func (c *Connect) Shell(session *ssh.Session) (err error) { // Used to start a shell with a specified command. func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { // Input terminal Make raw - fd := int(os.Stdin.Fd()) + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdin.Fd()) + } + state, err := terminal.MakeRaw(fd) if err != nil { return @@ -67,6 +91,13 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { return } + // set tty + if c.PtyRelayTty != nil { + session.Stdin = c.PtyRelayTty + session.Stdout = c.PtyRelayTty + session.Stderr = c.PtyRelayTty + } + // Start shell err = session.Start(command) if err != nil { @@ -84,6 +115,23 @@ func (c *Connect) CmdShell(session *ssh.Session, command string) (err error) { return } +func (c *Connect) ChangeWinSize(session *ssh.Session) { + // Get terminal window size + var fd int + if c.PtyRelayTty != nil { + fd = int(c.PtyRelayTty.Fd()) + } else { + fd = int(os.Stdout.Fd()) + } + width, height, err := terminal.GetSize(fd) + if err != nil { + return + } + + // Send window size + session.WindowChange(height, width) +} + // SetLog set up terminal log logging. // This only happens in Connect.Shell(). func (c *Connect) SetLog(path string, timestamp bool) { From 9368baee2e24cc7244453682f20a856efc17d748 Mon Sep 17 00:00:00 2001 From: blacknon Date: Fri, 6 Sep 2024 00:13:38 +0900 Subject: [PATCH 2/5] update. --- connect.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/connect.go b/connect.go index a397164..5c6bc14 100644 --- a/connect.go +++ b/connect.go @@ -203,16 +203,13 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { if _, err := session.SendRequest("keepalive@openssh.com", true, nil); err != nil { if !errors.Is(err, io.EOF) { log.Println("Failed to send keepalive packet:", err) - session.Close() - c.Client.Close() - break } else { - // sleep - time.Sleep(time.Duration(interval) * time.Second) - continue + // err is io.EOF + log.Println("Session io.EOF. exit keepalive.") } + break } else { - // sleep + // err is nil. time.Sleep(time.Duration(interval) * time.Second) continue } @@ -223,7 +220,7 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { // CheckClientAlive check alive ssh.Client. func (c *Connect) CheckClientAlive() error { _, _, err := c.Client.SendRequest("keepalive", true, nil) - if err == nil || err.Error() == "request failed" { + if err == nil { return nil } return err From 56659f9beaf82c5c12a2c92fe8311274235b4c0a Mon Sep 17 00:00:00 2001 From: blacknon Date: Fri, 6 Sep 2024 10:54:38 +0900 Subject: [PATCH 3/5] update. --- connect.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/connect.go b/connect.go index 5c6bc14..7b05372 100644 --- a/connect.go +++ b/connect.go @@ -203,15 +203,14 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { if _, err := session.SendRequest("keepalive@openssh.com", true, nil); err != nil { if !errors.Is(err, io.EOF) { log.Println("Failed to send keepalive packet:", err) + return } else { // err is io.EOF log.Println("Session io.EOF. exit keepalive.") } - break } else { // err is nil. time.Sleep(time.Duration(interval) * time.Second) - continue } } } From 45ad91d5e797284014973fab4210adf5ff96bbff Mon Sep 17 00:00:00 2001 From: blacknon Date: Fri, 6 Sep 2024 16:27:42 +0900 Subject: [PATCH 4/5] update keepalive code. --- connect.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connect.go b/connect.go index 7b05372..6730fe2 100644 --- a/connect.go +++ b/connect.go @@ -203,11 +203,11 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { if _, err := session.SendRequest("keepalive@openssh.com", true, nil); err != nil { if !errors.Is(err, io.EOF) { log.Println("Failed to send keepalive packet:", err) - return } else { // err is io.EOF log.Println("Session io.EOF. exit keepalive.") } + return } else { // err is nil. time.Sleep(time.Duration(interval) * time.Second) From 1b4de0c4e06d212b50c4ab4cde71d1401570ff5d Mon Sep 17 00:00:00 2001 From: blacknon Date: Sun, 8 Sep 2024 23:25:47 +0900 Subject: [PATCH 5/5] update. --- connect.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/connect.go b/connect.go index 6730fe2..d55b211 100644 --- a/connect.go +++ b/connect.go @@ -6,7 +6,6 @@ package sshlib import ( "context" - "errors" "io" "log" "net" @@ -194,25 +193,30 @@ func (c *Connect) SendKeepAlive(session *ssh.Session) { interval = c.SendKeepAliveInterval } + max := 3 + if c.SendKeepAliveMax > 0 { + max = c.SendKeepAliveMax + } + t := time.NewTicker(time.Duration(c.ConnectTimeout) * time.Second) defer t.Stop() + count := 0 for { select { case <-t.C: if _, err := session.SendRequest("keepalive@openssh.com", true, nil); err != nil { - if !errors.Is(err, io.EOF) { - log.Println("Failed to send keepalive packet:", err) - } else { - // err is io.EOF - log.Println("Session io.EOF. exit keepalive.") - } - return + log.Println("Failed to send keepalive packet:", err) + count += 1 } else { // err is nil. time.Sleep(time.Duration(interval) * time.Second) } } + + if count > max { + return + } } }