Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote port forwarding #213

Closed
smoqadam opened this issue Sep 1, 2023 · 2 comments
Closed

Remote port forwarding #213

smoqadam opened this issue Sep 1, 2023 · 2 comments

Comments

@smoqadam
Copy link

smoqadam commented Sep 1, 2023

hey guys, thank you for this great library.

As far as I know, when we run ssh -R0:localhost:9999 server-ip a random port will be chosen by OS (hence the 0: at the beginning), but I can't see which port has been chosen in the ReversePortForwardingCallback in the following example (taken from: https://github.com/gliderlabs/ssh/blob/master/_examples/ssh-remoteforward/portforward.go):

package main

import (
	"io"
	"log"

	"github.com/gliderlabs/ssh"
)

func main() {

	log.Println("starting ssh server on port 2222...")

	forwardHandler := &ssh.ForwardedTCPHandler{}

	server := ssh.Server{
		LocalPortForwardingCallback: ssh.LocalPortForwardingCallback(func(ctx ssh.Context, dhost string, dport uint32) bool {
			log.Println("Accepted forward", dhost, dport)
			return true
		}),
		Addr: ":2222",
		Handler: ssh.Handler(func(s ssh.Session) {
			io.WriteString(s, "Remote forwarding available...\n")
			select {}
		}),
		ReversePortForwardingCallback: ssh.ReversePortForwardingCallback(func(ctx ssh.Context, host string, port uint32) bool {
			log.Println("attempt to bind", host, port, "granted")
			return true
		}),
		RequestHandlers: map[string]ssh.RequestHandler{
			"tcpip-forward":        forwardHandler.HandleSSHRequest,
			"cancel-tcpip-forward": forwardHandler.HandleSSHRequest,
		},
	}

	log.Fatal(server.ListenAndServe())
}

If I connect to this server by ssh -R0:localhost:9999 server-ip I get this message on my terminal: attempt to bind localhost 0 granted.

Now, does this library choose a random port, and if yes how can I access it?

@smoqadam smoqadam closed this as completed Sep 2, 2023
@mohammed90
Copy link

For the sake of xkcd 979, do you have an answer?

@smoqadam
Copy link
Author

smoqadam commented Sep 2, 2023

@mohammed90 I ended up using "golang.org/x/crypto/ssh" package, and checking for the requested port if it's 0 I chose a random port. Here is a rough overview of what I've done to achieve this:

    type remoteForwardRequest struct {
	BindAddr string
	BindPort uint32
    }

	srvCon, channs, reqChannel, err := ssh.NewServerConn(conn, config)
        .... 
        req := <-reqChannel
	var reqPayload remoteForwardRequest
	ssh.Unmarshal(req.Payload, &reqPayload)
        port := reqPayload.BindPort
        if port == 0 {
             port = randomPort()
        } 

I took the logic from here: https://github.com/gliderlabs/ssh/blob/master/tcpip.go#L97


After digging a bit more and based on SSH manual page, if the listen port is 0 the server should inform the client by sending the dynamically allocated port. We can achieve that by this:

	if port == 0 {
		port = randomPort()
	}
	replyPayload := make([]byte, 4)
	binary.BigEndian.PutUint32(replyPayload, uint32(port))
	req.Reply(true, replyPayload)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants