2015-05-26 4 views
4

Я был в состоянии передать телнет через WebSocket, используя golang, используя что-то вродеGolang: вперед SSH через WebSocket

func forwardtcp(wsconn *websocket.Conn, conn *telnet.Conn) { 
    connbuf := bufio.NewReader(conn) 
    tcpbuffer := make([]byte, 128) 

    for { 
     n, err := connbuf.Read(tcpbuffer) 

     if err != nil { 
      log.Println("TCP Read failed") 
      break 
     } 
     if err == nil { 
      wsconn.WriteMessage(websocket.BinaryMessage, tcpbuffer[:n]) 
     } 
    } 
} 

Однако я не могу сделать то же с SSH или сеанс оболочки. Я не понимаю фундаментальную концепцию с использованием

targetStdout, _ := session.StdoutPipe() 
targetStdin, _ := session.StdinPipe() 

штук.

Я могу использовать io.Copy, но не уверен, как отформатировать их в дейтаграмме, которая может быть отправлена ​​с подключением к сети.

Можно ли обрабатывать каналы targetStdin и targetStdout таким образом, чтобы их можно было читать и записывать с помощью байтов, например, полученных из соединения веб-сокета? Или есть лучший способ получить io из SSH-соединения?

+0

Да - для браузера. –

ответ

1

Если вы хотите использовать SSH для сеанса удаленной оболочки, вы не должны использовать пакет websocket, кроме пакета golang.org/x/crypto/ssh. Существует отличный пример на godoc.org, который я повторяю здесь:

// An SSH client is represented with a ClientConn. Currently only 
// the "password" authentication method is supported. 
// 
// To authenticate with the remote server you must pass at least one 
// implementation of AuthMethod via the Auth field in ClientConfig. 
config := &ssh.ClientConfig{ 
    User: "username", 
    Auth: []ssh.AuthMethod{ 
     ssh.Password("yourpassword"), 
    }, 
} 
client, err := ssh.Dial("tcp", "yourserver.com:22", config) 
if err != nil { 
    panic("Failed to dial: " + err.Error()) 
} 

// Each ClientConn can support multiple interactive sessions, 
// represented by a Session. 
session, err := client.NewSession() 
if err != nil { 
    panic("Failed to create session: " + err.Error()) 
} 
defer session.Close() 

// Once a Session is created, you can execute a single command on 
// the remote side using the Run method. 
var b bytes.Buffer 
session.Stdout = &b 
if err := session.Run("/usr/bin/whoami"); err != nil { 
    panic("Failed to run: " + err.Error()) 
} 
fmt.Println(b.String()) 

Вы, вероятно, хотите использовать поля в ssh.Session структуры вместо использования StdoutPipe().

type Session struct { 
    Stdin io.Reader 
    Stdout io.Writer 
    Stderr io.Writer 
} 

Строка в примере session.Stdout = &b означает, что стандартный вывод из удаленного процесса будет записан в b. Аналогично, вы можете назначить любой io.Readersession.Stdin, который будет считаться удаленным процессом как stdin. Детальное поведение ssh.Session можно найти на godoc.org

+0

Спасибо - мне нужно переслать его удаленному браузеру, хотя - вот где я застреваю. Выполнение одной команды - хорошее начало, но в идеале я бы хотел отправить интерактивный сеанс. –

+0

Для потомков: проект GoTTY позволяет запускать команду на удаленном сервере и позволяет видеть сеанс терминала из веб-браузера. Вместо браузера вы можете использовать консоль-утилиту getty-client, поскольку она использует веб-файлы для подключения к серверу GoTTY. –

1

websocket.Conn является ReadWriter, поэтому он может быть и источником и местом для io.Copy. Оба Cmd.StdoutPipe и Session.StdoutPipe - io.Reader, а версии Stdin - io.Writer. Так что все должно склеиваться. Вам просто нужно скопировать в обоих направлениях.

go io.Copy(targetStdin, wsconn) 
io.Copy(wsconn, targetStdout) 
+0

Я попытался использовать реализацию веб-сайта Gorilla и получить ошибку: 'не может использовать wsConn (type * websocket.Conn) как тип io.Reader в аргументе io.Copy: \t * websocket.Conn не реализует io.Reader (отсутствует метод чтения) и не может использовать WSCONN (тип * websocket.Conn) в качестве типа io.Writer в аргументе io.Copy: \t * websocket.Conn не реализует io.Writer (отсутствует метод Write) \t \t есть websocket.write (int, time.Time, ...[] byte) error \t \t want Write ([] byte) (int, error) ' Я пытаюсь использовать NextReader() и NextWriter(), но пока не повезло. –

+0

Вместо этого вы должны посмотреть на golang.org/x/net/websocket. Но вы также можете обернуть версию гориллы в свой собственный тип, а затем добавить к ней методы чтения и записи. –