Skip to content

Commit 72260ad

Browse files
committed
htlcswitch: create error obfuscator with wrapped type for blinded
Create our error encrypter with a wrapped type if we have a blinding point present. Doing this in the iterator allows us to track this information when we have both pieces of information available to us, compared to trying to handle this later down the line: - Downstream link on failure: we know that we've set a blinding point for out outgoing HTLC, but not whether we're introduction or not - Upstream link on failure: once the failure packet has been sent through the switch, we no longer know whether we were the introduction point (without looking it up / examining our payload again / propagating this information through the switch).
1 parent 9f038c6 commit 72260ad

File tree

3 files changed

+77
-25
lines changed

3 files changed

+77
-25
lines changed

htlcswitch/hop/iterator.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ type Iterator interface {
103103

104104
// ExtractErrorEncrypter returns the ErrorEncrypter needed for this hop,
105105
// along with a failure code to signal if the decoding was successful.
106-
ExtractErrorEncrypter(ErrorEncrypterExtracter) (ErrorEncrypter,
107-
lnwire.FailCode)
106+
ExtractErrorEncrypter(extractor ErrorEncrypterExtracter,
107+
introductionNode bool) (ErrorEncrypter, lnwire.FailCode)
108108
}
109109

110110
// sphinxHopIterator is the Sphinx implementation of hop iterator which uses
@@ -235,9 +235,31 @@ func (r *sphinxHopIterator) HopPayload() (*Payload, RouteRole, error) {
235235
//
236236
// NOTE: Part of the HopIterator interface.
237237
func (r *sphinxHopIterator) ExtractErrorEncrypter(
238-
extracter ErrorEncrypterExtracter) (ErrorEncrypter, lnwire.FailCode) {
238+
extracter ErrorEncrypterExtracter, introductionNode bool) (
239+
ErrorEncrypter, lnwire.FailCode) {
240+
241+
encrypter, errCode := extracter(r.ogPacket.EphemeralKey)
242+
if errCode != lnwire.CodeNone {
243+
return nil, errCode
244+
}
245+
246+
// If we're in a blinded path, wrap the error encrypter that we just
247+
// derived in a "marker" type which we'll use to know what type of
248+
// error we're handling.
249+
switch {
250+
case introductionNode:
251+
return &IntroductionErrorEncrypter{
252+
ErrorEncrypter: encrypter,
253+
}, errCode
254+
255+
case r.blindingKit.UpdateAddBlinding.IsSome():
256+
return &RelayingErrorEncrypter{
257+
ErrorEncrypter: encrypter,
258+
}, errCode
239259

240-
return extracter(r.ogPacket.EphemeralKey)
260+
default:
261+
return encrypter, errCode
262+
}
241263
}
242264

243265
// BlindingProcessor is an interface that provides the cryptographic operations

htlcswitch/link.go

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3262,7 +3262,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
32623262
// DecodeHopIterator function which process the Sphinx packet.
32633263
chanIterator, failureCode := decodeResps[i].Result()
32643264
if failureCode != lnwire.CodeNone {
3265-
// If we're unable to process the onion blob than we
3265+
// If we're unable to process the onion blob then we
32663266
// should send the malformed htlc error to payment
32673267
// sender.
32683268
l.sendMalformedHTLCError(pd.HtlcIndex, failureCode,
@@ -3273,27 +3273,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
32733273
continue
32743274
}
32753275

3276-
// Retrieve onion obfuscator from onion blob in order to
3277-
// produce initial obfuscation of the onion failureCode.
3278-
obfuscator, failureCode := chanIterator.ExtractErrorEncrypter(
3279-
l.cfg.ExtractErrorEncrypter,
3280-
)
3281-
if failureCode != lnwire.CodeNone {
3282-
// If we're unable to process the onion blob than we
3283-
// should send the malformed htlc error to payment
3284-
// sender.
3285-
l.sendMalformedHTLCError(
3286-
pd.HtlcIndex, failureCode, onionBlob[:], pd.SourceRef,
3287-
)
3288-
3289-
l.log.Errorf("unable to decode onion "+
3290-
"obfuscator: %v", failureCode)
3291-
continue
3292-
}
3293-
32943276
heightNow := l.cfg.BestHeight()
32953277

3296-
pld, _, pldErr := chanIterator.HopPayload()
3278+
pld, routeRole, pldErr := chanIterator.HopPayload()
32973279
if pldErr != nil {
32983280
// If we're unable to process the onion payload, or we
32993281
// received invalid onion payload failure, then we
@@ -3308,6 +3290,33 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
33083290
failedType = uint64(e.Type)
33093291
}
33103292

3293+
// If we couldn't parse the payload, make our best
3294+
// effort at creating an error encrypter that knows
3295+
// what blinding type we were, but if we couldn't
3296+
// parse the payload we have no way of knowing whether
3297+
// we were the introduction node or not.
3298+
//
3299+
//nolint:lll
3300+
obfuscator, failCode := chanIterator.ExtractErrorEncrypter(
3301+
l.cfg.ExtractErrorEncrypter,
3302+
// We need our route role here because we
3303+
// couldn't parse or validate the payload.
3304+
routeRole == hop.RouteRoleIntroduction,
3305+
)
3306+
if failCode != lnwire.CodeNone {
3307+
l.log.Errorf("could not extract error "+
3308+
"encrypter: %v", pldErr)
3309+
3310+
// We can't process this htlc, send back
3311+
// malformed.
3312+
l.sendMalformedHTLCError(
3313+
pd.HtlcIndex, failureCode,
3314+
onionBlob[:], pd.SourceRef,
3315+
)
3316+
3317+
continue
3318+
}
3319+
33113320
// TODO: currently none of the test unit infrastructure
33123321
// is setup to handle TLV payloads, so testing this
33133322
// would require implementing a separate mock iterator
@@ -3325,6 +3334,27 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
33253334
continue
33263335
}
33273336

3337+
// Retrieve onion obfuscator from onion blob in order to
3338+
// produce initial obfuscation of the onion failureCode.
3339+
obfuscator, failureCode := chanIterator.ExtractErrorEncrypter(
3340+
l.cfg.ExtractErrorEncrypter,
3341+
routeRole == hop.RouteRoleIntroduction,
3342+
)
3343+
if failureCode != lnwire.CodeNone {
3344+
// If we're unable to process the onion blob than we
3345+
// should send the malformed htlc error to payment
3346+
// sender.
3347+
l.sendMalformedHTLCError(
3348+
pd.HtlcIndex, failureCode, onionBlob[:],
3349+
pd.SourceRef,
3350+
)
3351+
3352+
l.log.Errorf("unable to decode onion "+
3353+
"obfuscator: %v", failureCode)
3354+
3355+
continue
3356+
}
3357+
33283358
fwdInfo := pld.ForwardingInfo()
33293359

33303360
// Check whether the payload we've just processed uses our

htlcswitch/mock.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ func (r *mockHopIterator) ExtraOnionBlob() []byte {
341341
}
342342

343343
func (r *mockHopIterator) ExtractErrorEncrypter(
344-
extracter hop.ErrorEncrypterExtracter) (hop.ErrorEncrypter,
344+
extracter hop.ErrorEncrypterExtracter, _ bool) (hop.ErrorEncrypter,
345345
lnwire.FailCode) {
346346

347347
return extracter(nil)

0 commit comments

Comments
 (0)