diff -uprk.orig openssh-3.6.1p1.orig/clientloop.c openssh-3.6.1p1/clientloop.c --- openssh-3.6.1p1.orig/clientloop.c 2003-04-01 15:43:39 +0400 +++ openssh-3.6.1p1/clientloop.c 2003-04-11 19:50:52 +0400 @@ -319,8 +319,10 @@ client_check_window_change(void) static void client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, - int *maxfdp, int *nallocp, int rekeying) + int *maxfdp, int *nallocp, int rekeying, int trans_inter) { + int select_return; + /* Add any selections by the channel mechanism. */ channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); @@ -362,13 +364,38 @@ client_wait_until_can_do_something(fd_se /* * 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. + * Implemented timeout SSH_MSG_IGNORE packets to keep a minimum + * frequency of traffic present on a connection. This can be used to + * prevent a firewall (ip_masq f.e.) from timing out and causing a new + * port to be allocated which effectively kills the connection. + * To fool traffic analysis, the timeout on the SSH_MSG_IGNORE + * packets set randomly instead of periodically. */ - if (select((*maxfdp)+1, *readsetp, *writesetp, NULL, NULL) < 0) { + if( trans_inter > 0 ) { + struct timeval timeout; + timeout.tv_sec = trans_inter * + (1 + (arc4random() / (double) UINT_MAX - 0.5)); + timeout.tv_usec = 1000000 * (arc4random() / (double) UINT_MAX); + select_return = select((*maxfdp)+1, *readsetp, *writesetp, + NULL, &timeout); + if( !select_return ) { + int len = 1 + (arc4random() & 63); + int data[len]; + int i; + + for (i = 0; i < len; ++i) + data[i] = arc4random(); + packet_start(SSH_MSG_IGNORE); + packet_put_string((char *)data, sizeof(data)); + packet_send(); + } + } else + select_return = select((*maxfdp)+1, *readsetp, *writesetp, + NULL, NULL); + + if( select_return < 0 ) { char buf[100]; /* @@ -960,7 +987,7 @@ client_loop(int have_pty, int escape_cha */ max_fd2 = max_fd; client_wait_until_can_do_something(&readset, &writeset, - &max_fd2, &nalloc, rekeying); + &max_fd2, &nalloc, rekeying, options.trans_inter); if (quit_pending) break; diff -uprk.orig openssh-3.6.1p1.orig/readconf.c openssh-3.6.1p1/readconf.c --- openssh-3.6.1p1.orig/readconf.c 2003-04-11 19:50:16 +0400 +++ openssh-3.6.1p1/readconf.c 2003-04-11 19:50:52 +0400 @@ -81,6 +81,7 @@ RCSID("$OpenBSD: readconf.c,v 1.104 2003 RhostsRSAAuthentication yes StrictHostKeyChecking yes KeepAlives no + TransmitInterlude 0 IdentityFile ~/.ssh/identity Port 22 EscapeChar ~ @@ -107,7 +108,7 @@ typedef enum { oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, - oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts, + oCompressionLevel, oKeepAlives, oTransmitInterlude, oNumberOfPasswordPrompts, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, oSshVersion, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, @@ -179,6 +180,7 @@ static struct { { "compression", oCompression }, { "compressionlevel", oCompressionLevel }, { "keepalive", oKeepAlives }, + { "transmitinterlude", oTransmitInterlude }, { "numberofpasswordprompts", oNumberOfPasswordPrompts }, { "loglevel", oLogLevel }, { "dynamicforward", oDynamicForward }, @@ -416,6 +418,10 @@ parse_flag: intptr = &options->no_host_authentication_for_localhost; goto parse_flag; + case oTransmitInterlude: + intptr = &options->trans_inter; + goto parse_int; + case oNumberOfPasswordPrompts: intptr = &options->number_of_password_prompts; goto parse_int; @@ -772,6 +778,7 @@ initialize_options(Options * options) options->strict_host_key_checking = -1; options->compression = -1; options->keepalives = -1; + options->trans_inter = -1; options->compression_level = -1; options->port = -1; options->connection_attempts = -1; @@ -861,6 +868,8 @@ fill_default_options(Options * options) options->compression = 0; if (options->keepalives == -1) options->keepalives = 1; + if (options->trans_inter == -1) + options->trans_inter = 0; if (options->compression_level == -1) options->compression_level = 6; if (options->port == -1) diff -uprk.orig openssh-3.6.1p1.orig/readconf.h openssh-3.6.1p1/readconf.h --- openssh-3.6.1p1.orig/readconf.h 2003-04-11 19:50:16 +0400 +++ openssh-3.6.1p1/readconf.h 2003-04-11 19:50:52 +0400 @@ -61,6 +61,7 @@ typedef struct { int compression_level; /* Compression level 1 (fast) to 9 * (best). */ int keepalives; /* Set SO_KEEPALIVE. */ + int trans_inter; /* Guarantee transmit every n seconds. */ LogLevel log_level; /* Level for logging. */ int port; /* Port to connect. */ diff -uprk.orig openssh-3.6.1p1.orig/ssh_config openssh-3.6.1p1/ssh_config --- openssh-3.6.1p1.orig/ssh_config 2002-07-04 04:19:41 +0400 +++ openssh-3.6.1p1/ssh_config 2003-04-11 19:50:52 +0400 @@ -26,6 +26,7 @@ # BatchMode no # CheckHostIP yes # StrictHostKeyChecking ask +# TransmitInterlude 0 # IdentityFile ~/.ssh/identity # IdentityFile ~/.ssh/id_rsa # IdentityFile ~/.ssh/id_dsa diff -uprk.orig openssh-3.6.1p1.orig/ssh_config.5 openssh-3.6.1p1/ssh_config.5 --- openssh-3.6.1p1.orig/ssh_config.5 2003-04-11 19:50:16 +0400 +++ openssh-3.6.1p1/ssh_config.5 2003-04-11 19:50:52 +0400 @@ -370,6 +370,22 @@ This is important in scripts, and many u .Pp To disable keepalives, the value should be set to .Dq no . +.It Cm TransmitInterlude +Specifies a maximum time to allow between transmitting packets, +in seconds. If this amount of time passes and the client has +no data to send, it will send an ignore packet to the server. +One example where this is useful is when using ssh from behind +a Linux ip_masquerade firewall. If packets aren't sent through +such a firewall periodically, the firewall may forget about the +connection. Then when a packet finally is sent, the firewall +will assign a new port, which will cause the remote server to +disconnect the session. This option defaults to +.Dq 0 , +which means not sending periodic packets. A setting of a few +hundred seconds should be about right if this is needed. You +should probably try setting KeepAlive to +.Dq yes +in your conf files on both the server and the client first. .It Cm KerberosAuthentication Specifies whether Kerberos authentication will be used. The argument to this keyword must be