ssh: remove nopty option, request shell by default

This commit is contained in:
Pavel 2023-11-21 20:02:07 +03:00
parent 725f650193
commit b89011c631
4 changed files with 38 additions and 47 deletions

View File

@ -39,14 +39,11 @@ servers:
# Set this to true if you're using sish, otherwise you'll get weird domains with IP's in them. # Set this to true if you're using sish, otherwise you'll get weird domains with IP's in them.
# Default: false # Default: false
fake_remote_host: true fake_remote_host: true
# Disables PTY request for this server. Default: false
nopty: true
# Requests interactive shell for SSH sessions. Should be `true` for the `commands`. # Requests interactive shell for SSH sessions. Should be `true` for the `commands`.
# You can also pass a string with shell binary, for example, "/bin/sh". # You can also pass a string with shell binary, for example, "/bin/sh".
# Note: commands will be executed using provided shell binary. # Note: commands will be executed using provided shell binary.
# Note (2): some servers won't send you any data until you request a shell even without a PTY. # Note (2): some servers won't send you any data until you request a shell.
# You can use a combination of `nopty: true` & `shell: true`. Also, even with PTY you may need `shell` to be `true`. # Default: true
# Default: false
shell: false shell: false
# Spoof client version with provided (value below is taken directly from OpenSSH). This value must be compliant with RFC-4253. # Spoof client version with provided (value below is taken directly from OpenSSH). This value must be compliant with RFC-4253.
# Default: SSH-2.0-Go # Default: SSH-2.0-Go
@ -97,7 +94,6 @@ servers:
address: "your2.server" address: "your2.server"
forward_port: 80 forward_port: 80
fake_remote_host: true fake_remote_host: true
nopty: false
shell: "/usr/bin/bash" shell: "/usr/bin/bash"
mode: single mode: single
keepalive: keepalive:

View File

@ -76,8 +76,7 @@ func (d *SSH) forward(val sshtun.Forward, domainMatcher func(string)) conn {
sshtun.TunnelConfig{ sshtun.TunnelConfig{
Forward: val, Forward: val,
HostKeyCallback: d.hostKeyCallback, HostKeyCallback: d.hostKeyCallback,
NoPTY: d.params.NoPTY, Shell: d.params.Shell,
Shell: sshtun.BoolOrStr(d.params.Shell),
ClientVersion: d.clientVersion, ClientVersion: d.clientVersion,
FakeRemoteHost: d.params.FakeRemoteHost, FakeRemoteHost: d.params.FakeRemoteHost,
KeepAliveInterval: uint(d.params.KeepAlive.Interval), KeepAliveInterval: uint(d.params.KeepAlive.Interval),

View File

@ -1,36 +1,31 @@
package ssh package ssh
import ( import (
"errors" "github.com/Neur0toxine/sshpoke/internal/server/driver/ssh/sshtun"
"github.com/Neur0toxine/sshpoke/internal/server/driver/ssh/types" "github.com/Neur0toxine/sshpoke/internal/server/driver/ssh/types"
"github.com/Neur0toxine/sshpoke/internal/server/driver/util" "github.com/Neur0toxine/sshpoke/internal/server/driver/util"
) )
type Params struct { type Params struct {
Address string `mapstructure:"address" validate:"required"` Address string `mapstructure:"address" validate:"required"`
HostKeys string `mapstructure:"host_keys"` HostKeys string `mapstructure:"host_keys"`
DefaultHost *string `mapstructure:"default_host,omitempty"` DefaultHost *string `mapstructure:"default_host,omitempty"`
ForwardPort uint16 `mapstructure:"forward_port"` ForwardPort uint16 `mapstructure:"forward_port"`
Auth types.Auth `mapstructure:"auth"` Auth types.Auth `mapstructure:"auth"`
KeepAlive types.KeepAlive `mapstructure:"keepalive"` KeepAlive types.KeepAlive `mapstructure:"keepalive"`
DomainExtractRegex string `mapstructure:"domain_extract_regex" validate:"validregexp"` DomainExtractRegex string `mapstructure:"domain_extract_regex" validate:"validregexp"`
ReadRawPackets bool `mapstructure:"read_raw_packets"` ReadRawPackets bool `mapstructure:"read_raw_packets"`
ReadSessionsOutput *bool `mapstructure:"read_sessions_output"` ReadSessionsOutput *bool `mapstructure:"read_sessions_output"`
Mode types.DomainMode `mapstructure:"mode" validate:"required,oneof=single multi"` Mode types.DomainMode `mapstructure:"mode" validate:"required,oneof=single multi"`
FakeRemoteHost bool `mapstructure:"fake_remote_host"` FakeRemoteHost bool `mapstructure:"fake_remote_host"`
NoPTY bool `mapstructure:"nopty"` Shell *sshtun.BoolOrStr `mapstructure:"shell"`
Shell string `mapstructure:"shell"` ClientVersion string `mapstructure:"client_version"`
ClientVersion string `mapstructure:"client_version"` Commands types.Commands `mapstructure:"commands"`
Commands types.Commands `mapstructure:"commands"`
} }
func (p *Params) Validate() error { func (p *Params) Validate() error {
if err := util.Validator.Struct(p); err != nil { if err := util.Validator.Struct(p); err != nil {
return err return err
} }
if p.NoPTY && (len(p.Commands.OnConnect) > 0 || len(p.Commands.OnDisconnect) > 0) {
return errors.New("commands aren't available without PTY (nopty = true)")
}
return p.Auth.Validate() return p.Auth.Validate()
} }

View File

@ -28,8 +28,7 @@ type Tunnel struct {
type TunnelConfig struct { type TunnelConfig struct {
Forward Forward Forward Forward
HostKeyCallback ssh.HostKeyCallback HostKeyCallback ssh.HostKeyCallback
NoPTY bool Shell *BoolOrStr
Shell BoolOrStr
ClientVersion string ClientVersion string
FakeRemoteHost bool FakeRemoteHost bool
KeepAliveInterval uint KeepAliveInterval uint
@ -38,16 +37,27 @@ type TunnelConfig struct {
type BoolOrStr string type BoolOrStr string
func (b BoolOrStr) IsBool() bool { func (b *BoolOrStr) IsBool() bool {
return b == "true" || b == "false" || b == "1" || b == "0" || b == "" if b == nil {
return false
}
v := *b
return v == "true" || v == "false" || v == "1" || v == "0" || v == ""
} }
func (b BoolOrStr) Falsy() bool { func (b *BoolOrStr) Falsy() bool {
return b == "" || b == "0" || b == "false" if b == nil {
return true
}
v := *b
return v == "" || v == "0" || v == "false"
} }
func (b BoolOrStr) String() string { func (b *BoolOrStr) String() string {
return string(b) if b == nil {
return ""
}
return string(*b)
} }
func New(address, user string, auth []ssh.AuthMethod, sc TunnelConfig, log *zap.SugaredLogger) *Tunnel { func New(address, user string, auth []ssh.AuthMethod, sc TunnelConfig, log *zap.SugaredLogger) *Tunnel {
@ -127,17 +137,8 @@ func (t *Tunnel) connect(ctx context.Context,
sessionCb = func(*ssh.Session) {} sessionCb = func(*ssh.Session) {}
} }
if !t.tunConfig.NoPTY { if t.tunConfig.Shell == nil || !t.tunConfig.Shell.Falsy() {
err = sess.RequestPty("xterm", 80, 40, ssh.TerminalModes{ if t.tunConfig.Shell == nil || t.tunConfig.Shell.IsBool() {
ssh.ECHO: 0,
ssh.IGNCR: 1,
})
if err != nil {
t.log.Warnf("PTY allocation failed: %s", err.Error())
}
}
if !t.tunConfig.Shell.Falsy() {
if t.tunConfig.Shell.IsBool() {
if err := sess.Shell(); err != nil { if err := sess.Shell(); err != nil {
t.log.Warnf("failed to start empty shell: %s", err.Error()) t.log.Warnf("failed to start empty shell: %s", err.Error())
} }