|
|
@@ -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
|