nats-ssh-bridge.go

This commit is contained in:
traumschule 2019-03-24 19:37:28 -07:00
commit 15f6def3e0

177
nats-ssh.go Normal file
View File

@ -0,0 +1,177 @@
package main
import (
// nats client
"bufio"
"fmt"
"os"
"time"
nats "github.com/nats-io/go-nats"
// ssh
// "errors"
// "net"
"golang.org/x/crypto/ssh"
)
/* motivation
TLDR ssh <> ssh-chat-server <> [ssh-client & nats-client] <> nats-server
TLDR: ssh.in < nats.out ssh.out > nats.in :s
<ts> add an ssh server to nats-client :p <-- i really want to do this
<ts> not sure if everyone needs to run a ssh
<ron> uh? in that case no everyone would have to run nats-client..
<ts> sounds like the ricochet or cwtch where everyone runs an onion service
<ron> they would connect to nats-client over ssh
<ts> the idea was to let everyone connect to gnats via ssh over ssh-chat, right?
<ron> what you mean gnats? the nats server?
<ts> it's the nats server that runs on serge
<ron> its a nats server not an ssh server :s
<ts> right. so your idea was to add the ssh-server to the nats client instead? <ron> yes
<ts> who would connect to it? <ron> users like in ssh-chat
<ts> and it would be forwarded via nats?
<ron> the users ssh session stdin input would be published like the normal stdin is now
<ron> and received messages would be printed on all ssh user sessions tty
<ron> stdout .. hm no.. tty.. not stdout ;)
<ron> and for example another fork of nats-client could have a webserver
<ron> then user from browser can talk to ssh user
<ts> i want to be able to send messages to everyone's stderr! */
func main() {
server := "gam4soeb3t5f56fs.onion"
user := "test"
// connect to ssh server
//https://github.com/inatus/ssh-client-go/blob/master/main.go#L35
// https://github.com/shazow/ssh-chat/blob/master/sshd/client_test.go
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.KeyboardInteractive(func(user, instruction string,
questions []string, echos []bool) (answers []string, err error) {
return
}),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
conn, err := ssh.Dial("tcp", server+":2022", config)
if err != nil {
panic("Failed to dial: " + err.Error())
}
defer conn.Close()
// Each ClientConn can support multiple interactive sessions,
// represented by a Session.
session, err := conn.NewSession()
if err != nil {
panic("Failed to create session: " + err.Error())
}
defer session.Close()
// Set IO
session.Stdout = os.Stdout
session.Stderr = os.Stderr
// session.Stdin = os.Stdin
in, _ := session.StdinPipe()
// Set up terminal modes
modes := ssh.TerminalModes{
ssh.ECHO: 1, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
// Request pseudo terminal
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
fmt.Printf("request for pseudo terminal failed: %s", err)
}
// Start remote shell
if err := session.Shell(); err != nil {
fmt.Printf("failed to start shell: %s", err)
}
// no it copy reader to writer using the buffer
// you shouldnt use a buffer
/// or your input/output is only going to get copied $buffersize bytes at a time https://irc.anarchyplanet.org/git/ron/proxybang/src/master/main.go#L159
// reader := bufio.NewReader(resp.Body)
// if _, err := io.CopyBuffer(w, reader, buf); err != nil {
// if err == io.EOF {
// log.Println("eof")
// } else {
// log.Println(err)
// }
// }
answer, err := session.SendRequest("ping", true, nil)
if err != nil { fmt.Println("dammit")
}
fmt.Println(answer)
// Accepting commands
// TODO needs to be forked
// you can do that with channels using the select keyword
// go func(){}()
for {
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString('\n')
session.Run(str)
fmt.Fprint(in, str) // ssh-chat prob gives no real shell
}
// connect to nats server
opts := []nats.Option{
nats.ReconnectWait(time.Second),
nats.MaxReconnects(-1),
nats.DisconnectHandler(disconnectHandler),
nats.ReconnectHandler(reconnectHandler),
nats.ClosedHandler(closedHandler),
}
nc, err := nats.Connect(server, opts...)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
nc.Subscribe("chat", func(msg *nats.Msg) {
fmt.Println(string(msg.Data))
fmt.Print("> ")
})
nc.Flush()
err = nc.LastError()
if err != nil {
fmt.Print(err)
os.Exit(1)
}
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
text, _ := reader.ReadString('\n')
nc.Publish("chat", []byte(text))
}
os.Exit(1)
}
func disconnectHandler(nc *nats.Conn) {
fmt.Println("disconnected")
}
func reconnectHandler(nc *nats.Conn) {
fmt.Println("reconnected")
}
func closedHandler(nc *nats.Conn) {
fmt.Println("closed")
}