Skip to content

Commit 2390dbc

Browse files
authored
Merge pull request #1895 from TheBlueMatt/2022-12-fix-missing-data
Fix some onion errors and assert their length is correct
2 parents 36e6023 + c9fe69f commit 2390dbc

File tree

5 files changed

+290
-140
lines changed

5 files changed

+290
-140
lines changed

lightning/src/ln/channel.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ use crate::ln::features::{ChannelTypeFeatures, InitFeatures};
2727
use crate::ln::msgs;
2828
use crate::ln::msgs::{DecodeError, OptionalField, DataLossProtect};
2929
use crate::ln::script::{self, ShutdownScript};
30-
use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
30+
use crate::ln::channelmanager::{self, CounterpartyForwardingInfo, PendingHTLCStatus, HTLCSource, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT};
3131
use crate::ln::chan_utils::{CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, ClosingTransaction};
3232
use crate::ln::chan_utils;
33+
use crate::ln::onion_utils::HTLCFailReason;
3334
use crate::chain::BestBlock;
3435
use crate::chain::chaininterface::{FeeEstimator, ConfirmationTarget, LowerBoundedFeeEstimator};
3536
use crate::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, LATENCY_GRACE_PERIOD_BLOCKS};

lightning/src/ln/channelmanager.rs

+59-133
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use crate::ln::features::InvoiceFeatures;
4949
use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteHop, RoutePath, RouteParameters};
5050
use crate::ln::msgs;
5151
use crate::ln::onion_utils;
52+
use crate::ln::onion_utils::HTLCFailReason;
5253
use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT};
5354
use crate::ln::wire::Encode;
5455
use crate::chain::keysinterface::{Sign, KeysInterface, KeysManager, Recipient};
@@ -276,27 +277,6 @@ impl HTLCSource {
276277
}
277278
}
278279

279-
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
280-
pub(super) enum HTLCFailReason {
281-
LightningError {
282-
err: msgs::OnionErrorPacket,
283-
},
284-
Reason {
285-
failure_code: u16,
286-
data: Vec<u8>,
287-
}
288-
}
289-
290-
impl HTLCFailReason {
291-
pub(super) fn reason(failure_code: u16, data: Vec<u8>) -> Self {
292-
Self::Reason { failure_code, data }
293-
}
294-
295-
pub(super) fn from_failure_code(failure_code: u16) -> Self {
296-
Self::Reason { failure_code, data: Vec::new() }
297-
}
298-
}
299-
300280
struct ReceiveError {
301281
err_code: u16,
302282
err_data: Vec<u8>,
@@ -2062,10 +2042,13 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
20622042
// Also, ensure that, in the case of an unknown preimage for the received payment hash, our
20632043
// payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
20642044
// channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
2065-
if (hop_data.outgoing_cltv_value as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
2045+
let current_height: u32 = self.best_block.read().unwrap().height();
2046+
if (hop_data.outgoing_cltv_value as u64) <= current_height as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 {
2047+
let mut err_data = Vec::with_capacity(12);
2048+
err_data.extend_from_slice(&amt_msat.to_be_bytes());
2049+
err_data.extend_from_slice(&current_height.to_be_bytes());
20662050
return Err(ReceiveError {
2067-
err_code: 17,
2068-
err_data: Vec::new(),
2051+
err_code: 0x4000 | 15, err_data,
20692052
msg: "The final CLTV expiry is too soon to handle",
20702053
});
20712054
}
@@ -2173,7 +2156,8 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
21732156
return PendingHTLCStatus::Fail(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
21742157
channel_id: msg.channel_id,
21752158
htlc_id: msg.htlc_id,
2176-
reason: onion_utils::build_first_hop_failure_packet(&shared_secret, $err_code, $data),
2159+
reason: HTLCFailReason::reason($err_code, $data.to_vec())
2160+
.get_encrypted_failure_packet(&shared_secret, &None),
21772161
}));
21782162
}
21792163
}
@@ -2238,7 +2222,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
22382222
// with a short_channel_id of 0. This is important as various things later assume
22392223
// short_channel_id is non-0 in any ::Forward.
22402224
if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing {
2241-
if let Some((err, code, chan_update)) = loop {
2225+
if let Some((err, mut code, chan_update)) = loop {
22422226
let id_option = self.short_to_chan_info.read().unwrap().get(&short_channel_id).cloned();
22432227
let mut channel_state = self.channel_state.lock().unwrap();
22442228
let forwarding_id_opt = match id_option {
@@ -2295,10 +2279,13 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
22952279
}
22962280
chan_update_opt
22972281
} else {
2298-
if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 { // incorrect_cltv_expiry
2282+
if (msg.cltv_expiry as u64) < (*outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
2283+
// We really should set `incorrect_cltv_expiry` here but as we're not
2284+
// forwarding over a real channel we can't generate a channel_update
2285+
// for it. Instead we just return a generic temporary_node_failure.
22992286
break Some((
23002287
"Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
2301-
0x1000 | 13, None,
2288+
0x2000 | 2, None,
23022289
));
23032290
}
23042291
None
@@ -2344,6 +2331,12 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
23442331
(chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
23452332
msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
23462333
chan_update.write(&mut res).expect("Writes cannot fail");
2334+
} else if code & 0x1000 == 0x1000 {
2335+
// If we're trying to return an error that requires a `channel_update` but
2336+
// we're forwarding to a phantom or intercept "channel" (i.e. cannot
2337+
// generate an update), just use the generic "temporary_node_failure"
2338+
// instead.
2339+
code = 0x2000 | 2;
23472340
}
23482341
return_err!(err, code, &res.0[..]);
23492342
}
@@ -4048,114 +4041,57 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
40484041
} else { None };
40494042
log_trace!(self.logger, "Failing outbound payment HTLC with payment_hash {}", log_bytes!(payment_hash.0));
40504043

4051-
let path_failure = match &onion_error {
4052-
&HTLCFailReason::LightningError { ref err } => {
4044+
let path_failure = {
40534045
#[cfg(test)]
4054-
let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
4046+
let (network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_error.decode_onion_failure(&self.secp_ctx, &self.logger, &source);
40554047
#[cfg(not(test))]
4056-
let (network_update, short_channel_id, payment_retryable, _, _) = onion_utils::process_onion_failure(&self.secp_ctx, &self.logger, &source, err.data.clone());
4057-
4058-
if self.payment_is_probe(payment_hash, &payment_id) {
4059-
if !payment_retryable {
4060-
events::Event::ProbeSuccessful {
4061-
payment_id: *payment_id,
4062-
payment_hash: payment_hash.clone(),
4063-
path: path.clone(),
4064-
}
4065-
} else {
4066-
events::Event::ProbeFailed {
4067-
payment_id: *payment_id,
4068-
payment_hash: payment_hash.clone(),
4069-
path: path.clone(),
4070-
short_channel_id,
4071-
}
4072-
}
4073-
} else {
4074-
// TODO: If we decided to blame ourselves (or one of our channels) in
4075-
// process_onion_failure we should close that channel as it implies our
4076-
// next-hop is needlessly blaming us!
4077-
if let Some(scid) = short_channel_id {
4078-
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
4079-
}
4080-
events::Event::PaymentPathFailed {
4081-
payment_id: Some(*payment_id),
4082-
payment_hash: payment_hash.clone(),
4083-
payment_failed_permanently: !payment_retryable,
4084-
network_update,
4085-
all_paths_failed,
4086-
path: path.clone(),
4087-
short_channel_id,
4088-
retry,
4089-
#[cfg(test)]
4090-
error_code: onion_error_code,
4091-
#[cfg(test)]
4092-
error_data: onion_error_data
4093-
}
4094-
}
4095-
},
4096-
&HTLCFailReason::Reason {
4097-
#[cfg(test)]
4098-
ref failure_code,
4099-
#[cfg(test)]
4100-
ref data,
4101-
.. } => {
4102-
// we get a fail_malformed_htlc from the first hop
4103-
// TODO: We'd like to generate a NetworkUpdate for temporary
4104-
// failures here, but that would be insufficient as find_route
4105-
// generally ignores its view of our own channels as we provide them via
4106-
// ChannelDetails.
4107-
// TODO: For non-temporary failures, we really should be closing the
4108-
// channel here as we apparently can't relay through them anyway.
4109-
let scid = path.first().unwrap().short_channel_id;
4110-
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
4111-
4112-
if self.payment_is_probe(payment_hash, &payment_id) {
4113-
events::Event::ProbeFailed {
4048+
let (network_update, short_channel_id, payment_retryable, _, _) = onion_error.decode_onion_failure(&self.secp_ctx, &self.logger, &source);
4049+
4050+
if self.payment_is_probe(payment_hash, &payment_id) {
4051+
if !payment_retryable {
4052+
events::Event::ProbeSuccessful {
41144053
payment_id: *payment_id,
41154054
payment_hash: payment_hash.clone(),
41164055
path: path.clone(),
4117-
short_channel_id: Some(scid),
41184056
}
41194057
} else {
4120-
events::Event::PaymentPathFailed {
4121-
payment_id: Some(*payment_id),
4058+
events::Event::ProbeFailed {
4059+
payment_id: *payment_id,
41224060
payment_hash: payment_hash.clone(),
4123-
payment_failed_permanently: false,
4124-
network_update: None,
4125-
all_paths_failed,
41264061
path: path.clone(),
4127-
short_channel_id: Some(scid),
4128-
retry,
4129-
#[cfg(test)]
4130-
error_code: Some(*failure_code),
4131-
#[cfg(test)]
4132-
error_data: Some(data.clone()),
4062+
short_channel_id,
41334063
}
41344064
}
4065+
} else {
4066+
// TODO: If we decided to blame ourselves (or one of our channels) in
4067+
// process_onion_failure we should close that channel as it implies our
4068+
// next-hop is needlessly blaming us!
4069+
if let Some(scid) = short_channel_id {
4070+
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
4071+
}
4072+
events::Event::PaymentPathFailed {
4073+
payment_id: Some(*payment_id),
4074+
payment_hash: payment_hash.clone(),
4075+
payment_failed_permanently: !payment_retryable,
4076+
network_update,
4077+
all_paths_failed,
4078+
path: path.clone(),
4079+
short_channel_id,
4080+
retry,
4081+
#[cfg(test)]
4082+
error_code: onion_error_code,
4083+
#[cfg(test)]
4084+
error_data: onion_error_data
4085+
}
41354086
}
41364087
};
41374088
let mut pending_events = self.pending_events.lock().unwrap();
41384089
pending_events.push(path_failure);
41394090
if let Some(ev) = full_failure_ev { pending_events.push(ev); }
41404091
},
41414092
HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint }) => {
4142-
let err_packet = match onion_error {
4143-
HTLCFailReason::Reason { ref failure_code, ref data } => {
4144-
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with code {}", log_bytes!(payment_hash.0), failure_code);
4145-
if let Some(phantom_ss) = phantom_shared_secret {
4146-
let phantom_packet = onion_utils::build_failure_packet(phantom_ss, *failure_code, &data[..]).encode();
4147-
let encrypted_phantom_packet = onion_utils::encrypt_failure_packet(phantom_ss, &phantom_packet);
4148-
onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &encrypted_phantom_packet.data[..])
4149-
} else {
4150-
let packet = onion_utils::build_failure_packet(incoming_packet_shared_secret, *failure_code, &data[..]).encode();
4151-
onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &packet)
4152-
}
4153-
},
4154-
HTLCFailReason::LightningError { err } => {
4155-
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards with pre-built LightningError", log_bytes!(payment_hash.0));
4156-
onion_utils::encrypt_failure_packet(incoming_packet_shared_secret, &err.data)
4157-
}
4158-
};
4093+
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with {:?}", log_bytes!(payment_hash.0), onion_error);
4094+
let err_packet = onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret);
41594095

41604096
let mut forward_event = None;
41614097
let mut forward_htlcs = self.forward_htlcs.lock().unwrap();
@@ -5082,10 +5018,10 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
50825018
PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => {
50835019
let reason = if (error_code & 0x1000) != 0 {
50845020
let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan);
5085-
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, real_code, &error_data)
5021+
HTLCFailReason::reason(real_code, error_data)
50865022
} else {
5087-
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &[])
5088-
};
5023+
HTLCFailReason::from_failure_code(error_code)
5024+
}.get_encrypted_failure_packet(incoming_shared_secret, &None);
50895025
let msg = msgs::UpdateFailHTLC {
50905026
channel_id: msg.channel_id,
50915027
htlc_id: msg.htlc_id,
@@ -5129,7 +5065,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
51295065
if chan.get().get_counterparty_node_id() != *counterparty_node_id {
51305066
return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), msg.channel_id));
51315067
}
5132-
try_chan_entry!(self, chan.get_mut().update_fail_htlc(&msg, HTLCFailReason::LightningError { err: msg.reason.clone() }), chan);
5068+
try_chan_entry!(self, chan.get_mut().update_fail_htlc(&msg, HTLCFailReason::from_msg(msg)), chan);
51335069
},
51345070
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
51355071
}
@@ -5148,7 +5084,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
51485084
let chan_err: ChannelError = ChannelError::Close("Got update_fail_malformed_htlc with BADONION not set".to_owned());
51495085
try_chan_entry!(self, Err(chan_err), chan);
51505086
}
5151-
try_chan_entry!(self, chan.get_mut().update_fail_malformed_htlc(&msg, HTLCFailReason::from_failure_code(msg.failure_code)), chan);
5087+
try_chan_entry!(self, chan.get_mut().update_fail_malformed_htlc(&msg, HTLCFailReason::reason(msg.failure_code, msg.sha256_of_onion.to_vec())), chan);
51525088
Ok(())
51535089
},
51545090
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))
@@ -7037,16 +6973,6 @@ impl Writeable for HTLCSource {
70376973
}
70386974
}
70396975

7040-
impl_writeable_tlv_based_enum!(HTLCFailReason,
7041-
(0, LightningError) => {
7042-
(0, err, required),
7043-
},
7044-
(1, Reason) => {
7045-
(0, failure_code, required),
7046-
(2, data, vec_type),
7047-
},
7048-
;);
7049-
70506976
impl_writeable_tlv_based!(PendingAddHTLCInfo, {
70516977
(0, forward_info, required),
70526978
(1, prev_user_channel_id, (default_value, 0)),

0 commit comments

Comments
 (0)