From 5d8d32a3178133a7023f4e86238b83977fc8375a Mon Sep 17 00:00:00 2001 From: djm Date: Wed, 17 Dec 2003 05:33:10 +0000 Subject: [PATCH] - markus@cvs.openbsd.org 2003/12/16 15:49:51 [clientloop.c clientloop.h readconf.c readconf.h scp.1 sftp.1 ssh.1] [ssh.c ssh_config.5] application layer keep alive (ServerAliveInterval ServerAliveCountMax) for ssh(1), similar to the sshd(8) option; ok beck@; with help from jmc and dtucker@ --- ChangeLog | 6 ++++++ clientloop.c | 45 +++++++++++++++++++++++++++++++++++++-------- clientloop.h | 4 ++-- readconf.c | 21 +++++++++++++++++++-- readconf.h | 4 +++- scp.1 | 4 +++- sftp.1 | 4 +++- ssh.1 | 4 +++- ssh.c | 9 +++------ ssh_config.5 | 38 +++++++++++++++++++++++++++++++++++++- 10 files changed, 116 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index fb34576f..056fa3fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,12 @@ - markus@cvs.openbsd.org 2003/12/14 12:37:21 [ssh_config.5] we don't support GSS KEX; from Simon Wilkinson + - markus@cvs.openbsd.org 2003/12/16 15:49:51 + [clientloop.c clientloop.h readconf.c readconf.h scp.1 sftp.1 ssh.1] + [ssh.c ssh_config.5] + application layer keep alive (ServerAliveInterval ServerAliveCountMax) + for ssh(1), similar to the sshd(8) option; ok beck@; with help from + jmc and dtucker@ 20031209 - (dtucker) OpenBSD CVS Sync diff --git a/clientloop.c b/clientloop.c index 67b9dfce..626b29a5 100644 --- a/clientloop.c +++ b/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.116 2003/12/09 23:45:32 dtucker Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.117 2003/12/16 15:49:51 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -127,6 +127,7 @@ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ static int need_rekeying; /* Set to non-zero if rekeying is requested. */ static int session_closed = 0; /* In SSH2: login session closed. */ +static int server_alive_timeouts = 0; static void client_init_dispatch(void); int session_ident = -1; @@ -313,6 +314,24 @@ client_check_window_change(void) } } +static void +client_global_request_reply(int type, u_int32_t seq, void *ctxt) +{ + server_alive_timeouts = 0; + client_global_request_reply_fwd(type, seq, ctxt); +} + +static void +server_alive_check(void) +{ + if (++server_alive_timeouts > options.server_alive_count_max) + packet_disconnect("Timeout, server not responding."); + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("keepalive@openssh.com"); + packet_put_char(1); /* boolean: want reply */ + packet_send(); +} + /* * Waits until the client can do something (some data becomes available on * one of the file descriptors). @@ -322,6 +341,9 @@ static void client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, int *nallocp, int rekeying) { + struct timeval tv, *tvp; + int ret; + /* Add any selections by the channel mechanism. */ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); @@ -363,13 +385,18 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, /* * Wait for something to happen. This will suspend the process until * some selected descriptor can be read, written, or has some other - * event pending. Note: if you want to implement SSH_MSG_IGNORE - * messages to fool traffic analysis, this might be the place to do - * it: just have a random timeout for the select, and send a random - * SSH_MSG_IGNORE packet when the timeout expires. + * event pending. */ - if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { + if (options.server_alive_interval == 0 || !compat20) + tvp = NULL; + else { + tv.tv_sec = options.server_alive_interval; + tv.tv_usec = 0; + tvp = &tv; + } + ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); + if (ret < 0) { char buf[100]; /* @@ -386,7 +413,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; - } + } else if (ret == 0) + server_alive_check(); } static void @@ -1365,7 +1393,8 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) rtype = packet_get_string(NULL); want_reply = packet_get_char(); - debug("client_input_global_request: rtype %s want_reply %d", rtype, want_reply); + debug("client_input_global_request: rtype %s want_reply %d", + rtype, want_reply); if (want_reply) { packet_start(success ? SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); diff --git a/clientloop.h b/clientloop.h index 8056a40c..56af06bc 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.7 2002/04/22 21:04:52 markus Exp $ */ +/* $OpenBSD: clientloop.h,v 1.8 2003/12/16 15:49:51 markus Exp $ */ /* * Author: Tatu Ylonen @@ -37,4 +37,4 @@ /* Client side main loop for the interactive session. */ int client_loop(int, int, int); -void client_global_request_reply(int type, u_int32_t seq, void *ctxt); +void client_global_request_reply_fwd(int, u_int32_t, void *); diff --git a/readconf.c b/readconf.c index cd2c8144..2591e0db 100644 --- a/readconf.c +++ b/readconf.c @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: readconf.c,v 1.126 2003/12/09 21:53:36 markus Exp $"); +RCSID("$OpenBSD: readconf.c,v 1.127 2003/12/16 15:49:51 markus Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -105,6 +105,7 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, + oServerAliveInterval, oServerAliveCountMax, oDeprecated, oUnsupported } OpCodes; @@ -189,6 +190,8 @@ static struct { { "rekeylimit", oRekeyLimit }, { "connecttimeout", oConnectTimeout }, { "addressfamily", oAddressFamily }, + { "serveraliveinterval", oServerAliveInterval }, + { "serveralivecountmax", oServerAliveCountMax }, { NULL, oBadOption } }; @@ -307,7 +310,7 @@ process_config_line(Options *options, const char *host, /* NOTREACHED */ case oConnectTimeout: intptr = &options->connection_timeout; -/* parse_time: */ +parse_time: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%s line %d: missing time value.", @@ -733,6 +736,14 @@ parse_int: intptr = &options->enable_ssh_keysign; goto parse_flag; + case oServerAliveInterval: + intptr = &options->server_alive_interval; + goto parse_time; + + case oServerAliveCountMax: + intptr = &options->server_alive_count_max; + goto parse_int; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -860,6 +871,8 @@ initialize_options(Options * options) options->no_host_authentication_for_localhost = - 1; options->rekey_limit = - 1; options->verify_host_key_dns = -1; + options->server_alive_interval = -1; + options->server_alive_count_max = -1; } /* @@ -974,6 +987,10 @@ fill_default_options(Options * options) options->rekey_limit = 0; if (options->verify_host_key_dns == -1) options->verify_host_key_dns = 0; + if (options->server_alive_interval == -1) + options->server_alive_interval = 0; + if (options->server_alive_count_max == -1) + options->server_alive_count_max = 3; /* options->proxy_command should not be set by default */ /* options->user will be set in the main program if appropriate */ /* options->hostname will be set in the main program if appropriate */ diff --git a/readconf.h b/readconf.h index f2a859fb..3f27af96 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.58 2003/12/09 21:53:36 markus Exp $ */ +/* $OpenBSD: readconf.h,v 1.59 2003/12/16 15:49:51 markus Exp $ */ /* * Author: Tatu Ylonen @@ -100,6 +100,8 @@ typedef struct { int enable_ssh_keysign; int rekey_limit; int no_host_authentication_for_localhost; + int server_alive_interval; + int server_alive_count_max; } Options; diff --git a/scp.1 b/scp.1 index cbebb949..f5ca1e45 100644 --- a/scp.1 +++ b/scp.1 @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.31 2003/12/09 21:53:36 markus Exp $ +.\" $OpenBSD: scp.1,v 1.32 2003/12/16 15:49:51 markus Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -149,6 +149,8 @@ For full details of the options listed below, and their possible values, see .It PubkeyAuthentication .It RhostsRSAAuthentication .It RSAAuthentication +.It ServerAliveInterval +.It ServerAliveCountMax .It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive diff --git a/sftp.1 b/sftp.1 index 91a288df..8563e2bd 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.48 2003/12/09 21:53:37 markus Exp $ +.\" $OpenBSD: sftp.1,v 1.49 2003/12/16 15:49:51 markus Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -170,6 +170,8 @@ For full details of the options listed below, and their possible values, see .It PubkeyAuthentication .It RhostsRSAAuthentication .It RSAAuthentication +.It ServerAliveInterval +.It ServerAliveCountMax .It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive diff --git a/ssh.1 b/ssh.1 index 33521268..e2cd5d34 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,7 @@ .\" (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: ssh.1,v 1.180 2003/12/09 21:53:37 markus Exp $ +.\" $OpenBSD: ssh.1,v 1.181 2003/12/16 15:49:51 markus Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -648,6 +648,8 @@ For full details of the options listed below, and their possible values, see .It RemoteForward .It RhostsRSAAuthentication .It RSAAuthentication +.It ServerAliveInterval +.It ServerAliveCountMax .It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive diff --git a/ssh.c b/ssh.c index 222aaab7..da390c12 100644 --- a/ssh.c +++ b/ssh.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.205 2003/12/09 17:30:05 markus Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.206 2003/12/16 15:49:51 markus Exp $"); #include #include @@ -1029,16 +1029,13 @@ client_subsystem_reply(int type, u_int32_t seq, void *ctxt) } void -client_global_request_reply(int type, u_int32_t seq, void *ctxt) +client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) { int i; i = client_global_request_id++; - if (i >= options.num_remote_forwards) { - debug("client_global_request_reply: too many replies %d > %d", - i, options.num_remote_forwards); + if (i >= options.num_remote_forwards) return; - } debug("remote forward %s for: listen %d, connect %s:%d", type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", options.remote_forwards[i].port, diff --git a/ssh_config.5 b/ssh_config.5 index cb26eab6..210da059 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,7 +34,7 @@ .\" (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: ssh_config.5,v 1.27 2003/12/14 12:37:21 markus Exp $ +.\" $OpenBSD: ssh_config.5,v 1.28 2003/12/16 15:49:51 markus Exp $ .Dd September 25, 1999 .Dt SSH_CONFIG 5 .Os @@ -552,6 +552,42 @@ running. The default is .Dq yes . Note that this option applies to protocol version 1 only. +.It Cm ServerAliveInterval +Sets a timeout interval in seconds after which if no data has been received +from the server, +.Nm ssh +will send a message through the encrypted +channel to request a response from the server. +The default +is 0, indicating that these messages will not be sent to the server. +This option applies to protocol version 2 only. +.It Cm ServerAliveCountMax +Sets the number of server alive messages (see above) which may be +sent without +.Nm ssh +receiving any messages back from the server. +If this threshold is reached while server alive messages are being sent, +.Nm ssh +will disconnect from the server, terminating the session. +It is important to note that the use of server alive messages is very +different from +.Cm TCPKeepAlive +(below). +The server alive messages are sent through the encrypted channel +and therefore will not be spoofable. +The TCP keepalive option enabled by +.Cm TCPKeepAlive +is spoofable. +The server alive mechanism is valuable when the client or +server depend on knowing when a connection has become inactive. +.Pp +The default value is 3. +If, for example, +.Cm ServerAliveInterval +(above) is set to 15, and +.Cm ServerAliveCountMax +is left at the default, if the server becomes unresponsive ssh +will disconnect after approximately 45 seconds. .It Cm SmartcardDevice Specifies which smartcard device to use. The argument to this keyword is the device -- 2.45.1