I have an SSH tunnel which dial into the server endpoint and starts up a remote listener on a port 1080
. My goal is to dynamically forward any TCP traffic from that port to the client side of the tunnel. While I am able to accept TCP stream I am not able to find a way to Dial
out on the client side of the SSH tunnel. It looks like the dialer
I am passing is the serverConn
server SSH end of the tunnel. And when I am attempting to remote, err := dialer.DialTCP("tcp4", local.RemoteAddr().(*net.TCPAddr), addr)
I get the traffic dial on the remote end. I want to find a way to dial out at the client side over a reverse tunnel.
I am not looking to forward specific ports to a specific destination on local, but looking to do more dynamic port forwarding similar to ssh -D
option. I am managing destination of TCP traffic myself, this is not a concern.
I have tried to create ssh.NewClient
from the passed serverConn
but it needs to perform an SSH handshake, and Iam only receiving raw TCP on the port 1080
so it's not a valid SSH client. Thanks.
func main(){
type Dialer interface {
DialTCP(net string, laddr, raddr *net.TCPAddr) (net.Conn, error)
}
// SSH server connection
sshConfig := &ssh.ClientConfig{
User: "tester",
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// Connect to SSH remote server using serverEndpoint (port 22)
serverConn, err := ssh.Dial("tcp", serverEndpoint.String(), sshConfig)
if err != nil {
log.Fatalln(fmt.Printf("Dial INTO remote server error: %s", err))
}
// Listen on remote server port (port 1080)
listener, err := serverConn.Listen("tcp",
remoteEndpoint.String())
if err != nil {
log.Fatalln(fmt.Printf("Listen open port ON remote server error: %s", err))
}
defer listener.Close()
acceptSLoop(listener, serverConn)
}
func acceptSLoop(listener net.Listener, sshClient *ssh.Client) {
fmt.Printf("Listener: %s
", listener.Addr().String())
defer listener.Close()
for {
clientConn, err := listener.Accept()
fmt.Printf("local addr %s
", clientConn.LocalAddr())
if err != nil {
log.Fatal(err)
}
fmt.Printf("New connection found on %s
", listener.Addr().String())
listenSConnection(clientConn, sshClient, config)
}
}
func listenSConnection(SClientConn net.Conn, sshClient
*ssh.Client) {
// In a regular SSH I need to do
// sshConn, chans, reqs, err :=
ssh.NewServerConn(SClientConn, // config will be
passed in ..)
//
// But since it's TCP handoff I am passing socket data
directly
handleSConn(SClientConn, sshClient)
}
func handleSConn(local net.Conn, dialer Dialer) {
defer local.Close()
// Both of those establish socket from "remote" ssh side (Server) not "local" ssh side (client)
remote, err := dialer.DialTCP("tcp4", local.RemoteAddr().(*net.TCPAddr), addr)
//remote, err := net.Dial("tcp4", addr.String())
// transfer bytes from local SOCKS to remote desired endpoint over SSH
transfer(local, remote)
}
// in - local SOCKS conn, out - remote desired endpoint
func transfer(in, out net.Conn) {
//.... working
}