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 ...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
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 |