Coder Social home page Coder Social logo

sshtunnel's Introduction

๐Ÿš‡ sshtunnel

Ultra simple SSH tunnelling for Go programs.

Installation

go get -u github.com/elliotchance/sshtunnel

Or better with dep:

dep ensure -add github.com/elliotchance/sshtunnel

Example

// Setup the tunnel, but do not yet start it yet.
tunnel := sshtunnel.NewSSHTunnel(
   // User and host of tunnel server, it will default to port 22
   // if not specified.
   "[email protected]",

   // Pick ONE of the following authentication methods:
   sshtunnel.PrivateKeyFile("path/to/private/key.pem"), // 1. private key
   ssh.Password("password"),                            // 2. password
   sshtunnel.SSHAgent(),                                // 3. ssh-agent

   // The destination host and port of the actual server.
   "dqrsdfdssdfx.us-east-1.redshift.amazonaws.com:5439",
   
   // The local port you want to bind the remote port to.
   // Specifying "0" will lead to a random port.
   "8443",
)

// You can provide a logger for debugging, or remove this line to
// make it silent.
tunnel.Log = log.New(os.Stdout, "", log.Ldate | log.Lmicroseconds)

// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
time.Sleep(100 * time.Millisecond)

// NewSSHTunnel will bind to a random port so that you can have
// multiple SSH tunnels available. The port is available through:
//   tunnel.Local.Port

// You can use any normal Go code to connect to the destination server
// through localhost. You may need to use 127.0.0.1 for some libraries.
//
// Here is an example of connecting to a PostgreSQL server:
conn := fmt.Sprintf("host=127.0.0.1 port=%d username=foo", tunnel.Local.Port)
db, err := sql.Open("postgres", conn)

// ...

sshtunnel's People

Contributors

bnm3k avatar davidalexisnyt avatar elliotchance avatar hownowstephen avatar infra-red avatar isaaguilar avatar nyergler avatar rnsc avatar vl4deee11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sshtunnel's Issues

Add PrivateKeyFileWithPassphrase

Could we please add a PrivateKeyFileWithPassphrase for parsing private key files with a passphrase?

I can create a PR for it if you want to.

func PrivateKeyFileWithPassphrase(file string, passphrase string) ssh.AuthMethod {
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		return nil
	}

	key, err := ssh.ParsePrivateKeyWithPassphrase(buffer, []byte(passphrase))
	if err != nil {
		return nil
	}

	return ssh.PublicKeys(key)
}

Start server without go routine?

Hello, thank you again for creating this module

// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
time.Sleep(100 * time.Millisecond)

In the example we start the tunnel with a goroutine. Does this have to be put on a greenthread or could it be started with the goroutine.

Why I am asking is that we are experiencing errors from the tunnel.Start() call that we want to catch as errors.
But we are unable to do that

Question on having a tunnel open

Hey,

thank you so much of the sshtunnel.

Is it possible to get more info on whether one needs to close the connection.

...
// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
time.Sleep(100 * time.Millisecond)
...
// ...

is the example, I understand that maybe we should have a defer tunnel.Close()
but is that handled by the library itself?

...
// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
defer tunnel.Close()
time.Sleep(100 * time.Millisecond)
...
// ...

error

close signal received, closing...
panic: sync: negative WaitGroup counter

io.Copy Error for closing tunnel

I am experiencing a bit of error logs from the tunnel implementation.

	// Start the server in the background. You will need to wait a
	// small amount of time for it to bind to the localhost port
	// before you can start sending connections.
	go tunnel.Start()
	defer func() {
		time.Sleep(5 * time.Second)
		tunnel.Close()
	}()

Even if I wait 5 seconds for the tunnel to get any io.Copys out of the way (and I am not creating anything or so) I still get an error of io.Copy

2020/09/22 16:44:33.035361 accepted connection
2020/09/22 16:44:33.035380 listening for new connections...
2020/09/22 16:44:33.076055 connected to 11.11.11.11:22 (1 of 2)
2020/09/22 16:44:33.078677 connected to 22.22.22.22:22 (2 of 2)
2020/09/22 16:44:39.385185 close signal received, closing...
2020/09/22 16:44:39.385195 closing the netConn (1 of 2)
2020/09/22 16:44:39.385304 io.Copy error: read tcp 127.0.0.1:2000->127.0.0.1:40330: use of closed network connection
2020/09/22 16:44:39.385311 closing the netConn (2 of 2)
2020/09/22 16:44:39.385416 closing the serverConn (1 of 1)
2020/09/22 16:44:39.386128 tunnel closed

This is probably the interval workings of the tunnel implementation and closing before closing io.Copy implementations.

Hangs if connection to SSH host fails

The application hangs if the ssh.Dial() function call (first line in the forward() function) fails. The "server dial error" error is logged and the function returns, but tunnel channel is still open. Since it will now never receive anything, it just waits forever.

For now, I got it to close out by calling tunnel.close <- struct{}{} right after the tunnel.logf() call, but this is not the clean - a Panic ends up being thrown because something else is tries to close the channel, and the channel is already closed at that point.

Can sshtunnel handle Remote Port Forwarding

Thank you, this module is very helpful...
I've used it successfully for Local Port Forwarding. - (Forwards a connection from the client host to the SSH server host and then to the destination host port.)

But now I'm having trouble using it as Remote Port Forwarding. ( Forwards a port from the server host to the client host and then to the destination host port.)

Does this module already support Remote Port Forwarding? Please help, thank you very much.

Possibility to specify the Local port of a forwarded Port

Hello,

First, thank you for your work, it works perfectly!
I'm using your library to connect to SSH hosts via a tunnel and I was wondering, if it would be possible to specify both the remote and local port for the port forwarding?
For example, forwarding port 443 on remote to local port 8443, instead of a random one that your library picks up?

It'd be great to have a non mandatory parameter for that, so that if not specified, you pick up a random one.

Kind regards,

rnsc

Tunnel closed if forwarded connection is not in use anymore

Hello,

I was testing forwarding of ports and discovered that if you setup a tunnel and use the locally forwarded port, you can only use it once (example: one curl request), after that connection is closed by the client, the tunnel closes.

2020/01/15 10:25:44.654482 accepted connection
2020/01/15 10:25:44.654620 tunnel closed
2020/01/15 10:25:46.868374 connected to windows-host -> bastion-host:22 (1 of 2)
2020/01/15 10:25:47.816384 connected to windows-host:3389 (2 of 2)
2020/01/15 10:25:54.982384 io.Copy error: readfrom tcp 127.0.0.1:59612->127.0.0.1:59615: write tcp 127.0.0.1:59612->127.0.0.1:59615: write: broken pipe
2020/01/15 10:26:10.249962 close signal received, closing...

So basically, to reproduce the above, I create a tunnel and forward the RDP port of a windows machine that is accessible through a linux bastion host.
Then my program launches another program to open an RDP connection to that windows host.
If I close my RDP connection (the io.Copy error happens), then the tunnel closes.

Same symptom if I forward an HTTP port, I can do a cURL request just fine, but all subsequent requests will fail because the tunnel is closed.

Tunnel starting
Tunnel started
[INFO] You can access the remote port 9200 on your local port 9200
host: linux-host
proxyHost: bastion-host
Tunnel starting
Tunnel started
2020/01/15 10:37:10.310800 accepted connection
2020/01/15 10:37:10.310924 tunnel closed
2020/01/15 10:37:16.838399 connected to bastion-host:22 (1 of 2)
2020/01/15 10:37:17.353177 connected to linux-host:9200 (2 of 2)

~$ curl localhost:9200/_cat/health
1579081037 09:37:17 elasticsearch green 3 3 92 46 0 0 0 0 - 100.0%
~$
~$ curl localhost:9200/_cat/health
curl: (7) Failed to connect to localhost port 9200: Connection refused

In the above example, I'm create two tunnels, one to do SSH stuff and one to forward the 9200 port. (Thus the two "Tunnel Starting/Started" lines of log from my program)

Now I don't know if there's a logic flaw in my code or if it's an expected behaviour of the library.

Kind regards,

rnsc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.