diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 165 |
1 files changed, 30 insertions, 135 deletions
@@ -37,9 +37,7 @@ | |||
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include "includes.h" | 39 | #include "includes.h" |
40 | RCSID("$OpenBSD: packet.c,v 1.105 2003/04/02 09:48:07 markus Exp $"); | 40 | RCSID("$OpenBSD: packet.c,v 1.104 2003/04/01 10:22:21 markus Exp $"); |
41 | |||
42 | #include "openbsd-compat/sys-queue.h" | ||
43 | 41 | ||
44 | #include "xmalloc.h" | 42 | #include "xmalloc.h" |
45 | #include "buffer.h" | 43 | #include "buffer.h" |
@@ -118,14 +116,8 @@ static int interactive_mode = 0; | |||
118 | 116 | ||
119 | /* Session key information for Encryption and MAC */ | 117 | /* Session key information for Encryption and MAC */ |
120 | Newkeys *newkeys[MODE_MAX]; | 118 | Newkeys *newkeys[MODE_MAX]; |
121 | static struct packet_state { | 119 | static u_int32_t read_seqnr = 0; |
122 | u_int32_t seqnr; | 120 | static u_int32_t send_seqnr = 0; |
123 | u_int32_t packets; | ||
124 | u_int64_t blocks; | ||
125 | } p_read, p_send; | ||
126 | |||
127 | static u_int64_t max_blocks_in, max_blocks_out; | ||
128 | static u_int32_t rekey_limit; | ||
129 | 121 | ||
130 | /* Session key for protocol v1 */ | 122 | /* Session key for protocol v1 */ |
131 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; | 123 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
@@ -134,13 +126,6 @@ static u_int ssh1_keylen; | |||
134 | /* roundup current message to extra_pad bytes */ | 126 | /* roundup current message to extra_pad bytes */ |
135 | static u_char extra_pad = 0; | 127 | static u_char extra_pad = 0; |
136 | 128 | ||
137 | struct packet { | ||
138 | TAILQ_ENTRY(packet) next; | ||
139 | u_char type; | ||
140 | Buffer payload; | ||
141 | }; | ||
142 | TAILQ_HEAD(, packet) outgoing; | ||
143 | |||
144 | /* | 129 | /* |
145 | * Sets the descriptors used for communication. Disables encryption until | 130 | * Sets the descriptors used for communication. Disables encryption until |
146 | * packet_set_encryption_key is called. | 131 | * packet_set_encryption_key is called. |
@@ -163,7 +148,6 @@ packet_set_connection(int fd_in, int fd_out) | |||
163 | buffer_init(&output); | 148 | buffer_init(&output); |
164 | buffer_init(&outgoing_packet); | 149 | buffer_init(&outgoing_packet); |
165 | buffer_init(&incoming_packet); | 150 | buffer_init(&incoming_packet); |
166 | TAILQ_INIT(&outgoing); | ||
167 | } | 151 | } |
168 | /* Kludge: arrange the close function to be called from fatal(). */ | 152 | /* Kludge: arrange the close function to be called from fatal(). */ |
169 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); | 153 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); |
@@ -270,26 +254,22 @@ packet_get_ssh1_cipher() | |||
270 | return (cipher_get_number(receive_context.cipher)); | 254 | return (cipher_get_number(receive_context.cipher)); |
271 | } | 255 | } |
272 | 256 | ||
273 | void | ||
274 | packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets) | ||
275 | { | ||
276 | struct packet_state *state; | ||
277 | 257 | ||
278 | state = (mode == MODE_IN) ? &p_read : &p_send; | 258 | u_int32_t |
279 | *seqnr = state->seqnr; | 259 | packet_get_seqnr(int mode) |
280 | *blocks = state->blocks; | 260 | { |
281 | *packets = state->packets; | 261 | return (mode == MODE_IN ? read_seqnr : send_seqnr); |
282 | } | 262 | } |
283 | 263 | ||
284 | void | 264 | void |
285 | packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) | 265 | packet_set_seqnr(int mode, u_int32_t seqnr) |
286 | { | 266 | { |
287 | struct packet_state *state; | 267 | if (mode == MODE_IN) |
288 | 268 | read_seqnr = seqnr; | |
289 | state = (mode == MODE_IN) ? &p_read : &p_send; | 269 | else if (mode == MODE_OUT) |
290 | state->seqnr = seqnr; | 270 | send_seqnr = seqnr; |
291 | state->blocks = blocks; | 271 | else |
292 | state->packets = packets; | 272 | fatal("packet_set_seqnr: bad mode %d", mode); |
293 | } | 273 | } |
294 | 274 | ||
295 | /* returns 1 if connection is via ipv4 */ | 275 | /* returns 1 if connection is via ipv4 */ |
@@ -582,7 +562,6 @@ set_newkeys(int mode) | |||
582 | Mac *mac; | 562 | Mac *mac; |
583 | Comp *comp; | 563 | Comp *comp; |
584 | CipherContext *cc; | 564 | CipherContext *cc; |
585 | u_int64_t *max_blocks; | ||
586 | int encrypt; | 565 | int encrypt; |
587 | 566 | ||
588 | debug2("set_newkeys: mode %d", mode); | 567 | debug2("set_newkeys: mode %d", mode); |
@@ -590,13 +569,9 @@ set_newkeys(int mode) | |||
590 | if (mode == MODE_OUT) { | 569 | if (mode == MODE_OUT) { |
591 | cc = &send_context; | 570 | cc = &send_context; |
592 | encrypt = CIPHER_ENCRYPT; | 571 | encrypt = CIPHER_ENCRYPT; |
593 | p_send.packets = p_send.blocks = 0; | ||
594 | max_blocks = &max_blocks_out; | ||
595 | } else { | 572 | } else { |
596 | cc = &receive_context; | 573 | cc = &receive_context; |
597 | encrypt = CIPHER_DECRYPT; | 574 | encrypt = CIPHER_DECRYPT; |
598 | p_read.packets = p_read.blocks = 0; | ||
599 | max_blocks = &max_blocks_in; | ||
600 | } | 575 | } |
601 | if (newkeys[mode] != NULL) { | 576 | if (newkeys[mode] != NULL) { |
602 | debug("set_newkeys: rekeying"); | 577 | debug("set_newkeys: rekeying"); |
@@ -635,16 +610,13 @@ set_newkeys(int mode) | |||
635 | buffer_compress_init_recv(); | 610 | buffer_compress_init_recv(); |
636 | comp->enabled = 1; | 611 | comp->enabled = 1; |
637 | } | 612 | } |
638 | *max_blocks = ((u_int64_t)1 << (enc->block_size*2)); | ||
639 | if (rekey_limit) | ||
640 | *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); | ||
641 | } | 613 | } |
642 | 614 | ||
643 | /* | 615 | /* |
644 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) | 616 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) |
645 | */ | 617 | */ |
646 | static void | 618 | static void |
647 | packet_send2_wrapped(void) | 619 | packet_send2(void) |
648 | { | 620 | { |
649 | u_char type, *cp, *macbuf = NULL; | 621 | u_char type, *cp, *macbuf = NULL; |
650 | u_char padlen, pad; | 622 | u_char padlen, pad; |
@@ -726,10 +698,10 @@ packet_send2_wrapped(void) | |||
726 | 698 | ||
727 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ | 699 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ |
728 | if (mac && mac->enabled) { | 700 | if (mac && mac->enabled) { |
729 | macbuf = mac_compute(mac, p_send.seqnr, | 701 | macbuf = mac_compute(mac, send_seqnr, |
730 | buffer_ptr(&outgoing_packet), | 702 | buffer_ptr(&outgoing_packet), |
731 | buffer_len(&outgoing_packet)); | 703 | buffer_len(&outgoing_packet)); |
732 | DBG(debug("done calc MAC out #%d", p_send.seqnr)); | 704 | DBG(debug("done calc MAC out #%d", send_seqnr)); |
733 | } | 705 | } |
734 | /* encrypt packet and append to output buffer. */ | 706 | /* encrypt packet and append to output buffer. */ |
735 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); | 707 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
@@ -743,64 +715,14 @@ packet_send2_wrapped(void) | |||
743 | buffer_dump(&output); | 715 | buffer_dump(&output); |
744 | #endif | 716 | #endif |
745 | /* increment sequence number for outgoing packets */ | 717 | /* increment sequence number for outgoing packets */ |
746 | if (++p_send.seqnr == 0) | 718 | if (++send_seqnr == 0) |
747 | logit("outgoing seqnr wraps around"); | 719 | log("outgoing seqnr wraps around"); |
748 | if (++p_send.packets == 0) | ||
749 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
750 | fatal("XXX too many packets with same key"); | ||
751 | p_send.blocks += (packet_length + 4) / block_size; | ||
752 | buffer_clear(&outgoing_packet); | 720 | buffer_clear(&outgoing_packet); |
753 | 721 | ||
754 | if (type == SSH2_MSG_NEWKEYS) | 722 | if (type == SSH2_MSG_NEWKEYS) |
755 | set_newkeys(MODE_OUT); | 723 | set_newkeys(MODE_OUT); |
756 | } | 724 | } |
757 | 725 | ||
758 | static void | ||
759 | packet_send2(void) | ||
760 | { | ||
761 | static int rekeying = 0; | ||
762 | struct packet *p; | ||
763 | u_char type, *cp; | ||
764 | |||
765 | cp = buffer_ptr(&outgoing_packet); | ||
766 | type = cp[5]; | ||
767 | |||
768 | /* during rekeying we can only send key exchange messages */ | ||
769 | if (rekeying) { | ||
770 | if (!((type >= SSH2_MSG_TRANSPORT_MIN) && | ||
771 | (type <= SSH2_MSG_TRANSPORT_MAX))) { | ||
772 | debug("enqueue packet: %u", type); | ||
773 | p = xmalloc(sizeof(*p)); | ||
774 | p->type = type; | ||
775 | memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); | ||
776 | buffer_init(&outgoing_packet); | ||
777 | TAILQ_INSERT_TAIL(&outgoing, p, next); | ||
778 | return; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /* rekeying starts with sending KEXINIT */ | ||
783 | if (type == SSH2_MSG_KEXINIT) | ||
784 | rekeying = 1; | ||
785 | |||
786 | packet_send2_wrapped(); | ||
787 | |||
788 | /* after a NEWKEYS message we can send the complete queue */ | ||
789 | if (type == SSH2_MSG_NEWKEYS) { | ||
790 | rekeying = 0; | ||
791 | while ((p = TAILQ_FIRST(&outgoing))) { | ||
792 | type = p->type; | ||
793 | debug("dequeue packet: %u", type); | ||
794 | buffer_free(&outgoing_packet); | ||
795 | memcpy(&outgoing_packet, &p->payload, | ||
796 | sizeof(Buffer)); | ||
797 | TAILQ_REMOVE(&outgoing, p, next); | ||
798 | xfree(p); | ||
799 | packet_send2_wrapped(); | ||
800 | } | ||
801 | } | ||
802 | } | ||
803 | |||
804 | void | 726 | void |
805 | packet_send(void) | 727 | packet_send(void) |
806 | { | 728 | { |
@@ -862,7 +784,7 @@ packet_read_seqnr(u_int32_t *seqnr_p) | |||
862 | /* Read data from the socket. */ | 784 | /* Read data from the socket. */ |
863 | len = read(connection_in, buf, sizeof(buf)); | 785 | len = read(connection_in, buf, sizeof(buf)); |
864 | if (len == 0) { | 786 | if (len == 0) { |
865 | logit("Connection closed by %.200s", get_remote_ipaddr()); | 787 | log("Connection closed by %.200s", get_remote_ipaddr()); |
866 | fatal_cleanup(); | 788 | fatal_cleanup(); |
867 | } | 789 | } |
868 | if (len < 0) | 790 | if (len < 0) |
@@ -1044,22 +966,18 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1044 | * increment sequence number for incoming packet | 966 | * increment sequence number for incoming packet |
1045 | */ | 967 | */ |
1046 | if (mac && mac->enabled) { | 968 | if (mac && mac->enabled) { |
1047 | macbuf = mac_compute(mac, p_read.seqnr, | 969 | macbuf = mac_compute(mac, read_seqnr, |
1048 | buffer_ptr(&incoming_packet), | 970 | buffer_ptr(&incoming_packet), |
1049 | buffer_len(&incoming_packet)); | 971 | buffer_len(&incoming_packet)); |
1050 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) | 972 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) |
1051 | packet_disconnect("Corrupted MAC on input."); | 973 | packet_disconnect("Corrupted MAC on input."); |
1052 | DBG(debug("MAC #%d ok", p_read.seqnr)); | 974 | DBG(debug("MAC #%d ok", read_seqnr)); |
1053 | buffer_consume(&input, mac->mac_len); | 975 | buffer_consume(&input, mac->mac_len); |
1054 | } | 976 | } |
1055 | if (seqnr_p != NULL) | 977 | if (seqnr_p != NULL) |
1056 | *seqnr_p = p_read.seqnr; | 978 | *seqnr_p = read_seqnr; |
1057 | if (++p_read.seqnr == 0) | 979 | if (++read_seqnr == 0) |
1058 | logit("incoming seqnr wraps around"); | 980 | log("incoming seqnr wraps around"); |
1059 | if (++p_read.packets == 0) | ||
1060 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
1061 | fatal("XXX too many packets with same key"); | ||
1062 | p_read.blocks += (packet_length + 4) / block_size; | ||
1063 | 981 | ||
1064 | /* get padlen */ | 982 | /* get padlen */ |
1065 | cp = buffer_ptr(&incoming_packet); | 983 | cp = buffer_ptr(&incoming_packet); |
@@ -1124,7 +1042,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) | |||
1124 | case SSH2_MSG_DISCONNECT: | 1042 | case SSH2_MSG_DISCONNECT: |
1125 | reason = packet_get_int(); | 1043 | reason = packet_get_int(); |
1126 | msg = packet_get_string(NULL); | 1044 | msg = packet_get_string(NULL); |
1127 | logit("Received disconnect from %s: %u: %.400s", | 1045 | log("Received disconnect from %s: %u: %.400s", |
1128 | get_remote_ipaddr(), reason, msg); | 1046 | get_remote_ipaddr(), reason, msg); |
1129 | xfree(msg); | 1047 | xfree(msg); |
1130 | fatal_cleanup(); | 1048 | fatal_cleanup(); |
@@ -1150,7 +1068,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) | |||
1150 | break; | 1068 | break; |
1151 | case SSH_MSG_DISCONNECT: | 1069 | case SSH_MSG_DISCONNECT: |
1152 | msg = packet_get_string(NULL); | 1070 | msg = packet_get_string(NULL); |
1153 | logit("Received disconnect from %s: %.400s", | 1071 | log("Received disconnect from %s: %.400s", |
1154 | get_remote_ipaddr(), msg); | 1072 | get_remote_ipaddr(), msg); |
1155 | fatal_cleanup(); | 1073 | fatal_cleanup(); |
1156 | xfree(msg); | 1074 | xfree(msg); |
@@ -1309,7 +1227,7 @@ packet_disconnect(const char *fmt,...) | |||
1309 | va_end(args); | 1227 | va_end(args); |
1310 | 1228 | ||
1311 | /* Display the error locally */ | 1229 | /* Display the error locally */ |
1312 | logit("Disconnecting: %.100s", buf); | 1230 | log("Disconnecting: %.100s", buf); |
1313 | 1231 | ||
1314 | /* Send the disconnect message to the other side, and wait for it to get sent. */ | 1232 | /* Send the disconnect message to the other side, and wait for it to get sent. */ |
1315 | if (compat20) { | 1233 | if (compat20) { |
@@ -1396,8 +1314,6 @@ packet_not_very_much_data_to_write(void) | |||
1396 | return buffer_len(&output) < 128 * 1024; | 1314 | return buffer_len(&output) < 128 * 1024; |
1397 | } | 1315 | } |
1398 | 1316 | ||
1399 | |||
1400 | #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) | ||
1401 | static void | 1317 | static void |
1402 | packet_set_tos(int interactive) | 1318 | packet_set_tos(int interactive) |
1403 | { | 1319 | { |
@@ -1411,7 +1327,6 @@ packet_set_tos(int interactive) | |||
1411 | error("setsockopt IP_TOS %d: %.100s:", | 1327 | error("setsockopt IP_TOS %d: %.100s:", |
1412 | tos, strerror(errno)); | 1328 | tos, strerror(errno)); |
1413 | } | 1329 | } |
1414 | #endif | ||
1415 | 1330 | ||
1416 | /* Informs that the current session is interactive. Sets IP flags for that. */ | 1331 | /* Informs that the current session is interactive. Sets IP flags for that. */ |
1417 | 1332 | ||
@@ -1429,7 +1344,6 @@ packet_set_interactive(int interactive) | |||
1429 | 1344 | ||
1430 | /* Only set socket options if using a socket. */ | 1345 | /* Only set socket options if using a socket. */ |
1431 | if (!packet_connection_is_on_socket()) | 1346 | if (!packet_connection_is_on_socket()) |
1432 | return; | ||
1433 | if (interactive) | 1347 | if (interactive) |
1434 | set_nodelay(connection_in); | 1348 | set_nodelay(connection_in); |
1435 | #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) | 1349 | #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) |
@@ -1452,12 +1366,12 @@ packet_set_maxsize(int s) | |||
1452 | static int called = 0; | 1366 | static int called = 0; |
1453 | 1367 | ||
1454 | if (called) { | 1368 | if (called) { |
1455 | logit("packet_set_maxsize: called twice: old %d new %d", | 1369 | log("packet_set_maxsize: called twice: old %d new %d", |
1456 | max_packet_size, s); | 1370 | max_packet_size, s); |
1457 | return -1; | 1371 | return -1; |
1458 | } | 1372 | } |
1459 | if (s < 4 * 1024 || s > 1024 * 1024) { | 1373 | if (s < 4 * 1024 || s > 1024 * 1024) { |
1460 | logit("packet_set_maxsize: bad size %d", s); | 1374 | log("packet_set_maxsize: bad size %d", s); |
1461 | return -1; | 1375 | return -1; |
1462 | } | 1376 | } |
1463 | called = 1; | 1377 | called = 1; |
@@ -1499,22 +1413,3 @@ packet_send_ignore(int nbytes) | |||
1499 | rand >>= 8; | 1413 | rand >>= 8; |
1500 | } | 1414 | } |
1501 | } | 1415 | } |
1502 | |||
1503 | #define MAX_PACKETS (1<<31) | ||
1504 | int | ||
1505 | packet_need_rekeying(void) | ||
1506 | { | ||
1507 | if (datafellows & SSH_BUG_NOREKEY) | ||
1508 | return 0; | ||
1509 | return | ||
1510 | (p_send.packets > MAX_PACKETS) || | ||
1511 | (p_read.packets > MAX_PACKETS) || | ||
1512 | (max_blocks_out && (p_send.blocks > max_blocks_out)) || | ||
1513 | (max_blocks_in && (p_read.blocks > max_blocks_in)); | ||
1514 | } | ||
1515 | |||
1516 | void | ||
1517 | packet_set_rekey_limit(u_int32_t bytes) | ||
1518 | { | ||
1519 | rekey_limit = bytes; | ||
1520 | } | ||