upstream: Add a sshd_config UnusedConnectionTimeout option to terminate
client connections that have no open channels for some length of time. This complements the recently-added ChannelTimeout option that terminates inactive channels after a timeout. ok markus@ OpenBSD-Commit-ID: ca983be74c0350364c11f8ba3bd692f6f24f5da9
This commit is contained in:
parent
8ec2e31238
commit
0293c19807
25
servconf.c
25
servconf.c
|
@ -1,5 +1,5 @@
|
|||
|
||||
/* $OpenBSD: servconf.c,v 1.389 2023/01/06 02:47:18 djm Exp $ */
|
||||
/* $OpenBSD: servconf.c,v 1.390 2023/01/17 09:44:48 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
* All rights reserved
|
||||
|
@ -198,6 +198,7 @@ initialize_server_options(ServerOptions *options)
|
|||
options->required_rsa_size = -1;
|
||||
options->channel_timeouts = NULL;
|
||||
options->num_channel_timeouts = 0;
|
||||
options->unused_connection_timeout = -1;
|
||||
}
|
||||
|
||||
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
|
||||
|
@ -446,6 +447,8 @@ fill_default_server_options(ServerOptions *options)
|
|||
options->sk_provider = xstrdup("internal");
|
||||
if (options->required_rsa_size == -1)
|
||||
options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
|
||||
if (options->unused_connection_timeout == -1)
|
||||
options->unused_connection_timeout = 0;
|
||||
|
||||
assemble_algorithms(options);
|
||||
|
||||
|
@ -529,7 +532,7 @@ typedef enum {
|
|||
sStreamLocalBindMask, sStreamLocalBindUnlink,
|
||||
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
|
||||
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
|
||||
sRequiredRSASize, sChannelTimeout,
|
||||
sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
|
||||
sDeprecated, sIgnore, sUnsupported
|
||||
} ServerOpCodes;
|
||||
|
||||
|
@ -691,6 +694,7 @@ static struct {
|
|||
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
|
||||
{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
|
||||
{ "channeltimeout", sChannelTimeout, SSHCFG_ALL },
|
||||
{ "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
|
||||
{ NULL, sBadOption, 0 }
|
||||
};
|
||||
|
||||
|
@ -2537,6 +2541,17 @@ process_server_config_line_depth(ServerOptions *options, char *line,
|
|||
}
|
||||
break;
|
||||
|
||||
case sUnusedConnectionTimeout:
|
||||
intptr = &options->unused_connection_timeout;
|
||||
/* peek at first arg for "none" so we can reuse parse_time */
|
||||
if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
|
||||
(void)argv_next(&ac, &av); /* consume arg */
|
||||
if (*activep)
|
||||
*intptr = 0;
|
||||
break;
|
||||
}
|
||||
goto parse_time;
|
||||
|
||||
case sDeprecated:
|
||||
case sIgnore:
|
||||
case sUnsupported:
|
||||
|
@ -2709,6 +2724,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
|
|||
M_CP_INTOPT(rekey_interval);
|
||||
M_CP_INTOPT(log_level);
|
||||
M_CP_INTOPT(required_rsa_size);
|
||||
M_CP_INTOPT(unused_connection_timeout);
|
||||
|
||||
/*
|
||||
* The bind_mask is a mode_t that may be unsigned, so we can't use
|
||||
|
@ -2861,6 +2877,10 @@ fmt_intarg(ServerOpCodes code, int val)
|
|||
static void
|
||||
dump_cfg_int(ServerOpCodes code, int val)
|
||||
{
|
||||
if (code == sUnusedConnectionTimeout && val == 0) {
|
||||
printf("%s none\n", lookup_opcode_name(code));
|
||||
return;
|
||||
}
|
||||
printf("%s %d\n", lookup_opcode_name(code), val);
|
||||
}
|
||||
|
||||
|
@ -2977,6 +2997,7 @@ dump_config(ServerOptions *o)
|
|||
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
|
||||
dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
|
||||
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
|
||||
dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
|
||||
|
||||
/* formatted integer arguments */
|
||||
dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: servconf.h,v 1.158 2023/01/06 02:47:19 djm Exp $ */
|
||||
/* $OpenBSD: servconf.h,v 1.159 2023/01/17 09:44:48 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
|
@ -233,6 +233,8 @@ typedef struct {
|
|||
|
||||
char **channel_timeouts; /* inactivity timeout by channel type */
|
||||
u_int num_channel_timeouts;
|
||||
|
||||
int unused_connection_timeout;
|
||||
} ServerOptions;
|
||||
|
||||
/* Information about the incoming connection as used by Match */
|
||||
|
|
33
serverloop.c
33
serverloop.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: serverloop.c,v 1.233 2023/01/06 02:38:23 djm Exp $ */
|
||||
/* $OpenBSD: serverloop.c,v 1.234 2023/01/17 09:44:48 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -172,17 +172,19 @@ wait_until_can_do_something(struct ssh *ssh,
|
|||
int *conn_in_readyp, int *conn_out_readyp)
|
||||
{
|
||||
struct timespec timeout;
|
||||
char remote_id[512];
|
||||
int ret;
|
||||
int client_alive_scheduled = 0;
|
||||
u_int p;
|
||||
/* time we last heard from the client OR sent a keepalive */
|
||||
static time_t last_client_time;
|
||||
time_t now;
|
||||
static time_t last_client_time, unused_connection_expiry;
|
||||
|
||||
*conn_in_readyp = *conn_out_readyp = 0;
|
||||
|
||||
/* Prepare channel poll. First two pollfd entries are reserved */
|
||||
ptimeout_init(&timeout);
|
||||
channel_prepare_poll(ssh, pfdp, npfd_allocp, npfd_activep, 2, &timeout);
|
||||
now = monotime();
|
||||
if (*npfd_activep < 2)
|
||||
fatal_f("bad npfd %u", *npfd_activep); /* shouldn't happen */
|
||||
if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh)) {
|
||||
|
@ -190,6 +192,18 @@ wait_until_can_do_something(struct ssh *ssh,
|
|||
ssh_packet_get_rekey_timeout(ssh));
|
||||
}
|
||||
|
||||
/*
|
||||
* If no channels are open and UnusedConnectionTimeout is set, then
|
||||
* start the clock to terminate the connection.
|
||||
*/
|
||||
if (options.unused_connection_timeout != 0) {
|
||||
if (channel_still_open(ssh) || unused_connection_expiry == 0) {
|
||||
unused_connection_expiry = now +
|
||||
options.unused_connection_timeout;
|
||||
}
|
||||
ptimeout_deadline_monotime(&timeout, unused_connection_expiry);
|
||||
}
|
||||
|
||||
/*
|
||||
* if using client_alive, set the max timeout accordingly,
|
||||
* and indicate that this particular timeout was for client
|
||||
|
@ -199,8 +213,9 @@ wait_until_can_do_something(struct ssh *ssh,
|
|||
* analysis more difficult, but we're not doing it yet.
|
||||
*/
|
||||
if (options.client_alive_interval) {
|
||||
/* Time we last heard from the client OR sent a keepalive */
|
||||
if (last_client_time == 0)
|
||||
last_client_time = monotime();
|
||||
last_client_time = now;
|
||||
ptimeout_deadline_sec(&timeout, options.client_alive_interval);
|
||||
/* XXX ? deadline_monotime(last_client_time + alive_interval) */
|
||||
client_alive_scheduled = 1;
|
||||
|
@ -237,9 +252,9 @@ wait_until_can_do_something(struct ssh *ssh,
|
|||
*conn_in_readyp = (*pfdp)[0].revents != 0;
|
||||
*conn_out_readyp = (*pfdp)[1].revents != 0;
|
||||
|
||||
now = monotime(); /* need to reset after ppoll() */
|
||||
/* ClientAliveInterval probing */
|
||||
if (client_alive_scheduled) {
|
||||
time_t now = monotime();
|
||||
if (ret == 0 &&
|
||||
now > last_client_time + options.client_alive_interval) {
|
||||
/* ppoll timed out and we're due to probe */
|
||||
|
@ -250,6 +265,14 @@ wait_until_can_do_something(struct ssh *ssh,
|
|||
last_client_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
/* UnusedConnectionTimeout handling */
|
||||
if (unused_connection_expiry != 0 &&
|
||||
now > unused_connection_expiry && !channel_still_open(ssh)) {
|
||||
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
|
||||
logit("terminating inactive connection from %s", remote_id);
|
||||
cleanup_exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: sshd_config.5,v 1.345 2023/01/06 08:44:11 jmc Exp $
|
||||
.Dd $Mdocdate: January 6 2023 $
|
||||
.\" $OpenBSD: sshd_config.5,v 1.346 2023/01/17 09:44:48 djm Exp $
|
||||
.Dd $Mdocdate: January 17 2023 $
|
||||
.Dt SSHD_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -459,6 +459,9 @@ close the SSH connection, nor does it prevent a client from
|
|||
requesting another channel of the same type.
|
||||
In particular, expiring an inactive forwarding session does not prevent
|
||||
another identical forwarding from being subsequently created.
|
||||
See also
|
||||
.Cm UnusedConnectionTimeout ,
|
||||
which may be used in conjunction with this option.
|
||||
.Pp
|
||||
The default is not to expire channels of any type for inactivity.
|
||||
.It Cm ChrootDirectory
|
||||
|
@ -1256,6 +1259,7 @@ Available keywords are
|
|||
.Cm AuthorizedPrincipalsFile ,
|
||||
.Cm Banner ,
|
||||
.Cm CASignatureAlgorithms ,
|
||||
.Cm ChannelTimeout ,
|
||||
.Cm ChrootDirectory ,
|
||||
.Cm ClientAliveCountMax ,
|
||||
.Cm ClientAliveInterval ,
|
||||
|
@ -1295,6 +1299,7 @@ Available keywords are
|
|||
.Cm StreamLocalBindMask ,
|
||||
.Cm StreamLocalBindUnlink ,
|
||||
.Cm TrustedUserCAKeys ,
|
||||
.Cm UnusedConnectionTimeout ,
|
||||
.Cm X11DisplayOffset ,
|
||||
.Cm X11Forwarding
|
||||
and
|
||||
|
@ -1811,6 +1816,33 @@ for authentication using
|
|||
.Cm TrustedUserCAKeys .
|
||||
For more details on certificates, see the CERTIFICATES section in
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Cm UnusedConnectionTimeout
|
||||
Specifies whether and how quickly
|
||||
.Xr sshd 8
|
||||
should close client connections with no open channels.
|
||||
Open channels include active shell, command execution or subsystem
|
||||
sessions, connected network, socket, agent of X11 forwardings.
|
||||
Forwarding listeners, such as those from the
|
||||
.Xr ssh 1
|
||||
.Fl R
|
||||
flag are not considered as open channels and do not prevent the timeout.
|
||||
The timeout value
|
||||
is specified in seconds or may use any of the units documented in the
|
||||
.Sx TIME FORMATS
|
||||
section.
|
||||
.Pp
|
||||
Note that this timeout starts when the client connection completes
|
||||
user authentication but before the client has an opportunity to open any
|
||||
channels.
|
||||
Caution should be used when using short timeout values, as they may not
|
||||
provide sufficient time for the client to request and open its channels
|
||||
before terminating the connection.
|
||||
.Pp
|
||||
The default
|
||||
.Cm none
|
||||
is to never expire connections for having no open channels.
|
||||
This option may be useful in conjunction with
|
||||
.Cm ChannelTimeout .
|
||||
.It Cm UseDNS
|
||||
Specifies whether
|
||||
.Xr sshd 8
|
||||
|
|
Loading…
Reference in New Issue