Idletimeout patch

Jani Jaakkola jjaakkol at cs.Helsinki.FI
Mon Aug 20 23:30:17 EST 2001


On Fri, 17 Aug 2001, Per Allansson wrote:

> There is at least one thing missing in the patch - handling
> of key re-exchange - a key re-exchange should not reset
> the idle timeout timer.

Right. So it seems that it really is necessary to reset idletimeout
on certain packets, but not on others. Included is a more complicated but
hopefully more correct patch; this patch does not reset idletimeout on
packets which are used for rekeying and for packets which are used
client alive timeouts. It also only resets idletimeouts on actual packets
and not on other events in the select loop.

Included patch is also available from
http://www.cs.helsinki.fi/u/jjaakkol/idletimeout.patch
The old patch is available from
http://www.cs.helsinki.fi/u/jjaakkol/idletimeout.patch.old

I'm still willing to improve the patch and also to document it, if you
are willing to include it in the openssh distribution.

- Jani
-------------- next part --------------
diff -ru openssh-2.9p2.orig/CREDITS openssh-2.9p2/CREDITS
--- openssh-2.9p2.orig/CREDITS	Mon Apr 16 03:41:46 2001
+++ openssh-2.9p2/CREDITS	Wed Aug 15 22:00:02 2001
@@ -42,6 +42,7 @@
 IWAMURO Motonori <iwa at mmp.fujitsu.co.jp> - bugfixes
 Jani Hakala <jahakala at cc.jyu.fi> - Patches
 Jarno Huuskonen <jhuuskon at hytti.uku.fi> - Bugfixes
+Jani Jaakkola <jjaakkol at cs.helsinki.fi> - IdleTimeOut
 Jim Knoble <jmknoble at jmknoble.cx> - Many patches
 Jonchen (email unknown) - the original author of PAM support of SSH
 Juergen Keil <jk at tools.de> - scp bugfixing
diff -ru openssh-2.9p2.orig/clientloop.c openssh-2.9p2/clientloop.c
--- openssh-2.9p2.orig/clientloop.c	Fri Apr 20 15:50:51 2001
+++ openssh-2.9p2/clientloop.c	Mon Aug 20 15:08:36 2001
@@ -1250,3 +1250,9 @@
 	else
 		client_init_dispatch_15();
 }
+
+/* Idletimeouts not implemented on client side (yet) */
+void idletimeout_check(int type, int received) 
+{
+    /* Nothing here */
+}
diff -ru openssh-2.9p2.orig/dispatch.c openssh-2.9p2/dispatch.c
--- openssh-2.9p2.orig/dispatch.c	Mon Feb 19 12:51:08 2001
+++ openssh-2.9p2/dispatch.c	Mon Aug 20 15:00:38 2001
@@ -69,9 +69,10 @@
 			if (type == SSH_MSG_NONE)
 				return;
 		}
-		if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
+		if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) {
+		        idletimeout_check(type,1);
 			(*dispatch[type])(type, plen, ctxt);
-		else
+		} else
 			packet_disconnect("protocol error: rcvd type %d", type);
 		if (done != NULL && *done)
 			return;
diff -ru openssh-2.9p2.orig/packet.c openssh-2.9p2/packet.c
--- openssh-2.9p2.orig/packet.c	Fri Apr  6 02:26:33 2001
+++ openssh-2.9p2/packet.c	Mon Aug 20 15:01:06 2001
@@ -383,6 +383,7 @@
 		packet_start2(type);
 	else
 		packet_start1(type);
+        idletimeout_check(type,0);
 }
 
 /* Appends a character to the packet data. */
diff -ru openssh-2.9p2.orig/packet.h openssh-2.9p2/packet.h
--- openssh-2.9p2.orig/packet.h	Sun Apr 15 02:13:03 2001
+++ openssh-2.9p2/packet.h	Mon Aug 20 14:59:34 2001
@@ -220,4 +220,9 @@
 /* add an ignore message and make sure size (current+ignore) = n*sumlen */
 void	packet_inject_ignore(int sumlen);
 
+/* This is called whenever packets are being received or sent to check
+ * if idletimeout counter should be reset. Type is packet type, received==1
+ * if packet was received, zero if packet was sent. */
+void    idletimeout_check(int type, int received);
+
 #endif				/* PACKET_H */
diff -ru openssh-2.9p2.orig/servconf.c openssh-2.9p2/servconf.c
--- openssh-2.9p2.orig/servconf.c	Wed Apr 25 15:44:15 2001
+++ openssh-2.9p2/servconf.c	Wed Aug 15 22:10:23 2001
@@ -102,6 +102,7 @@
 	options->client_alive_interval = -1;
 	options->client_alive_count_max = -1;
 	options->pam_authentication_via_kbd_int = -1;
+	options->idletimeout = -1;
 }
 
 void
@@ -210,6 +211,8 @@
 		options->client_alive_count_max = 3;
 	if (options->pam_authentication_via_kbd_int == -1)
 		options->pam_authentication_via_kbd_int = 0;
+	if (options->idletimeout == -1)
+		options->idletimeout=0;
 }
 
 /* Keyword tokens. */
@@ -235,7 +238,8 @@
 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups,
 	sBanner, sReverseMappingCheck, sHostbasedAuthentication,
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 
-	sClientAliveCountMax, sPAMAuthenticationViaKbdInt
+	sClientAliveCountMax, sPAMAuthenticationViaKbdInt,
+	sIdleTimeout
 } ServerOpCodes;
 
 /* Textual representation of the tokens. */
@@ -302,6 +306,7 @@
 	{ "clientaliveinterval", sClientAliveInterval },
 	{ "clientalivecountmax", sClientAliveCountMax },
 	{ "PAMAuthenticationViaKbdInt", sPAMAuthenticationViaKbdInt },
+	{ "idletimeout", sIdleTimeout },
 	{ NULL, 0 }
 };
 
@@ -801,7 +806,28 @@
 		case sPAMAuthenticationViaKbdInt:
 			intptr = &options->pam_authentication_via_kbd_int;
 			goto parse_flag;
-
+               case sIdleTimeout:
+			arg = strdelim(&cp);
+			if (!arg || *arg == '\0')
+				fatal("%s line %d: Missing IdleTimeout argument",
+					filename,linenum);
+			options->idletimeout=atoi(arg);
+			switch(arg[strlen(arg)-1]) {
+				case 'w': options->idletimeout*=7;
+				case 'd': options->idletimeout*=24;
+				case 'h': options->idletimeout*=60;
+				case 'm': options->idletimeout*=60;
+				case 's': 
+				case '0': case '1': case '2': case '3': 
+				case '4': case '5': case '6': case '7': 
+				case '8': case '9':
+	                               break;
+				default:
+					fatal("%s line %d: Invalid IdleTimeout argument",
+						filename,linenum);
+			}
+			break;
+	
 		default:
 			fatal("%s line %d: Missing handler for opcode %s (%d)",
 			    filename, linenum, arg, opcode);
diff -ru openssh-2.9p2.orig/servconf.h openssh-2.9p2/servconf.h
--- openssh-2.9p2.orig/servconf.h	Wed Apr 25 15:44:16 2001
+++ openssh-2.9p2/servconf.h	Wed Aug 15 22:09:33 2001
@@ -125,6 +125,10 @@
 					 * diconnect the session 
 					 */
 	int	pam_authentication_via_kbd_int;
+	int	idletimeout;		/*
+					 * If nonzero, the number of second
+					 * after which idle connections
+					 * will be terminated */
 }       ServerOptions;
 /*
  * Initializes the server options to special values that indicate that they
diff -ru openssh-2.9p2.orig/serverloop.c openssh-2.9p2/serverloop.c
--- openssh-2.9p2.orig/serverloop.c	Sat Apr 14 02:28:03 2001
+++ openssh-2.9p2/serverloop.c	Mon Aug 20 15:57:05 2001
@@ -79,7 +79,8 @@
 static int connection_out;	/* Connection to client (output). */
 static int connection_closed = 0;	/* Connection to client closed. */
 static u_int buffer_high;	/* "Soft" max buffer size. */
-
+static time_t idletime_last=0; /* The last time something happened
+				* for idletimeout. */
 /*
  * This SIGCHLD kludge is used to detect when the child exits.  The server
  * will exit after that, as soon as forwarded connections have terminated.
@@ -180,6 +181,46 @@
 	}
 }
 
+/* Called by dispatch.c and packet.c whenever packets are sent or received.
+ * This function decides whenever server idletimeout should be reset */
+void idletimeout_check(int type, int received) {
+        /* No-op, if idletimeouts are not configured */
+        if (options.idletimeout==0) return;
+
+	/* The following packets receive idletimeout on input or output */
+	switch(type) {
+	case SSH2_MSG_KEXINIT:         /* Ignore rekeying */
+	case SSH2_MSG_NEWKEYS:
+	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:   
+	case SSH2_MSG_KEX_DH_GEX_GROUP:
+	case SSH2_MSG_KEX_DH_GEX_INIT:
+	case SSH2_MSG_KEX_DH_GEX_REPLY:
+	case SSH2_MSG_KEX_DH_GEX_REQUEST:
+	case SSH_MSG_NONE:             /* Ignore dummies */
+	    debug("Server i/o idlecheck ignored msg %d, received=%d",
+		  type,received);
+	    return;
+	}
+
+	if (received) {
+	        /* The following packets do not reset idletimeout on input */
+	        switch(type) {
+		case SSH2_MSG_CHANNEL_FAILURE: /* used for client alive */
+		        debug("Server i idlecheck ignored msg %d",type);
+			return;
+		}
+	} else {
+	        /* The following packets do not reset idletimeout on output */
+	        switch(type) {
+		case SSH2_MSG_CHANNEL_REQUEST: /* used for client alive */
+		        debug("Server o idlecheck ignored msg %d",type);
+			return;
+		}
+	}
+	/* Reset idletime */
+	time(&idletime_last);
+}
+
 /*
  * Sleep in select() until we can do something.  This will initialize the
  * select masks.  Upon return, the masks will indicate which descriptors
@@ -193,7 +234,9 @@
 	struct timeval tv, *tvp;
 	int ret;
 	int client_alive_scheduled = 0;
-
+	/* Secs until idletimeout, zero if no idletimeout */
+	int max_time_seconds=0; 
+	
 	/*
 	 * if using client_alive, set the max timeout accordingly, 
 	 * and indicate that this particular timeout was for client
@@ -208,6 +251,24 @@
 	} else 
 	        client_alive_scheduled = 0;
 
+
+	if (options.idletimeout>0) {
+		if (idletime_last==0) {
+			/* Initialize idletime_last */		
+			time(&idletime_last);  
+		}
+		/* Schedule idletimeout if no other timeouts are scheduled.
+		 * Idletimeouts are the longest and it is not a big deal,
+		 * if they are missed by few seconds. */
+		if (max_time_milliseconds == 0) {
+			time_t diff=time(NULL)-idletime_last;
+			if (diff>=options.idletimeout)
+				max_time_seconds=1;
+			else 
+				max_time_seconds=options.idletimeout-diff;
+		}
+	}
+	
 	/* When select fails we restart from here. */
 retry_select:
 
@@ -258,10 +319,17 @@
 	if (child_terminated && packet_not_very_much_data_to_write())
 		if (max_time_milliseconds == 0 || client_alive_scheduled)
 			max_time_milliseconds = 100;
-
-	if (max_time_milliseconds == 0)
-		tvp = NULL;
-	else {
+	
+	if (max_time_milliseconds == 0) {
+		/* Use max_time_seconds only if max_time_milliseconds is
+		 * not set */
+		if (max_time_seconds>0) {
+			tv.tv_sec=max_time_seconds;
+			tv.tv_usec=0;
+			tvp=&tv;
+		} else
+			tvp = NULL;
+	} else {
 		tv.tv_sec = max_time_milliseconds / 1000;
 		tv.tv_usec = 1000 * (max_time_milliseconds % 1000);
 		tvp = &tv;
@@ -301,7 +369,14 @@
 				packet_disconnect(
 					"No open channels after timeout!");
 		}
-	} 
+	}
+
+	/* Check if idletimeout has happened */
+	if (options.idletimeout>0 && ret==0 && 
+	    time(NULL)-idletime_last>options.idletimeout) {
+	            packet_disconnect("Idletimeout.");
+		    options.idletimeout=0;
+	}
 }
 
 /*


More information about the openssh-unix-dev mailing list