I am writing a simple bastion service which will log input/output of a ssh session. The ssh connection part looks like:
func connect(user, host string, logger sessionLogger) error {
cmd := exec.Command("ssh", user+"@"+host)
t, err := pty.Start(cmd)
if err != nil {
return err
}
defer t.Close()
go func() {
buf := make([]byte, 1024)
for {
n, err := t.Read(buf)
if err != nil {
break
}
os.Stdout.Write(buf[:n])
logger(buf[:n])
}
}()
go func() { io.Copy(t, os.Stdin) }()
return cmd.Wait()
}
The problem is all commands entered by user is echoed to the PTY twice, like this:
I have tried to play with the stdin/stdout of a cmd, including not using pty at all, but having various strange problems, e.g. no output of command prompt etc. most of them related to the nature of stdout of a Command (it must be a pty).
This is the best result I have now. But I do need to eliminate the excessive echo of command.
I am writing a simple bastion service which will log input/output of a ssh session. The ssh connection part looks like:
func connect(user, host string, logger sessionLogger) error {
cmd := exec.Command("ssh", user+"@"+host)
t, err := pty.Start(cmd)
if err != nil {
return err
}
defer t.Close()
go func() {
buf := make([]byte, 1024)
for {
n, err := t.Read(buf)
if err != nil {
break
}
os.Stdout.Write(buf[:n])
logger(buf[:n])
}
}()
go func() { io.Copy(t, os.Stdin) }()
return cmd.Wait()
}
The problem is all commands entered by user is echoed to the PTY twice, like this:
I have tried to play with the stdin/stdout of a cmd, including not using pty at all, but having various strange problems, e.g. no output of command prompt etc. most of them related to the nature of stdout of a Command (it must be a pty).
This is the best result I have now. But I do need to eliminate the excessive echo of command.
Share Improve this question asked Feb 8 at 6:58 xrfangxrfang 2,3105 gold badges24 silver badges51 bronze badges 2 |1 Answer
Reset to default 1You need to use raw mode to prevent duplicate input
// import "golang.org/x/term"
...
defer t.Close()
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
return err
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
...
os.Stdout.Write(buf[:n])
, so why are you surprised that you get that output in addition to the tty's own echo? – Toby Speight Commented Feb 8 at 9:38