head 1.4; access; symbols; locks; strict; comment @# @; 1.4 date 2009.10.02.11.17.28; author rse; state Exp; branches; next 1.3; commitid Xk4IjVbjJ3Tu3X5u; 1.3 date 2009.02.25.11.30.07; author rse; state Exp; branches; next 1.2; commitid bjaokXKw9Z0haODt; 1.2 date 2008.11.22.08.25.55; author rse; state Exp; branches; next 1.1; commitid cgzYIW4V9XxpcArt; 1.1 date 2008.11.15.09.21.19; author rse; state Exp; branches; next ; commitid RLamfWkLgHfnJGqt; desc @@ 1.4 log @upgrading package: openssh 5.2p1 -> 5.3p1 @ text @Watchdog Patch Forward ported from the upstream vendor patch http://www.sc.isc.tohoku.ac.jp/~hgot/sources/openssh-watchdog.html http://www.sc.isc.tohoku.ac.jp/~hgot/sources/openssh-4.4p1-watchdog.patch.tgz Index: clientloop.c --- clientloop.c.orig 2009-08-28 03:21:07 +0200 +++ clientloop.c 2009-10-02 13:12:46 +0200 @@@@ -155,6 +155,7 @@@@ static u_int buffer_high;/* Soft max buffer size. */ static int connection_in; /* Connection to server (input). */ static int connection_out; /* Connection to server (output). */ +static time_t idle_time_last; /* Last time of packet transmission. */ static int need_rekeying; /* Set to non-zero if rekeying is requested. */ static int session_closed = 0; /* In SSH2: login session closed. */ @@@@ -568,16 +569,19 @@@@ * event pending. */ - if (options.server_alive_interval == 0 || !compat20) - tvp = NULL; - else { + if (options.server_alive_interval != 0 && compat20){ tv.tv_sec = options.server_alive_interval; - tv.tv_usec = 0; + tv.tv_usec = 0; + tvp = &tv; + } + else{ + tv.tv_sec = 0; + tv.tv_usec = 500 * 1000; /* time slot is 0.5sec */ tvp = &tv; } - ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); - if (ret < 0) { - char buf[100]; + ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); + if (ret < 0) { + char buf[100]; /* * We have to clear the select masks, because we return. @@@@ -593,8 +597,43 @@@@ snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); buffer_append(&stderr_buffer, buf, strlen(buf)); quit_pending = 1; - } else if (ret == 0) - server_alive_check(); + } else if (ret == 0){ + if (options.server_alive_interval != 0 && compat20){ + server_alive_check(); + } + } + + /* If the output channel has been silent for more than a specified + * time, send a keepalive packet (heartbeat) to the server. + * Keepalive packet is useful for keeping the connection over + * IP masquerade / NAT boxes, firewalls, etc. + * Some servers equipped with a watchdog timer require keepalive + * packets (heartbeats) to detect link down. + * + * Note: Although the interval between keepalive packets is not + * very precise, it's okay. + * + * Note: Some old servers may crash when they receive SSH_MSG_IGNORE. + * Those who want to connect to such a server should turn this + * function off by the option setting (e.g. Heartbeat 0). + */ + if (options.heartbeat_interval > 0) { + if (FD_ISSET(connection_out,*writesetp)) { + /* Update the time of last data transmission. */ + idle_time_last = time(NULL); + } + if (time(NULL) - idle_time_last >= (int)options.heartbeat_interval){ + if (compat20) { + packet_start(SSH2_MSG_IGNORE); + } + else { + packet_start(SSH_MSG_IGNORE); + } + packet_put_string("", 0); + packet_send(); + /* fputs("*",stderr); */ + } + } } static void @@@@ -1312,6 +1351,7 @@@@ debug("Entering interactive session."); start_time = get_current_time(); + idle_time_last = time(NULL); /* Initialize variables. */ escape_pending1 = 0; Index: readconf.c --- readconf.c.orig 2009-07-05 23:12:27 +0200 +++ readconf.c 2009-10-02 13:12:46 +0200 @@@@ -118,7 +118,7 @@@@ oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, - oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, + oCompressionLevel, oTCPKeepAlive, oHeartbeat, oNumberOfPasswordPrompts, oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, @@@@ -199,6 +199,7 @@@@ { "compressionlevel", oCompressionLevel }, { "tcpkeepalive", oTCPKeepAlive }, { "keepalive", oTCPKeepAlive }, /* obsolete */ + { "heartbeat", oHeartbeat }, { "numberofpasswordprompts", oNumberOfPasswordPrompts }, { "loglevel", oLogLevel }, { "dynamicforward", oDynamicForward }, @@@@ -502,6 +503,10 @@@@ intptr = &options->no_host_authentication_for_localhost; goto parse_flag; + case oHeartbeat: + intptr = &options->heartbeat_interval; + goto parse_int; + case oNumberOfPasswordPrompts: intptr = &options->number_of_password_prompts; goto parse_int; @@@@ -1024,6 +1029,7 @@@@ options->strict_host_key_checking = -1; options->compression = -1; options->tcp_keep_alive = -1; + options->heartbeat_interval = -1; options->compression_level = -1; options->port = -1; options->address_family = -1; @@@@ -1125,6 +1131,8 @@@@ options->compression = 0; if (options->tcp_keep_alive == -1) options->tcp_keep_alive = 1; + if (options->heartbeat_interval == -1) + options->heartbeat_interval = 0; /* 0 means "no heartbeat" */ if (options->compression_level == -1) options->compression_level = 6; if (options->port == -1) Index: readconf.h --- readconf.h.orig 2009-07-05 23:12:27 +0200 +++ readconf.h 2009-10-02 13:12:46 +0200 @@@@ -57,6 +57,9 @@@@ int compression_level; /* Compression level 1 (fast) to 9 * (best). */ int tcp_keep_alive; /* Set SO_KEEPALIVE. */ + int heartbeat_interval; /* Number of seconds between keepalive + * packets (heartbeats) over encrypted + * channel. (in secs.) */ LogLevel log_level; /* Level for logging. */ int port; /* Port to connect. */ Index: servconf.c --- servconf.c.orig 2009-06-21 12:26:17 +0200 +++ servconf.c 2009-10-02 13:12:46 +0200 @@@@ -80,6 +80,8 @@@@ options->xauth_location = NULL; options->strict_modes = -1; options->tcp_keep_alive = -1; + options->watchdog_timeout = -1; + options->watchdog_timeout1 = -1; options->log_facility = SYSLOG_FACILITY_NOT_SET; options->log_level = SYSLOG_LEVEL_NOT_SET; options->rhosts_rsa_authentication = -1; @@@@ -186,6 +188,10 @@@@ options->strict_modes = 1; if (options->tcp_keep_alive == -1) options->tcp_keep_alive = 1; + if (options->watchdog_timeout == -1) + options->watchdog_timeout = 0; /* 0 means "no timeout" */ + if (options->watchdog_timeout1 == -1) + options->watchdog_timeout1 = 0; /* 0 means "no timeout" */ if (options->log_facility == SYSLOG_FACILITY_NOT_SET) options->log_facility = SYSLOG_FACILITY_AUTH; if (options->log_level == SYSLOG_LEVEL_NOT_SET) @@@@ -293,7 +299,7 @@@@ sListenAddress, sAddressFamily, sPrintMotd, sPrintLastLog, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, - sStrictModes, sEmptyPasswd, sTCPKeepAlive, + sStrictModes, sEmptyPasswd, sTCPKeepAlive, sWatchdogTimeout, sWatchdogTimeout1, sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, @@@@ -395,6 +401,8 @@@@ { "compression", sCompression, SSHCFG_GLOBAL }, { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL }, /* obsolete alias */ + { "watchdogtimeout", sWatchdogTimeout, SSHCFG_GLOBAL }, + { "watchdogtimeout1", sWatchdogTimeout1, SSHCFG_GLOBAL }, { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL }, { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL }, { "allowusers", sAllowUsers, SSHCFG_GLOBAL }, @@@@ -943,6 +951,14 @@@@ intptr = &options->tcp_keep_alive; goto parse_flag; + case sWatchdogTimeout: + intptr = &options->watchdog_timeout; + goto parse_int; + + case sWatchdogTimeout1: + intptr = &options->watchdog_timeout1; + goto parse_int; + case sEmptyPasswd: intptr = &options->permit_empty_passwd; goto parse_flag; Index: servconf.h --- servconf.h.orig 2009-01-28 06:31:23 +0100 +++ servconf.h 2009-10-02 13:12:46 +0200 @@@@ -67,6 +67,10 @@@@ char *xauth_location; /* Location of xauth program */ int strict_modes; /* If true, require string home dir modes. */ int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */ + int watchdog_timeout, watchdog_timeout1; + /* Timeout of the watchdog timer which + checks the input activities over + encrypted channel. (in secs.) */ char *ciphers; /* Supported SSH2 ciphers. */ char *macs; /* Supported SSH2 macs. */ int protocol; /* Supported protocol versions. */ Index: serverloop.c --- serverloop.c.orig 2009-09-09 03:07:28 +0200 +++ serverloop.c 2009-10-02 13:12:46 +0200 @@@@ -107,6 +107,8 @@@@ static int connection_closed = 0; /* Connection to client closed. */ static u_int buffer_high; /* "Soft" max buffer size. */ static int no_more_sessions = 0; /* Disallow further sessions. */ +static time_t idle_time_last; /* Last time of packet receipt. */ +static int child_forced_to_terminate; /* The child will be killed by sshd. */ /* * This SIGCHLD kludge is used to detect when the child exits. The server @@@@ -281,6 +283,7 @@@@ { struct timeval tv, *tvp; int ret; + int watchdog_timeout = 0; int client_alive_scheduled = 0; int program_alive_scheduled = 0; @@@@ -350,6 +353,19 @@@@ if (max_time_milliseconds == 0 || client_alive_scheduled) max_time_milliseconds = 100; + /* When the watchdog is needed, set the maximum length + * of timeout to 0.25sec. + */ + watchdog_timeout = options.watchdog_timeout; + if (!compat20 && options.watchdog_timeout1 > 0){ + watchdog_timeout = options.watchdog_timeout1; + } + if (watchdog_timeout > 0) { + if (max_time_milliseconds == 0 || max_time_milliseconds > 250) { + max_time_milliseconds = 250; + } + } + if (max_time_milliseconds == 0) tvp = NULL; else { @@@@ -377,6 +393,23 @@@@ } } + /* + * Watchdog timer: + * If the input channel has been silent for more than the specified + * time, try to kill the child process(es) to protect server resources. + */ + if (watchdog_timeout > 0) { + if (FD_ISSET(connection_in,*readsetp)) { + /* Update the time of last data receipt. */ + idle_time_last = time(NULL); + /* fputs("*",stderr); */ + } + if (!child_terminated && \ + (time(NULL) - idle_time_last) > watchdog_timeout) { + child_forced_to_terminate = 1; + } + } + notify_done(*readsetp); } @@@@ -560,7 +593,9 @@@@ u_int max_time_milliseconds; u_int previous_stdout_buffer_bytes; u_int stdout_buffer_bytes; - int type; + int type, i; + + child_forced_to_terminate = 0; debug("Entering interactive session."); @@@@ -627,6 +662,8 @@@@ server_init_dispatch(); + idle_time_last = time(NULL); + /* Main loop of the server for the interactive session mode. */ for (;;) { @@@@ -707,6 +744,9 @@@@ cleanup_exit(255); } + /* Break, if watchdog timeout occured. */ + if (child_forced_to_terminate) break; + /* Process any channel events. */ channel_after_select(readset, writeset); @@@@ -716,6 +756,24 @@@@ /* Process output to the client and to program stdin. */ process_output(writeset); } + + /* + * If the child should be terminated due to + * watchdog timeout, send kill signal to the child. + */ + if (child_forced_to_terminate) { + /* We won't have pid=0. However, for safety... */ + if ( pid != 0 ){ + kill(pid, SIGHUP); + for (i=0 ; i<5 ; i++){ + sleep(1); + if (child_terminated) break; + } + if (i>=5) kill(pid, SIGKILL); + logit("Warning: Command has been killed due to watchdog timeout."); + } + } + if (readset) xfree(readset); if (writeset) @@@@ -724,7 +782,9 @@@@ /* Cleanup and termination code. */ /* Wait until all output has been sent to the client. */ - drain_output(); + if (!child_forced_to_terminate) { + drain_output(); + } debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); @@@@ -752,6 +812,12 @@@@ /* We no longer want our SIGCHLD handler to be called. */ mysignal(SIGCHLD, SIG_DFL); + /* If the child has been terminated, free the session and exit here. */ + if (child_forced_to_terminate) { + session_destroy_all(NULL); + return; + } + while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) if (errno != EINTR) packet_disconnect("wait: %.100s", strerror(errno)); @@@@ -825,6 +891,7 @@@@ mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; + child_forced_to_terminate = 0; connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); @@@@ -841,6 +908,8 @@@@ server_init_dispatch(); + idle_time_last = time(NULL); + for (;;) { process_buffered_input_packets(); @@@@ -857,6 +926,12 @@@@ cleanup_exit(255); } + /* Terminate child processes, if watchdog timeout occured. */ + if (child_forced_to_terminate){ + packet_disconnect("Command has been killed due to watchdog timeout."); + logit("Warning: Command has been killed due to watchdog timeout."); + } + collect_children(); if (!rekeying) { channel_after_select(readset, writeset); Index: ssh.1 --- ssh.1.orig 2009-06-21 09:48:52 +0200 +++ ssh.1 2009-10-02 13:12:46 +0200 @@@@ -453,6 +453,7 @@@@ .It GSSAPIAuthentication .It GSSAPIDelegateCredentials .It HashKnownHosts +.It Heartbeat .It Host .It HostbasedAuthentication .It HostKeyAlgorithms Index: ssh_config.5 --- ssh_config.5.orig 2009-02-23 00:53:58 +0100 +++ ssh_config.5 2009-10-02 13:12:46 +0200 @@@@ -500,6 +500,23 @@@@ will not be converted automatically, but may be manually hashed using .Xr ssh-keygen 1 . +.It Cm Heartbeat +Specifies the interval between heartbeats, in seconds. If the output +channel has been silent for more than the specified time, a null message +(SSH_MSG_IGNORE) is sent to the server. +.Cm Heartbeat +is useful for keeping alive connections over IP masquerade / NAT boxes, +firewalls, etc., that implement connection timeouts, and in combination +with the +.Cm WatchdogTimeout +option to +.Xr sshd 8 . +Heartbeat does not work if +.Cm ServerAliveInterval +is enabled at the same time. +The default is +.Dq 0 , +which disables the hearbeat. .It Cm HostbasedAuthentication Specifies whether to try rhosts based authentication with public key authentication. Index: sshd_config.5 --- sshd_config.5.orig 2009-08-28 02:27:08 +0200 +++ sshd_config.5 2009-10-02 13:12:46 +0200 @@@@ -939,6 +939,30 @@@@ escalation by containing any corruption within the unprivileged processes. The default is .Dq yes . +.It Cm WatchdogTimeout +Specifies the watchdog timeout interval, in seconds. +If a session input channel has been silent for more than the specified interval, +.Cm sshd +terminates the session by killing the child process(es). Only input +packets from the client reset the watchdog timer; this makes it possible +to terminate a session even if the server continues sending some data +to the client. +When used in combination with +.Cm ClientAliveInterval +and/or the +.Cm Heartbeat +option of +.Xr ssh 1 +this feature will detect and terminate hung sessions over unreliable +networks, without interfering with normal usage. +The default is +.Dq 0 , +which disables the watchdog. +.It Cm WatchdogTimeout1 +Specifies the watchdog timeout interval, in seconds, for SSH1 protocol +only. See the +.Cm WatchdogTimeout +option. .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's @ 1.3 log @upgrading package: openssh 5.1p1 -> 5.2p1 @ text @d7 3 a9 3 --- clientloop.c.orig 2009-02-14 06:28:21 +0100 +++ clientloop.c 2009-02-25 12:25:48 +0100 @@@@ -154,6 +154,7 @@@@ d17 1 a17 1 @@@@ -567,16 +568,19 @@@@ d44 1 a44 1 @@@@ -592,8 +596,43 @@@@ d90 1 a90 1 @@@@ -1311,6 +1350,7 @@@@ d99 2 a100 2 --- readconf.c.orig 2009-02-14 06:28:21 +0100 +++ readconf.c 2009-02-25 12:25:48 +0100 d118 1 a118 1 @@@@ -501,6 +502,10 @@@@ d129 1 a129 1 @@@@ -1019,6 +1024,7 @@@@ d137 1 a137 1 @@@@ -1119,6 +1125,8 @@@@ d147 2 a148 2 --- readconf.h.orig 2009-02-14 06:28:21 +0100 +++ readconf.h 2009-02-25 12:25:48 +0100 d160 2 a161 2 --- servconf.c.orig 2009-01-28 06:31:23 +0100 +++ servconf.c 2009-02-25 12:25:48 +0100 d217 1 a217 1 +++ servconf.h 2009-02-25 12:25:48 +0100 d230 3 a232 3 --- serverloop.c.orig 2009-02-14 06:33:09 +0100 +++ serverloop.c 2009-02-25 12:25:48 +0100 @@@@ -106,6 +106,8 @@@@ d241 1 a241 1 @@@@ -280,6 +282,7 @@@@ d249 1 a249 1 @@@@ -349,6 +352,19 @@@@ d269 1 a269 1 @@@@ -376,6 +392,23 @@@@ d293 1 a293 1 @@@@ -556,7 +589,9 @@@@ d304 1 a304 1 @@@@ -623,6 +658,8 @@@@ d313 1 a313 1 @@@@ -703,6 +740,9 @@@@ d323 1 a323 1 @@@@ -712,6 +752,24 @@@@ d348 1 a348 1 @@@@ -720,7 +778,9 @@@@ d359 1 a359 1 @@@@ -748,6 +808,12 @@@@ d372 1 a372 1 @@@@ -821,6 +887,7 @@@@ d380 1 a380 1 @@@@ -837,6 +904,8 @@@@ d389 1 a389 1 @@@@ -853,6 +922,12 @@@@ d403 3 a405 3 --- ssh.1.orig 2009-02-14 06:34:05 +0100 +++ ssh.1 2009-02-25 12:25:48 +0100 @@@@ -470,6 +470,7 @@@@ d415 1 a415 1 +++ ssh_config.5 2009-02-25 12:25:48 +0100 d441 3 a443 3 --- sshd_config.5.orig 2009-02-23 01:00:24 +0100 +++ sshd_config.5 2009-02-25 12:25:48 +0100 @@@@ -934,6 +934,30 @@@@ @ 1.2 log @fix typo @ text @d7 3 a9 3 --- clientloop.c.orig 2008-07-16 14:40:52 +0200 +++ clientloop.c 2008-11-15 10:14:27 +0100 @@@@ -155,6 +155,7 @@@@ d17 1 a17 1 @@@@ -568,16 +569,19 @@@@ d44 1 a44 1 @@@@ -593,8 +597,43 @@@@ d90 1 a90 1 @@@@ -1305,6 +1344,7 @@@@ d99 2 a100 2 --- readconf.c.orig 2008-06-29 16:04:03 +0200 +++ readconf.c 2008-11-15 10:14:27 +0100 d118 1 a118 1 @@@@ -492,6 +493,10 @@@@ d129 1 a129 1 @@@@ -1027,6 +1032,7 @@@@ d137 1 a137 1 @@@@ -1126,6 +1132,8 @@@@ d147 3 a149 3 --- readconf.h.orig 2008-06-29 16:04:03 +0200 +++ readconf.h 2008-11-15 10:14:27 +0100 @@@@ -56,6 +56,9 @@@@ d160 2 a161 2 --- servconf.c.orig 2008-07-04 05:51:12 +0200 +++ servconf.c 2008-11-15 10:14:27 +0100 d171 1 a171 1 @@@@ -185,6 +187,10 @@@@ d182 1 a182 1 @@@@ -290,7 +296,7 @@@@ d191 1 a191 1 @@@@ -386,6 +392,8 @@@@ d200 1 a200 1 @@@@ -930,6 +938,14 @@@@ d216 2 a217 2 --- servconf.h.orig 2008-06-10 15:01:51 +0200 +++ servconf.h 2008-11-15 10:14:27 +0100 d230 2 a231 2 --- serverloop.c.orig 2008-07-04 15:10:49 +0200 +++ serverloop.c 2008-11-15 10:15:01 +0100 d403 2 a404 2 --- ssh.1.orig 2008-07-04 04:53:50 +0200 +++ ssh.1 2008-11-15 10:14:27 +0100 d414 2 a415 2 --- ssh_config.5.orig 2008-06-29 16:04:03 +0200 +++ ssh_config.5 2008-11-15 10:14:27 +0100 d441 3 a443 3 --- sshd_config.5.orig 2008-07-02 14:35:43 +0200 +++ sshd_config.5 2008-11-15 10:14:27 +0100 @@@@ -932,6 +932,30 @@@@ @ 1.1 log @fix Watchdog patch @ text @d453 1 a453 1 +to terminate a session even if the serever continues sending some data @