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.
This commit is contained in:
bitromortac 2023-07-31 17:52:33 +02:00
parent a7246e1dae
commit ef84753f6b
No known key found for this signature in database
GPG key ID: 1965063FC13BEBE2
3 changed files with 229 additions and 6 deletions

View file

@ -284,6 +284,12 @@ func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB,
handleWalletBalanceResponse(db, flags, p.randIntn),
mid.PassThroughErrorHandler,
),
"/lnrpc.Lightning/ClosedChannels": mid.NewResponseRewriter(
&lnrpc.ClosedChannelsRequest{},
&lnrpc.ClosedChannelsResponse{},
handleClosedChannelsResponse(db, flags, p.randIntn),
mid.PassThroughErrorHandler,
),
}
}
@ -887,6 +893,119 @@ func handleWalletBalanceResponse(_ firewalldb.PrivacyMapDB,
}
}
func handleClosedChannelsResponse(db firewalldb.PrivacyMapDB,
flags session.PrivacyFlags,
randIntn func(int) (int, error)) func(ctx context.Context,
r *lnrpc.ClosedChannelsResponse) (proto.Message, error) {
return func(_ context.Context, r *lnrpc.ClosedChannelsResponse) (
proto.Message, error) {
closedChannels := make(
[]*lnrpc.ChannelCloseSummary,
len(r.Channels),
)
err := db.Update(func(tx firewalldb.PrivacyMapTx) error {
for i, c := range r.Channels {
var err error
remotePub := c.RemotePubkey
if !flags.Contains(session.ClearPubkeys) {
remotePub, err = firewalldb.HideString(
tx, remotePub,
)
if err != nil {
return err
}
}
capacity, err := maybeHideAmount(
flags, randIntn, c.Capacity,
)
if err != nil {
return err
}
settledBalance, err := maybeHideAmount(
flags, randIntn, c.SettledBalance,
)
if err != nil {
return err
}
if settledBalance > capacity {
settledBalance = capacity
}
channelPoint := c.ChannelPoint
if !flags.Contains(session.ClearChanIDs) {
channelPoint, err = firewalldb.HideChanPointStr(
tx, c.ChannelPoint,
)
if err != nil {
return err
}
}
chanID := c.ChanId
if !flags.Contains(session.ClearChanIDs) {
chanID, err = firewalldb.HideUint64(
tx, c.ChanId,
)
if err != nil {
return err
}
}
closingTxid := c.ClosingTxHash
if !flags.Contains(session.ClearClosingTxIds) {
closingTxid, err = firewalldb.HideString(
tx, c.ClosingTxHash,
)
if err != nil {
return err
}
}
channel := lnrpc.ChannelCloseSummary{
// Obfuscated fields.
RemotePubkey: remotePub,
Capacity: capacity,
SettledBalance: settledBalance,
ChannelPoint: channelPoint,
ChanId: chanID,
ClosingTxHash: closingTxid,
// Non-obfuscated fields.
ChainHash: c.ChainHash,
CloseInitiator: c.CloseInitiator,
CloseType: c.CloseType,
OpenInitiator: c.OpenInitiator,
// Omitted fields.
// CloseHeight
// TimeLockedBalance
// Resolutions
// AliasScids
// ZeroConfConfirmedScid
}
closedChannels[i] = &channel
}
return nil
})
if err != nil {
return nil, err
}
return &lnrpc.ClosedChannelsResponse{
Channels: closedChannels,
}, nil
}
}
// maybeHideAmount hides an amount if the privacy flag is not set.
func maybeHideAmount(flags session.PrivacyFlags, randIntn func(int) (int,
error), a int64) (int64, error) {

View file

@ -43,6 +43,7 @@ func TestPrivacyMapper(t *testing.T) {
"0000000000000141": "2fd42e84b9ffaaeb",
"00000000000002a6": "7859bf41241787c2",
"000000000000036c": "1320e5d25b7b5973",
clearTxID: obfusTxID0,
outPoint(clearTxID, 0): outPoint(obfusTxID0, obfusOut0),
outPoint(clearTxID, 1): outPoint(obfusTxID1, obfusOut1),
"01020304": "c8134495",
@ -419,6 +420,104 @@ func TestPrivacyMapper(t *testing.T) {
},
},
},
{
name: "ClosedChannels Response",
uri: "/lnrpc.Lightning/ClosedChannels",
msgType: rpcperms.TypeResponse,
msg: &lnrpc.ClosedChannelsResponse{
Channels: []*lnrpc.ChannelCloseSummary{
{
ChannelPoint: outPoint(
clearTxID, 1,
),
ChanId: 123,
ClosingTxHash: clearTxID,
RemotePubkey: "01020304",
Capacity: 1_000_000,
SettledBalance: 500_000,
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
CloseHeight: 100_000,
Resolutions: []*lnrpc.Resolution{
{
ResolutionType: lnrpc.ResolutionType_ANCHOR,
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
},
},
},
},
},
expectedReplacement: &lnrpc.ClosedChannelsResponse{
Channels: []*lnrpc.ChannelCloseSummary{
{
ChannelPoint: outPoint(
obfusTxID1, obfusOut1,
),
ChanId: 5178778334600911958,
ClosingTxHash: obfusTxID0,
RemotePubkey: "c8134495",
Capacity: 950_100,
SettledBalance: 475_100,
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
},
},
},
},
{
name: "ClosedChannels Response clear",
uri: "/lnrpc.Lightning/ClosedChannels",
msgType: rpcperms.TypeResponse,
msg: &lnrpc.ClosedChannelsResponse{
Channels: []*lnrpc.ChannelCloseSummary{
{
ChannelPoint: outPoint(
clearTxID, 1,
),
ChanId: 123,
ClosingTxHash: clearTxID,
RemotePubkey: "01020304",
Capacity: 1_000_000,
SettledBalance: 500_000,
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
CloseHeight: 100_000,
Resolutions: []*lnrpc.Resolution{
{
ResolutionType: lnrpc.ResolutionType_ANCHOR,
Outcome: lnrpc.ResolutionOutcome_CLAIMED,
},
},
},
},
},
privacyFlags: []session.PrivacyFlag{
session.ClearPubkeys,
session.ClearChanIDs,
session.ClearClosingTxIds,
session.ClearAmounts,
},
expectedReplacement: &lnrpc.ClosedChannelsResponse{
Channels: []*lnrpc.ChannelCloseSummary{
{
ChannelPoint: outPoint(
clearTxID, 1,
),
ChanId: 123,
ClosingTxHash: clearTxID,
RemotePubkey: "01020304",
Capacity: 1_000_000,
SettledBalance: 500_000,
CloseType: lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE,
CloseInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
OpenInitiator: lnrpc.Initiator_INITIATOR_LOCAL,
},
},
},
},
}
decodedID := &lnrpc.MacaroonId{

View file

@ -41,15 +41,20 @@ const (
// ClearHTLCs is a privacy flag that indicates that the HTLCs in the API
// should not be obfuscated.
ClearHTLCs PrivacyFlag = 5
// ClearClosingTxIds is a privacy flag that indicates that the channel
// closing transaction ids in the API should not be obfuscated.
ClearClosingTxIds PrivacyFlag = 6
)
var flagMap = map[PrivacyFlag]string{
ClearPubkeys: "ClearPubkeys",
ClearAmounts: "ClearAmounts",
ClearChanIDs: "ClearChanIDs",
ClearTimeStamps: "ClearTimeStamps",
ClearChanInitiator: "ClearChanInitiator",
ClearHTLCs: "ClearHTLCs",
ClearPubkeys: "ClearPubkeys",
ClearAmounts: "ClearAmounts",
ClearChanIDs: "ClearChanIDs",
ClearTimeStamps: "ClearTimeStamps",
ClearChanInitiator: "ClearChanInitiator",
ClearHTLCs: "ClearHTLCs",
ClearClosingTxIds: "ClearClosingTxIds",
}
// String returns a string representation of the privacy flag.