Skip to content

Commit 10041e6

Browse files
committed
Check the PK of the source of an error before closing chans from it
When we receive an error message from a peer, it can indicate a channel which we should close. However, we previously did not check that the counterparty who sends us such a message is the counterparty with whom we have the channel, allowing any connected peer to make us force-close any channel we have as long as they know the channel id. This commit simply changes the force-close logic to check that the sender matches the channel's counterparty node_id, though as noted in lightningdevkit#105, we eventually need to change the indexing anyway to allow absurdly terrible peers to open channels with us.
1 parent e4b516d commit 10041e6

File tree

1 file changed

+19
-9
lines changed

1 file changed

+19
-9
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -916,19 +916,22 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
916916
}
917917
}
918918

919-
/// Force closes a channel, immediately broadcasting the latest local commitment transaction to
920-
/// the chain and rejecting new HTLCs on the given channel. Fails if channel_id is unknown to the manager.
921-
pub fn force_close_channel(&self, channel_id: &[u8; 32]) -> Result<(), APIError>{
922-
let _consistency_lock = self.total_consistency_lock.read().unwrap();
923-
919+
fn force_close_channel_with_peer(&self, channel_id: &[u8; 32], peer_node_id: Option<&PublicKey>) -> Result<(), APIError> {
924920
let mut chan = {
925921
let mut channel_state_lock = self.channel_state.lock().unwrap();
926922
let channel_state = &mut *channel_state_lock;
927-
if let Some(chan) = channel_state.by_id.remove(channel_id) {
928-
if let Some(short_id) = chan.get_short_channel_id() {
923+
if let hash_map::Entry::Occupied(chan) = channel_state.by_id.entry(channel_id.clone()) {
924+
if let Some(node_id) = peer_node_id {
925+
if chan.get().get_counterparty_node_id() != *node_id {
926+
// Error or Ok here doesn't matter - the result is only exposed publicly
927+
// when peer_node_id is None anyway.
928+
return Ok(());
929+
}
930+
}
931+
if let Some(short_id) = chan.get().get_short_channel_id() {
929932
channel_state.short_to_id.remove(&short_id);
930933
}
931-
chan
934+
chan.remove_entry().1
932935
} else {
933936
return Err(APIError::ChannelUnavailable{err: "No such channel".to_owned()});
934937
}
@@ -945,6 +948,13 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
945948
Ok(())
946949
}
947950

951+
/// Force closes a channel, immediately broadcasting the latest local commitment transaction to
952+
/// the chain and rejecting new HTLCs on the given channel. Fails if channel_id is unknown to the manager.
953+
pub fn force_close_channel(&self, channel_id: &[u8; 32]) -> Result<(), APIError> {
954+
let _consistency_lock = self.total_consistency_lock.read().unwrap();
955+
self.force_close_channel_with_peer(channel_id, None)
956+
}
957+
948958
/// Force close all channels, immediately broadcasting the latest local commitment transaction
949959
/// for each to the chain and rejecting new HTLCs on each.
950960
pub fn force_close_all_channels(&self) {
@@ -3479,7 +3489,7 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
34793489
}
34803490
} else {
34813491
// Untrusted messages from peer, we throw away the error if id points to a non-existent channel
3482-
let _ = self.force_close_channel(&msg.channel_id);
3492+
let _ = self.force_close_channel_with_peer(&msg.channel_id, Some(counterparty_node_id));
34833493
}
34843494
}
34853495
}

0 commit comments

Comments
 (0)