diff --git a/cmd/configs/config_template.yaml b/cmd/configs/config_template.yaml index 94f3198..4ed4e90 100644 --- a/cmd/configs/config_template.yaml +++ b/cmd/configs/config_template.yaml @@ -81,6 +81,8 @@ sshd: # if true no banner will be displayed while interacting # with the sshd server disable_banner: false + # if disabled, server will not allow forward and reverse tunnels + disable_tunnelling: false # OPTIONAL: default false. If set to true clients can connect without # any authentication form (so no keys and no passwords!). # Use with caution! diff --git a/pkg/sshd/channel_handler.go b/pkg/sshd/channel_handler.go index a623525..7e9245f 100644 --- a/pkg/sshd/channel_handler.go +++ b/pkg/sshd/channel_handler.go @@ -327,6 +327,10 @@ func (s *channelHandler) handleChannels() { // shell, exec and sft subsystem go s.serveChannelSession(newChannel) case "direct-tcpip": + if s.server.disableTunnelling { + newChannel.Reject(ssh.Prohibited, "tunnelling is disabled") + continue + } // used by forward requests go s.handleChannelDirect(newChannel) default: diff --git a/pkg/sshd/conf.go b/pkg/sshd/conf.go index ec0d6fc..ad0360b 100644 --- a/pkg/sshd/conf.go +++ b/pkg/sshd/conf.go @@ -19,6 +19,9 @@ type SshDConf struct { // If true the sftp subsystem will be disabled and no file transfer // will be allowed DisableSftpSubsystem bool `yaml:"disable_sftp_subsystem"` + // if disabled, forward and reverse tunnelling will be not allowed + // on this server + DisableTunnelling bool `yaml:"disable_tunnelling"` // shell executable. Leave empty for default behaviour ShellExecutable string `yaml:"shell_executable"` } diff --git a/pkg/sshd/request_handler.go b/pkg/sshd/request_handler.go index 646e304..07ab60c 100644 --- a/pkg/sshd/request_handler.go +++ b/pkg/sshd/request_handler.go @@ -12,6 +12,7 @@ import ( ) type requestHandler struct { + server *sshServer sshConn *ssh.ServerConn reqs <-chan *ssh.Request @@ -22,8 +23,9 @@ type requestHandler struct { forwardsKeepAliveInterval time.Duration } -func newRequestHandler(sshConn *ssh.ServerConn, reqs <-chan *ssh.Request) *requestHandler { +func newRequestHandler(server *sshServer, sshConn *ssh.ServerConn, reqs <-chan *ssh.Request) *requestHandler { return &requestHandler{ + server: server, sshConn: sshConn, reqs: reqs, forwards: make(map[string]net.Listener), @@ -113,9 +115,17 @@ func (r *requestHandler) handleRequests() { for req := range r.reqs { switch req.Type { case "tcpip-forward": + if r.server.disableTunnelling { + req.Reply(false, nil) + continue + } r.tcpipForwardHandler(req) case "cancel-tcpip-forward": + if r.server.disableTunnelling { + req.Reply(false, nil) + continue + } r.cancelTcpIpForwardHandler(req) default: if strings.Contains(req.Type, "keepalive") { diff --git a/pkg/sshd/server.go b/pkg/sshd/server.go index 95a663c..de77991 100644 --- a/pkg/sshd/server.go +++ b/pkg/sshd/server.go @@ -29,6 +29,7 @@ type sshServer struct { disableAuth bool disableBanner bool disableSftpSubsystem bool + disableTunnelling bool shellExecutable string @@ -82,8 +83,10 @@ func NewSshServer(conf *SshDConf) *sshServer { disableBanner: conf.DisableBanner, disableSftpSubsystem: conf.DisableSftpSubsystem, disableAuth: conf.DisableAuth, - listenAddress: &conf.ListenAddress, - activeSessions: 0, + disableTunnelling: conf.DisableTunnelling, + + listenAddress: &conf.ListenAddress, + activeSessions: 0, } // run here, to make sure I have a valid authorized keys // file on start @@ -211,7 +214,7 @@ func (s *sshServer) serveConnection(conn net.Conn, config ssh.ServerConfig) { log.Println("logged in WITHOUT authentication") } - requestHandler := newRequestHandler(sshConn, reqs) + requestHandler := newRequestHandler(s, sshConn, reqs) go requestHandler.handleRequests() channelHandler := newChannelHandler(