- djm@cvs.openbsd.org 2003/05/15 14:55:25
[readconf.c readconf.h ssh_config ssh_config.5 sshconnect.c]
add a ConnectTimeout option to ssh, based on patch from
Jean-Charles Longuet (jclonguet at free.fr); portable #207 ok markus@
diff --git a/ChangeLog b/ChangeLog
index 1e031aa..7a36475 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,10 @@
- markus@cvs.openbsd.org 2003/05/15 14:09:21
[auth2-krb5.c]
fix 64bit issue; report itojun@
+ - djm@cvs.openbsd.org 2003/05/15 14:55:25
+ [readconf.c readconf.h ssh_config ssh_config.5 sshconnect.c]
+ add a ConnectTimeout option to ssh, based on patch from
+ Jean-Charles Longuet (jclonguet at free.fr); portable #207 ok markus@
20030515
- (djm) OpenBSD CVS Sync
@@ -1541,4 +1545,4 @@
save auth method before monitor_reset_key_state(); bugzilla bug #284;
ok provos@
-$Id: ChangeLog,v 1.2726 2003/05/16 01:38:46 djm Exp $
+$Id: ChangeLog,v 1.2727 2003/05/16 01:39:04 djm Exp $
diff --git a/readconf.c b/readconf.c
index fee7a89..a0cf3d6 100644
--- a/readconf.c
+++ b/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.110 2003/05/15 14:02:47 jakob Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.111 2003/05/15 14:55:25 djm Exp $");
#include "ssh.h"
#include "xmalloc.h"
@@ -106,7 +106,7 @@
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
- oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS,
+ oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oDeprecated, oUnsupported
} OpCodes;
@@ -193,6 +193,7 @@
#endif
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ "rekeylimit", oRekeyLimit },
+ { "connecttimeout", oConnectTimeout },
{ NULL, oBadOption }
};
@@ -309,6 +310,20 @@
/* 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("%s line %d: missing time value.",
+ filename, linenum);
+ if ((value = convtime(arg)) == -1)
+ fatal("%s line %d: invalid time value.",
+ filename, linenum);
+ if (*intptr == -1)
+ *intptr = value;
+ break;
+
case oForwardAgent:
intptr = &options->forward_agent;
parse_flag:
@@ -808,6 +823,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;
diff --git a/readconf.h b/readconf.h
index 991e200..c884de6 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.49 2003/05/15 01:48:10 jakob Exp $ */
+/* $OpenBSD: readconf.h,v 1.50 2003/05/15 14:55:25 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -60,6 +60,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. */
diff --git a/ssh_config b/ssh_config
index 94cffbf..8a0acc1 100644
--- a/ssh_config
+++ b/ssh_config
@@ -1,4 +1,4 @@
-# $OpenBSD: ssh_config,v 1.16 2002/07/03 14:21:05 markus Exp $
+# $OpenBSD: ssh_config,v 1.17 2003/05/15 14:55:25 djm Exp $
# This is the ssh client system-wide configuration file. See
# ssh_config(5) for more information. This file provides defaults for
@@ -25,6 +25,7 @@
# HostbasedAuthentication no
# BatchMode no
# CheckHostIP yes
+# ConnectTimeout 0
# StrictHostKeyChecking ask
# IdentityFile ~/.ssh/identity
# IdentityFile ~/.ssh/id_rsa
diff --git a/ssh_config.5 b/ssh_config.5
index 2f33aa3..c5de4a9 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh_config.5,v 1.8 2003/05/14 18:16:20 jakob Exp $
+.\" $OpenBSD: ssh_config.5,v 1.9 2003/05/15 14:55:25 djm Exp $
.Dd September 25, 1999
.Dt SSH_CONFIG 5
.Os
@@ -227,6 +227,11 @@
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 (in seconds) used when connecting to the ssh
+server, instead of using the default system TCP timeout. This value is
+used only when the target is down or really unreachable, not when it
+refuses the connection.
.It Cm DynamicForward
Specifies that a TCP/IP port on the local machine be forwarded
over the secure channel, and the application
diff --git a/sshconnect.c b/sshconnect.c
index 32bef7d..8aac221 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -13,7 +13,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.140 2003/05/14 18:16:21 jakob Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.141 2003/05/15 14:55:25 djm Exp $");
#include <openssl/bn.h>
@@ -218,6 +218,71 @@
return sock;
}
+static 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;
+
+ for(;;) {
+ rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
+ if (rc != -1 || errno != EINTR)
+ break;
+ }
+
+ switch(rc) {
+ case 0:
+ /* Timed out */
+ errno = ETIMEDOUT;
+ return (-1);
+ case -1:
+ /* Select error */
+ debug("select: %s", strerror(errno));
+ return (-1);
+ case 1:
+ /* Completed or failed */
+ optval = 0;
+ optlen = sizeof(optval);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
+ &optlen) == -1)
+ debug("getsockopt: %s", strerror(errno));
+ return (-1);
+ if (optval != 0) {
+ errno = optval;
+ return (-1);
+ }
+ break;
+ default:
+ /* Should not occur */
+ fatal("Bogus return (%d) from select()", rc);
+ }
+
+ return (0);
+}
+
/*
* Opens a TCP/IP connection to the remote server on the given host.
* The address of the remote host will be returned in hostaddr.
@@ -306,7 +371,8 @@
/* Any error is already output */
continue;
- if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
+ if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
+ options.connection_timeout) >= 0) {
/* Successful connection. */
memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
break;