Here are the new versions of this widely used patch for OpenSSH 3.2.2p1 and 3.2.3p1. The patch avoids waiting to long when using ssh() or scp() on a down host, it is usefull when you have to update many hosts via rsync or rdist themselves relying upon ssh(). It enables a new option 'ConnectTimeout' to control exactly the timeout value, so that it can be used even on slow links. These patches can also be found on http://charts.free.fr/ If you think this patch is worth to be included in the main tree, then you can vote for it on http://bugzilla.mindrot.org/showvotes.cgi?voteon=207 but this requires a login. You can also just browse the case at http://bugzilla.mindrot.org/show_bug.cgi?id=207 Hope this patch help you. -- Jean-Charles -------------- next part -------------- --- openssh-3.2.2p1/readconf.c.ORIG Tue Feb 5 02:26:35 2002 +++ openssh-3.2.2p1/readconf.c Tue May 21 15:40:06 2002 @@ -115,7 +115,8 @@ oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, - oClearAllForwardings, oNoHostAuthenticationForLocalhost + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oConnectTimeout } OpCodes; /* Textual representations of the tokens. */ @@ -187,6 +188,7 @@ { "smartcarddevice", oSmartcardDevice }, { "clearallforwardings", oClearAllForwardings }, { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, + { "connecttimeout", oConnectTimeout }, { NULL, oBadOption } }; @@ -294,6 +296,19 @@ /* don't panic, but count bad options */ return -1; /* NOTREACHED */ + + case oConnectTimeout: + intptr = &options->connection_timeout; +parse_time: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing time argument.", filename, linenum); + if ((value = convtime(arg)) == -1) + fatal("%.200s line %d: Invalid time argument.", filename, linenum); + if (*intptr == -1) + *intptr = value; + break; + case oForwardAgent: intptr = &options->forward_agent; parse_flag: @@ -775,6 +790,7 @@ options->compression_level = -1; options->port = -1; options->connection_attempts = -1; + options->connection_timeout = -1; options->number_of_password_prompts = -1; options->cipher = -1; options->ciphers = NULL; --- openssh-3.2.2p1/readconf.h.ORIG Tue Mar 5 02:53:05 2002 +++ openssh-3.2.2p1/readconf.h Tue May 21 15:40:06 2002 @@ -68,6 +68,8 @@ int port; /* Port to connect. */ int connection_attempts; /* Max attempts (seconds) before * giving up */ + int connection_timeout; /* Max time (seconds) before + * aborting connection attempt */ int number_of_password_prompts; /* Max number of password * prompts. */ int cipher; /* Cipher to use. */ --- openssh-3.2.2p1/ssh.1.ORIG Wed May 15 23:36:46 2002 +++ openssh-3.2.2p1/ssh.1 Tue May 21 15:40:06 2002 @@ -813,6 +813,12 @@ The argument must be an integer. This may be useful in scripts if the connection sometimes fails. The default is 1. +.It Cm ConnectTimeout +Specifies the timeout used when connecting to the ssh +server, instead of using default system values. This value is used +only when the target is down or really unreachable, not when it +refuses the connection. This may be usefull for tools using ssh +for communication, as it avoid long TCP timeouts. .It Cm DynamicForward Specifies that a TCP/IP port on the local machine be forwarded over the secure channel, and the application --- openssh-3.2.2p1/ssh.c.ORIG Tue Apr 23 13:09:46 2002 +++ openssh-3.2.2p1/ssh.c Tue May 21 15:40:06 2002 @@ -677,7 +677,7 @@ /* Open a connection to the remote host. */ cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6, - options.connection_attempts, + options.connection_attempts, options.connection_timeout, original_effective_uid != 0 || !options.use_privileged_port, pw, options.proxy_command); --- openssh-3.2.2p1/sshconnect.c.ORIG Tue Mar 5 19:59:46 2002 +++ openssh-3.2.2p1/sshconnect.c Tue May 21 15:40:06 2002 @@ -222,6 +222,63 @@ return sock; } +int +timeout_connect(int sockfd, const struct sockaddr *serv_addr, + socklen_t addrlen, int timeout) +{ + fd_set *fdset; + struct timeval tv; + socklen_t optlen; + int fdsetsz, optval, rc; + + if (timeout <= 0) + return(connect(sockfd, serv_addr, addrlen)); + + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) + return -1; + + rc = connect(sockfd, serv_addr, addrlen); + if (rc == 0) + return 0; + if (errno != EINPROGRESS) + return -1; + + fdsetsz = howmany(sockfd+1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + memset(fdset, 0, fdsetsz); + FD_SET(sockfd, fdset); + tv.tv_sec = timeout; + tv.tv_usec = 0; + rc=select(sockfd+1, NULL, fdset, NULL, &tv); + + switch(rc) { + case 0: + errno = ETIMEDOUT; + case -1: + return -1; + break; + case 1: + optval = 0; + optlen = sizeof(optval); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) + return -1; + if (optval != 0) + { + errno = optval; + return -1; + } + return 0; + + default: + /* Should not occur */ + return -1; + break; + } + + return -1; + +} + /* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. @@ -241,7 +298,7 @@ */ int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, - u_short port, int family, int connection_attempts, + u_short port, int family, int connection_attempts, int connection_timeout, int anonymous, struct passwd *pw, const char *proxy_command) { int gaierr; @@ -323,7 +380,8 @@ * the remote uid as root. */ temporarily_use_uid(pw); - if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { + if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, + connection_timeout) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); restore_uid(); --- openssh-3.2.2p1/sshconnect.h.ORIG Wed Oct 10 07:07:45 2001 +++ openssh-3.2.2p1/sshconnect.h Tue May 21 15:40:06 2002 @@ -28,7 +28,7 @@ int ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, - int, struct passwd *, const char *); + int, int, struct passwd *, const char *); void ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *); -------------- next part -------------- --- openssh-3.2.3p1/readconf.c.ORIG Tue Feb 5 02:26:35 2002 +++ openssh-3.2.3p1/readconf.c Wed May 22 19:45:13 2002 @@ -115,7 +115,8 @@ oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, - oClearAllForwardings, oNoHostAuthenticationForLocalhost + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oConnectTimeout } OpCodes; /* Textual representations of the tokens. */ @@ -187,6 +188,7 @@ { "smartcarddevice", oSmartcardDevice }, { "clearallforwardings", oClearAllForwardings }, { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, + { "connecttimeout", oConnectTimeout }, { NULL, oBadOption } }; @@ -294,6 +296,19 @@ /* don't panic, but count bad options */ return -1; /* NOTREACHED */ + + case oConnectTimeout: + intptr = &options->connection_timeout; +parse_time: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing time argument.", filename, linenum); + if ((value = convtime(arg)) == -1) + fatal("%.200s line %d: Invalid time argument.", filename, linenum); + if (*intptr == -1) + *intptr = value; + break; + case oForwardAgent: intptr = &options->forward_agent; parse_flag: @@ -775,6 +790,7 @@ options->compression_level = -1; options->port = -1; options->connection_attempts = -1; + options->connection_timeout = -1; options->number_of_password_prompts = -1; options->cipher = -1; options->ciphers = NULL; --- openssh-3.2.3p1/readconf.h.ORIG Tue Mar 5 02:53:05 2002 +++ openssh-3.2.3p1/readconf.h Wed May 22 19:45:13 2002 @@ -68,6 +68,8 @@ int port; /* Port to connect. */ int connection_attempts; /* Max attempts (seconds) before * giving up */ + int connection_timeout; /* Max time (seconds) before + * aborting connection attempt */ int number_of_password_prompts; /* Max number of password * prompts. */ int cipher; /* Cipher to use. */ --- openssh-3.2.3p1/ssh.1.ORIG Wed May 15 23:36:46 2002 +++ openssh-3.2.3p1/ssh.1 Wed May 22 19:45:13 2002 @@ -813,6 +813,12 @@ The argument must be an integer. This may be useful in scripts if the connection sometimes fails. The default is 1. +.It Cm ConnectTimeout +Specifies the timeout used when connecting to the ssh +server, instead of using default system values. This value is used +only when the target is down or really unreachable, not when it +refuses the connection. This may be usefull for tools using ssh +for communication, as it avoid long TCP timeouts. .It Cm DynamicForward Specifies that a TCP/IP port on the local machine be forwarded over the secure channel, and the application --- openssh-3.2.3p1/ssh.c.ORIG Tue Apr 23 13:09:46 2002 +++ openssh-3.2.3p1/ssh.c Wed May 22 19:45:13 2002 @@ -677,7 +677,7 @@ /* Open a connection to the remote host. */ cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6, - options.connection_attempts, + options.connection_attempts, options.connection_timeout, original_effective_uid != 0 || !options.use_privileged_port, pw, options.proxy_command); --- openssh-3.2.3p1/sshconnect.c.ORIG Tue Mar 5 19:59:46 2002 +++ openssh-3.2.3p1/sshconnect.c Wed May 22 19:45:13 2002 @@ -222,6 +222,63 @@ return sock; } +int +timeout_connect(int sockfd, const struct sockaddr *serv_addr, + socklen_t addrlen, int timeout) +{ + fd_set *fdset; + struct timeval tv; + socklen_t optlen; + int fdsetsz, optval, rc; + + if (timeout <= 0) + return(connect(sockfd, serv_addr, addrlen)); + + if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) + return -1; + + rc = connect(sockfd, serv_addr, addrlen); + if (rc == 0) + return 0; + if (errno != EINPROGRESS) + return -1; + + fdsetsz = howmany(sockfd+1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + memset(fdset, 0, fdsetsz); + FD_SET(sockfd, fdset); + tv.tv_sec = timeout; + tv.tv_usec = 0; + rc=select(sockfd+1, NULL, fdset, NULL, &tv); + + switch(rc) { + case 0: + errno = ETIMEDOUT; + case -1: + return -1; + break; + case 1: + optval = 0; + optlen = sizeof(optval); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) + return -1; + if (optval != 0) + { + errno = optval; + return -1; + } + return 0; + + default: + /* Should not occur */ + return -1; + break; + } + + return -1; + +} + /* * Opens a TCP/IP connection to the remote server on the given host. * The address of the remote host will be returned in hostaddr. @@ -241,7 +298,7 @@ */ int ssh_connect(const char *host, struct sockaddr_storage * hostaddr, - u_short port, int family, int connection_attempts, + u_short port, int family, int connection_attempts, int connection_timeout, int anonymous, struct passwd *pw, const char *proxy_command) { int gaierr; @@ -323,7 +380,8 @@ * the remote uid as root. */ temporarily_use_uid(pw); - if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { + if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, + connection_timeout) >= 0) { /* Successful connection. */ memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); restore_uid(); --- openssh-3.2.3p1/sshconnect.h.ORIG Wed Oct 10 07:07:45 2001 +++ openssh-3.2.3p1/sshconnect.h Wed May 22 19:45:13 2002 @@ -28,7 +28,7 @@ int ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, - int, struct passwd *, const char *); + int, int, struct passwd *, const char *); void ssh_login(Key **, int, const char *, struct sockaddr *, struct passwd *);