@@ -1157,122 +1157,44 @@ handle_event(info, {Proto, Sock, Info}, {hello,_}, #data{socket = Sock,
11571157 {keep_state_and_data , [{next_event , internal , {info_line ,Info }}]}
11581158 end ;
11591159
1160+ handle_event (info , {Proto , Sock , NewData }, StateName ,
1161+ D0 = # data {transport_protocol = Proto ,
1162+ socket = Sock ,
1163+ discard_bytes_left = DiscardBytesLeft ,
1164+ discard_mac_already = DiscardMacAlready ,
1165+ discard_reason = Reason ,
1166+ ssh_params = Ssh }) when DiscardBytesLeft > 0 ->
1167+ D1 = reset_alive (D0 ), % % TODO: Should this be here?
1168+ NewDataSize = byte_size (NewData ),
1169+ case NewDataSize >= DiscardBytesLeft of
1170+ true ->
1171+ % % Enough bytes discarded
1172+ ssh_transport :finish_packet_discard (DiscardMacAlready , Ssh ),
1173+ handle_packet_part_result (Reason , StateName , D1 );
1174+ false ->
1175+ % % We don't have enough bytes to finish packet discard,
1176+ % % we must get more from the socket
1177+ inet :setopts (Sock , [{active , once }]),
1178+ D = D1 # data {discard_bytes_left = DiscardBytesLeft - NewDataSize },
1179+ {keep_state , D }
1180+ end ;
11601181
11611182handle_event (info , {Proto , Sock , NewData }, StateName ,
11621183 D0 = # data {socket = Sock ,
11631184 transport_protocol = Proto ,
11641185 ssh_params = SshParams }) ->
11651186 D1 = reset_alive (D0 ),
11661187 try ssh_transport :handle_packet_part (
1167- D1 # data .decrypted_data_buffer ,
1168- <<(D1 # data .encrypted_data_buffer )/binary , NewData /binary >>,
1188+ D1 # data .decrypted_data_buffer ,
1189+ <<(D1 # data .encrypted_data_buffer )/binary , NewData /binary >>,
11691190 D1 # data .aead_data ,
11701191 D1 # data .undecrypted_packet_length ,
1171- D1 # data .ssh_params )
1192+ D1 # data .ssh_params )
11721193 of
1173- {packet_decrypted , DecryptedBytes , EncryptedDataRest , Ssh1 } ->
1174- D2 = D1 # data {ssh_params =
1175- Ssh1 # ssh {recv_sequence =
1176- ssh_transport :next_seqnum (StateName ,
1177- Ssh1 # ssh .recv_sequence ,
1178- SshParams )},
1179- decrypted_data_buffer = <<>>,
1180- undecrypted_packet_length = undefined ,
1181- aead_data = <<>>,
1182- encrypted_data_buffer = EncryptedDataRest },
1183- try
1184- ssh_message :decode (set_kex_overload_prefix (DecryptedBytes ,D2 ))
1185- of
1186- # ssh_msg_kexinit {} = Msg ->
1187- {keep_state , D2 , [{next_event , internal , prepare_next_packet },
1188- {next_event , internal , {Msg ,DecryptedBytes }}
1189- ]};
1190-
1191- # ssh_msg_global_request {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1192- # ssh_msg_request_success {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1193- # ssh_msg_request_failure {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1194- # ssh_msg_channel_open {} = Msg -> {keep_state , D2 ,
1195- [{{timeout , max_initial_idle_time }, cancel } |
1196- ? CONNECTION_MSG (Msg )
1197- ]};
1198- # ssh_msg_channel_open_confirmation {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1199- # ssh_msg_channel_open_failure {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1200- # ssh_msg_channel_window_adjust {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1201- # ssh_msg_channel_data {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1202- # ssh_msg_channel_extended_data {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1203- # ssh_msg_channel_eof {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1204- # ssh_msg_channel_close {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1205- # ssh_msg_channel_request {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1206- # ssh_msg_channel_failure {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1207- # ssh_msg_channel_success {} = Msg -> {keep_state , D2 , ? CONNECTION_MSG (Msg )};
1208-
1209- Msg ->
1210- {keep_state , D2 , [{next_event , internal , prepare_next_packet },
1211- {next_event , internal , Msg }
1212- ]}
1213- catch
1214- Class :Reason0 :Stacktrace ->
1215- Reason = ssh_lib :trim_reason (Reason0 ),
1216- MsgFun =
1217- fun (debug ) ->
1218- io_lib :format (" Bad packet: Decrypted, but can't decode~n~p :~p~n~p " ,
1219- [Class ,Reason ,Stacktrace ],
1220- [{chars_limit , ssh_lib :max_log_len (SshParams )}]);
1221- (_ ) ->
1222- io_lib :format (" Bad packet: Decrypted, but can't decode ~p :~p " ,
1223- [Class , Reason ],
1224- [{chars_limit , ssh_lib :max_log_len (SshParams )}])
1225- end ,
1226- {Shutdown , D } =
1227- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1228- ? SELECT_MSG (MsgFun ),
1229- StateName , D2 ),
1230- {stop , Shutdown , D }
1231- end ;
1232-
1233- {get_more , DecryptedBytes , EncryptedDataRest , AeadData , RemainingSshPacketLen , Ssh1 } ->
1234- % % Here we know that there are not enough bytes in
1235- % % EncryptedDataRest to use. We must wait for more.
1236- inet :setopts (Sock , [{active , once }]),
1237- {keep_state , D1 # data {encrypted_data_buffer = EncryptedDataRest ,
1238- decrypted_data_buffer = DecryptedBytes ,
1239- undecrypted_packet_length = RemainingSshPacketLen ,
1240- aead_data = AeadData ,
1241- ssh_params = Ssh1 }};
1242-
1243- {bad_mac , Ssh1 } ->
1244- {Shutdown , D } =
1245- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1246- " Bad packet: bad mac" ,
1247- StateName , D1 # data {ssh_params = Ssh1 }),
1248- {stop , Shutdown , D };
1249-
1250- {error , {exceeds_max_size ,PacketLen }} ->
1251- {Shutdown , D } =
1252- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1253- io_lib :format (" Bad packet: Size (~p bytes) exceeds max size" ,
1254- [PacketLen ]),
1255- StateName , D1 ),
1256- {stop , Shutdown , D };
1257-
1258- {error , exceeds_max_decompressed_size } ->
1259- {Shutdown , D } =
1260- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1261- " Bad packet: Size after decompression exceeds max size" ,
1262- StateName , D1 ),
1263- {stop , Shutdown , D };
1264-
1265- {error , {packet_not_aligned , PacketLen }} ->
1266- BlockSize0 = SshParams # ssh .decrypt_block_size ,
1267- BlockSize = max (8 , BlockSize0 ),
1268- {Shutdown , D } =
1269- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1270- io_lib :format (" Bad packet: Size (~p bytes) not aligned to block size (~p )" ,
1271- [PacketLen , BlockSize ]),
1272- StateName , D1 ),
1273- {stop , Shutdown , D }
1194+ Result ->
1195+ handle_packet_part_result (Result , StateName , D1 )
12741196 catch
1275- Class :Reason0 :Stacktrace ->
1197+ Class :Reason0 :Stacktrace ->
12761198 MsgFun =
12771199 fun (debug ) ->
12781200 io_lib :format (" Bad packet: Couldn't decrypt~n~p :~p~n~p " ,
@@ -1488,6 +1410,119 @@ handle_event(Type, Ev, StateName, D0) ->
14881410 ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR , Details , StateName , D0 ),
14891411 {stop , Shutdown , D }.
14901412
1413+ % % Handle reason returned from handle_packet_part, or discard_reason
1414+ handle_packet_part_result ({packet_decrypted , DecryptedBytes , EncryptedDataRest , Ssh },
1415+ StateName ,
1416+ D0 = # data {ssh_params = Ssh0 }) ->
1417+ D1 = D0 # data {ssh_params =
1418+ Ssh # ssh {recv_sequence =
1419+ ssh_transport :next_seqnum (StateName ,
1420+ Ssh # ssh .recv_sequence ,
1421+ Ssh0 )},
1422+ decrypted_data_buffer = <<>>,
1423+ undecrypted_packet_length = undefined ,
1424+ aead_data = <<>>,
1425+ encrypted_data_buffer = EncryptedDataRest },
1426+ try
1427+ ssh_message :decode (set_kex_overload_prefix (DecryptedBytes ,D1 ))
1428+ of
1429+ # ssh_msg_kexinit {} = Msg ->
1430+ {keep_state , D1 , [{next_event , internal , prepare_next_packet },
1431+ {next_event , internal , {Msg ,DecryptedBytes }}
1432+ ]};
1433+
1434+ # ssh_msg_global_request {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1435+ # ssh_msg_request_success {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1436+ # ssh_msg_request_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1437+ # ssh_msg_channel_open {} = Msg -> {keep_state , D1 ,
1438+ [{{timeout , max_initial_idle_time }, cancel } |
1439+ ? CONNECTION_MSG (Msg )
1440+ ]};
1441+ # ssh_msg_channel_open_confirmation {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1442+ # ssh_msg_channel_open_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1443+ # ssh_msg_channel_window_adjust {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1444+ # ssh_msg_channel_data {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1445+ # ssh_msg_channel_extended_data {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1446+ # ssh_msg_channel_eof {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1447+ # ssh_msg_channel_close {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1448+ # ssh_msg_channel_request {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1449+ # ssh_msg_channel_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1450+ # ssh_msg_channel_success {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1451+
1452+ Msg ->
1453+ {keep_state , D1 , [{next_event , internal , prepare_next_packet },
1454+ {next_event , internal , Msg }
1455+ ]}
1456+ catch
1457+ Class :Reason0 :Stacktrace ->
1458+ Reason = ssh_lib :trim_reason (Reason0 ),
1459+ MsgFun =
1460+ fun (debug ) ->
1461+ io_lib :format (" Bad packet: Decrypted, but can't decode~n~p :~p~n~p " ,
1462+ [Class ,Reason ,Stacktrace ],
1463+ [{chars_limit , ssh_lib :max_log_len (Ssh0 )}]);
1464+ (_ ) ->
1465+ io_lib :format (" Bad packet: Decrypted, but can't decode ~p :~p " ,
1466+ [Class , Reason ],
1467+ [{chars_limit , ssh_lib :max_log_len (Ssh0 )}])
1468+ end ,
1469+ {Shutdown , D } =
1470+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1471+ ? SELECT_MSG (MsgFun ),
1472+ StateName , D1 ),
1473+ {stop , Shutdown , D }
1474+ end ;
1475+ handle_packet_part_result ({get_more , DecryptedBytes , EncryptedDataRest , AeadData , RemainingSshPacketLen , Ssh },
1476+ _StateName , D0 = # data {socket = Sock }) ->
1477+ % % Here we know that there are not enough bytes in
1478+ % % EncryptedDataRest to use. We must wait for more.
1479+ inet :setopts (Sock , [{active , once }]),
1480+ {keep_state , D0 # data {encrypted_data_buffer = EncryptedDataRest ,
1481+ decrypted_data_buffer = DecryptedBytes ,
1482+ undecrypted_packet_length = RemainingSshPacketLen ,
1483+ aead_data = AeadData ,
1484+ ssh_params = Ssh }};
1485+ handle_packet_part_result ({bad_mac , Ssh }, StateName , D0 ) ->
1486+ {Shutdown , D } =
1487+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1488+ " Bad packet: bad mac" ,
1489+ StateName , D0 # data {ssh_params = Ssh }),
1490+ {stop , Shutdown , D };
1491+ handle_packet_part_result ({error , {exceeds_max_size , PacketLen }}, StateName , D0 ) ->
1492+ {Shutdown , D } =
1493+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1494+ io_lib :format (" Bad packet: Size (~p bytes) exceeds max size" ,
1495+ [PacketLen ]),
1496+ StateName , D0 ),
1497+ {stop , Shutdown , D };
1498+ handle_packet_part_result ({error , exceeds_max_decompressed_size }, StateName , D0 ) ->
1499+ {Shutdown , D } =
1500+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1501+ " Bad packet: Size after decompression exceeds max size" ,
1502+ StateName , D0 ),
1503+ {stop , Shutdown , D };
1504+ handle_packet_part_result ({error , {packet_not_aligned , PacketLen , BlockSize }}, StateName , D0 ) ->
1505+ {Shutdown , D } =
1506+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1507+ io_lib :format (" Bad packet: Size (~p bytes) not aligned to block size (~p )" ,
1508+ [PacketLen , BlockSize ]),
1509+ StateName , D0 ),
1510+ {stop , Shutdown , D };
1511+ handle_packet_part_result ({start_packet_discard , DiscardBytesLeft , DiscardMacAlready , DiscardReason , Ssh },
1512+ StateName , D ) when DiscardBytesLeft =< 0 ->
1513+ % % Immediately upon start of packet discard we have enough bytes from the socket,
1514+ % % we can finish packet discard
1515+ ssh_transport :finish_packet_discard (DiscardMacAlready , Ssh ),
1516+ handle_packet_part_result (DiscardReason , StateName , D # data {ssh_params = Ssh });
1517+ handle_packet_part_result ({start_packet_discard , DiscardBytesLeft , DiscardMacAlready , DiscardReason , Ssh },
1518+ _StateName , D0 = # data {socket = Sock }) ->
1519+ % % We don't have enough bytes to finish packet discard, we must get more from the socket
1520+ inet :setopts (Sock , [{active , once }]),
1521+ D = D0 # data {discard_bytes_left = DiscardBytesLeft ,
1522+ discard_mac_already = DiscardMacAlready ,
1523+ discard_reason = DiscardReason ,
1524+ ssh_params = Ssh },
1525+ {keep_state , D }.
14911526
14921527% %--------------------------------------------------------------------
14931528-spec terminate (any (),
0 commit comments