diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 155 |
1 files changed, 120 insertions, 35 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.157 2008/07/10 18:08:11 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -93,8 +93,6 @@ | |||
93 | static int connection_in = -1; | 93 | static int connection_in = -1; |
94 | static int connection_out = -1; | 94 | static int connection_out = -1; |
95 | 95 | ||
96 | static int setup_timeout = -1; | ||
97 | |||
98 | /* Protocol flags for the remote side. */ | 96 | /* Protocol flags for the remote side. */ |
99 | static u_int remote_protocol_flags = 0; | 97 | static u_int remote_protocol_flags = 0; |
100 | 98 | ||
@@ -138,12 +136,18 @@ static int server_side = 0; | |||
138 | /* Set to true if we are authenticated. */ | 136 | /* Set to true if we are authenticated. */ |
139 | static int after_authentication = 0; | 137 | static int after_authentication = 0; |
140 | 138 | ||
139 | int keep_alive_timeouts = 0; | ||
140 | |||
141 | /* Set to the maximum time that we will wait to send or receive a packet */ | ||
142 | static int packet_timeout_ms = -1; | ||
143 | |||
141 | /* Session key information for Encryption and MAC */ | 144 | /* Session key information for Encryption and MAC */ |
142 | Newkeys *newkeys[MODE_MAX]; | 145 | Newkeys *newkeys[MODE_MAX]; |
143 | static struct packet_state { | 146 | static struct packet_state { |
144 | u_int32_t seqnr; | 147 | u_int32_t seqnr; |
145 | u_int32_t packets; | 148 | u_int32_t packets; |
146 | u_int64_t blocks; | 149 | u_int64_t blocks; |
150 | u_int64_t bytes; | ||
147 | } p_read, p_send; | 151 | } p_read, p_send; |
148 | 152 | ||
149 | static u_int64_t max_blocks_in, max_blocks_out; | 153 | static u_int64_t max_blocks_in, max_blocks_out; |
@@ -168,7 +172,7 @@ TAILQ_HEAD(, packet) outgoing; | |||
168 | * packet_set_encryption_key is called. | 172 | * packet_set_encryption_key is called. |
169 | */ | 173 | */ |
170 | void | 174 | void |
171 | packet_set_connection(int fd_in, int fd_out, int new_setup_timeout) | 175 | packet_set_connection(int fd_in, int fd_out) |
172 | { | 176 | { |
173 | Cipher *none = cipher_by_name("none"); | 177 | Cipher *none = cipher_by_name("none"); |
174 | 178 | ||
@@ -176,7 +180,6 @@ packet_set_connection(int fd_in, int fd_out, int new_setup_timeout) | |||
176 | fatal("packet_set_connection: cannot load cipher 'none'"); | 180 | fatal("packet_set_connection: cannot load cipher 'none'"); |
177 | connection_in = fd_in; | 181 | connection_in = fd_in; |
178 | connection_out = fd_out; | 182 | connection_out = fd_out; |
179 | setup_timeout = new_setup_timeout; | ||
180 | cipher_init(&send_context, none, (const u_char *)"", | 183 | cipher_init(&send_context, none, (const u_char *)"", |
181 | 0, NULL, 0, CIPHER_ENCRYPT); | 184 | 0, NULL, 0, CIPHER_ENCRYPT); |
182 | cipher_init(&receive_context, none, (const u_char *)"", | 185 | cipher_init(&receive_context, none, (const u_char *)"", |
@@ -189,9 +192,23 @@ packet_set_connection(int fd_in, int fd_out, int new_setup_timeout) | |||
189 | buffer_init(&outgoing_packet); | 192 | buffer_init(&outgoing_packet); |
190 | buffer_init(&incoming_packet); | 193 | buffer_init(&incoming_packet); |
191 | TAILQ_INIT(&outgoing); | 194 | TAILQ_INIT(&outgoing); |
195 | p_send.packets = p_read.packets = 0; | ||
192 | } | 196 | } |
193 | } | 197 | } |
194 | 198 | ||
199 | void | ||
200 | packet_set_timeout(int timeout, int count) | ||
201 | { | ||
202 | if (timeout == 0 || count == 0) { | ||
203 | packet_timeout_ms = -1; | ||
204 | return; | ||
205 | } | ||
206 | if ((INT_MAX / 1000) / count < timeout) | ||
207 | packet_timeout_ms = INT_MAX; | ||
208 | else | ||
209 | packet_timeout_ms = timeout * count * 1000; | ||
210 | } | ||
211 | |||
195 | /* Returns 1 if remote host is connected via socket, 0 if not. */ | 212 | /* Returns 1 if remote host is connected via socket, 0 if not. */ |
196 | 213 | ||
197 | int | 214 | int |
@@ -296,18 +313,25 @@ packet_get_ssh1_cipher(void) | |||
296 | } | 313 | } |
297 | 314 | ||
298 | void | 315 | void |
299 | packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets) | 316 | packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets, |
317 | u_int64_t *bytes) | ||
300 | { | 318 | { |
301 | struct packet_state *state; | 319 | struct packet_state *state; |
302 | 320 | ||
303 | state = (mode == MODE_IN) ? &p_read : &p_send; | 321 | state = (mode == MODE_IN) ? &p_read : &p_send; |
304 | *seqnr = state->seqnr; | 322 | if (seqnr) |
305 | *blocks = state->blocks; | 323 | *seqnr = state->seqnr; |
306 | *packets = state->packets; | 324 | if (blocks) |
325 | *blocks = state->blocks; | ||
326 | if (packets) | ||
327 | *packets = state->packets; | ||
328 | if (bytes) | ||
329 | *bytes = state->bytes; | ||
307 | } | 330 | } |
308 | 331 | ||
309 | void | 332 | void |
310 | packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) | 333 | packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets, |
334 | u_int64_t bytes) | ||
311 | { | 335 | { |
312 | struct packet_state *state; | 336 | struct packet_state *state; |
313 | 337 | ||
@@ -315,6 +339,7 @@ packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) | |||
315 | state->seqnr = seqnr; | 339 | state->seqnr = seqnr; |
316 | state->blocks = blocks; | 340 | state->blocks = blocks; |
317 | state->packets = packets; | 341 | state->packets = packets; |
342 | state->bytes = bytes; | ||
318 | } | 343 | } |
319 | 344 | ||
320 | /* returns 1 if connection is via ipv4 */ | 345 | /* returns 1 if connection is via ipv4 */ |
@@ -593,7 +618,8 @@ packet_send1(void) | |||
593 | fprintf(stderr, "encrypted: "); | 618 | fprintf(stderr, "encrypted: "); |
594 | buffer_dump(&output); | 619 | buffer_dump(&output); |
595 | #endif | 620 | #endif |
596 | 621 | p_send.packets++; | |
622 | p_send.bytes += len + buffer_len(&outgoing_packet); | ||
597 | buffer_clear(&outgoing_packet); | 623 | buffer_clear(&outgoing_packet); |
598 | 624 | ||
599 | /* | 625 | /* |
@@ -819,6 +845,7 @@ packet_send2_wrapped(void) | |||
819 | if (!(datafellows & SSH_BUG_NOREKEY)) | 845 | if (!(datafellows & SSH_BUG_NOREKEY)) |
820 | fatal("XXX too many packets with same key"); | 846 | fatal("XXX too many packets with same key"); |
821 | p_send.blocks += (packet_length + 4) / block_size; | 847 | p_send.blocks += (packet_length + 4) / block_size; |
848 | p_send.bytes += packet_length + 4; | ||
822 | buffer_clear(&outgoing_packet); | 849 | buffer_clear(&outgoing_packet); |
823 | 850 | ||
824 | if (type == SSH2_MSG_NEWKEYS) | 851 | if (type == SSH2_MSG_NEWKEYS) |
@@ -892,10 +919,11 @@ packet_send(void) | |||
892 | int | 919 | int |
893 | packet_read_seqnr(u_int32_t *seqnr_p) | 920 | packet_read_seqnr(u_int32_t *seqnr_p) |
894 | { | 921 | { |
895 | int type, len; | 922 | int type, len, ret, ms_remain; |
896 | fd_set *setp; | 923 | fd_set *setp; |
897 | char buf[8192]; | 924 | char buf[8192]; |
898 | struct timeval tv, *tvp; | 925 | struct timeval timeout, start, *timeoutp = NULL; |
926 | |||
899 | DBG(debug("packet_read()")); | 927 | DBG(debug("packet_read()")); |
900 | 928 | ||
901 | setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS), | 929 | setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS), |
@@ -927,21 +955,35 @@ packet_read_seqnr(u_int32_t *seqnr_p) | |||
927 | sizeof(fd_mask)); | 955 | sizeof(fd_mask)); |
928 | FD_SET(connection_in, setp); | 956 | FD_SET(connection_in, setp); |
929 | 957 | ||
930 | if (setup_timeout > 0) { | 958 | if (packet_timeout_ms > 0) { |
931 | tvp = &tv; | 959 | ms_remain = packet_timeout_ms; |
932 | tv.tv_sec = setup_timeout; | 960 | timeoutp = &timeout; |
933 | tv.tv_usec = 0; | 961 | } |
934 | } else | ||
935 | tvp = NULL; | ||
936 | |||
937 | /* Wait for some data to arrive. */ | 962 | /* Wait for some data to arrive. */ |
938 | while (select(connection_in + 1, setp, NULL, NULL, tvp) == -1 && | 963 | for (;;) { |
939 | (errno == EAGAIN || errno == EINTR)) | 964 | if (packet_timeout_ms != -1) { |
940 | ; | 965 | ms_to_timeval(&timeout, ms_remain); |
941 | 966 | gettimeofday(&start, NULL); | |
942 | if (!FD_ISSET(connection_in, setp)) | 967 | } |
943 | fatal("packet_read: Setup timeout expired, giving up"); | 968 | if ((ret = select(connection_in + 1, setp, NULL, |
944 | 969 | NULL, timeoutp)) >= 0) | |
970 | break; | ||
971 | if (errno != EAGAIN && errno != EINTR && | ||
972 | errno != EWOULDBLOCK) | ||
973 | break; | ||
974 | if (packet_timeout_ms == -1) | ||
975 | continue; | ||
976 | ms_subtract_diff(&start, &ms_remain); | ||
977 | if (ms_remain <= 0) { | ||
978 | ret = 0; | ||
979 | break; | ||
980 | } | ||
981 | } | ||
982 | if (ret == 0) { | ||
983 | logit("Connection to %.200s timed out while " | ||
984 | "waiting to read", get_remote_ipaddr()); | ||
985 | cleanup_exit(255); | ||
986 | } | ||
945 | /* Read data from the socket. */ | 987 | /* Read data from the socket. */ |
946 | len = read(connection_in, buf, sizeof(buf)); | 988 | len = read(connection_in, buf, sizeof(buf)); |
947 | if (len == 0) { | 989 | if (len == 0) { |
@@ -1066,6 +1108,8 @@ packet_read_poll1(void) | |||
1066 | buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), | 1108 | buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), |
1067 | buffer_len(&compression_buffer)); | 1109 | buffer_len(&compression_buffer)); |
1068 | } | 1110 | } |
1111 | p_read.packets++; | ||
1112 | p_read.bytes += padded_len + 4; | ||
1069 | type = buffer_get_char(&incoming_packet); | 1113 | type = buffer_get_char(&incoming_packet); |
1070 | if (type < SSH_MSG_MIN || type > SSH_MSG_MAX) | 1114 | if (type < SSH_MSG_MIN || type > SSH_MSG_MAX) |
1071 | packet_disconnect("Invalid ssh1 packet type: %d", type); | 1115 | packet_disconnect("Invalid ssh1 packet type: %d", type); |
@@ -1154,6 +1198,7 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1154 | if (!(datafellows & SSH_BUG_NOREKEY)) | 1198 | if (!(datafellows & SSH_BUG_NOREKEY)) |
1155 | fatal("XXX too many packets with same key"); | 1199 | fatal("XXX too many packets with same key"); |
1156 | p_read.blocks += (packet_length + 4) / block_size; | 1200 | p_read.blocks += (packet_length + 4) / block_size; |
1201 | p_read.bytes += packet_length + 4; | ||
1157 | 1202 | ||
1158 | /* get padlen */ | 1203 | /* get padlen */ |
1159 | cp = buffer_ptr(&incoming_packet); | 1204 | cp = buffer_ptr(&incoming_packet); |
@@ -1206,10 +1251,13 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) | |||
1206 | for (;;) { | 1251 | for (;;) { |
1207 | if (compat20) { | 1252 | if (compat20) { |
1208 | type = packet_read_poll2(seqnr_p); | 1253 | type = packet_read_poll2(seqnr_p); |
1209 | if (type) | 1254 | if (type) { |
1255 | keep_alive_timeouts = 0; | ||
1210 | DBG(debug("received packet type %d", type)); | 1256 | DBG(debug("received packet type %d", type)); |
1257 | } | ||
1211 | switch (type) { | 1258 | switch (type) { |
1212 | case SSH2_MSG_IGNORE: | 1259 | case SSH2_MSG_IGNORE: |
1260 | debug3("Received SSH2_MSG_IGNORE"); | ||
1213 | break; | 1261 | break; |
1214 | case SSH2_MSG_DEBUG: | 1262 | case SSH2_MSG_DEBUG: |
1215 | packet_get_char(); | 1263 | packet_get_char(); |
@@ -1342,6 +1390,12 @@ packet_get_string(u_int *length_ptr) | |||
1342 | return buffer_get_string(&incoming_packet, length_ptr); | 1390 | return buffer_get_string(&incoming_packet, length_ptr); |
1343 | } | 1391 | } |
1344 | 1392 | ||
1393 | void * | ||
1394 | packet_get_string_ptr(u_int *length_ptr) | ||
1395 | { | ||
1396 | return buffer_get_string_ptr(&incoming_packet, length_ptr); | ||
1397 | } | ||
1398 | |||
1345 | /* | 1399 | /* |
1346 | * Sends a diagnostic message from the server to the client. This message | 1400 | * Sends a diagnostic message from the server to the client. This message |
1347 | * can be sent at any time (but not while constructing another message). The | 1401 | * can be sent at any time (but not while constructing another message). The |
@@ -1436,16 +1490,19 @@ packet_write_poll(void) | |||
1436 | 1490 | ||
1437 | if (len > 0) { | 1491 | if (len > 0) { |
1438 | len = write(connection_out, buffer_ptr(&output), len); | 1492 | len = write(connection_out, buffer_ptr(&output), len); |
1439 | if (len <= 0) { | 1493 | if (len == -1) { |
1440 | if (errno == EAGAIN) | 1494 | if (errno == EINTR || errno == EAGAIN || |
1495 | errno == EWOULDBLOCK) | ||
1441 | return; | 1496 | return; |
1442 | else | 1497 | fatal("Write failed: %.100s", strerror(errno)); |
1443 | fatal("Write failed: %.100s", strerror(errno)); | ||
1444 | } | 1498 | } |
1499 | if (len == 0) | ||
1500 | fatal("Write connection closed"); | ||
1445 | buffer_consume(&output, len); | 1501 | buffer_consume(&output, len); |
1446 | } | 1502 | } |
1447 | } | 1503 | } |
1448 | 1504 | ||
1505 | |||
1449 | /* | 1506 | /* |
1450 | * Calls packet_write_poll repeatedly until all pending output data has been | 1507 | * Calls packet_write_poll repeatedly until all pending output data has been |
1451 | * written. | 1508 | * written. |
@@ -1455,6 +1512,8 @@ void | |||
1455 | packet_write_wait(void) | 1512 | packet_write_wait(void) |
1456 | { | 1513 | { |
1457 | fd_set *setp; | 1514 | fd_set *setp; |
1515 | int ret, ms_remain; | ||
1516 | struct timeval start, timeout, *timeoutp = NULL; | ||
1458 | 1517 | ||
1459 | setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), | 1518 | setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), |
1460 | sizeof(fd_mask)); | 1519 | sizeof(fd_mask)); |
@@ -1463,9 +1522,35 @@ packet_write_wait(void) | |||
1463 | memset(setp, 0, howmany(connection_out + 1, NFDBITS) * | 1522 | memset(setp, 0, howmany(connection_out + 1, NFDBITS) * |
1464 | sizeof(fd_mask)); | 1523 | sizeof(fd_mask)); |
1465 | FD_SET(connection_out, setp); | 1524 | FD_SET(connection_out, setp); |
1466 | while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && | 1525 | |
1467 | (errno == EAGAIN || errno == EINTR)) | 1526 | if (packet_timeout_ms > 0) { |
1468 | ; | 1527 | ms_remain = packet_timeout_ms; |
1528 | timeoutp = &timeout; | ||
1529 | } | ||
1530 | for (;;) { | ||
1531 | if (packet_timeout_ms != -1) { | ||
1532 | ms_to_timeval(&timeout, ms_remain); | ||
1533 | gettimeofday(&start, NULL); | ||
1534 | } | ||
1535 | if ((ret = select(connection_out + 1, NULL, setp, | ||
1536 | NULL, timeoutp)) >= 0) | ||
1537 | break; | ||
1538 | if (errno != EAGAIN && errno != EINTR && | ||
1539 | errno != EWOULDBLOCK) | ||
1540 | break; | ||
1541 | if (packet_timeout_ms == -1) | ||
1542 | continue; | ||
1543 | ms_subtract_diff(&start, &ms_remain); | ||
1544 | if (ms_remain <= 0) { | ||
1545 | ret = 0; | ||
1546 | break; | ||
1547 | } | ||
1548 | } | ||
1549 | if (ret == 0) { | ||
1550 | logit("Connection to %.200s timed out while " | ||
1551 | "waiting to write", get_remote_ipaddr()); | ||
1552 | cleanup_exit(255); | ||
1553 | } | ||
1469 | packet_write_poll(); | 1554 | packet_write_poll(); |
1470 | } | 1555 | } |
1471 | xfree(setp); | 1556 | xfree(setp); |