htlcswitch+invoices: always return incorrect_or_unknown_payment_details

In order to prevent information leaks by nodes probing with a payment
hash, this commit changes exit hop processing so that it always returns
incorrect_or_unknown_payment_details and leaves the prober in the dark
about whether an invoice actually exists.
This commit is contained in:
Joost Jager 2019-06-11 08:54:29 +02:00
parent 922f133fd2
commit 98fac9fb99
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7
3 changed files with 14 additions and 71 deletions

@ -1204,29 +1204,15 @@ func (l *channelLink) processHodlEvent(hodlEvent invoices.HodlEvent,
) )
} }
} else { } else {
l.debugf("Received hodl cancel event for %v, reason=%v", l.debugf("Received hodl cancel event for %v", hash)
hash, hodlEvent.CancelReason)
hodlAction = func(htlc hodlHtlc) error { hodlAction = func(htlc hodlHtlc) error {
var failure lnwire.FailureMessage // In case of a cancel, always return
switch hodlEvent.CancelReason { // incorrect_or_unknown_payment_details in order to
// avoid leaking info.
case invoices.CancelAmountTooLow: failure := lnwire.NewFailIncorrectDetails(
fallthrough htlc.pd.Amount,
case invoices.CancelInvoiceUnknown: )
fallthrough
case invoices.CancelInvoiceCanceled:
failure = lnwire.NewFailIncorrectDetails(
htlc.pd.Amount,
)
case invoices.CancelExpiryTooSoon:
failure = &lnwire.FailFinalExpiryTooSoon{}
default:
return fmt.Errorf("unknown cancel reason: %v",
hodlEvent.CancelReason)
}
l.sendHTLCError( l.sendHTLCError(
htlc.pd.HtlcIndex, failure, htlc.obfuscator, htlc.pd.HtlcIndex, failure, htlc.obfuscator,

@ -1413,10 +1413,10 @@ func TestChannelLinkExpiryTooSoonExitNode(t *testing.T) {
} }
switch ferr.FailureMessage.(type) { switch ferr.FailureMessage.(type) {
case *lnwire.FailFinalExpiryTooSoon: case *lnwire.FailIncorrectDetails:
default: default:
t.Fatalf("incorrect error, expected final time lock too "+ t.Fatalf("expected incorrect_or_unknown_payment_details, "+
"early, instead have: %v", err) "instead have: %v", err)
} }
} }

@ -28,41 +28,6 @@ var (
DebugHash = DebugPre.Hash() DebugHash = DebugPre.Hash()
) )
// HtlcCancelReason defines reasons for which htlcs can be canceled.
type HtlcCancelReason uint8
const (
// CancelInvoiceUnknown is returned if the preimage is unknown.
CancelInvoiceUnknown HtlcCancelReason = iota
// CancelExpiryTooSoon is returned when the timelock of the htlc
// does not satisfy the invoice cltv expiry requirement.
CancelExpiryTooSoon
// CancelInvoiceCanceled is returned when the invoice is already
// canceled and can't be paid to anymore.
CancelInvoiceCanceled
// CancelAmountTooLow is returned when the amount paid is too low.
CancelAmountTooLow
)
// String returns a human readable identifier for the cancel reason.
func (r HtlcCancelReason) String() string {
switch r {
case CancelInvoiceUnknown:
return "InvoiceUnknown"
case CancelExpiryTooSoon:
return "ExpiryTooSoon"
case CancelInvoiceCanceled:
return "InvoiceCanceled"
case CancelAmountTooLow:
return "CancelAmountTooLow"
default:
return "Unknown"
}
}
var ( var (
// ErrInvoiceExpiryTooSoon is returned when an invoice is attempted to be // ErrInvoiceExpiryTooSoon is returned when an invoice is attempted to be
// accepted or settled with not enough blocks remaining. // accepted or settled with not enough blocks remaining.
@ -82,10 +47,6 @@ type HodlEvent struct {
// Hash is the htlc hash. // Hash is the htlc hash.
Hash lntypes.Hash Hash lntypes.Hash
// CancelReason specifies the reason why invoice registry decided to
// cancel the htlc.
CancelReason HtlcCancelReason
} }
// InvoiceRegistry is a central registry of all the outstanding invoices // InvoiceRegistry is a central registry of all the outstanding invoices
@ -644,8 +605,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
debugLog("invoice already canceled") debugLog("invoice already canceled")
return &HodlEvent{ return &HodlEvent{
Hash: rHash, Hash: rHash,
CancelReason: CancelInvoiceCanceled,
}, nil }, nil
// If invoice is already accepted, add this htlc to the list of // If invoice is already accepted, add this htlc to the list of
@ -661,8 +621,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
debugLog("expiry too soon") debugLog("expiry too soon")
return &HodlEvent{ return &HodlEvent{
Hash: rHash, Hash: rHash,
CancelReason: CancelExpiryTooSoon,
}, nil }, nil
// If there are not enough blocks left, cancel the htlc. // If there are not enough blocks left, cancel the htlc.
@ -670,8 +629,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
debugLog("amount too low") debugLog("amount too low")
return &HodlEvent{ return &HodlEvent{
Hash: rHash, Hash: rHash,
CancelReason: CancelAmountTooLow,
}, nil }, nil
// If this call settled the invoice, settle the htlc. Otherwise // If this call settled the invoice, settle the htlc. Otherwise
@ -750,8 +708,7 @@ func (i *InvoiceRegistry) CancelInvoice(payHash lntypes.Hash) error {
log.Debugf("Invoice(%v): canceled", payHash) log.Debugf("Invoice(%v): canceled", payHash)
i.notifyHodlSubscribers(HodlEvent{ i.notifyHodlSubscribers(HodlEvent{
Hash: payHash, Hash: payHash,
CancelReason: CancelInvoiceCanceled,
}) })
i.notifyClients(payHash, invoice, channeldb.ContractCanceled) i.notifyClients(payHash, invoice, channeldb.ContractCanceled)