@@ -1044,22 +1044,43 @@ 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
+ let decrypt_result = 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 = match decrypt_result {
1058
+ Ok ( p) => p,
1059
+ Err ( _) => {
1060
+ log_warn ! ( logger, "Unreadable failure from {}" , route_hop. pubkey) ;
1061
+
1062
+ let network_update = Some ( NetworkUpdate :: NodeFailure {
1063
+ node_id : route_hop. pubkey ,
1064
+ is_permanent : true ,
1065
+ } ) ;
1066
+ let short_channel_id = Some ( route_hop. short_channel_id ) ;
1067
+ res = Some ( FailureLearnings {
1068
+ network_update,
1069
+ short_channel_id,
1070
+ payment_failed_permanently : is_from_final_node,
1071
+ failed_within_blinded_path : false ,
1072
+ } ) ;
1073
+ return ;
1074
+ } ,
1075
+ } ;
1076
+
1058
1077
let error_code_slice = match err_packet. failuremsg . get ( 0 ..2 ) {
1059
1078
Some ( s) => s,
1060
1079
None => {
1061
1080
// Useless packet that we can't use but it passed HMAC, so it definitely came from the peer
1062
1081
// in question
1082
+ log_warn ! ( logger, "Missing error code in failure from {}" , route_hop. pubkey) ;
1083
+
1063
1084
let network_update = Some ( NetworkUpdate :: NodeFailure {
1064
1085
node_id : route_hop. pubkey ,
1065
1086
is_permanent : true ,
@@ -1219,6 +1240,12 @@ where
1219
1240
} else {
1220
1241
// only not set either packet unparseable or hmac does not match with any
1221
1242
// payment not retryable only when garbage is from the final node
1243
+ log_warn ! (
1244
+ logger,
1245
+ "Non-attributable failure encountered on route {}" ,
1246
+ path. hops. iter( ) . map( |h| h. pubkey. to_string( ) ) . collect:: <Vec <_>>( ) . join( "->" )
1247
+ ) ;
1248
+
1222
1249
DecodedOnionFailure {
1223
1250
network_update : None ,
1224
1251
short_channel_id : None ,
@@ -1768,7 +1795,7 @@ mod tests {
1768
1795
1769
1796
use crate :: io;
1770
1797
use crate :: ln:: channelmanager:: PaymentId ;
1771
- use crate :: ln:: msgs;
1798
+ use crate :: ln:: msgs:: { self , OnionErrorPacket } ;
1772
1799
use crate :: routing:: router:: { Path , PaymentParameters , Route , RouteHop } ;
1773
1800
use crate :: types:: features:: { ChannelFeatures , NodeFeatures } ;
1774
1801
use crate :: types:: payment:: PaymentHash ;
@@ -2104,6 +2131,75 @@ mod tests {
2104
2131
assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x2002 ) ) ;
2105
2132
}
2106
2133
2134
+ #[ test]
2135
+ fn test_non_attributable_failure_packet_onion ( ) {
2136
+ // Create a failure packet with bogus data.
2137
+ let packet = vec ! [ 1u8 ; 292 ] ;
2138
+
2139
+ // In the current protocol, it is unfortunately not possible to identify the failure source.
2140
+ let decrypted_failure = test_failure_attribution ( & packet) ;
2141
+ assert_eq ! ( decrypted_failure. short_channel_id, None ) ;
2142
+ }
2143
+
2144
+ #[ test]
2145
+ fn test_unreadable_failure_packet_onion ( ) {
2146
+ // Create a failure packet with a valid hmac but unreadable failure message.
2147
+ let onion_keys: Vec < OnionKeys > = build_test_onion_keys ( ) ;
2148
+ let shared_secret = onion_keys[ 0 ] . shared_secret . as_ref ( ) ;
2149
+ let um = gen_um_from_shared_secret ( & shared_secret) ;
2150
+
2151
+ // The failure message is a single 0 byte.
2152
+ let mut packet = [ 0u8 ; 33 ] ;
2153
+
2154
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & um) ;
2155
+ hmac. input ( & packet[ 32 ..] ) ;
2156
+ let hmac = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
2157
+ packet[ ..32 ] . copy_from_slice ( & hmac) ;
2158
+
2159
+ let packet = encrypt_failure_packet ( shared_secret, & packet) ;
2160
+
2161
+ // For the unreadable failure, it is still expected that the failing channel can be identified.
2162
+ let decrypted_failure = test_failure_attribution ( & packet. data ) ;
2163
+ assert_eq ! ( decrypted_failure. short_channel_id, Some ( 0 ) ) ;
2164
+ }
2165
+
2166
+ #[ test]
2167
+ fn test_missing_error_code ( ) {
2168
+ // Create a failure packet with a valid hmac and structure, but no error code.
2169
+ let onion_keys: Vec < OnionKeys > = build_test_onion_keys ( ) ;
2170
+ let shared_secret = onion_keys[ 0 ] . shared_secret . as_ref ( ) ;
2171
+ let um = gen_um_from_shared_secret ( & shared_secret) ;
2172
+
2173
+ let failuremsg = vec ! [ 1 ] ;
2174
+ let pad = Vec :: new ( ) ;
2175
+ let mut packet = msgs:: DecodedOnionErrorPacket { hmac : [ 0 ; 32 ] , failuremsg, pad } ;
2176
+
2177
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & um) ;
2178
+ hmac. input ( & packet. encode ( ) [ 32 ..] ) ;
2179
+ packet. hmac = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
2180
+
2181
+ let packet = encrypt_failure_packet ( shared_secret, & packet. encode ( ) [ ..] ) ;
2182
+
2183
+ let decrypted_failure = test_failure_attribution ( & packet. data ) ;
2184
+ assert_eq ! ( decrypted_failure. short_channel_id, Some ( 0 ) ) ;
2185
+ }
2186
+
2187
+ fn test_failure_attribution ( packet : & [ u8 ] ) -> DecodedOnionFailure {
2188
+ let logger: Arc < TestLogger > = Arc :: new ( TestLogger :: new ( ) ) ;
2189
+ let ctx_full = Secp256k1 :: new ( ) ;
2190
+ let path = build_test_path ( ) ;
2191
+ let htlc_source = HTLCSource :: OutboundRoute {
2192
+ path : path,
2193
+ session_priv : get_test_session_key ( ) ,
2194
+ first_hop_htlc_msat : 0 ,
2195
+ payment_id : PaymentId ( [ 1 ; 32 ] )
2196
+ , } ;
2197
+
2198
+ let decrypted_failure = process_onion_failure ( & ctx_full, & logger, & htlc_source, packet. into ( ) ) ;
2199
+
2200
+ decrypted_failure
2201
+ }
2202
+
2107
2203
struct RawOnionHopData {
2108
2204
data : Vec < u8 > ,
2109
2205
}
0 commit comments