John Bowman
2001-May-18 04:03 UTC
PATCH: implement delay (sleep) after last tunnelled connection exits
Here is a patch to implement a handy new feature proposed by
John Hardin <johnh at aproposretail.com>. 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 -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.
-- John Bowman
University of Alberta
http://www.math.ualberta.ca/~bowman
diff -ur openssh-2.9p1/clientloop.c openssh-2.9p1S/clientloop.c
--- openssh-2.9p1/clientloop.c Fri Apr 20 06:50:51 2001
+++ openssh-2.9p1S/clientloop.c Thu May 17 21:41:44 2001
@@ -121,8 +121,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. */
void client_init_dispatch(void);
int session_ident = -1;
@@ -324,6 +324,10 @@
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
int *maxfdp, int rekeying)
{
+ struct timeval timer;
+ struct timeval *timerp;
+ int rc;
+
/* Add any selections by the channel mechanism. */
channel_prepare_select(readsetp, writesetp, maxfdp, rekeying);
@@ -346,7 +350,15 @@
if (buffer_len(&stderr_buffer) > 0)
FD_SET(fileno(stderr), *writesetp);
} else {
- FD_SET(connection_in, *readsetp);
+ /* channel_prepare_select could have closed the last channel */
+ if ((session_status == SessionClose)
+ && !channel_still_open()) {
+ if (!packet_have_data_to_write()) {
+ return;
+ }
+ } else {
+ FD_SET(connection_in, *readsetp);
+ }
}
/* Select server connection if have data to write to the server. */
@@ -362,7 +374,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;
+ timer.tv_usec=0;
+ timerp=&timer;
+ } else {
+ timerp=NULL;
+ }
+
+ rc=select((*maxfdp)+1, *readsetp, *writesetp, NULL, timerp);
+ if (rc < 0) {
char buf[100];
/*
@@ -379,7 +400,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;
}
void
@@ -751,7 +773,7 @@
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
- session_closed = 1;
+ session_status = (options.sleep >= 0) ? SessionWait : SessionClose;
if (in_raw_mode())
leave_raw_mode();
}
@@ -776,6 +798,7 @@
start_time = get_current_time();
/* Initialize variables. */
+ if(!have_pty) session_status=SessionWait;
escape_pending = 0;
last_was_cr = 1;
exit_status = -1;
@@ -840,7 +863,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-2.9p1/readconf.c openssh-2.9p1S/readconf.c
--- openssh-2.9p1/readconf.c Tue Apr 17 12:11:37 2001
+++ openssh-2.9p1S/readconf.c Thu May 17 19:23:52 2001
@@ -111,7 +111,7 @@
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
- oHostKeyAlgorithms
+ oHostKeyAlgorithms, oSleep
} OpCodes;
/* Textual representations of the tokens. */
@@ -177,6 +177,7 @@
{ "dynamicforward", oDynamicForward },
{ "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms },
+ { "sleep", oSleep },
{ NULL, 0 }
};
@@ -494,6 +495,10 @@
intptr = &options->connection_attempts;
goto parse_int;
+ case oSleep:
+ intptr = &options->sleep;
+ goto parse_int;
+
case oCipher:
intptr = &options->cipher;
arg = strdelim(&s);
@@ -761,6 +766,7 @@
options->num_remote_forwards = 0;
options->log_level = (LogLevel) - 1;
options->preferred_authentications = NULL;
+ options->sleep = -1;
}
/*
diff -ur openssh-2.9p1/readconf.h openssh-2.9p1S/readconf.h
--- openssh-2.9p1/readconf.h Tue Apr 17 12:11:37 2001
+++ openssh-2.9p1S/readconf.h Thu May 17 19:23:25 2001
@@ -97,6 +97,7 @@
/* Remote TCP/IP forward requests. */
int num_remote_forwards;
Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+ int sleep; /* Exit delay in seconds */
} Options;
diff -ur openssh-2.9p1/ssh.c openssh-2.9p1S/ssh.c
--- openssh-2.9p1/ssh.c Tue Apr 17 12:14:35 2001
+++ openssh-2.9p1S/ssh.c Thu May 17 21:13:54 2001
@@ -182,6 +182,7 @@
fprintf(stderr, " -R listen-port:host:port Forward remote port to
local address\n");
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, " -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");
@@ -318,7 +319,7 @@
opt = av[optind][1];
if (!opt)
usage();
- if (strchr("eilcmpLRDo", opt)) { /* options with arguments */
+ if (strchr("eilcmpLRSDo", opt)) { /* options with arguments */
optarg = av[optind] + 2;
if (strcmp(optarg, "") == 0) {
if (optind >= ac - 1)
@@ -488,7 +489,13 @@
}
add_local_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) {
Apparently Analagous Threads
- [PATCH] Add an exit delay to Openssh-3.0.2p1 for use in tunneling
- [PATCH] fix for Linux hang on exit bug in 2.9.9p2
- [PATCH]: Patch to fix hang on exit bug under Linux and add optional exit delay
- sshd hangs on logout -- is this a bug?
- patch: properly zeroing fd_set in clientloop
