@@ -933,13 +933,10 @@ pub(crate) struct DecodedOnionFailure {
933
933
934
934
/// Note that we always decrypt `packet` in-place here even if the deserialization into
935
935
/// [`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 ) {
939
937
let ammag = gen_ammag_from_shared_secret ( shared_secret. as_ref ( ) ) ;
940
938
let mut chacha = ChaCha20 :: new ( & ammag, & [ 0u8 ; 8 ] ) ;
941
939
chacha. process_in_place ( packet) ;
942
- msgs:: DecodedOnionErrorPacket :: read ( & mut Cursor :: new ( packet) )
943
940
}
944
941
945
942
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
@@ -1021,9 +1018,12 @@ where
1021
1018
{
1022
1019
// Actually parse the onion error data in tests so we can check that blinded hops fail
1023
1020
// 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
+
1027
1027
error_code_ret = Some ( u16:: from_be_bytes (
1028
1028
err_packet. failuremsg . get ( 0 ..2 ) . unwrap ( ) . try_into ( ) . unwrap ( ) ,
1029
1029
) ) ;
@@ -1044,22 +1044,33 @@ where
1044
1044
let amt_to_forward = htlc_msat - route_hop. fee_msat ;
1045
1045
htlc_msat = amt_to_forward;
1046
1046
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
+
1051
1049
let um = gen_um_from_shared_secret ( shared_secret. as_ref ( ) ) ;
1052
1050
let mut hmac = HmacEngine :: < Sha256 > :: new ( & um) ;
1053
- hmac. input ( & err_packet . encode ( ) [ 32 ..] ) ;
1051
+ hmac. input ( & encrypted_packet [ 32 ..] ) ;
1054
1052
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 ] ) {
1056
1054
return ;
1057
1055
}
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
+
1058
1067
let error_code_slice = match err_packet. failuremsg . get ( 0 ..2 ) {
1059
1068
Some ( s) => s,
1060
1069
None => {
1061
1070
// Useless packet that we can't use but it passed HMAC, so it definitely came from the peer
1062
1071
// in question
1072
+ log_warn ! ( logger, "Missing error code in failure from {}" , route_hop. pubkey) ;
1073
+
1063
1074
let network_update = Some ( NetworkUpdate :: NodeFailure {
1064
1075
node_id : route_hop. pubkey ,
1065
1076
is_permanent : true ,
@@ -1219,6 +1230,12 @@ where
1219
1230
} else {
1220
1231
// only not set either packet unparseable or hmac does not match with any
1221
1232
// 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
+
1222
1239
DecodedOnionFailure {
1223
1240
network_update : None ,
1224
1241
short_channel_id : None ,
@@ -2155,6 +2172,67 @@ mod tests {
2155
2172
assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x2002 ) ) ;
2156
2173
}
2157
2174
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
+
2158
2236
struct RawOnionHopData {
2159
2237
data : Vec < u8 > ,
2160
2238
}
0 commit comments