From 012098ec325815a7e81cdf038b25cc4b6334a1da Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 12 Mar 2022 13:57:01 -0800 Subject: [PATCH] ssh/tailssh: fix terminal corruption (temporary hack) Maisem figured out the real problem but will take several commits (e.g. tailscale/ssh#2) in different repos to get it fixed properly. This is an interim hack. Details of real fix: https://github.com/tailscale/tailscale/issues/4146#issuecomment-1065952947 Updates #4146 Updates #3802 Change-Id: I7b7dc5713baa3e5de75b87b69e7179a6e7549b0b Signed-off-by: Brad Fitzpatrick --- ssh/tailssh/tailssh.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ssh/tailssh/tailssh.go b/ssh/tailssh/tailssh.go index 6e872a36a..8438de4a7 100644 --- a/ssh/tailssh/tailssh.go +++ b/ssh/tailssh/tailssh.go @@ -19,6 +19,7 @@ import ( "os" "os/exec" "os/user" + "reflect" "strings" "sync" "time" @@ -375,7 +376,14 @@ func (srv *server) handleAcceptedSSH(ctx context.Context, s ssh.Session, ci *ssh stdin.Close() }() go func() { - _, err := io.Copy(s, stdout) + // Write to s.Channel directly, avoiding gliderlab/ssh's (*session).Write + // call that translates newline endings, which we don't need. + // See https://github.com/tailscale/tailscale/issues/4146. + // TODO(bradfitz,maisem): remove this reflect hackery once gliderlab/ssh changes + // are all in. + // s is an gliderlabs/ssh.(*session); write to its Channel field. + sshChan := reflect.ValueOf(s).Elem().FieldByName("Channel").Interface().(io.Writer) + _, err := io.Copy(sshChan, stdout) if err != nil { // TODO: don't log in the success case. logf("ssh: stdout copy: %v", err)