浏览代码

fix Watchdog patch

Ralf S. Engelschall 17 年之前
父节点
当前提交
91ee71e466
共有 2 个文件被更改,包括 475 次插入9 次删除
  1. 473 0
      openssh/openssh.patch.watchdog
  2. 2 9
      openssh/openssh.spec

+ 473 - 0
openssh/openssh.patch.watchdog

@@ -0,0 +1,473 @@
+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	2008-07-16 14:40:52 +0200
++++ clientloop.c	2008-11-15 10:14:27 +0100
+@@ -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
+@@ -1305,6 +1344,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	2008-06-29 16:04:03 +0200
++++ readconf.c	2008-11-15 10:14:27 +0100
+@@ -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 },
+@@ -492,6 +493,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;
+@@ -1027,6 +1032,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;
+@@ -1126,6 +1132,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	2008-06-29 16:04:03 +0200
++++ readconf.h	2008-11-15 10:14:27 +0100
+@@ -56,6 +56,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	2008-07-04 05:51:12 +0200
++++ servconf.c	2008-11-15 10:14:27 +0100
+@@ -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;
+@@ -185,6 +187,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)
+@@ -290,7 +296,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,
+@@ -386,6 +392,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 },
+@@ -930,6 +938,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	2008-06-10 15:01:51 +0200
++++ servconf.h	2008-11-15 10:14:27 +0100
+@@ -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	2008-07-04 15:10:49 +0200
++++ serverloop.c	2008-11-15 10:15:01 +0100
+@@ -106,6 +106,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
+@@ -280,6 +282,7 @@
+ {
+ 	struct timeval tv, *tvp;
+ 	int ret;
++	int watchdog_timeout = 0;
+ 	int client_alive_scheduled = 0;
+ 	int program_alive_scheduled = 0;
+ 
+@@ -349,6 +352,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 {
+@@ -376,6 +392,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);
+ }
+ 
+@@ -556,7 +589,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.");
+ 
+@@ -623,6 +658,8 @@
+ 
+ 	server_init_dispatch();
+ 
++	idle_time_last = time(NULL);
++
+ 	/* Main loop of the server for the interactive session mode. */
+ 	for (;;) {
+ 
+@@ -703,6 +740,9 @@
+ 			cleanup_exit(255);
+ 		}
+ 
++		/* Break, if watchdog timeout occured. */
++		if (child_forced_to_terminate)  break;
++
+ 		/* Process any channel events. */
+ 		channel_after_select(readset, writeset);
+ 
+@@ -712,6 +752,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)
+@@ -720,7 +778,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);
+@@ -748,6 +808,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));
+@@ -821,6 +887,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();
+ 
+@@ -837,6 +904,8 @@
+ 
+ 	server_init_dispatch();
+ 
++	idle_time_last = time(NULL);
++
+ 	for (;;) {
+ 		process_buffered_input_packets();
+ 
+@@ -853,6 +922,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	2008-07-04 04:53:50 +0200
++++ ssh.1	2008-11-15 10:14:27 +0100
+@@ -470,6 +470,7 @@
+ .It GSSAPIAuthentication
+ .It GSSAPIDelegateCredentials
+ .It HashKnownHosts
++.It Heartbeat
+ .It Host
+ .It HostbasedAuthentication
+ .It HostKeyAlgorithms
+Index: ssh_config.5
+--- ssh_config.5.orig	2008-06-29 16:04:03 +0200
++++ ssh_config.5	2008-11-15 10:14:27 +0100
+@@ -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	2008-07-02 14:35:43 +0200
++++ sshd_config.5	2008-11-15 10:14:27 +0100
+@@ -932,6 +932,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 serever 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

+ 2 - 9
openssh/openssh.spec

@@ -24,7 +24,6 @@
 #   package versions
 %define       V_base        5.1
 %define       V_portable    p1
-%define       V_watchdog    4.4p1
 %define       V_connect     100
 %define       V_hpn         5.1p1-hpn13v5
 
@@ -72,7 +71,7 @@ Source9:      ftp://ftp.openpkg.org/sources/CPY/VERSIONED/openssh-connect/openss
 Patch0:       openssh.patch
 Patch1:       openssh.patch.chroot
 Patch2:       openssh.patch.alias
-Patch3:       http://www.sc.isc.tohoku.ac.jp/~hgot/sources/openssh-%{V_watchdog}-watchdog.patch.tgz
+Patch3:       openssh.patch.watchdog
 Patch4:       openssh.patch.lpk
 Patch5:       openssh.patch.sftplogging
 Patch6:       openssh.patch.scpbindir
@@ -137,11 +136,6 @@ AutoReqProv:  no
         url       = ftp://ftp.openssh.com/pub/OpenBSD/OpenSSH/portable/
         regex     = openssh-(__VER__)\.tar\.gz
     }
-    prog openssh:watchdog = {
-        version   = %{V_watchdog}
-        url       = http://www.sc.isc.tohoku.ac.jp/~hgot/sources/openssh-watchdog.html
-        regex     = HREF=.openssh-(__VER__)-watchdog\.patch\.tgz
-    }
     prog openssh:hpn = {
         version   = %{V_hpn}
         url       = http://www.psc.edu/networking/projects/hpn-ssh/
@@ -165,8 +159,7 @@ AutoReqProv:  no
     %patch -p0 -P 2
 %endif
 %if "%{with_watchdog}" == "yes"
-    %{l_gzip} -d -c %{SOURCE openssh-%{V_watchdog}-watchdog.patch.tgz} | %{l_tar} xf -
-    %{l_patch} -p0 -b <openssh-%{V_watchdog}-watchdog.patch
+    %patch -p0 -P 3
 %endif
 %if "%{with_ldap}" == "yes"
     %patch -p0 -P 4