diff --git a/client/client.go b/client/client.go index c9cfccc..5710809 100644 --- a/client/client.go +++ b/client/client.go @@ -106,6 +106,10 @@ func NewClient(c *Config) (*Client, error) { } hasStdio = true } + //confirm non-reverse tunnel is available + if !r.Reverse && !r.CanListen() { + return nil, fmt.Errorf("Remote %s cannot listen", r.String()) + } client.computed.Remotes = append(client.computed.Remotes, r) } //set default log level diff --git a/server/server_handler.go b/server/server_handler.go index e1ba8b1..79ac9a3 100644 --- a/server/server_handler.go +++ b/server/server_handler.go @@ -109,24 +109,28 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, req *http.Request) { l.Infof("Client version (%s) differs from server version (%s)", v, chshare.BuildVersion) } - //confirm reverse tunnels are allowed + //validate remotes for _, r := range c.Remotes { - if r.Reverse && !s.config.Reverse { - l.Debugf("Denied reverse port forwarding request, please enable --reverse") - failed(s.Errorf("Reverse port forwaring not enabled on server")) - return - } - } - //if user is provided, ensure they have - //access to the desired remotes - if user != nil { - for _, r := range c.Remotes { + //if user is provided, ensure they have + //access to the desired remotes + if user != nil { addr := r.UserAddr() if !user.HasAccess(addr) { failed(s.Errorf("access to '%s' denied", addr)) return } } + //confirm reverse tunnels are allowed + if r.Reverse && !s.config.Reverse { + l.Debugf("Denied reverse port forwarding request, please enable --reverse") + failed(s.Errorf("Reverse port forwaring not enabled on server")) + return + } + //confirm reverse tunnel is available + if r.Reverse && !r.CanListen() { + failed(s.Errorf("Remote %s cannot listen", r.String())) + return + } } //successfuly validated config! r.Reply(true, nil) diff --git a/share/settings/remote.go b/share/settings/remote.go index 58fa64e..928954b 100644 --- a/share/settings/remote.go +++ b/share/settings/remote.go @@ -2,6 +2,7 @@ package settings import ( "errors" + "net" "net/url" "regexp" "strconv" @@ -223,6 +224,33 @@ func (r Remote) UserAddr() string { return r.RemoteHost + ":" + r.RemotePort } +//CanListen checks if the port can be listened on +func (r Remote) CanListen() bool { + switch r.LocalProto { + case "tcp": + //valid + conn, err := net.Listen("tcp", r.Local()) + if err == nil { + conn.Close() + return true + } + return false + case "udp": + addr, err := net.ResolveUDPAddr("udp", r.Local()) + if err != nil { + return false + } + conn, err := net.ListenUDP(r.LocalProto, addr) + if err == nil { + conn.Close() + return true + } + return false + } + //invalid + return false +} + type Remotes []*Remote //Filter out forward reversed/non-reversed remotes diff --git a/share/tunnel/tunnel_in_proxy.go b/share/tunnel/tunnel_in_proxy.go index 07b04d7..b267e59 100644 --- a/share/tunnel/tunnel_in_proxy.go +++ b/share/tunnel/tunnel_in_proxy.go @@ -52,14 +52,14 @@ func (p *Proxy) listen() error { if err != nil { return p.Errorf("tcp: %s", err) } - p.Debugf("Listening") + p.Infof("Listening") p.tcp = l } else if p.remote.LocalProto == "udp" { l, err := listenUDP(p.Logger, p.sshTun, p.remote) if err != nil { return err } - p.Debugf("Listening") + p.Infof("Listening") p.udp = l } else { return p.Errorf("unknown local proto") @@ -70,7 +70,6 @@ func (p *Proxy) listen() error { //Run enables the proxy and blocks while its active, //close the proxy by cancelling the context. func (p *Proxy) Run(ctx context.Context) error { - defer p.Debugf("Closed") if p.remote.Stdio { return p.runStdio(ctx) } else if p.remote.LocalProto == "tcp" { @@ -82,6 +81,7 @@ func (p *Proxy) Run(ctx context.Context) error { } func (p *Proxy) runStdio(ctx context.Context) error { + defer p.Infof("Closed") for { p.pipeRemote(ctx, cio.Stdio) select { diff --git a/share/tunnel/tunnel_in_proxy_udp.go b/share/tunnel/tunnel_in_proxy_udp.go index f244195..35811c5 100644 --- a/share/tunnel/tunnel_in_proxy_udp.go +++ b/share/tunnel/tunnel_in_proxy_udp.go @@ -13,6 +13,7 @@ import ( "github.com/jpillora/chisel/share/cio" "github.com/jpillora/chisel/share/settings" + "github.com/jpillora/sizestr" "golang.org/x/crypto/ssh" "golang.org/x/sync/errgroup" ) @@ -59,6 +60,7 @@ type udpListener struct { } func (u *udpListener) run(ctx context.Context) error { + defer u.inbound.Close() //udp doesnt accept connections, //udp simply forwards packets //and therefore only needs to listen @@ -73,7 +75,7 @@ func (u *udpListener) run(ctx context.Context) error { u.Debugf("listen: %s", err) return err } - u.Debugf("sent %d, received %d", u.sent, u.recv) + u.Debugf("Close (sent %s received %s)", sizestr.ToString(u.sent), sizestr.ToString(u.recv)) return nil } diff --git a/test/e2e/setup_test.go b/test/e2e/setup_test.go index af2077e..9d36d15 100644 --- a/test/e2e/setup_test.go +++ b/test/e2e/setup_test.go @@ -119,7 +119,7 @@ func post(url, body string) (string, error) { } func availablePort() string { - l, err := net.Listen("tcp4", "127.0.0.1:0") + l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { log.Panic(err) }