Re: ssh client does not timeout if the network fails after

This is a discussion on Re: ssh client does not timeout if the network fails after within the OpenSSH Development forums, part of the Networking and Network Related category; Thanks for the updates. Jiaying On 7/26/07, Damien Miller <djm@mindrot.org> wrote: > > On ...


Go Back   Usenet Forums > Networking and Network Related > OpenSSH Development

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 07-27-2007
Jiaying Zhang
 
Posts: n/a
Default Re: ssh client does not timeout if the network fails after

Thanks for the updates.

Jiaying

On 7/26/07, Damien Miller <djm@mindrot.org> wrote:
>
> On Wed, 25 Jul 2007, Jiaying Zhang wrote:
>
> > Hello again,
> >
> > Here is the patch I came up with to prevent the hanging in
> > ssh_exchange_identification. I tested it a little bit and it seems to

> have
> > solved the problem. Could anyone help to have a look at the patch?

> Thanks a
> > lot!

>
> Here is a patch that I did a while ago to make ConnectTimeout apply
> to banner exchange too (updated to -current):
>
> Index: ssh.c
> ================================================== =================
> RCS file: /cvs/src/usr.bin/ssh/ssh.c,v
> retrieving revision 1.300
> diff -u -p -r1.300 ssh.c
> --- ssh.c 14 Jun 2007 22:48:05 -0000 1.300
> +++ ssh.c 27 Jul 2007 02:14:11 -0000
> @@ -202,7 +202,7 @@ main(int ac, char **av)
> char *p, *cp, *line, buf[256];
> struct stat st;
> struct passwd *pw;
> - int dummy;
> + int dummy, timeout_ms;
> extern int optind, optreset;
> extern char *optarg;
> struct servent *sp;
> @@ -666,13 +666,19 @@ main(int ac, char **av)
> if (options.control_path != NULL)
> control_client(options.control_path);
>
> + timeout_ms = options.connection_timeout * 1000;
> +
> /* Open a connection to the remote host. */
> if (ssh_connect(host, &hostaddr, options.port,
> - options.address_family, options.connection_attempts,
> + options.address_family, options.connection_attempts,
> &timeout_ms,
> + options.tcp_keep_alive,
> original_effective_uid == 0 && options.use_privileged_port,
> options.proxy_command) != 0)
> exit(255);
>
> + if (timeout_ms > 0)
> + debug3("timeout: %d ms remain after connect", timeout_ms);
> +
> /*
> * If we successfully made the connection, load the host private
> key
> * in case we will need it later for combined rsa-rhosts
> @@ -748,7 +754,8 @@ main(int ac, char **av)
> signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
>
> /* Log into the remote system. This never returns if the login
> fails. */
> - ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
> pw);
> + ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
> + pw, timeout_ms);
>
> /* We no longer need the private host keys. Clear them now. */
> if (sensitive_data.nkeys != 0) {
> Index: sshconnect.c
> ================================================== =================
> RCS file: /cvs/src/usr.bin/ssh/sshconnect.c,v
> retrieving revision 1.200
> diff -u -p -r1.200 sshconnect.c
> --- sshconnect.c 10 Oct 2006 10:12:45 -0000 1.200
> +++ sshconnect.c 27 Jul 2007 02:14:11 -0000
> @@ -64,6 +64,23 @@ extern pid_t proxy_command_pid;
> static int show_other_keys(const char *, Key *);
> static void warn_changed_key(Key *);
>
> +static void
> +ms_subtract_time(struct timeval *start, int *ms)
> +{
> + struct timeval diff, finish;
> +
> + gettimeofday(&finish, NULL);
> + timersub(&finish, start, &diff);
> + *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
> +}
> +
> +static void
> +ms_to_timeval(struct timeval *tv, int ms)
> +{
> + tv->tv_sec = ms / 1000;
> + tv->tv_usec = (ms % 1000) * 1000;
> +}
> +
> /*
> * Connect to the given ssh server using a proxy command.
> */
> @@ -207,30 +224,36 @@ ssh_create_socket(int privileged, struct
>
> static int
> timeout_connect(int sockfd, const struct sockaddr *serv_addr,
> - socklen_t addrlen, int timeout)
> + socklen_t addrlen, int *timeoutp)
> {
> fd_set *fdset;
> - struct timeval tv;
> + struct timeval tv, t_start;
> socklen_t optlen;
> int optval, rc, result = -1;
>
> - if (timeout <= 0)
> - return (connect(sockfd, serv_addr, addrlen));
> + gettimeofday(&t_start, NULL);
> +
> + if (*timeoutp <= 0) {
> + result = connect(sockfd, serv_addr, addrlen);
> + goto done;
> + }
>
> set_nonblock(sockfd);
> rc = connect(sockfd, serv_addr, addrlen);
> if (rc == 0) {
> unset_nonblock(sockfd);
> - return (0);
> + result = 0;
> + goto done;
> + }
> + if (errno != EINPROGRESS) {
> + result = -1;
> + goto done;
> }
> - if (errno != EINPROGRESS)
> - return (-1);
>
> fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
> sizeof(fd_mask));
> FD_SET(sockfd, fdset);
> - tv.tv_sec = timeout;
> - tv.tv_usec = 0;
> + ms_to_timeval(&tv, *timeoutp);
>
> for (;;) {
> rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
> @@ -269,6 +292,11 @@ timeout_connect(int sockfd, const struct
> }
>
> xfree(fdset);
> +
> + done:
> + if (result == 0 && *timeoutp > 0)
> + ms_subtract_time(&t_start, timeoutp);
> +
> return (result);
> }
>
> @@ -285,8 +313,8 @@ timeout_connect(int sockfd, const struct
> */
> int
> ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
> - u_short port, int family, int connection_attempts,
> - int needpriv, const char *proxy_command)
> + u_short port, int family, int connection_attempts, int *timeout_ms,
> + int want_keepalive, int needpriv, const char *proxy_command)
> {
> int gaierr;
> int on = 1;
> @@ -339,7 +367,7 @@ ssh_connect(const char *host, struct soc
> continue;
>
> if (timeout_connect(sock, ai->ai_addr,
> ai->ai_addrlen,
> - options.connection_timeout) >= 0) {
> + timeout_ms) >= 0) {
> /* Successful connection. */
> memcpy(hostaddr, ai->ai_addr,
> ai->ai_addrlen);
> break;
> @@ -366,7 +394,7 @@ ssh_connect(const char *host, struct soc
> debug("Connection established.");
>
> /* Set SO_KEEPALIVE if requested. */
> - if (options.tcp_keep_alive &&
> + if (want_keepalive &&
> setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
> sizeof(on)) < 0)
> error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
> @@ -382,7 +410,7 @@ ssh_connect(const char *host, struct soc
> * identification string.
> */
> static void
> -ssh_exchange_identification(void)
> +ssh_exchange_identification(int timeout_ms)
> {
> char buf[256], remote_version[256]; /* must be same size! */
> int remote_major, remote_minor, mismatch;
> @@ -390,16 +418,44 @@ ssh_exchange_identification(void)
> int connection_out = packet_get_connection_out();
> int minor1 = PROTOCOL_MINOR_1;
> u_int i, n;
> + size_t len;
> + int fdsetsz, remaining, rc;
> + struct timeval t_start, t_remaining;
> + fd_set *fdset;
> +
> + fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
> + fdset = xcalloc(1, fdsetsz);
>
> /* Read other side's version identification. */
> + remaining = timeout_ms;
> for (n = 0;;) {
> for (i = 0; i < sizeof(buf) - 1; i++) {
> - size_t len = atomicio(read, connection_in,
> &buf[i], 1);
> + if (timeout_ms > 0) {
> + gettimeofday(&t_start, NULL);
> + ms_to_timeval(&t_remaining, remaining);
> + FD_SET(connection_in, fdset);
> + rc = select(connection_in + 1, fdset,
> NULL,
> + fdset, &t_remaining);
> + ms_subtract_time(&t_start, &remaining);
> + if (rc == 0 || remaining <= 0)
> + fatal("Connection timed out during
> "
> + "banner exchange");
> + if (rc == -1) {
> + if (errno == EINTR)
> + continue;
> +
> fatal("ssh_exchange_identification: "
> + "select: %s",
> strerror(errno));
> + }
> + }
> +
> + len = atomicio(read, connection_in, &buf[i], 1);
>
> if (len != 1 && errno == EPIPE)
> - fatal("ssh_exchange_identification:
> Connection closed by remote host");
> + fatal("ssh_exchange_identification: "
> + "Connection closed by remote host");
> else if (len != 1)
> - fatal("ssh_exchange_identification: read:
> %.100s", strerror(errno));
> + fatal("ssh_exchange_identification: "
> + "read: %.100s", strerror(errno));
> if (buf[i] == '\r') {
> buf[i] = '\n';
> buf[i + 1] = 0;
> @@ -410,7 +466,8 @@ ssh_exchange_identification(void)
> break;
> }
> if (++n > 65536)
> - fatal("ssh_exchange_identification: No
> banner received");
> + fatal("ssh_exchange_identification: "
> + "No banner received");
> }
> buf[sizeof(buf) - 1] = 0;
> if (strncmp(buf, "SSH-", 4) == 0)
> @@ -418,6 +475,7 @@ ssh_exchange_identification(void)
> debug("ssh_exchange_identification: %s", buf);
> }
> server_version_string = xstrdup(buf);
> + xfree(fdset);
>
> /*
> * Check that the versions match. In future this might accept
> @@ -926,7 +984,7 @@ verify_host_key(char *host, struct socka
> */
> void
> ssh_login(Sensitive *sensitive, const char *orighost,
> - struct sockaddr *hostaddr, struct passwd *pw)
> + struct sockaddr *hostaddr, struct passwd *pw, int timeout_ms)
> {
> char *host, *cp;
> char *server_user, *local_user;
> @@ -941,7 +999,7 @@ ssh_login(Sensitive *sensitive, const ch
> *cp = (char)tolower(*cp);
>
> /* Exchange protocol version identification strings with the
> server. */
> - ssh_exchange_identification();
> + ssh_exchange_identification(timeout_ms);
>
> /* Put the connection into non-blocking mode. */
> packet_set_nonblocking();
> Index: sshconnect.h
> ================================================== =================
> RCS file: /cvs/src/usr.bin/ssh/sshconnect.h,v
> retrieving revision 1.23
> diff -u -p -r1.23 sshconnect.h
> --- sshconnect.h 3 Aug 2006 03:34:42 -0000 1.23
> +++ sshconnect.h 27 Jul 2007 02:14:11 -0000
> @@ -33,10 +33,10 @@ struct Sensitive {
>
> int
> ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
> - int, const char *);
> + int *, int, int, const char *);
>
> void
> -ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *);
> +ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *,
> int);
>
> int verify_host_key(char *, struct sockaddr *, Key *);
>
>

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/li...enssh-unix-dev
Reply With Quote
Reply
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are Off
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



All times are GMT +1. The time now is 04:45 AM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO 3.0.0