@@ -933,13 +933,10 @@ pub(crate) struct DecodedOnionFailure {
933933
934934/// Note that we always decrypt `packet` in-place here even if the deserialization into
935935/// [`msgs::DecodedOnionErrorPacket`] ultimately fails.
936- fn decrypt_onion_error_packet (
937- packet : & mut Vec < u8 > , shared_secret : SharedSecret ,
938- ) -> Result < msgs:: DecodedOnionErrorPacket , msgs:: DecodeError > {
936+ fn decrypt_onion_error_packet ( packet : & mut Vec < u8 > , shared_secret : SharedSecret ) {
939937 let ammag = gen_ammag_from_shared_secret ( shared_secret. as_ref ( ) ) ;
940938 let mut chacha = ChaCha20 :: new ( & ammag, & [ 0u8 ; 8 ] ) ;
941939 chacha. process_in_place ( packet) ;
942- msgs:: DecodedOnionErrorPacket :: read ( & mut Cursor :: new ( packet) )
943940}
944941
945942/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
@@ -1021,9 +1018,12 @@ where
10211018 {
10221019 // Actually parse the onion error data in tests so we can check that blinded hops fail
10231020 // back correctly.
1024- let err_packet =
1025- decrypt_onion_error_packet ( & mut encrypted_packet, shared_secret)
1026- . unwrap ( ) ;
1021+ decrypt_onion_error_packet ( & mut encrypted_packet, shared_secret) ;
1022+ let err_packet = msgs:: DecodedOnionErrorPacket :: read ( & mut Cursor :: new (
1023+ & encrypted_packet,
1024+ ) )
1025+ . unwrap ( ) ;
1026+
10271027 error_code_ret = Some ( u16:: from_be_bytes (
10281028 err_packet. failuremsg . get ( 0 ..2 ) . unwrap ( ) . try_into ( ) . unwrap ( ) ,
10291029 ) ) ;
@@ -1044,22 +1044,33 @@ where
10441044 let amt_to_forward = htlc_msat - route_hop. fee_msat ;
10451045 htlc_msat = amt_to_forward;
10461046
1047- let err_packet = match decrypt_onion_error_packet ( & mut encrypted_packet, shared_secret) {
1048- Ok ( p) => p,
1049- Err ( _) => return ,
1050- } ;
1047+ decrypt_onion_error_packet ( & mut encrypted_packet, shared_secret) ;
1048+
10511049 let um = gen_um_from_shared_secret ( shared_secret. as_ref ( ) ) ;
10521050 let mut hmac = HmacEngine :: < Sha256 > :: new ( & um) ;
1053- hmac. input ( & err_packet . encode ( ) [ 32 ..] ) ;
1051+ hmac. input ( & encrypted_packet [ 32 ..] ) ;
10541052
1055- if !fixed_time_eq ( & Hmac :: from_engine ( hmac) . to_byte_array ( ) , & err_packet . hmac ) {
1053+ if !fixed_time_eq ( & Hmac :: from_engine ( hmac) . to_byte_array ( ) , & encrypted_packet [ .. 32 ] ) {
10561054 return ;
10571055 }
1056+
1057+ let err_packet =
1058+ match msgs:: DecodedOnionErrorPacket :: read ( & mut Cursor :: new ( & encrypted_packet) ) {
1059+ Ok ( p) => p,
1060+ Err ( _) => {
1061+ log_warn ! ( logger, "Unreadable failure from {}" , route_hop. pubkey) ;
1062+
1063+ return ;
1064+ } ,
1065+ } ;
1066+
10581067 let error_code_slice = match err_packet. failuremsg . get ( 0 ..2 ) {
10591068 Some ( s) => s,
10601069 None => {
10611070 // Useless packet that we can't use but it passed HMAC, so it definitely came from the peer
10621071 // in question
1072+ log_warn ! ( logger, "Missing error code in failure from {}" , route_hop. pubkey) ;
1073+
10631074 let network_update = Some ( NetworkUpdate :: NodeFailure {
10641075 node_id : route_hop. pubkey ,
10651076 is_permanent : true ,
@@ -1219,6 +1230,12 @@ where
12191230 } else {
12201231 // only not set either packet unparseable or hmac does not match with any
12211232 // payment not retryable only when garbage is from the final node
1233+ log_warn ! (
1234+ logger,
1235+ "Non-attributable failure encountered on route {}" ,
1236+ path. hops. iter( ) . map( |h| h. pubkey. to_string( ) ) . collect:: <Vec <_>>( ) . join( "->" )
1237+ ) ;
1238+
12221239 DecodedOnionFailure {
12231240 network_update : None ,
12241241 short_channel_id : None ,
@@ -2155,6 +2172,67 @@ mod tests {
21552172 assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x2002 ) ) ;
21562173 }
21572174
2175+ #[ test]
2176+ fn test_non_attributable_failure_packet_onion ( ) {
2177+ // Create a failure packet with bogus data.
2178+ let packet = vec ! [ 1u8 ; 292 ] ;
2179+
2180+ // In the current protocol, it is unfortunately not possible to identify the failure source.
2181+ let logger = TestLogger :: new ( ) ;
2182+ let decrypted_failure = test_failure_attribution ( & logger, & packet) ;
2183+ assert_eq ! ( decrypted_failure. short_channel_id, None ) ;
2184+
2185+ logger. assert_log_contains (
2186+ "lightning::ln::onion_utils" ,
2187+ "Non-attributable failure encountered" ,
2188+ 1 ,
2189+ ) ;
2190+ }
2191+
2192+ #[ test]
2193+ fn test_missing_error_code ( ) {
2194+ // Create a failure packet with a valid hmac and structure, but no error code.
2195+ let onion_keys: Vec < OnionKeys > = build_test_onion_keys ( ) ;
2196+ let shared_secret = onion_keys[ 0 ] . shared_secret . as_ref ( ) ;
2197+ let um = gen_um_from_shared_secret ( & shared_secret) ;
2198+
2199+ let failuremsg = vec ! [ 1 ] ;
2200+ let pad = Vec :: new ( ) ;
2201+ let mut packet = msgs:: DecodedOnionErrorPacket { hmac : [ 0 ; 32 ] , failuremsg, pad } ;
2202+
2203+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & um) ;
2204+ hmac. input ( & packet. encode ( ) [ 32 ..] ) ;
2205+ packet. hmac = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
2206+
2207+ let packet = encrypt_failure_packet ( shared_secret, & packet. encode ( ) [ ..] ) ;
2208+
2209+ let logger = TestLogger :: new ( ) ;
2210+ let decrypted_failure = test_failure_attribution ( & logger, & packet. data ) ;
2211+ assert_eq ! ( decrypted_failure. short_channel_id, Some ( 0 ) ) ;
2212+
2213+ logger. assert_log_contains (
2214+ "lightning::ln::onion_utils" ,
2215+ "Missing error code in failure" ,
2216+ 1 ,
2217+ ) ;
2218+ }
2219+
2220+ fn test_failure_attribution ( logger : & TestLogger , packet : & [ u8 ] ) -> DecodedOnionFailure {
2221+ let ctx_full = Secp256k1 :: new ( ) ;
2222+ let path = build_test_path ( ) ;
2223+ let htlc_source = HTLCSource :: OutboundRoute {
2224+ path,
2225+ session_priv : get_test_session_key ( ) ,
2226+ first_hop_htlc_msat : 0 ,
2227+ payment_id : PaymentId ( [ 1 ; 32 ] ) ,
2228+ } ;
2229+
2230+ let decrypted_failure =
2231+ process_onion_failure ( & ctx_full, & logger, & htlc_source, packet. into ( ) ) ;
2232+
2233+ decrypted_failure
2234+ }
2235+
21582236 struct RawOnionHopData {
21592237 data : Vec < u8 > ,
21602238 }
0 commit comments