Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions ssh_tunnel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package sup

import (
"github.com/pkg/errors"
"fmt"
"net"
"io"
"strings"
"os"
)

type SSHTunnel struct {
Tunnel Tunnel
SSHClient *SSHClient
err chan error
}

func (t Tunnel) String() string {
return fmt.Sprintf("%d:%s:%d\n", t.ListenPort, t.Host, t.DstPort)
}

func (t *SSHTunnel) StartTunnel() {
lAddr := fmt.Sprintf("localhost:%d", t.Tunnel.ListenPort)
ln, err := t.SSHClient.conn.Listen("tcp", lAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "Remote tunnel listen failed: %s\n", err)
return
}
defer ln.Close()

for {
conn, err := ln.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "Remote tunnel accept faild: %s\n", err)
}
go t.forward(conn)
}
}

func (t *SSHTunnel) forward(remoteConn net.Conn) {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", t.Tunnel.Host, t.Tunnel.DstPort))
if err != nil {
t.err <- errors.Wrap(err, "local tunnel connection error")
}

copy := func(writer, reader net.Conn) {
_, err:= io.Copy(writer, reader)
if err != nil && ! strings.Contains(err.Error(), "use of closed network connection") {
t.err <- errors.Wrap(err, "Tunnel forward error")
}
writer.Close()
}

go copy(conn, remoteConn)
go copy(remoteConn, conn);
}
8 changes: 8 additions & 0 deletions sup.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ func (sup *Stackup) Run(network *Network, envVars EnvList, commands ...*Command)
errCh <- errors.Wrap(err, "connecting to remote host failed")
return
}
for _, tunnel := range network.Tunnels {
sshTunnel := &SSHTunnel {
Tunnel: tunnel,
SSHClient: remote,
}
go sshTunnel.StartTunnel()
}

}
clientCh <- remote
}(i, host)
Expand Down
9 changes: 8 additions & 1 deletion supfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ type Network struct {
Inventory string `yaml:"inventory"`
Hosts []string `yaml:"hosts"`
Bastion string `yaml:"bastion"` // Jump host for the environment
Tunnels []Tunnel `yaml:"tunnels"`// Add remote port forwarding
}

// Command represents command(s) to be run remotely.
type Command struct {
Name string `yaml:"-"` // Command name.
Expand All @@ -55,6 +55,13 @@ type Upload struct {
Exc string `yaml:"exclude"`
}

// Tunnel represents a Remote Port forwarding specification
type Tunnel struct {
ListenPort int `yaml:"listen"`
Host string `yaml:"host"`
DstPort int `yaml:"port"`
}

// EnvVar represents an environment variable
type EnvVar struct {
Key string
Expand Down