Skip to content

Commit ef84753

Browse files
committed
firewall: obfuscate ClosedChannels
For closes we need to know the close type and settle balances to know which peers should be avoided in the future.
1 parent a7246e1 commit ef84753

File tree

3 files changed

+229
-6
lines changed

3 files changed

+229
-6
lines changed

firewall/privacy_mapper.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,12 @@ func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB,
284284
handleWalletBalanceResponse(db, flags, p.randIntn),
285285
mid.PassThroughErrorHandler,
286286
),
287+
"/lnrpc.Lightning/ClosedChannels": mid.NewResponseRewriter(
288+
&lnrpc.ClosedChannelsRequest{},
289+
&lnrpc.ClosedChannelsResponse{},
290+
handleClosedChannelsResponse(db, flags, p.randIntn),
291+
mid.PassThroughErrorHandler,
292+
),
287293
}
288294
}
289295

@@ -887,6 +893,119 @@ func handleWalletBalanceResponse(_ firewalldb.PrivacyMapDB,
887893
}
888894
}
889895

896+
func handleClosedChannelsResponse(db firewalldb.PrivacyMapDB,
897+
flags session.PrivacyFlags,
898+
randIntn func(int) (int, error)) func(ctx context.Context,
899+
r *lnrpc.ClosedChannelsResponse) (proto.Message, error) {
900+
901+
return func(_ context.Context, r *lnrpc.ClosedChannelsResponse) (
902+
proto.Message, error) {
903+
904+
closedChannels := make(
905+
[]*lnrpc.ChannelCloseSummary,
906+
len(r.Channels),
907+
)
908+
909+
err := db.Update(func(tx firewalldb.PrivacyMapTx) error {
910+
for i, c := range r.Channels {
911+
var err error
912+
913+
remotePub := c.RemotePubkey
914+
if !flags.Contains(session.ClearPubkeys) {
915+
remotePub, err = firewalldb.HideString(
916+
tx, remotePub,
917+
)
918+
if err != nil {
919+
return err
920+
}
921+
}
922+
923+
capacity, err := maybeHideAmount(
924+
flags, randIntn, c.Capacity,
925+
)
926+
if err != nil {
927+
return err
928+
}
929+
930+
settledBalance, err := maybeHideAmount(
931+
flags, randIntn, c.SettledBalance,
932+
)
933+
if err != nil {
934+
return err
935+
}
936+
937+
if settledBalance > capacity {
938+
settledBalance = capacity
939+
}
940+
941+
channelPoint := c.ChannelPoint
942+
if !flags.Contains(session.ClearChanIDs) {
943+
channelPoint, err = firewalldb.HideChanPointStr(
944+
tx, c.ChannelPoint,
945+
)
946+
if err != nil {
947+
return err
948+
}
949+
}
950+
951+
chanID := c.ChanId
952+
if !flags.Contains(session.ClearChanIDs) {
953+
chanID, err = firewalldb.HideUint64(
954+
tx, c.ChanId,
955+
)
956+
if err != nil {
957+
return err
958+
}
959+
}
960+
961+
closingTxid := c.ClosingTxHash
962+
if !flags.Contains(session.ClearClosingTxIds) {
963+
closingTxid, err = firewalldb.HideString(
964+
tx, c.ClosingTxHash,
965+
)
966+
if err != nil {
967+
return err
968+
}
969+
}
970+
971+
channel := lnrpc.ChannelCloseSummary{
972+
// Obfuscated fields.
973+
RemotePubkey: remotePub,
974+
Capacity: capacity,
975+
SettledBalance: settledBalance,
976+
ChannelPoint: channelPoint,
977+
ChanId: chanID,
978+
ClosingTxHash: closingTxid,
979+
980+
// Non-obfuscated fields.
981+
ChainHash: c.ChainHash,
982+
CloseInitiator: c.CloseInitiator,
983+
CloseType: c.CloseType,
984+
OpenInitiator: c.OpenInitiator,
985+
986+
// Omitted fields.
987+
// CloseHeight
988+
// TimeLockedBalance
989+
// Resolutions
990+
// AliasScids
991+
// ZeroConfConfirmedScid
992+
}
993+
994+
closedChannels[i] = &channel
995+
}
996+
997+
return nil
998+
})
999+
if err != nil {
1000+
return nil, err
1001+
}
1002+
1003+
return &lnrpc.ClosedChannelsResponse{
1004+
Channels: closedChannels,
1005+
}, nil
1006+
}
1007+
}
1008+
8901009
// maybeHideAmount hides an amount if the privacy flag is not set.
8911010
func maybeHideAmount(flags session.PrivacyFlags, randIntn func(int) (int,
8921011
error), a int64) (int64, error) {

firewall/privacy_mapper_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func TestPrivacyMapper(t *testing.T) {
4343
"0000000000000141": "2fd42e84b9ffaaeb",
4444
"00000000000002a6": "7859bf41241787c2",
4545
"000000000000036c": "1320e5d25b7b5973",
46+
clearTxID: obfusTxID0,
4647
outPoint(clearTxID, 0): outPoint(obfusTxID0, obfusOut0),
4748
outPoint(clearTxID, 1): outPoint(obfusTxID1, obfusOut1),
4849
"01020304": "c8134495",
@@ -419,6 +420,104 @@ func TestPrivacyMapper(t *testing.T) {
419420
},
420421
},
421422
},
423+
{
424+
name: "ClosedChannels Response",
425+
uri: "/lnrpc.Lightning/ClosedChannels",
426+
msgType: rpcperms.TypeResponse,
427+
msg: &lnrpc.ClosedChannelsResponse{
428+
Channels: []*lnrpc.ChannelCloseSummary{
429+
{
430+
ChannelPoint: outPoint(
431+
clearTxID, 1,
432+
),
433+
ChanId: 123,
434+
ClosingTxHash: clearTxID,
435+
RemotePubkey: "01020304",
436+
Capacity: 1_000_000,
437+
SettledBalance: 500_000,
438+
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
439+
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
440+
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
441+
CloseHeight: 100_000,
442+
Resolutions: []*lnrpc.Resolution{
443+
{
444+
ResolutionType: lnrpc.ResolutionType_ANCHOR,
445+
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
446+
},
447+
},
448+
},
449+
},
450+
},
451+
expectedReplacement: &lnrpc.ClosedChannelsResponse{
452+
Channels: []*lnrpc.ChannelCloseSummary{
453+
{
454+
ChannelPoint: outPoint(
455+
obfusTxID1, obfusOut1,
456+
),
457+
ChanId: 5178778334600911958,
458+
ClosingTxHash: obfusTxID0,
459+
RemotePubkey: "c8134495",
460+
Capacity: 950_100,
461+
SettledBalance: 475_100,
462+
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
463+
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
464+
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
465+
},
466+
},
467+
},
468+
},
469+
{
470+
name: "ClosedChannels Response clear",
471+
uri: "/lnrpc.Lightning/ClosedChannels",
472+
msgType: rpcperms.TypeResponse,
473+
msg: &lnrpc.ClosedChannelsResponse{
474+
Channels: []*lnrpc.ChannelCloseSummary{
475+
{
476+
ChannelPoint: outPoint(
477+
clearTxID, 1,
478+
),
479+
ChanId: 123,
480+
ClosingTxHash: clearTxID,
481+
RemotePubkey: "01020304",
482+
Capacity: 1_000_000,
483+
SettledBalance: 500_000,
484+
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
485+
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
486+
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
487+
CloseHeight: 100_000,
488+
Resolutions: []*lnrpc.Resolution{
489+
{
490+
ResolutionType: lnrpc.ResolutionType_ANCHOR,
491+
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
492+
},
493+
},
494+
},
495+
},
496+
},
497+
privacyFlags: []session.PrivacyFlag{
498+
session.ClearPubkeys,
499+
session.ClearChanIDs,
500+
session.ClearClosingTxIds,
501+
session.ClearAmounts,
502+
},
503+
expectedReplacement: &lnrpc.ClosedChannelsResponse{
504+
Channels: []*lnrpc.ChannelCloseSummary{
505+
{
506+
ChannelPoint: outPoint(
507+
clearTxID, 1,
508+
),
509+
ChanId: 123,
510+
ClosingTxHash: clearTxID,
511+
RemotePubkey: "01020304",
512+
Capacity: 1_000_000,
513+
SettledBalance: 500_000,
514+
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
515+
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
516+
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
517+
},
518+
},
519+
},
520+
},
422521
}
423522

424523
decodedID := &lnrpc.MacaroonId{

session/privacy_flags.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@ const (
4141
// ClearHTLCs is a privacy flag that indicates that the HTLCs in the API
4242
// should not be obfuscated.
4343
ClearHTLCs PrivacyFlag = 5
44+
45+
// ClearClosingTxIds is a privacy flag that indicates that the channel
46+
// closing transaction ids in the API should not be obfuscated.
47+
ClearClosingTxIds PrivacyFlag = 6
4448
)
4549

4650
var flagMap = map[PrivacyFlag]string{
47-
ClearPubkeys: "ClearPubkeys",
48-
ClearAmounts: "ClearAmounts",
49-
ClearChanIDs: "ClearChanIDs",
50-
ClearTimeStamps: "ClearTimeStamps",
51-
ClearChanInitiator: "ClearChanInitiator",
52-
ClearHTLCs: "ClearHTLCs",
51+
ClearPubkeys: "ClearPubkeys",
52+
ClearAmounts: "ClearAmounts",
53+
ClearChanIDs: "ClearChanIDs",
54+
ClearTimeStamps: "ClearTimeStamps",
55+
ClearChanInitiator: "ClearChanInitiator",
56+
ClearHTLCs: "ClearHTLCs",
57+
ClearClosingTxIds: "ClearClosingTxIds",
5358
}
5459

5560
// String returns a string representation of the privacy flag.

0 commit comments

Comments
 (0)