John Bowman
2002-Jan-27 19:49 UTC
[PATCH] Add an exit delay to Openssh-3.0.2p1 for use in tunneling
Here is a patch to implement an exit delay in OpenSSH-3.0.2p1, proposed by John Hardin. This is his description of the feature: New option for OpenSSH: Delay before exit. Command line option: -S delay Config file option: sleep {delay} Purpose: Wait the specified number of seconds after last traffic before dropping the connection and exiting. If ports are forwarded, this causes the ssh client to allow another forwarded connection to begin after the current one closes. This permits multiple sequential port-forwarded connections without using a long-running remote sleep command. For example, for fetchmail polling of several accounts on a remote POP server over an SSH tunnel, you might say: ssh -n -L 11000:popserver:110 -S 30 host exit or ssh -N -L 11000:popserver:110 -S 30 host The ssh client would exit after thirty seconds of inactivity, rather than exiting immediately when the first forwarded connection closes. This would allow multiple sequential POP sessions to be carried over the same tunnel without specifying a long-running remote sleep command. Why not just use a long-running remote sleep command? In the above example, you may wish the ssh session to terminate promptly if no new mail is spooled: maybe this is running over a demand-dialled ISP connection. The -S option also removes the need to run a sleep command on the remote host in the first place. A delay value of zero means wait forever. This patch and others are maintained on the secure nfs (SNFS) web page: http://www.math.ualberta.ca/imaging/snfs/ -- John Bowman University of Alberta diff -ur openssh-3.0.2p1/clientloop.c openssh-3.0.2p1S/clientloop.c --- openssh-3.0.2p1/clientloop.c Sun Nov 11 17:06:33 2001 +++ openssh-3.0.2p1S/clientloop.c Sat Jan 19 14:50:11 2002 @@ -84,6 +84,7 @@ /* import options */ extern Options options; +extern int no_tty_flag; /* Flag indicating that stdin should be redirected from /dev/null. */ extern int stdin_null_flag; @@ -122,7 +123,8 @@ 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. */ +enum SessionStatus {SessionOpen, SessionClose, SessionWait}; +static int session_status = SessionOpen; /* In SSH2: login session closed. */ static void client_init_dispatch(void); int session_ident = -1; @@ -320,6 +322,10 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, int *nallocp, int rekeying) { + struct timeval timer; + struct timeval *timerp; + int rc; + /* Add any selections by the channel mechanism. */ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); @@ -343,7 +349,7 @@ FD_SET(fileno(stderr), *writesetp); } else { /* channel_prepare_select could have closed the last channel */ - if (session_closed && !channel_still_open() && + if (session_status == SessionClose && !channel_still_open() && !packet_have_data_to_write()) { /* clear mask since we did not call select() */ memset(*readsetp, 0, *nallocp); @@ -367,7 +373,16 @@ * SSH_MSG_IGNORE packet when the timeout expires. */ - if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { + if(session_status == SessionWait && options.sleep > 0) { + timer.tv_sec=options.sleep > 0 ? options.sleep : 0; + timer.tv_usec=0; + timerp=&timer; + } else { + timerp=NULL; + } + + rc=select((*maxfdp)+1, *readsetp, *writesetp, NULL, timerp); + if (rc < 0) { char buf[100]; /* @@ -384,7 +399,8 @@ snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; - } + } else if (rc == 0 && session_status == SessionWait) + session_status=SessionClose; } static void @@ -760,7 +776,7 @@ error("client_channel_closed: id %d != session_ident %d", id, session_ident); channel_cancel_cleanup(id); - session_closed = 1; + session_status = (options.sleep >= 0) ? SessionWait : SessionClose; if (in_raw_mode()) leave_raw_mode(); } @@ -785,6 +801,7 @@ start_time = get_current_time(); /* Initialize variables. */ + if(!have_pty) session_status=SessionWait; escape_pending = 0; last_was_cr = 1; exit_status = -1; @@ -848,7 +865,8 @@ /* Process buffered packets sent by the server. */ client_process_buffered_input_packets(); - if (compat20 && session_closed && !channel_still_open()) + if (compat20 && (session_status == SessionClose) + && !channel_still_open()) break; rekeying = (xxx_kex != NULL && !xxx_kex->done); diff -ur openssh-3.0.2p1/readconf.c openssh-3.0.2p1S/readconf.c --- openssh-3.0.2p1/readconf.c Wed Oct 3 11:39:39 2001 +++ openssh-3.0.2p1S/readconf.c Sat Jan 19 14:49:50 2002 @@ -115,7 +115,7 @@ oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, - oClearAllForwardings, oNoHostAuthenticationForLocalhost + oClearAllForwardings, oNoHostAuthenticationForLocalhost, oSleep } OpCodes; /* Textual representations of the tokens. */ @@ -187,6 +187,7 @@ { "smartcarddevice", oSmartcardDevice }, { "clearallforwardings", oClearAllForwardings }, { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, + { "sleep", oSleep }, { NULL, 0 } }; @@ -528,6 +529,10 @@ intptr = &options->connection_attempts; goto parse_int; + case oSleep: + intptr = &options->sleep; + goto parse_int; + case oCipher: intptr = &options->cipher; arg = strdelim(&s); @@ -799,6 +804,7 @@ options->bind_address = NULL; options->smartcard_device = NULL; options->no_host_authentication_for_localhost = - 1; + options->sleep = -1; } /* diff -ur openssh-3.0.2p1/readconf.h openssh-3.0.2p1S/readconf.h --- openssh-3.0.2p1/readconf.h Wed Oct 3 11:39:39 2001 +++ openssh-3.0.2p1S/readconf.h Sat Jan 19 14:49:50 2002 @@ -102,6 +102,7 @@ Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; int clear_forwardings; int no_host_authentication_for_localhost; + int sleep; /* Exit delay in seconds */ } Options; diff -ur openssh-3.0.2p1/ssh.c openssh-3.0.2p1S/ssh.c --- openssh-3.0.2p1/ssh.c Sun Nov 11 16:52:04 2001 +++ openssh-3.0.2p1S/ssh.c Sat Jan 19 14:49:51 2002 @@ -187,6 +187,7 @@ fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname); fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); fprintf(stderr, " -D port Enable dynamic application-level port forwarding.\n"); + fprintf(stderr, " -S delay Set exit delay (in seconds; 0 means wait forever).\n"); fprintf(stderr, " -C Enable compression.\n"); fprintf(stderr, " -N Do not execute a shell or command.\n"); fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n"); @@ -312,7 +313,7 @@ again: while ((opt = getopt(ac, av, - "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) { + "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:S:TVX")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -487,7 +488,13 @@ add_remote_forward(&options, fwd_port, buf, fwd_host_port); break; - + case 'S': + options.sleep = atoi(optarg); + if (options.sleep < 0) { + fprintf(stderr, "Bad delay value '%s'\n", optarg); + exit(1); + } + break; case 'D': fwd_port = a2port(optarg); if (fwd_port == 0) {
Seemingly Similar Threads
- [PATCH] fix for Linux hang on exit bug in 2.9.9p2
- PATCH: implement delay (sleep) after last tunnelled connection exits
- [PATCH]: Patch to fix hang on exit bug under Linux and add optional exit delay
- sshd hangs on logout -- is this a bug?
- [patch] option to prevent connection timeout