server+htlcswitch: prevent privacy leaks, allow alias routing

This intent of this change is to prevent privacy leaks when routing
with aliases and also to allow routing when using an alias. The
aliases are our aliases.

Introduces are two maps:

* aliasToReal:
  This is an N->1 mapping for a channel. The keys are the set of
  aliases and the value is the confirmed, on-chain SCID.

* baseIndex:
  This is also an N->1 mapping for a channel. The keys are the set
  of aliases and the value is the "base" SCID (whatever is in the
  OpenChannel.ShortChannelID field). There is also a base->base
  mapping, so not all keys are aliases.

The above maps are populated when a link is added to the switch and
when the channel has confirmed on-chain. The maps are not removed
from if the link is removed, but this is fine since forwarding won't
occur.

* getLinkByMapping
  This function is introduced to adhere to the spec requirements that
  using the confirmed SCID of a private, scid-alias-feature-bit
  channel does not work. Lnd implements a stricter version of the spec
  and disallows this behavior if the feature-bit was negotiated, rather
  than just the channel type. The old, privacy-leak behavior is
  preserved.

The spec also requires that if we must fail back an HTLC, the
ChannelUpdate must use the SCID of whatever was in the onion, to avoid
a privacy leak. This is also done by passing in the relevant SCID to
the mailbox and link. Lnd will also cancel back on the "incoming" side
if the InterceptableSwitch was used or if the link failed to decrypt
the onion. In this case, we are cautious and replace the SCID if an
alias exists.
This commit is contained in:
eugene committed 2022-07-07 17:10:28 -04:00
1 parent 59fea192b7
commit 13c15e8038
12 files changed
+2406 -298

No files matched your search

+29 -7
View File
@@ -1874,6 +1874,12 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
return nil
}
getAliases := func(
base lnwire.ShortChannelID) []lnwire.ShortChannelID {
return nil
}
// Instantiate with a long interval, so that we can precisely control
// the firing via force feeding.
bticker := ticker.NewForce(time.Hour)
@@ -1917,6 +1923,7 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
NotifyActiveChannel: func(wire.OutPoint) {},
NotifyInactiveChannel: func(wire.OutPoint) {},
HtlcNotifier: aliceSwitch.cfg.HtlcNotifier,
GetAliases: getAliases,
}
aliceLink := NewChannelLink(aliceCfg, aliceLc.channel)
@@ -4325,6 +4332,12 @@ func (h *persistentLinkHarness) restartLink(
return nil
}
getAliases := func(
base lnwire.ShortChannelID) []lnwire.ShortChannelID {
return nil
}
// Instantiate with a long interval, so that we can precisely control
// the firing via force feeding.
bticker := ticker.NewForce(time.Hour)
@@ -4371,6 +4384,7 @@ func (h *persistentLinkHarness) restartLink(
NotifyInactiveChannel: func(wire.OutPoint) {},
HtlcNotifier: aliceSwitch.cfg.HtlcNotifier,
SyncStates: syncStates,
GetAliases: getAliases,
}
aliceLink := NewChannelLink(aliceCfg, aliceChannel)
@@ -5571,6 +5585,12 @@ func TestCheckHtlcForward(t *testing.T) {
return &lnwire.ChannelUpdate{}, nil
}
failAliasUpdate := func(sid lnwire.ShortChannelID,
incoming bool) *lnwire.ChannelUpdate {
return nil
}
testChannel, _, fCleanUp, err := createTestChannel(
alicePrivKey, bobPrivKey, 100000, 100000,
1000, 1000, lnwire.ShortChannelID{},
@@ -5596,11 +5616,13 @@ func TestCheckHtlcForward(t *testing.T) {
channel: testChannel.channel,
}
link.attachFailAliasUpdate(failAliasUpdate)
var hash [32]byte
t.Run("satisfied", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 1500, 1000,
200, 150, 0)
200, 150, 0, lnwire.ShortChannelID{})
if result != nil {
t.Fatalf("expected policy to be satisfied")
}
@@ -5608,7 +5630,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("below minhtlc", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 100, 50,
200, 150, 0)
200, 150, 0, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailAmountBelowMinimum); !ok {
t.Fatalf("expected FailAmountBelowMinimum failure code")
}
@@ -5616,7 +5638,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("above maxhtlc", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 1500, 1200,
200, 150, 0)
200, 150, 0, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailTemporaryChannelFailure); !ok {
t.Fatalf("expected FailTemporaryChannelFailure failure code")
}
@@ -5624,7 +5646,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("insufficient fee", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 1005, 1000,
200, 150, 0)
200, 150, 0, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailFeeInsufficient); !ok {
t.Fatalf("expected FailFeeInsufficient failure code")
}
@@ -5632,7 +5654,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("expiry too soon", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 1500, 1000,
200, 150, 190)
200, 150, 190, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailExpiryTooSoon); !ok {
t.Fatalf("expected FailExpiryTooSoon failure code")
}
@@ -5640,7 +5662,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("incorrect cltv expiry", func(t *testing.T) {
result := link.CheckHtlcForward(hash, 1500, 1000,
200, 190, 0)
200, 190, 0, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailIncorrectCltvExpiry); !ok {
t.Fatalf("expected FailIncorrectCltvExpiry failure code")
}
@@ -5650,7 +5672,7 @@ func TestCheckHtlcForward(t *testing.T) {
t.Run("cltv expiry too far in the future", func(t *testing.T) {
// Check that expiry isn't too far in the future.
result := link.CheckHtlcForward(hash, 1500, 1000,
10200, 10100, 0)
10200, 10100, 0, lnwire.ShortChannelID{})
if _, ok := result.WireMessage().(*lnwire.FailExpiryTooFar); !ok {
t.Fatalf("expected FailExpiryTooFar failure code")
}