summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/channels.c37
-rw-r--r--usr.bin/ssh/channels.h4
-rw-r--r--usr.bin/ssh/servconf.c20
-rw-r--r--usr.bin/ssh/servconf.h11
-rw-r--r--usr.bin/ssh/serverloop.c64
-rw-r--r--usr.bin/ssh/sshd.827
6 files changed, 152 insertions, 11 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 0ba7199d47b..006f395885b 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -40,7 +40,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.106 2001/04/11 13:56:13 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.107 2001/04/13 22:46:52 beck Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
@@ -1843,6 +1843,41 @@ channel_still_open()
return 0;
}
+/* Returns the id of an open channel suitable for keepaliving */
+
+int
+channel_find_open()
+{
+ u_int i;
+ for (i = 0; i < channels_alloc; i++)
+ switch (channels[i].type) {
+ case SSH_CHANNEL_CLOSED:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_CONNECTING: /* XXX ??? */
+ case SSH_CHANNEL_FREE:
+ case SSH_CHANNEL_X11_LISTENER:
+ case SSH_CHANNEL_PORT_LISTENER:
+ case SSH_CHANNEL_RPORT_LISTENER:
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return i;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return i;
+ default:
+ fatal("channel_find_open: bad channel type %d", channels[i].type);
+ /* NOTREACHED */
+ }
+ return -1;
+}
+
+
/*
* Returns a message describing the currently open forwarded connections,
* suitable for sending to the client. The message contains crlf pairs for
diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h
index 23e6ece839d..bf70a8f215b 100644
--- a/usr.bin/ssh/channels.h
+++ b/usr.bin/ssh/channels.h
@@ -32,7 +32,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.
*/
-/* RCSID("$OpenBSD: channels.h,v 1.30 2001/04/07 08:55:17 markus Exp $"); */
+/* RCSID("$OpenBSD: channels.h,v 1.31 2001/04/13 22:46:53 beck Exp $"); */
#ifndef CHANNELS_H
#define CHANNELS_H
@@ -307,4 +307,6 @@ int channel_connect_to(const char *host, u_short host_port);
int channel_connect_by_listen_adress(u_short listen_port);
int x11_connect_display(void);
+int channel_find_open(void);
+
#endif
diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c
index f3d5068c012..f978c632b30 100644
--- a/usr.bin/ssh/servconf.c
+++ b/usr.bin/ssh/servconf.c
@@ -10,7 +10,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.76 2001/04/12 20:09:37 stevesk Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.77 2001/04/13 22:46:53 beck Exp $");
#ifdef KRB4
#include <krb.h>
@@ -99,6 +99,8 @@ initialize_server_options(ServerOptions *options)
options->max_startups = -1;
options->banner = NULL;
options->reverse_mapping_check = -1;
+ options->client_alive_interval = -1;
+ options->client_alive_count_max = -1;
}
void
@@ -201,6 +203,10 @@ fill_default_server_options(ServerOptions *options)
options->max_startups_begin = options->max_startups;
if (options->reverse_mapping_check == -1)
options->reverse_mapping_check = 0;
+ if (options->client_alive_interval == -1)
+ options->client_alive_interval = 0;
+ if (options->client_alive_count_max == -1)
+ options->client_alive_count_max = 3;
}
/* Keyword tokens. */
@@ -225,7 +231,8 @@ typedef enum {
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
sBanner, sReverseMappingCheck, sHostbasedAuthentication,
- sHostbasedUsesNameFromPacketOnly
+ sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+ sClientAliveCountMax
} ServerOpCodes;
/* Textual representation of the tokens. */
@@ -289,6 +296,8 @@ static struct {
{ "maxstartups", sMaxStartups },
{ "banner", sBanner },
{ "reversemappingcheck", sReverseMappingCheck },
+ { "clientaliveinterval", sClientAliveInterval },
+ { "clientalivecountmax", sClientAliveCountMax },
{ NULL, 0 }
};
@@ -792,7 +801,12 @@ parse_flag:
case sBanner:
charptr = &options->banner;
goto parse_filename;
-
+ case sClientAliveInterval:
+ intptr = &options->client_alive_interval;
+ goto parse_int;
+ case sClientAliveCountMax:
+ intptr = &options->client_alive_count_max;
+ goto parse_int;
default:
fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n",
filename, linenum, arg, opcode);
diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h
index 9b3a60f08f7..4c02c0f5218 100644
--- a/usr.bin/ssh/servconf.h
+++ b/usr.bin/ssh/servconf.h
@@ -11,7 +11,7 @@
* called by a name other than "ssh" or "Secure Shell".
*/
-/* RCSID("$OpenBSD: servconf.h,v 1.40 2001/04/12 19:15:25 markus Exp $"); */
+/* RCSID("$OpenBSD: servconf.h,v 1.41 2001/04/13 22:46:53 beck Exp $"); */
#ifndef SERVCONF_H
#define SERVCONF_H
@@ -115,6 +115,15 @@ typedef struct {
int max_startups;
char *banner; /* SSH-2 banner message */
int reverse_mapping_check; /* cross-check ip and dns */
+ int client_alive_interval; /*
+ * poke the client this often to
+ * see if it's still there
+ */
+ int client_alive_count_max; /*
+ *If the client is unresponsive
+ * for this many intervals, above
+ * diconnect the session
+ */
} ServerOptions;
/*
diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c
index d1a24252d9e..8bd2c000a06 100644
--- a/usr.bin/ssh/serverloop.c
+++ b/usr.bin/ssh/serverloop.c
@@ -35,7 +35,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.60 2001/04/05 23:39:20 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.61 2001/04/13 22:46:54 beck Exp $");
#include "xmalloc.h"
#include "packet.h"
@@ -91,6 +91,8 @@ static volatile int child_wait_status; /* Status from wait(). */
void server_init_dispatch(void);
+int client_alive_timeouts = 0;
+
void
sigchld_handler(int sig)
{
@@ -190,6 +192,21 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
{
struct timeval tv, *tvp;
int ret;
+ int client_alive_scheduled = 0;
+
+ /*
+ * if using client_alive, set the max timeout accordingly,
+ * and indicate that this particular timeout was for client
+ * alive by setting the client_alive_scheduled flag.
+ *
+ * this could be randomized somewhat to make traffic
+ * analysis more difficult, but we're not doing it yet.
+ */
+ if (max_time_milliseconds == 0 && options.client_alive_interval) {
+ client_alive_scheduled = 1;
+ max_time_milliseconds = options.client_alive_interval * 1000;
+ } else
+ client_alive_scheduled = 0;
/* When select fails we restart from here. */
retry_select:
@@ -239,7 +256,7 @@ retry_select:
* from it, then read as much as is available and exit.
*/
if (child_terminated && packet_not_very_much_data_to_write())
- if (max_time_milliseconds == 0)
+ if (max_time_milliseconds == 0 || client_alive_scheduled)
max_time_milliseconds = 100;
if (max_time_milliseconds == 0)
@@ -255,12 +272,36 @@ retry_select:
/* Wait for something to happen, or the timeout to expire. */
ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
- if (ret < 0) {
+ if (ret == -1) {
if (errno != EINTR)
error("select: %.100s", strerror(errno));
else
goto retry_select;
}
+ if (ret == 0 && client_alive_scheduled) {
+ /* timeout, check to see how many we have had */
+ client_alive_timeouts++;
+
+ if (client_alive_timeouts > options.client_alive_count_max ) {
+ packet_disconnect(
+ "Timeout, your session not responding.");
+ } else {
+ /*
+ * send a bogus channel request with "wantreply"
+ * we should get back a failure
+ */
+ int id;
+
+ id = channel_find_open();
+ if (id != -1) {
+ channel_request_start(id,
+ "keepalive@openssh.com", 1);
+ packet_send();
+ } else
+ packet_disconnect(
+ "No open channels after timeout!");
+ }
+ }
}
/*
@@ -701,6 +742,19 @@ server_loop2(void)
}
void
+server_input_channel_failure(int type, int plen, void *ctxt)
+{
+ debug("Got CHANNEL_FAILURE for keepalive");
+ /*
+ * reset timeout, since we got a sane answer from the client.
+ * even if this was generated by something other than
+ * the bogus CHANNEL_REQUEST we send for keepalives.
+ */
+ client_alive_timeouts = 0;
+}
+
+
+void
server_input_stdin_data(int type, int plen, void *ctxt)
{
char *data;
@@ -912,7 +966,8 @@ server_init_dispatch_20(void)
dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
-
+ /* client_alive */
+ dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_channel_failure);
/* rekeying */
dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
}
@@ -949,3 +1004,4 @@ server_init_dispatch(void)
else
server_init_dispatch_15();
}
+
diff --git a/usr.bin/ssh/sshd.8 b/usr.bin/ssh/sshd.8
index da95eaef717..887cc3ba37a 100644
--- a/usr.bin/ssh/sshd.8
+++ b/usr.bin/ssh/sshd.8
@@ -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: sshd.8,v 1.114 2001/04/11 16:25:31 lebel Exp $
+.\" $OpenBSD: sshd.8,v 1.115 2001/04/13 22:46:54 beck Exp $
.Dd September 25, 1999
.Dt SSHD 8
.Os
@@ -363,6 +363,31 @@ Specifies whether
should check for new mail for interactive logins.
The default is
.Dq no .
+.It Cm ClientAliveInterval
+Sets a timeout interval in seconds after which if no data has been received
+from the client,
+.Nm
+will send a message through the encrypted
+channel to request a response from the client. This may only be
+used on a server supporting only protocol version 2. The default
+is 0, indicating that these messages will not be sent to the client.
+.It Cm ClientAliveCountMax
+Sets the number of client alive messages (see above) which may be
+sent without
+.Nm
+receiving any messages back from the client. If this threshold is
+reached while client alive messages are being sent,
+.Nm
+will disconnect the client, terminating the session. It is important
+to note that the use of client alive messages is very different from
+Keepalive (below). The client alive messages are sent through the
+encrypted channel and therefore will not be spoofable. The TCP keepalive
+option enable by Keepalive is spoofable. You want to use the client
+alive mechanism when you are basing something important on
+clients having an active connection to the server.
+ The default is value is 3. If you set ClientAliveInterval
+(above) to 15, and leave this value at the default, unresponsive ssh clients
+will be disconnected after approximately 45 seconds.
.It Cm DenyGroups
This keyword can be followed by a number of group names, separated
by spaces.