easyssh/client.go

146 lines
3.1 KiB
Go

package easyssh
import (
"net"
"golang.org/x/crypto/ssh"
)
// Client wraps an SSH Client
type Client struct {
*ssh.Client
}
// Dial starts an ssh connection to the provided server
func Dial(network, addr string, config *ssh.ClientConfig) (*Client, error) {
c, err := ssh.Dial(network, addr, config)
return &Client{c}, err
}
// NewClient returns a new SSH Client.
func NewClient(c ssh.Conn, chans <-chan ssh.NewChannel, reqs <-chan *ssh.Request) *Client {
client := ssh.NewClient(c, chans, reqs)
return &Client{client}
}
// LocalForward performs a port forwarding over the ssh connection - ssh -L. Client will bind to the local address, and will tunnel those requests to host addr
func (c *Client) LocalForward(laddr, raddr *net.TCPAddr) error {
ln, err := net.ListenTCP("tcp", laddr) //tie to the client connection
if err != nil {
println(err.Error())
return err
}
logger.Println("Listening on address: ", ln.Addr().String())
quit := make(chan bool)
go func() { // Handle incoming connections on this new listener
for {
select {
case <-quit:
return
default:
conn, err := ln.Accept()
if err != nil { // Unable to accept new connection - listener likely closed
continue
}
go func(conn net.Conn) {
conn2, err := c.DialTCP("tcp", laddr, raddr)
if err != nil {
return
}
go func(conn, conn2 net.Conn) {
close := func() {
conn.Close()
conn2.Close()
}
go CopyReadWriters(conn, conn2, close)
}(conn, conn2)
}(conn)
}
}
}()
c.Wait()
ln.Close()
quit <- true
return nil
}
// RemoteForward forwards a remote port - ssh -R
func (c *Client) RemoteForward(remote, local string) error {
ln, err := c.Listen("tcp", remote)
if err != nil {
return err
}
quit := make(chan bool)
go func() { // Handle incoming connections on this new listener
for {
select {
case <-quit:
return
default:
conn, err := ln.Accept()
if err != nil { // Unable to accept new connection - listener likely closed
continue
}
conn2, err := net.Dial("tcp", local)
if err != nil {
continue
}
close := func() {
conn.Close()
conn2.Close()
}
go CopyReadWriters(conn, conn2, close)
}
}
}()
c.Wait()
ln.Close()
quit <- true
return nil
}
// HandleOpenChannel requests that the remote end accept a channel request and if accepted,
// passes the newly opened channel and requests to the provided handler
func (c *Client) HandleOpenChannel(channelName string, handler ChannelMultipleRequestsHandler, data ...byte) error {
ch, reqs, err := c.OpenChannel(channelName, data)
if err != nil {
return err
}
handler.HandleMultipleRequests(reqs, c.Conn, channelName, ch)
return nil
}
// HandleOpenChannelFunc requests that the remote end accept a channel request and if accepted,
// passes the newly opened channel and requests to the provided handler function
func (c *Client) HandleOpenChannelFunc(channelName string, handler ChannelMultipleRequestsHandlerFunc, data ...byte) error {
return c.HandleOpenChannel(channelName, ChannelMultipleRequestsHandlerFunc(handler), data...)
}