ssh client does not timeout if the network fails after ssh_connect but before ssh_exchange_identification, even with Alive options set

Dan Yefimov dan at D00M.lightwave.net.ru
Thu Jul 26 21:52:11 EST 2007


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!
> 
> --- sshconnect.c~old    2007-07-25 10:44:26.000000000 -0700
> +++ sshconnect.c        2007-07-25 14:45:57.000000000 -0700
> @@ -404,9 +404,26 @@ ssh_exchange_identification(void)
>         int minor1 = PROTOCOL_MINOR_1;
>         u_int i, n;
> 
> +       if (options.server_alive_interval) {
> +               fd_set rfds;
> +               struct timeval timeo = { .tv_usec=0 };
> +               int read_timeouts, ret;
> +
> +               FD_SET(connection_in, &rfds);
> +               for (read_timeouts = 0;;) {
> +                       timeo.tv_sec = options.server_alive_interval;
> +                       ret = select(connection_in+1, &rfds, NULL, NULL,
> &timeo);
> +                       if (ret < 0) {

I think you should handle errno == EINTR case here restarting select(), 
otherwise any arriving signal would make ssh fail here.

> +                               fatal("ssh_exchange_identification: select
> read error: %.100s", strerror(errno));
> +                       } else if (ret == 0) {
> +                               if (++read_timeouts >=
> options.server_alive_count_max)
> +                                       fatal("ssh_exchange_identification:
> Timeout, server not responding");
> +                       } else
> +                               break;
> +               }
> +
> +       }
>         /* Read other side's version identification. */
> -       struct timeval timeo = { .tv_sec=10, .tv_usec=0 };
> -       setsockopt(connection_in, SOL_SOCKET, SO_SNDTIMEO, &timeo,
> sizeof(timeo));
>         for (n = 0;;) {
>                 for (i = 0; i < sizeof(buf) - 1; i++) {
>                         size_t len = atomicio(read, connection_in, &buf[i],
> 1);
> @@ -490,6 +507,25 @@ ssh_exchange_identification(void)
>             compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
>             compat20 ? PROTOCOL_MINOR_2 : minor1,
>             SSH_VERSION);
> +       if (options.server_alive_interval) {
> +               fd_set wfds;
> +               struct timeval timeo = { .tv_usec=0 };
> +               int write_timeouts, ret;
> +
> +               FD_SET(connection_out, &wfds);
> +               for (write_timeouts = 0;;) {
> +                       timeo.tv_sec = options.server_alive_interval;
> +                       ret = select(connection_out+1, NULL, &wfds, NULL,
> &timeo);
> +                       if (ret < 0) {

The same notice as above here.

> +                               fatal("ssh_exchange_identification: select
> write error: %.100s", strerror(errno));
> +                       } else if (ret == 0) {
> +                               if (++write_timeouts >=
> options.server_alive_count_max)
> +                                       fatal("ssh_exchange_identification:
> Timeout, server not responding");
> +                       } else
> +                               break;
> +               }
> +
> +       }
>         if (atomicio(vwrite, connection_out, buf, strlen(buf)) !=
> strlen(buf))
>                 fatal("write: %.100s", strerror(errno));
>         client_version_string = xstrdup(buf);
> 
-- 

    Sincerely Your, Dan.



More information about the openssh-unix-dev mailing list