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 charts.free.fr If you think this patch is worth to be included in the main tree, then you can vote for it on bugzilla.mindrot.org/showvotes.cgi?voteon=207 but this requires a login. You can also just browse the case at 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 *);