diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 181 |
1 files changed, 147 insertions, 34 deletions
@@ -37,7 +37,9 @@ | |||
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include "includes.h" | 39 | #include "includes.h" |
40 | RCSID("$OpenBSD: packet.c,v 1.104 2003/04/01 10:22:21 markus Exp $"); | 40 | RCSID("$OpenBSD: packet.c,v 1.110 2003/09/19 09:02:02 markus Exp $"); |
41 | |||
42 | #include "openbsd-compat/sys-queue.h" | ||
41 | 43 | ||
42 | #include "xmalloc.h" | 44 | #include "xmalloc.h" |
43 | #include "buffer.h" | 45 | #include "buffer.h" |
@@ -108,7 +110,7 @@ static int compression_buffer_ready = 0; | |||
108 | static int packet_compression = 0; | 110 | static int packet_compression = 0; |
109 | 111 | ||
110 | /* default maximum packet size */ | 112 | /* default maximum packet size */ |
111 | int max_packet_size = 32768; | 113 | u_int max_packet_size = 32768; |
112 | 114 | ||
113 | /* Flag indicating whether this module has been initialized. */ | 115 | /* Flag indicating whether this module has been initialized. */ |
114 | static int initialized = 0; | 116 | static int initialized = 0; |
@@ -118,8 +120,14 @@ static int interactive_mode = 0; | |||
118 | 120 | ||
119 | /* Session key information for Encryption and MAC */ | 121 | /* Session key information for Encryption and MAC */ |
120 | Newkeys *newkeys[MODE_MAX]; | 122 | Newkeys *newkeys[MODE_MAX]; |
121 | static u_int32_t read_seqnr = 0; | 123 | static struct packet_state { |
122 | static u_int32_t send_seqnr = 0; | 124 | u_int32_t seqnr; |
125 | u_int32_t packets; | ||
126 | u_int64_t blocks; | ||
127 | } p_read, p_send; | ||
128 | |||
129 | static u_int64_t max_blocks_in, max_blocks_out; | ||
130 | static u_int32_t rekey_limit; | ||
123 | 131 | ||
124 | /* Session key for protocol v1 */ | 132 | /* Session key for protocol v1 */ |
125 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; | 133 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
@@ -128,6 +136,13 @@ static u_int ssh1_keylen; | |||
128 | /* roundup current message to extra_pad bytes */ | 136 | /* roundup current message to extra_pad bytes */ |
129 | static u_char extra_pad = 0; | 137 | static u_char extra_pad = 0; |
130 | 138 | ||
139 | struct packet { | ||
140 | TAILQ_ENTRY(packet) next; | ||
141 | u_char type; | ||
142 | Buffer payload; | ||
143 | }; | ||
144 | TAILQ_HEAD(, packet) outgoing; | ||
145 | |||
131 | /* | 146 | /* |
132 | * Sets the descriptors used for communication. Disables encryption until | 147 | * Sets the descriptors used for communication. Disables encryption until |
133 | * packet_set_encryption_key is called. | 148 | * packet_set_encryption_key is called. |
@@ -151,6 +166,7 @@ packet_set_connection(int fd_in, int fd_out, int new_setup_timeout) | |||
151 | buffer_init(&output); | 166 | buffer_init(&output); |
152 | buffer_init(&outgoing_packet); | 167 | buffer_init(&outgoing_packet); |
153 | buffer_init(&incoming_packet); | 168 | buffer_init(&incoming_packet); |
169 | TAILQ_INIT(&outgoing); | ||
154 | } | 170 | } |
155 | /* Kludge: arrange the close function to be called from fatal(). */ | 171 | /* Kludge: arrange the close function to be called from fatal(). */ |
156 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); | 172 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); |
@@ -252,27 +268,31 @@ packet_set_iv(int mode, u_char *dat) | |||
252 | cipher_set_keyiv(cc, dat); | 268 | cipher_set_keyiv(cc, dat); |
253 | } | 269 | } |
254 | int | 270 | int |
255 | packet_get_ssh1_cipher() | 271 | packet_get_ssh1_cipher(void) |
256 | { | 272 | { |
257 | return (cipher_get_number(receive_context.cipher)); | 273 | return (cipher_get_number(receive_context.cipher)); |
258 | } | 274 | } |
259 | 275 | ||
260 | 276 | void | |
261 | u_int32_t | 277 | packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets) |
262 | packet_get_seqnr(int mode) | ||
263 | { | 278 | { |
264 | return (mode == MODE_IN ? read_seqnr : send_seqnr); | 279 | struct packet_state *state; |
280 | |||
281 | state = (mode == MODE_IN) ? &p_read : &p_send; | ||
282 | *seqnr = state->seqnr; | ||
283 | *blocks = state->blocks; | ||
284 | *packets = state->packets; | ||
265 | } | 285 | } |
266 | 286 | ||
267 | void | 287 | void |
268 | packet_set_seqnr(int mode, u_int32_t seqnr) | 288 | packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) |
269 | { | 289 | { |
270 | if (mode == MODE_IN) | 290 | struct packet_state *state; |
271 | read_seqnr = seqnr; | 291 | |
272 | else if (mode == MODE_OUT) | 292 | state = (mode == MODE_IN) ? &p_read : &p_send; |
273 | send_seqnr = seqnr; | 293 | state->seqnr = seqnr; |
274 | else | 294 | state->blocks = blocks; |
275 | fatal("packet_set_seqnr: bad mode %d", mode); | 295 | state->packets = packets; |
276 | } | 296 | } |
277 | 297 | ||
278 | /* returns 1 if connection is via ipv4 */ | 298 | /* returns 1 if connection is via ipv4 */ |
@@ -565,6 +585,7 @@ set_newkeys(int mode) | |||
565 | Mac *mac; | 585 | Mac *mac; |
566 | Comp *comp; | 586 | Comp *comp; |
567 | CipherContext *cc; | 587 | CipherContext *cc; |
588 | u_int64_t *max_blocks; | ||
568 | int encrypt; | 589 | int encrypt; |
569 | 590 | ||
570 | debug2("set_newkeys: mode %d", mode); | 591 | debug2("set_newkeys: mode %d", mode); |
@@ -572,9 +593,13 @@ set_newkeys(int mode) | |||
572 | if (mode == MODE_OUT) { | 593 | if (mode == MODE_OUT) { |
573 | cc = &send_context; | 594 | cc = &send_context; |
574 | encrypt = CIPHER_ENCRYPT; | 595 | encrypt = CIPHER_ENCRYPT; |
596 | p_send.packets = p_send.blocks = 0; | ||
597 | max_blocks = &max_blocks_out; | ||
575 | } else { | 598 | } else { |
576 | cc = &receive_context; | 599 | cc = &receive_context; |
577 | encrypt = CIPHER_DECRYPT; | 600 | encrypt = CIPHER_DECRYPT; |
601 | p_read.packets = p_read.blocks = 0; | ||
602 | max_blocks = &max_blocks_in; | ||
578 | } | 603 | } |
579 | if (newkeys[mode] != NULL) { | 604 | if (newkeys[mode] != NULL) { |
580 | debug("set_newkeys: rekeying"); | 605 | debug("set_newkeys: rekeying"); |
@@ -613,13 +638,23 @@ set_newkeys(int mode) | |||
613 | buffer_compress_init_recv(); | 638 | buffer_compress_init_recv(); |
614 | comp->enabled = 1; | 639 | comp->enabled = 1; |
615 | } | 640 | } |
641 | /* | ||
642 | * The 2^(blocksize*2) limit is too expensive for 3DES, | ||
643 | * blowfish, etc, so enforce a 1GB limit for small blocksizes. | ||
644 | */ | ||
645 | if (enc->block_size >= 16) | ||
646 | *max_blocks = (u_int64_t)1 << (enc->block_size*2); | ||
647 | else | ||
648 | *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; | ||
649 | if (rekey_limit) | ||
650 | *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); | ||
616 | } | 651 | } |
617 | 652 | ||
618 | /* | 653 | /* |
619 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) | 654 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) |
620 | */ | 655 | */ |
621 | static void | 656 | static void |
622 | packet_send2(void) | 657 | packet_send2_wrapped(void) |
623 | { | 658 | { |
624 | u_char type, *cp, *macbuf = NULL; | 659 | u_char type, *cp, *macbuf = NULL; |
625 | u_char padlen, pad; | 660 | u_char padlen, pad; |
@@ -701,10 +736,10 @@ packet_send2(void) | |||
701 | 736 | ||
702 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ | 737 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ |
703 | if (mac && mac->enabled) { | 738 | if (mac && mac->enabled) { |
704 | macbuf = mac_compute(mac, send_seqnr, | 739 | macbuf = mac_compute(mac, p_send.seqnr, |
705 | buffer_ptr(&outgoing_packet), | 740 | buffer_ptr(&outgoing_packet), |
706 | buffer_len(&outgoing_packet)); | 741 | buffer_len(&outgoing_packet)); |
707 | DBG(debug("done calc MAC out #%d", send_seqnr)); | 742 | DBG(debug("done calc MAC out #%d", p_send.seqnr)); |
708 | } | 743 | } |
709 | /* encrypt packet and append to output buffer. */ | 744 | /* encrypt packet and append to output buffer. */ |
710 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); | 745 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
@@ -718,14 +753,64 @@ packet_send2(void) | |||
718 | buffer_dump(&output); | 753 | buffer_dump(&output); |
719 | #endif | 754 | #endif |
720 | /* increment sequence number for outgoing packets */ | 755 | /* increment sequence number for outgoing packets */ |
721 | if (++send_seqnr == 0) | 756 | if (++p_send.seqnr == 0) |
722 | log("outgoing seqnr wraps around"); | 757 | logit("outgoing seqnr wraps around"); |
758 | if (++p_send.packets == 0) | ||
759 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
760 | fatal("XXX too many packets with same key"); | ||
761 | p_send.blocks += (packet_length + 4) / block_size; | ||
723 | buffer_clear(&outgoing_packet); | 762 | buffer_clear(&outgoing_packet); |
724 | 763 | ||
725 | if (type == SSH2_MSG_NEWKEYS) | 764 | if (type == SSH2_MSG_NEWKEYS) |
726 | set_newkeys(MODE_OUT); | 765 | set_newkeys(MODE_OUT); |
727 | } | 766 | } |
728 | 767 | ||
768 | static void | ||
769 | packet_send2(void) | ||
770 | { | ||
771 | static int rekeying = 0; | ||
772 | struct packet *p; | ||
773 | u_char type, *cp; | ||
774 | |||
775 | cp = buffer_ptr(&outgoing_packet); | ||
776 | type = cp[5]; | ||
777 | |||
778 | /* during rekeying we can only send key exchange messages */ | ||
779 | if (rekeying) { | ||
780 | if (!((type >= SSH2_MSG_TRANSPORT_MIN) && | ||
781 | (type <= SSH2_MSG_TRANSPORT_MAX))) { | ||
782 | debug("enqueue packet: %u", type); | ||
783 | p = xmalloc(sizeof(*p)); | ||
784 | p->type = type; | ||
785 | memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); | ||
786 | buffer_init(&outgoing_packet); | ||
787 | TAILQ_INSERT_TAIL(&outgoing, p, next); | ||
788 | return; | ||
789 | } | ||
790 | } | ||
791 | |||
792 | /* rekeying starts with sending KEXINIT */ | ||
793 | if (type == SSH2_MSG_KEXINIT) | ||
794 | rekeying = 1; | ||
795 | |||
796 | packet_send2_wrapped(); | ||
797 | |||
798 | /* after a NEWKEYS message we can send the complete queue */ | ||
799 | if (type == SSH2_MSG_NEWKEYS) { | ||
800 | rekeying = 0; | ||
801 | while ((p = TAILQ_FIRST(&outgoing))) { | ||
802 | type = p->type; | ||
803 | debug("dequeue packet: %u", type); | ||
804 | buffer_free(&outgoing_packet); | ||
805 | memcpy(&outgoing_packet, &p->payload, | ||
806 | sizeof(Buffer)); | ||
807 | TAILQ_REMOVE(&outgoing, p, next); | ||
808 | xfree(p); | ||
809 | packet_send2_wrapped(); | ||
810 | } | ||
811 | } | ||
812 | } | ||
813 | |||
729 | void | 814 | void |
730 | packet_send(void) | 815 | packet_send(void) |
731 | { | 816 | { |
@@ -798,7 +883,7 @@ packet_read_seqnr(u_int32_t *seqnr_p) | |||
798 | /* Read data from the socket. */ | 883 | /* Read data from the socket. */ |
799 | len = read(connection_in, buf, sizeof(buf)); | 884 | len = read(connection_in, buf, sizeof(buf)); |
800 | if (len == 0) { | 885 | if (len == 0) { |
801 | log("Connection closed by %.200s", get_remote_ipaddr()); | 886 | logit("Connection closed by %.200s", get_remote_ipaddr()); |
802 | fatal_cleanup(); | 887 | fatal_cleanup(); |
803 | } | 888 | } |
804 | if (len < 0) | 889 | if (len < 0) |
@@ -949,7 +1034,9 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
949 | cp = buffer_ptr(&incoming_packet); | 1034 | cp = buffer_ptr(&incoming_packet); |
950 | packet_length = GET_32BIT(cp); | 1035 | packet_length = GET_32BIT(cp); |
951 | if (packet_length < 1 + 4 || packet_length > 256 * 1024) { | 1036 | if (packet_length < 1 + 4 || packet_length > 256 * 1024) { |
1037 | #ifdef PACKET_DEBUG | ||
952 | buffer_dump(&incoming_packet); | 1038 | buffer_dump(&incoming_packet); |
1039 | #endif | ||
953 | packet_disconnect("Bad packet length %u.", packet_length); | 1040 | packet_disconnect("Bad packet length %u.", packet_length); |
954 | } | 1041 | } |
955 | DBG(debug("input: packet len %u", packet_length+4)); | 1042 | DBG(debug("input: packet len %u", packet_length+4)); |
@@ -980,18 +1067,22 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
980 | * increment sequence number for incoming packet | 1067 | * increment sequence number for incoming packet |
981 | */ | 1068 | */ |
982 | if (mac && mac->enabled) { | 1069 | if (mac && mac->enabled) { |
983 | macbuf = mac_compute(mac, read_seqnr, | 1070 | macbuf = mac_compute(mac, p_read.seqnr, |
984 | buffer_ptr(&incoming_packet), | 1071 | buffer_ptr(&incoming_packet), |
985 | buffer_len(&incoming_packet)); | 1072 | buffer_len(&incoming_packet)); |
986 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) | 1073 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) |
987 | packet_disconnect("Corrupted MAC on input."); | 1074 | packet_disconnect("Corrupted MAC on input."); |
988 | DBG(debug("MAC #%d ok", read_seqnr)); | 1075 | DBG(debug("MAC #%d ok", p_read.seqnr)); |
989 | buffer_consume(&input, mac->mac_len); | 1076 | buffer_consume(&input, mac->mac_len); |
990 | } | 1077 | } |
991 | if (seqnr_p != NULL) | 1078 | if (seqnr_p != NULL) |
992 | *seqnr_p = read_seqnr; | 1079 | *seqnr_p = p_read.seqnr; |
993 | if (++read_seqnr == 0) | 1080 | if (++p_read.seqnr == 0) |
994 | log("incoming seqnr wraps around"); | 1081 | logit("incoming seqnr wraps around"); |
1082 | if (++p_read.packets == 0) | ||
1083 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
1084 | fatal("XXX too many packets with same key"); | ||
1085 | p_read.blocks += (packet_length + 4) / block_size; | ||
995 | 1086 | ||
996 | /* get padlen */ | 1087 | /* get padlen */ |
997 | cp = buffer_ptr(&incoming_packet); | 1088 | cp = buffer_ptr(&incoming_packet); |
@@ -1056,7 +1147,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) | |||
1056 | case SSH2_MSG_DISCONNECT: | 1147 | case SSH2_MSG_DISCONNECT: |
1057 | reason = packet_get_int(); | 1148 | reason = packet_get_int(); |
1058 | msg = packet_get_string(NULL); | 1149 | msg = packet_get_string(NULL); |
1059 | log("Received disconnect from %s: %u: %.400s", | 1150 | logit("Received disconnect from %s: %u: %.400s", |
1060 | get_remote_ipaddr(), reason, msg); | 1151 | get_remote_ipaddr(), reason, msg); |
1061 | xfree(msg); | 1152 | xfree(msg); |
1062 | fatal_cleanup(); | 1153 | fatal_cleanup(); |
@@ -1082,7 +1173,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) | |||
1082 | break; | 1173 | break; |
1083 | case SSH_MSG_DISCONNECT: | 1174 | case SSH_MSG_DISCONNECT: |
1084 | msg = packet_get_string(NULL); | 1175 | msg = packet_get_string(NULL); |
1085 | log("Received disconnect from %s: %.400s", | 1176 | logit("Received disconnect from %s: %.400s", |
1086 | get_remote_ipaddr(), msg); | 1177 | get_remote_ipaddr(), msg); |
1087 | fatal_cleanup(); | 1178 | fatal_cleanup(); |
1088 | xfree(msg); | 1179 | xfree(msg); |
@@ -1241,7 +1332,7 @@ packet_disconnect(const char *fmt,...) | |||
1241 | va_end(args); | 1332 | va_end(args); |
1242 | 1333 | ||
1243 | /* Display the error locally */ | 1334 | /* Display the error locally */ |
1244 | log("Disconnecting: %.100s", buf); | 1335 | logit("Disconnecting: %.100s", buf); |
1245 | 1336 | ||
1246 | /* Send the disconnect message to the other side, and wait for it to get sent. */ | 1337 | /* Send the disconnect message to the other side, and wait for it to get sent. */ |
1247 | if (compat20) { | 1338 | if (compat20) { |
@@ -1328,6 +1419,8 @@ packet_not_very_much_data_to_write(void) | |||
1328 | return buffer_len(&output) < 128 * 1024; | 1419 | return buffer_len(&output) < 128 * 1024; |
1329 | } | 1420 | } |
1330 | 1421 | ||
1422 | |||
1423 | #if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) | ||
1331 | static void | 1424 | static void |
1332 | packet_set_tos(int interactive) | 1425 | packet_set_tos(int interactive) |
1333 | { | 1426 | { |
@@ -1341,6 +1434,7 @@ packet_set_tos(int interactive) | |||
1341 | error("setsockopt IP_TOS %d: %.100s:", | 1434 | error("setsockopt IP_TOS %d: %.100s:", |
1342 | tos, strerror(errno)); | 1435 | tos, strerror(errno)); |
1343 | } | 1436 | } |
1437 | #endif | ||
1344 | 1438 | ||
1345 | /* Informs that the current session is interactive. Sets IP flags for that. */ | 1439 | /* Informs that the current session is interactive. Sets IP flags for that. */ |
1346 | 1440 | ||
@@ -1375,18 +1469,18 @@ packet_is_interactive(void) | |||
1375 | return interactive_mode; | 1469 | return interactive_mode; |
1376 | } | 1470 | } |
1377 | 1471 | ||
1378 | int | 1472 | u_int |
1379 | packet_set_maxsize(int s) | 1473 | packet_set_maxsize(u_int s) |
1380 | { | 1474 | { |
1381 | static int called = 0; | 1475 | static int called = 0; |
1382 | 1476 | ||
1383 | if (called) { | 1477 | if (called) { |
1384 | log("packet_set_maxsize: called twice: old %d new %d", | 1478 | logit("packet_set_maxsize: called twice: old %d new %d", |
1385 | max_packet_size, s); | 1479 | max_packet_size, s); |
1386 | return -1; | 1480 | return -1; |
1387 | } | 1481 | } |
1388 | if (s < 4 * 1024 || s > 1024 * 1024) { | 1482 | if (s < 4 * 1024 || s > 1024 * 1024) { |
1389 | log("packet_set_maxsize: bad size %d", s); | 1483 | logit("packet_set_maxsize: bad size %d", s); |
1390 | return -1; | 1484 | return -1; |
1391 | } | 1485 | } |
1392 | called = 1; | 1486 | called = 1; |
@@ -1428,3 +1522,22 @@ packet_send_ignore(int nbytes) | |||
1428 | rand >>= 8; | 1522 | rand >>= 8; |
1429 | } | 1523 | } |
1430 | } | 1524 | } |
1525 | |||
1526 | #define MAX_PACKETS (1<<31) | ||
1527 | int | ||
1528 | packet_need_rekeying(void) | ||
1529 | { | ||
1530 | if (datafellows & SSH_BUG_NOREKEY) | ||
1531 | return 0; | ||
1532 | return | ||
1533 | (p_send.packets > MAX_PACKETS) || | ||
1534 | (p_read.packets > MAX_PACKETS) || | ||
1535 | (max_blocks_out && (p_send.blocks > max_blocks_out)) || | ||
1536 | (max_blocks_in && (p_read.blocks > max_blocks_in)); | ||
1537 | } | ||
1538 | |||
1539 | void | ||
1540 | packet_set_rekey_limit(u_int32_t bytes) | ||
1541 | { | ||
1542 | rekey_limit = bytes; | ||
1543 | } | ||