- dtucker@cvs.openbsd.org 2008/06/12 20:38:28
[sshd.c sshconnect.c packet.h misc.c misc.h packet.c]
Make keepalive timeouts apply while waiting for a packet, particularly
during key renegotiation (bz #1363). With djm and Matt Day, ok djm@
diff --git a/packet.c b/packet.c
index c0e91b2..9fd43ec 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.153 2008/05/19 06:14:02 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.154 2008/06/12 20:38:28 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -138,6 +138,9 @@
int keep_alive_timeouts = 0;
+/* Set to the maximum time that we will wait to send or receive a packet */
+static int packet_timeout_ms = -1;
+
/* Session key information for Encryption and MAC */
Newkeys *newkeys[MODE_MAX];
static struct packet_state {
@@ -191,6 +194,19 @@
}
}
+void
+packet_set_timeout(int timeout, int count)
+{
+ if (timeout == 0 || count == 0) {
+ packet_timeout_ms = -1;
+ return;
+ }
+ if ((INT_MAX / 1000) / count < timeout)
+ packet_timeout_ms = INT_MAX;
+ else
+ packet_timeout_ms = timeout * count * 1000;
+}
+
/* Returns 1 if remote host is connected via socket, 0 if not. */
int
@@ -891,10 +907,11 @@
int
packet_read_seqnr(u_int32_t *seqnr_p)
{
- int type, len;
+ int type, len, ret, ms_remain;
fd_set *setp;
char buf[8192];
DBG(debug("packet_read()"));
+ struct timeval timeout, start, *timeoutp = NULL;
setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS),
sizeof(fd_mask));
@@ -925,11 +942,34 @@
sizeof(fd_mask));
FD_SET(connection_in, setp);
+ if (packet_timeout_ms > 0) {
+ ms_remain = packet_timeout_ms;
+ timeoutp = &timeout;
+ }
/* Wait for some data to arrive. */
- while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
- (errno == EAGAIN || errno == EINTR))
- ;
-
+ for (;;) {
+ if (packet_timeout_ms != -1) {
+ ms_to_timeval(&timeout, ms_remain);
+ gettimeofday(&start, NULL);
+ }
+ if ((ret = select(connection_in + 1, setp, NULL,
+ NULL, timeoutp)) >= 0)
+ break;
+ if (errno != EAGAIN && errno != EINTR)
+ break;
+ if (packet_timeout_ms == -1)
+ continue;
+ ms_subtract_diff(&start, &ms_remain);
+ if (ms_remain <= 0) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret == 0) {
+ logit("Connection to %.200s timed out while "
+ "waiting to read", get_remote_ipaddr());
+ cleanup_exit(255);
+ }
/* Read data from the socket. */
len = read(connection_in, buf, sizeof(buf));
if (len == 0) {
@@ -1452,6 +1492,8 @@
packet_write_wait(void)
{
fd_set *setp;
+ int ret, ms_remain;
+ struct timeval start, timeout, *timeoutp = NULL;
setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS),
sizeof(fd_mask));
@@ -1460,9 +1502,34 @@
memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
sizeof(fd_mask));
FD_SET(connection_out, setp);
- while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
- (errno == EAGAIN || errno == EINTR))
- ;
+
+ if (packet_timeout_ms > 0) {
+ ms_remain = packet_timeout_ms;
+ timeoutp = &timeout;
+ }
+ for (;;) {
+ if (packet_timeout_ms != -1) {
+ ms_to_timeval(&timeout, ms_remain);
+ gettimeofday(&start, NULL);
+ }
+ if ((ret = select(connection_out + 1, NULL, setp,
+ NULL, timeoutp)) >= 0)
+ break;
+ if (errno != EAGAIN && errno != EINTR)
+ break;
+ if (packet_timeout_ms == -1)
+ continue;
+ ms_subtract_diff(&start, &ms_remain);
+ if (ms_remain <= 0) {
+ ret = 0;
+ break;
+ }
+ }
+ if (ret == 0) {
+ logit("Connection to %.200s timed out while "
+ "waiting to write", get_remote_ipaddr());
+ cleanup_exit(255);
+ }
packet_write_poll();
}
xfree(setp);