@@ -1157,131 +1157,43 @@ 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 {discard_bytes_left = DiscardBytesLeft ,
1162+ discard_mac_already = DiscardMacAlready ,
1163+ discard_reason = DiscardReason }) when DiscardBytesLeft > 0 ->
1164+ % % Receiving data during discard proves peer is alive;
1165+ % % prevents keepalive timeout from interrupting camouflage
1166+ D1 = reset_alive (D0 ),
1167+ NewDataSize = byte_size (NewData ),
1168+ case NewDataSize >= DiscardBytesLeft of
1169+ true ->
1170+ % % Enough bytes discarded
1171+ ssh_transport :finish_packet_discard (DiscardMacAlready , D1 # data .ssh_params ),
1172+ handle_packet_part_result (DiscardReason , StateName , D1 );
1173+ false ->
1174+ % % We don't have enough bytes to finish packet discard,
1175+ % % we must get more from the socket
1176+ inet :setopts (Sock , [{active , once }]),
1177+ D = D1 # data {discard_bytes_left = DiscardBytesLeft - NewDataSize },
1178+ {keep_state , D }
1179+ end ;
11601180
11611181handle_event (info , {Proto , Sock , NewData }, StateName ,
11621182 D0 = # data {socket = Sock ,
11631183 transport_protocol = Proto ,
11641184 ssh_params = SshParams }) ->
11651185 D1 = reset_alive (D0 ),
11661186 try ssh_transport :handle_packet_part (
1167- D1 # data .decrypted_data_buffer ,
1168- <<(D1 # data .encrypted_data_buffer )/binary , NewData /binary >>,
1187+ D1 # data .decrypted_data_buffer ,
1188+ <<(D1 # data .encrypted_data_buffer )/binary , NewData /binary >>,
11691189 D1 # data .aead_data ,
11701190 D1 # data .undecrypted_packet_length ,
1171- D1 # data .ssh_params )
1191+ D1 # data .ssh_params )
11721192 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- # ssh_msg_userauth_request {} = Msg ->
1210- DecryptedSize = byte_size (DecryptedBytes ),
1211- case ? GET_OPT (max_auth_request_size , (D2 # data .ssh_params )# ssh .opts ) of
1212- MaxAuthRequestSize when DecryptedSize > MaxAuthRequestSize ->
1213- DetailedMsg = io_lib :format (" Auth length exceeded, message has ~B bytes"
1214- " and the maximum is ~B bytes." ,
1215- [DecryptedSize , MaxAuthRequestSize ]),
1216- {Shutdown , D } =
1217- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1218- " Auth length exceeded." ,
1219- DetailedMsg ,
1220- StateName , D2 ),
1221- {stop , Shutdown , D };
1222- _ ->
1223- {keep_state , D2 , [{next_event , internal , prepare_next_packet },
1224- {next_event , internal , Msg }
1225- ]}
1226- end ;
1227-
1228- Msg ->
1229- {keep_state , D2 , [{next_event , internal , prepare_next_packet },
1230- {next_event , internal , Msg }
1231- ]}
1232- catch
1233- Class :Reason0 :Stacktrace ->
1234- Reason = ssh_lib :trim_reason (Reason0 ),
1235- MsgFun =
1236- fun (debug ) ->
1237- io_lib :format (" Bad packet: Decrypted, but can't decode~n~p :~p~n~p " ,
1238- [Class ,Reason ,Stacktrace ],
1239- [{chars_limit , ssh_lib :max_log_len (SshParams )}]);
1240- (_ ) ->
1241- io_lib :format (" Bad packet: Decrypted, but can't decode ~p :~p " ,
1242- [Class , Reason ],
1243- [{chars_limit , ssh_lib :max_log_len (SshParams )}])
1244- end ,
1245- {Shutdown , D } =
1246- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1247- ? SELECT_MSG (MsgFun ),
1248- StateName , D2 ),
1249- {stop , Shutdown , D }
1250- end ;
1251-
1252- {get_more , DecryptedBytes , EncryptedDataRest , AeadData , RemainingSshPacketLen , Ssh1 } ->
1253- % % Here we know that there are not enough bytes in
1254- % % EncryptedDataRest to use. We must wait for more.
1255- inet :setopts (Sock , [{active , once }]),
1256- {keep_state , D1 # data {encrypted_data_buffer = EncryptedDataRest ,
1257- decrypted_data_buffer = DecryptedBytes ,
1258- undecrypted_packet_length = RemainingSshPacketLen ,
1259- aead_data = AeadData ,
1260- ssh_params = Ssh1 }};
1261-
1262- {bad_mac , Ssh1 } ->
1263- {Shutdown , D } =
1264- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1265- " Bad packet: bad mac" ,
1266- StateName , D1 # data {ssh_params = Ssh1 }),
1267- {stop , Shutdown , D };
1268-
1269- {error , {exceeds_max_size ,PacketLen }} ->
1270- {Shutdown , D } =
1271- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1272- io_lib :format (" Bad packet: Size (~p bytes) exceeds max size" ,
1273- [PacketLen ]),
1274- StateName , D1 ),
1275- {stop , Shutdown , D };
1276-
1277- {error , exceeds_max_decompressed_size } ->
1278- {Shutdown , D } =
1279- ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1280- " Bad packet: Size after decompression exceeds max size" ,
1281- StateName , D1 ),
1282- {stop , Shutdown , D }
1193+ Result ->
1194+ handle_packet_part_result (Result , StateName , D1 )
12831195 catch
1284- Class :Reason0 :Stacktrace ->
1196+ Class :Reason0 :Stacktrace ->
12851197 MsgFun =
12861198 fun (debug ) ->
12871199 io_lib :format (" Bad packet: Couldn't decrypt~n~p :~p~n~p " ,
@@ -1497,6 +1409,139 @@ handle_event(Type, Ev, StateName, D0) ->
14971409 ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR , Details , StateName , D0 ),
14981410 {stop , Shutdown , D }.
14991411
1412+ % % Handle reason returned from handle_packet_part, or {start_packet_discard, ...}
1413+ handle_packet_part_result ({packet_decrypted , DecryptedBytes , EncryptedDataRest , Ssh },
1414+ StateName ,
1415+ D0 = # data {ssh_params = Ssh0 }) ->
1416+ D1 = D0 # data {ssh_params =
1417+ Ssh # ssh {recv_sequence =
1418+ ssh_transport :next_seqnum (StateName ,
1419+ Ssh # ssh .recv_sequence ,
1420+ Ssh0 )},
1421+ decrypted_data_buffer = <<>>,
1422+ undecrypted_packet_length = undefined ,
1423+ aead_data = <<>>,
1424+ encrypted_data_buffer = EncryptedDataRest },
1425+ try
1426+ ssh_message :decode (set_kex_overload_prefix (DecryptedBytes ,D1 ))
1427+ of
1428+ # ssh_msg_kexinit {} = Msg ->
1429+ {keep_state , D1 , [{next_event , internal , prepare_next_packet },
1430+ {next_event , internal , {Msg ,DecryptedBytes }}
1431+ ]};
1432+
1433+ # ssh_msg_global_request {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1434+ # ssh_msg_request_success {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1435+ # ssh_msg_request_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1436+ # ssh_msg_channel_open {} = Msg -> {keep_state , D1 ,
1437+ [{{timeout , max_initial_idle_time }, cancel } |
1438+ ? CONNECTION_MSG (Msg )
1439+ ]};
1440+ # ssh_msg_channel_open_confirmation {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1441+ # ssh_msg_channel_open_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1442+ # ssh_msg_channel_window_adjust {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1443+ # ssh_msg_channel_data {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1444+ # ssh_msg_channel_extended_data {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1445+ # ssh_msg_channel_eof {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1446+ # ssh_msg_channel_close {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1447+ # ssh_msg_channel_request {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1448+ # ssh_msg_channel_failure {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1449+ # ssh_msg_channel_success {} = Msg -> {keep_state , D1 , ? CONNECTION_MSG (Msg )};
1450+
1451+
1452+ # ssh_msg_userauth_request {} = Msg ->
1453+ DecryptedSize = byte_size (DecryptedBytes ),
1454+ case ? GET_OPT (max_auth_request_size , (D1 # data .ssh_params )# ssh .opts ) of
1455+ MaxAuthRequestSize when DecryptedSize > MaxAuthRequestSize ->
1456+ DetailedMsg = io_lib :format (" Auth length exceeded, message has ~B bytes"
1457+ " and the maximum is ~B bytes." ,
1458+ [DecryptedSize , MaxAuthRequestSize ]),
1459+ {Shutdown , D } =
1460+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1461+ " Auth length exceeded." ,
1462+ DetailedMsg ,
1463+ StateName , D1 ),
1464+ {stop , Shutdown , D };
1465+ _ ->
1466+ {keep_state , D1 , [{next_event , internal , prepare_next_packet },
1467+ {next_event , internal , Msg }
1468+ ]}
1469+ end ;
1470+
1471+ Msg ->
1472+ {keep_state , D1 , [{next_event , internal , prepare_next_packet },
1473+ {next_event , internal , Msg }
1474+ ]}
1475+ catch
1476+ Class :Reason0 :Stacktrace ->
1477+ Reason = ssh_lib :trim_reason (Reason0 ),
1478+ MsgFun =
1479+ fun (debug ) ->
1480+ io_lib :format (" Bad packet: Decrypted, but can't decode~n~p :~p~n~p " ,
1481+ [Class ,Reason ,Stacktrace ],
1482+ [{chars_limit , ssh_lib :max_log_len (Ssh0 )}]);
1483+ (_ ) ->
1484+ io_lib :format (" Bad packet: Decrypted, but can't decode ~p :~p " ,
1485+ [Class , Reason ],
1486+ [{chars_limit , ssh_lib :max_log_len (Ssh0 )}])
1487+ end ,
1488+ {Shutdown , D } =
1489+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1490+ ? SELECT_MSG (MsgFun ),
1491+ StateName , D1 ),
1492+ {stop , Shutdown , D }
1493+ end ;
1494+ handle_packet_part_result ({get_more , DecryptedBytes , EncryptedDataRest , AeadData , RemainingSshPacketLen , Ssh },
1495+ _StateName , D0 = # data {socket = Sock }) ->
1496+ % % Here we know that there are not enough bytes in
1497+ % % EncryptedDataRest to use. We must wait for more.
1498+ inet :setopts (Sock , [{active , once }]),
1499+ {keep_state , D0 # data {encrypted_data_buffer = EncryptedDataRest ,
1500+ decrypted_data_buffer = DecryptedBytes ,
1501+ undecrypted_packet_length = RemainingSshPacketLen ,
1502+ aead_data = AeadData ,
1503+ ssh_params = Ssh }};
1504+ handle_packet_part_result ({bad_mac , Ssh }, StateName , D0 ) ->
1505+ {Shutdown , D } =
1506+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1507+ " Bad packet: bad mac" ,
1508+ StateName , D0 # data {ssh_params = Ssh }),
1509+ {stop , Shutdown , D };
1510+ handle_packet_part_result ({error , {exceeds_max_size , PacketLen }}, StateName , D0 ) ->
1511+ {Shutdown , D } =
1512+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1513+ io_lib :format (" Bad packet: Size (~p bytes) exceeds max size" ,
1514+ [PacketLen ]),
1515+ StateName , D0 ),
1516+ {stop , Shutdown , D };
1517+ handle_packet_part_result ({error , exceeds_max_decompressed_size }, StateName , D0 ) ->
1518+ {Shutdown , D } =
1519+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1520+ " Bad packet: Size after decompression exceeds max size" ,
1521+ StateName , D0 ),
1522+ {stop , Shutdown , D };
1523+ handle_packet_part_result ({error , {packet_not_aligned , PacketLen , BlockSize }}, StateName , D0 ) ->
1524+ {Shutdown , D } =
1525+ ? send_disconnect (? SSH_DISCONNECT_PROTOCOL_ERROR ,
1526+ io_lib :format (" Bad packet: Size (~p bytes) not aligned to block size (~p )" ,
1527+ [PacketLen , BlockSize ]),
1528+ StateName , D0 ),
1529+ {stop , Shutdown , D };
1530+ handle_packet_part_result ({start_packet_discard , DiscardBytesLeft , DiscardMacAlready , DiscardReason , Ssh },
1531+ StateName , D ) when DiscardBytesLeft =< 0 ->
1532+ % % Immediately upon start of packet discard we have enough bytes from the socket,
1533+ % % we can finish packet discard
1534+ ssh_transport :finish_packet_discard (DiscardMacAlready , Ssh ),
1535+ handle_packet_part_result (DiscardReason , StateName , D # data {ssh_params = Ssh });
1536+ handle_packet_part_result ({start_packet_discard , DiscardBytesLeft , DiscardMacAlready , DiscardReason , Ssh },
1537+ _StateName , D0 = # data {socket = Sock }) ->
1538+ % % We don't have enough bytes to finish packet discard, we must get more from the socket
1539+ inet :setopts (Sock , [{active , once }]),
1540+ D = D0 # data {discard_bytes_left = DiscardBytesLeft ,
1541+ discard_mac_already = DiscardMacAlready ,
1542+ discard_reason = DiscardReason ,
1543+ ssh_params = Ssh },
1544+ {keep_state , D }.
15001545
15011546% %--------------------------------------------------------------------
15021547-spec terminate (any (),
0 commit comments