From e9440a24a289c80a1b4cbb93c8cff34d791e9fa4 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Fri, 14 Oct 2022 11:03:31 +0200 Subject: [PATCH 1/5] htlcswitch/test: more realistic mock encryption This mock is used in the switch test TestUpdateFailMalformedHTLCErrorConversion. But because the mock isn't very realistic, it doesn't detect problems in the handling of malformed failures in the link. --- htlcswitch/mock.go | 19 +++++++++++++++++-- htlcswitch/switch_test.go | 15 ++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 9eac221dd2..b7bc9b34a6 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -419,12 +419,16 @@ func (o *mockObfuscator) Reextract( return nil } +var fakeHmac = []byte("hmachmachmachmachmachmachmachmac") + func (o *mockObfuscator) EncryptFirstHop(failure lnwire.FailureMessage) ( lnwire.OpaqueReason, error) { o.failure = failure var b bytes.Buffer + b.Write(fakeHmac) + if err := lnwire.EncodeFailure(&b, failure, 0); err != nil { return nil, err } @@ -436,7 +440,12 @@ func (o *mockObfuscator) IntermediateEncrypt(reason lnwire.OpaqueReason) lnwire. } func (o *mockObfuscator) EncryptMalformedError(reason lnwire.OpaqueReason) lnwire.OpaqueReason { - return reason + var b bytes.Buffer + b.Write(fakeHmac) + + b.Write(reason) + + return b.Bytes() } // mockDeobfuscator mock implementation of the failure deobfuscator which @@ -447,7 +456,13 @@ func newMockDeobfuscator() ErrorDecrypter { return &mockDeobfuscator{} } -func (o *mockDeobfuscator) DecryptError(reason lnwire.OpaqueReason) (*ForwardingError, error) { +func (o *mockDeobfuscator) DecryptError(reason lnwire.OpaqueReason) ( + *ForwardingError, error) { + + if !bytes.Equal(reason[:32], fakeHmac) { + return nil, errors.New("fake decryption error") + } + reason = reason[32:] r := bytes.NewReader(reason) failure, err := lnwire.DecodeFailure(r, 0) diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 461d8875a8..4d666b7607 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -1,7 +1,6 @@ package htlcswitch import ( - "bytes" "crypto/rand" "crypto/sha256" "fmt" @@ -23,7 +22,6 @@ import ( "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/ticker" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -4088,10 +4086,10 @@ func TestSwitchHoldForward(t *testing.T) { expectedFailure := &lnwire.FailInvalidOnionKey{ OnionSHA256: shaOnionBlob, } - var b bytes.Buffer - require.NoError(t, lnwire.EncodeFailure(&b, expectedFailure, 0)) - assert.Equal(t, lnwire.OpaqueReason(b.Bytes()), failPacket.Reason) + fwdErr, err := newMockDeobfuscator().DecryptError(failPacket.Reason) + require.NoError(t, err) + require.Equal(t, expectedFailure, fwdErr.WireMessage()) assertNumCircuits(t, c.s, 0, 0) @@ -5515,10 +5513,13 @@ func testSwitchAliasInterceptFail(t *testing.T, zeroConf bool) { failHtlc, ok := failPacket.htlc.(*lnwire.UpdateFailHTLC) require.True(t, ok) - r := bytes.NewReader(failHtlc.Reason) - failure, err := lnwire.DecodeFailure(r, 0) + fwdErr, err := newMockDeobfuscator().DecryptError( + failHtlc.Reason, + ) require.NoError(t, err) + failure := fwdErr.WireMessage() + failureMsg, ok := failure.(*lnwire.FailTemporaryChannelFailure) require.True(t, ok) From 9730bc1ca01a4eb06cb7427874fedb9e25b3e32f Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Fri, 28 Oct 2022 08:45:27 +0200 Subject: [PATCH 2/5] lnwire: verify failure message length Adds extra checks to make sure the failure message is well-formed. --- lnwire/onion_error.go | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 593f58e3d6..0f252c59d9 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -7,6 +7,7 @@ import ( "encoding/binary" "fmt" "io" + "io/ioutil" "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" @@ -1222,18 +1223,41 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { // is a 2 byte length followed by the payload itself. var failureLength uint16 if err := ReadElement(r, &failureLength); err != nil { - return nil, fmt.Errorf("unable to read error len: %v", err) - } - if failureLength > FailureMessageLength { - return nil, fmt.Errorf("failure message is too "+ - "long: %v", failureLength) + return nil, fmt.Errorf("unable to read failure len: %w", err) } + failureData := make([]byte, failureLength) if _, err := io.ReadFull(r, failureData); err != nil { return nil, fmt.Errorf("unable to full read payload of "+ - "%v: %v", failureLength, err) + "%v: %w", failureLength, err) + } + + // Read the padding. + var padLength uint16 + if err := ReadElement(r, &padLength); err != nil { + return nil, fmt.Errorf("unable to read pad len: %w", err) + } + + if _, err := io.CopyN(ioutil.Discard, r, int64(padLength)); err != nil { + return nil, fmt.Errorf("unable to read padding %w", err) + } + + // Verify that we are at the end of the stream now. + scratch := make([]byte, 1) + _, err := r.Read(scratch) + if err != io.EOF { + return nil, fmt.Errorf("unexpected failure bytes") + } + + // Check the total length. Convert to 32 bits to prevent overflow. + totalLength := uint32(padLength) + uint32(failureLength) + if totalLength != FailureMessageLength { + return nil, fmt.Errorf("failure message length is "+ + "incorrect: msg=%v, pad=%v, total=%v", + failureLength, padLength, totalLength) } + // Decode the failure message. dataReader := bytes.NewReader(failureData) return DecodeFailureMessage(dataReader, pver) From 5f4465b14f110fc702f023eb3a264aa2141699bc Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 26 Oct 2022 13:44:57 +0200 Subject: [PATCH 3/5] link: ensure minimum failure reason length This commit modifies the link behavior so that every failure reason that we pass back is length-compliant (>=256 bytes). --- htlcswitch/link.go | 30 +++++++++++ htlcswitch/link_test.go | 111 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index c3c824afc1..23c37cebd0 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2,6 +2,7 @@ package htlcswitch import ( "bytes" + crand "crypto/rand" "crypto/sha256" "fmt" prand "math/rand" @@ -1850,6 +1851,35 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { } case *lnwire.UpdateFailHTLC: + // Verify that the failure reason is at least 256 bytes plus + // overhead. + const minimumFailReasonLength = lnwire.FailureMessageLength + + 2 + 2 + 32 + + if len(msg.Reason) < minimumFailReasonLength { + // We've received a reason with a non-compliant length. + // Older nodes happily relay back these failures that + // may originate from a node further downstream. + // Therefore we can't just fail the channel. + // + // We want to be compliant ourselves, so we also can't + // pass back the reason unmodified. And we must make + // sure that we don't hit the magic length check of 260 + // bytes in processRemoteSettleFails either. + // + // Because the reason is unreadable for the payer + // anyway, we just replace it by a compliant-length + // series of random bytes. + msg.Reason = make([]byte, minimumFailReasonLength) + _, err := crand.Read(msg.Reason[:]) + if err != nil { + l.log.Errorf("Random generation error: %v", err) + + return + } + } + + // Add fail to the update log. idx := msg.ID err := l.channel.ReceiveFailHTLC(idx, msg.Reason[:]) if err != nil { diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index b16f3893c5..cd3890d17c 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -2255,11 +2255,14 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { // With that processed, we'll now generate an HTLC fail (sent by the // remote peer) to cancel the HTLC we just added. This should return us // back to the bandwidth of the link right before the HTLC was sent. - err = bobChannel.FailHTLC(bobIndex, []byte("nop"), nil, nil, nil) + reason := make([]byte, 292) + copy(reason, []byte("nop")) + + err = bobChannel.FailHTLC(bobIndex, reason, nil, nil, nil) require.NoError(t, err, "unable to fail htlc") failMsg := &lnwire.UpdateFailHTLC{ ID: 1, - Reason: lnwire.OpaqueReason([]byte("nop")), + Reason: lnwire.OpaqueReason(reason), } aliceLink.HandleChannelUpdate(failMsg) @@ -2431,7 +2434,8 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { outgoingChanID: addPkt.outgoingChanID, outgoingHTLCID: addPkt.outgoingHTLCID, htlc: &lnwire.UpdateFailHTLC{ - ID: 1, + ID: 1, + Reason: reason, }, obfuscator: NewMockObfuscator(), } @@ -6606,3 +6610,104 @@ func assertFailureCode(t *testing.T, err error, code lnwire.FailCode) { code, rtErr.WireMessage().Code()) } } + +// TestChannelLinkShortFailureRelay tests that failure reasons that are too +// short are replaced by a spec-compliant length failure message and relayed +// back. +func TestChannelLinkShortFailureRelay(t *testing.T) { + t.Parallel() + + defer timeout()() + + const chanAmt = btcutil.SatoshiPerBitcoin * 5 + + aliceLink, bobChannel, batchTicker, start, _, err := + newSingleLinkTestHarness(t, chanAmt, 0) + require.NoError(t, err, "unable to create link") + + require.NoError(t, start()) + + coreLink, ok := aliceLink.(*channelLink) + require.True(t, ok) + + mockPeer, ok := coreLink.cfg.Peer.(*mockPeer) + require.True(t, ok) + + aliceMsgs := mockPeer.sentMsgs + switchChan := make(chan *htlcPacket) + + coreLink.cfg.ForwardPackets = func(linkQuit chan struct{}, _ bool, + packets ...*htlcPacket) error { + + for _, p := range packets { + switchChan <- p + } + + return nil + } + + ctx := linkTestContext{ + t: t, + aliceLink: aliceLink, + aliceMsgs: aliceMsgs, + bobChannel: bobChannel, + } + + // Send and lock in htlc from Alice to Bob. + const htlcID = 0 + + htlc, _ := generateHtlcAndInvoice(t, htlcID) + ctx.sendHtlcAliceToBob(htlcID, htlc) + ctx.receiveHtlcAliceToBob() + + batchTicker <- time.Now() + + ctx.receiveCommitSigAliceToBob(1) + ctx.sendRevAndAckBobToAlice() + + ctx.sendCommitSigBobToAlice(1) + ctx.receiveRevAndAckAliceToBob() + + // Return a short htlc failure from Bob to Alice and lock in. + shortReason := make([]byte, 260) + + err = bobChannel.FailHTLC(0, shortReason, nil, nil, nil) + require.NoError(t, err) + + aliceLink.HandleChannelUpdate(&lnwire.UpdateFailHTLC{ + ID: htlcID, + Reason: shortReason, + }) + + ctx.sendCommitSigBobToAlice(0) + ctx.receiveRevAndAckAliceToBob() + ctx.receiveCommitSigAliceToBob(0) + ctx.sendRevAndAckBobToAlice() + + // Assert that switch gets the fail message. + msg := <-switchChan + + htlcFailMsg, ok := msg.htlc.(*lnwire.UpdateFailHTLC) + require.True(t, ok) + + // Assert that it is not a converted error. + require.False(t, msg.convertedError) + + // Assert that the length is corrected to the spec-compliant length of + // 256 bytes plus overhead. + require.Len(t, htlcFailMsg.Reason, 292) + + // Stop the link + aliceLink.Stop() + + // Check that no unexpected messages were sent. + select { + case msg := <-aliceMsgs: + require.Fail(t, "did not expect message %T", msg) + + case msg := <-switchChan: + require.Fail(t, "did not expect switch message %T", msg) + + default: + } +} From 5ff5838d7495fc3f441c07e61b538f35788f86a1 Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Wed, 14 Sep 2022 12:22:09 +0200 Subject: [PATCH 4/5] lnwire: add extra opaque data to FailIncorrectDetails --- lnwire/onion_error.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 0f252c59d9..11d1fa5dab 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -345,6 +345,9 @@ type FailIncorrectDetails struct { // height is the block height when the htlc was received. height uint32 + + // extraOpaqueData contains additional failure message tlv data. + extraOpaqueData ExtraOpaqueData } // NewFailIncorrectDetails makes a new instance of the FailIncorrectDetails @@ -353,8 +356,9 @@ func NewFailIncorrectDetails(amt MilliSatoshi, height uint32) *FailIncorrectDetails { return &FailIncorrectDetails{ - amount: amt, - height: height, + amount: amt, + height: height, + extraOpaqueData: []byte{}, } } @@ -368,6 +372,11 @@ func (f *FailIncorrectDetails) Height() uint32 { return f.height } +// ExtraOpaqueData returns additional failure message tlv data. +func (f *FailIncorrectDetails) ExtraOpaqueData() ExtraOpaqueData { + return f.extraOpaqueData +} + // Code returns the failure unique code. // // NOTE: Part of the FailureMessage interface. @@ -413,7 +422,7 @@ func (f *FailIncorrectDetails) Decode(r io.Reader, pver uint32) error { return err } - return nil + return f.extraOpaqueData.Decode(r) } // Encode writes the failure in bytes stream. @@ -424,7 +433,11 @@ func (f *FailIncorrectDetails) Encode(w *bytes.Buffer, pver uint32) error { return err } - return WriteUint32(w, f.height) + if err := WriteUint32(w, f.height); err != nil { + return err + } + + return f.extraOpaqueData.Encode(w) } // FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final From 4c8ea29336dd68a9f14cca6cf758d4ceff1e5dbe Mon Sep 17 00:00:00 2001 From: Joost Jager Date: Tue, 13 Sep 2022 16:13:46 +0200 Subject: [PATCH 5/5] lnwire: allow longer failure messages This fixes an incompatibility where lnd enforces a strict 256 byte failure message, where as the spec sets this only as the recommended length. --- channeldb/mp_payment.go | 3 +- docs/release-notes/release-notes-0.16.0.md | 4 + go.mod | 2 +- go.sum | 4 +- htlcswitch/failure_test.go | 86 ++++++++++++++++++++++ htlcswitch/testdata/long_failure_msg.json | 11 +++ lnwire/onion_error.go | 6 +- routing/missioncontrol_store.go | 3 +- 8 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 htlcswitch/failure_test.go create mode 100644 htlcswitch/testdata/long_failure_msg.json diff --git a/channeldb/mp_payment.go b/channeldb/mp_payment.go index 0e29db95da..3137be640e 100644 --- a/channeldb/mp_payment.go +++ b/channeldb/mp_payment.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "io" + "math" "time" "github.com/btcsuite/btcd/btcec/v2" @@ -298,7 +299,7 @@ func deserializeHTLCFailInfo(r io.Reader) (*HTLCFailInfo, error) { // Read failure. failureBytes, err := wire.ReadVarBytes( - r, 0, lnwire.FailureMessageLength, "failure", + r, 0, math.MaxUint16, "failure", ) if err != nil { return nil, err diff --git a/docs/release-notes/release-notes-0.16.0.md b/docs/release-notes/release-notes-0.16.0.md index 1bc9bfb135..cc4c199903 100644 --- a/docs/release-notes/release-notes-0.16.0.md +++ b/docs/release-notes/release-notes-0.16.0.md @@ -5,6 +5,10 @@ * Warning messages from peers are now recognized and [logged](https://github.com/lightningnetwork/lnd/pull/6546) by lnd. +* Decrypt onion failure messages with a [length greater than 256 + bytes](https://github.com/lightningnetwork/lnd/pull/6913). This moves LND + closer to being spec compliant. + ## RPC * The `RegisterConfirmationsNtfn` call of the `chainnotifier` RPC sub-server diff --git a/go.mod b/go.mod index c95f1358eb..5433b550c6 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/kkdai/bstream v1.0.0 github.com/lightninglabs/neutrino v0.14.2 github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display - github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5 + github.com/lightningnetwork/lightning-onion v1.2.1-0.20221202012345-ca23184850a1 github.com/lightningnetwork/lnd/cert v1.1.1 github.com/lightningnetwork/lnd/clock v1.1.0 github.com/lightningnetwork/lnd/healthcheck v1.2.2 diff --git a/go.sum b/go.sum index 30e24f44ab..4003fcfdfd 100644 --- a/go.sum +++ b/go.sum @@ -440,8 +440,8 @@ github.com/lightninglabs/neutrino v0.14.2 h1:yrnZUCYMZ5ECtXhgDrzqPq2oX8awoAN2D/c github.com/lightninglabs/neutrino v0.14.2/go.mod h1:OICUeTCn+4Tu27YRJIpWvvqySxx4oH4vgdP33Sw9RDc= github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display h1:RZJ8H4ueU/aQ9pFtx5wqsuD3B/DezrewJeVwDKKYY8E= github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE= -github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5 h1:TkKwqFcQTGYoI+VEqyxA8rxpCin8qDaYX0AfVRinT3k= -github.com/lightningnetwork/lightning-onion v1.0.2-0.20220211021909-bb84a1ccb0c5/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20221202012345-ca23184850a1 h1:Wm0g70gkcAu2pGpNZwfWPSVOY21j8IyYsNewwK4OkT4= +github.com/lightningnetwork/lightning-onion v1.2.1-0.20221202012345-ca23184850a1/go.mod h1:7dDx73ApjEZA0kcknI799m2O5kkpfg4/gr7N092ojNo= github.com/lightningnetwork/lnd/cert v1.1.1 h1:Nsav0RlIDRbOnzz2Yu69SQlK939IKya3Q2S0mDviIN8= github.com/lightningnetwork/lnd/cert v1.1.1/go.mod h1:1P46svkkd73oSoeI4zjkVKgZNwGq8bkGuPR8z+5vQUs= github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg= diff --git a/htlcswitch/failure_test.go b/htlcswitch/failure_test.go new file mode 100644 index 0000000000..3dfadc8820 --- /dev/null +++ b/htlcswitch/failure_test.go @@ -0,0 +1,86 @@ +package htlcswitch + +import ( + "encoding/hex" + "encoding/json" + "os" + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + sphinx "github.com/lightningnetwork/lightning-onion" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/require" +) + +// TestLongFailureMessage tests that longer failure messages can be interpreted +// correctly. +func TestLongFailureMessage(t *testing.T) { + t.Parallel() + + var testData struct { + SessionKey string + Path []string + Reason string + } + + // Use long 1024-byte test vector from BOLT 04. + testDataBytes, err := os.ReadFile("testdata/long_failure_msg.json") + require.NoError(t, err) + require.NoError(t, json.Unmarshal(testDataBytes, &testData)) + + sessionKeyBytes, _ := hex.DecodeString(testData.SessionKey) + + reason, _ := hex.DecodeString(testData.Reason) + + sphinxPath := make([]*btcec.PublicKey, len(testData.Path)) + for i, sKey := range testData.Path { + bKey, err := hex.DecodeString(sKey) + require.NoError(t, err) + + key, err := btcec.ParsePubKey(bKey) + require.NoError(t, err) + + sphinxPath[i] = key + } + + sessionKey, _ := btcec.PrivKeyFromBytes(sessionKeyBytes) + + circuit := &sphinx.Circuit{ + SessionKey: sessionKey, + PaymentPath: sphinxPath, + } + + errorDecryptor := &SphinxErrorDecrypter{ + OnionErrorDecrypter: sphinx.NewOnionErrorDecrypter(circuit), + } + + // Assert that the failure message can still be extracted. + failure, err := errorDecryptor.DecryptError(reason) + require.NoError(t, err) + + incorrectDetails, ok := failure.msg.(*lnwire.FailIncorrectDetails) + require.True(t, ok) + + var value varBytesRecordProducer + + extraData := incorrectDetails.ExtraOpaqueData() + typeMap, err := extraData.ExtractRecords(&value) + require.NoError(t, err) + require.Len(t, typeMap, 1) + + expectedValue := make([]byte, 300) + for i := range expectedValue { + expectedValue[i] = 128 + } + + require.Equal(t, expectedValue, value.data) +} + +type varBytesRecordProducer struct { + data []byte +} + +func (v *varBytesRecordProducer) Record() tlv.Record { + return tlv.MakePrimitiveRecord(34001, &v.data) +} diff --git a/htlcswitch/testdata/long_failure_msg.json b/htlcswitch/testdata/long_failure_msg.json new file mode 100644 index 0000000000..aabe6adc47 --- /dev/null +++ b/htlcswitch/testdata/long_failure_msg.json @@ -0,0 +1,11 @@ +{ + "sessionKey": "4141414141414141414141414141414141414141414141414141414141414141", + "path": [ + "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", + "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007", + "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", + "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145" + ], + "reason": "2dd2f49c1f5af0fcad371d96e8cddbdcd5096dc309c1d4e110f955926506b3c03b44c192896f45610741c85ed4074212537e0c118d472ff3a559ae244acd9d783c65977765c5d4e00b723d00f12475aafaafff7b31c1be5a589e6e25f8da2959107206dd42bbcb43438129ce6cce2b6b4ae63edc76b876136ca5ea6cd1c6a04ca86eca143d15e53ccdc9e23953e49dc2f87bb11e5238cd6536e57387225b8fff3bf5f3e686fd08458ffe0211b87d64770db9353500af9b122828a006da754cf979738b4374e146ea79dd93656170b89c98c5f2299d6e9c0410c826c721950c780486cd6d5b7130380d7eaff994a8503a8fef3270ce94889fe996da66ed121741987010f785494415ca991b2e8b39ef2df6bde98efd2aec7d251b2772485194c8368451ad49c2354f9d30d95367bde316fec6cbdddc7dc0d25e99d3075e13d3de0822669861dafcd29de74eac48b64411987285491f98d78584d0c2a163b7221ea796f9e8671b2bb91e38ef5e18aaf32c6c02f2fb690358872a1ed28166172631a82c2568d23238017188ebbd48944a147f6cdb3690d5f88e51371cb70adf1fa02afe4ed8b581afc8bcc5104922843a55d52acde09bc9d2b71a663e178788280f3c3eae127d21b0b95777976b3eb17be40a702c244d0e5f833ff49dae6403ff44b131e66df8b88e33ab0a58e379f2c34bf5113c66b9ea8241fc7aa2b1fa53cf4ed3cdd91d407730c66fb039ef3a36d4050dde37d34e80bcfe02a48a6b14ae28227b1627b5ad07608a7763a531f2ffc96dff850e8c583461831b19feffc783bc1beab6301f647e9617d14c92c4b1d63f5147ccda56a35df8ca4806b8884c4aa3c3cc6a174fdc2232404822569c01aba686c1df5eecc059ba97e9688c8b16b70f0d24eacfdba15db1c71f72af1b2af85bd168f0b0800483f115eeccd9b02adf03bdd4a88eab03e43ce342877af2b61f9d3d85497cd1c6b96674f3d4f07f635bb26add1e36835e321d70263b1c04234e222124dad30ffb9f2a138e3ef453442df1af7e566890aedee568093aa922dd62db188aa8361c55503f8e2c2e6ba93de744b55c15260f15ec8e69bb01048ca1fa7bbbd26975bde80930a5b95054688a0ea73af0353cc84b997626a987cc06a517e18f91e02908829d4f4efc011b9867bd9bfe04c5f94e4b9261d30cc39982eb7b250f12aee2a4cce0484ff34eebba89bc6e35bd48d3968e4ca2d77527212017e202141900152f2fd8af0ac3aa456aae13276a13b9b9492a9a636e18244654b3245f07b20eb76b8e1cea8c55e5427f08a63a16b0a633af67c8e48ef8e53519041c9138176eb14b8782c6c2ee76146b8490b97978ee73cd0104e12f483be5a4af414404618e9f6633c55dda6f22252cb793d3d16fae4f0e1431434e7acc8fa2c009d4f6e345ade172313d558a4e61b4377e31b8ed4e28f7cd13a7fe3f72a409bc3bdabfe0ba47a6d861e21f64d2fac706dab18b3e546df4" +} \ No newline at end of file diff --git a/lnwire/onion_error.go b/lnwire/onion_error.go index 11d1fa5dab..623ca0bf4a 100644 --- a/lnwire/onion_error.go +++ b/lnwire/onion_error.go @@ -1264,9 +1264,9 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) { // Check the total length. Convert to 32 bits to prevent overflow. totalLength := uint32(padLength) + uint32(failureLength) - if totalLength != FailureMessageLength { - return nil, fmt.Errorf("failure message length is "+ - "incorrect: msg=%v, pad=%v, total=%v", + if totalLength < FailureMessageLength { + return nil, fmt.Errorf("failure message too short: "+ + "msg=%v, pad=%v, total=%v", failureLength, padLength, totalLength) } diff --git a/routing/missioncontrol_store.go b/routing/missioncontrol_store.go index 27be86821d..a6c98571fd 100644 --- a/routing/missioncontrol_store.go +++ b/routing/missioncontrol_store.go @@ -5,6 +5,7 @@ import ( "container/list" "encoding/binary" "fmt" + "math" "sync" "time" @@ -245,7 +246,7 @@ func deserializeResult(k, v []byte) (*paymentResult, error) { // Read failure. failureBytes, err := wire.ReadVarBytes( - r, 0, lnwire.FailureMessageLength, "failure", + r, 0, math.MaxUint16, "failure", ) if err != nil { return nil, err