Skip to content

Commit bca729a

Browse files
committed
firewall: obfuscate OpenChannelSync
1 parent 275a882 commit bca729a

File tree

2 files changed

+257
-0
lines changed

2 files changed

+257
-0
lines changed

firewall/privacy_mapper.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB,
305305
handleBatchOpenChannelResponse(db, flags),
306306
mid.PassThroughErrorHandler,
307307
),
308+
"/lnrpc.Lightning/OpenChannelSync": mid.NewFullRewriter(
309+
&lnrpc.OpenChannelRequest{},
310+
&lnrpc.ChannelPoint{},
311+
handleChannelOpenRequest(db, flags),
312+
handleChannelOpenResponse(db, flags),
313+
mid.PassThroughErrorHandler,
314+
),
308315
}
309316
}
310317

@@ -1454,6 +1461,157 @@ func handleBatchOpenChannelResponse(db firewalldb.PrivacyMapDB,
14541461
}
14551462
}
14561463

1464+
func handleChannelOpenRequest(db firewalldb.PrivacyMapDB,
1465+
flags session.PrivacyFlags) func(ctx context.Context,
1466+
r *lnrpc.OpenChannelRequest) (proto.Message, error) {
1467+
1468+
return func(_ context.Context, r *lnrpc.OpenChannelRequest) (
1469+
proto.Message, error) {
1470+
1471+
var nodePubkey []byte
1472+
1473+
err := db.View(func(tx firewalldb.PrivacyMapTx) error {
1474+
var err error
1475+
1476+
// We use the byte slice representation of the
1477+
// pubkey and fall back to the hex string if present.
1478+
nodePubkey = r.NodePubkey
1479+
if len(nodePubkey) == 0 && r.NodePubkeyString != "" {
1480+
nodePubkey, err = hex.DecodeString(
1481+
r.NodePubkeyString,
1482+
)
1483+
if err != nil {
1484+
return err
1485+
}
1486+
}
1487+
1488+
if !flags.Contains(session.ClearPubkeys) {
1489+
nodePubkey, err = firewalldb.RevealBytes(
1490+
tx, nodePubkey,
1491+
)
1492+
if err != nil {
1493+
return err
1494+
}
1495+
}
1496+
1497+
return nil
1498+
})
1499+
if err != nil {
1500+
return nil, err
1501+
}
1502+
1503+
return &lnrpc.OpenChannelRequest{
1504+
// Obfuscated fields.
1505+
NodePubkey: nodePubkey,
1506+
1507+
// Omitted fields.
1508+
// NodePubkeyString
1509+
1510+
// Non-obfuscated fields.
1511+
SatPerVbyte: r.SatPerVbyte,
1512+
LocalFundingAmount: r.LocalFundingAmount,
1513+
PushSat: r.PushSat,
1514+
TargetConf: r.TargetConf,
1515+
SatPerByte: r.SatPerByte,
1516+
Private: r.Private,
1517+
MinHtlcMsat: r.MinHtlcMsat,
1518+
RemoteCsvDelay: r.RemoteCsvDelay,
1519+
MinConfs: r.MinConfs,
1520+
SpendUnconfirmed: r.SpendUnconfirmed,
1521+
CloseAddress: r.CloseAddress,
1522+
FundingShim: r.FundingShim,
1523+
RemoteMaxValueInFlightMsat: r.RemoteMaxValueInFlightMsat,
1524+
RemoteMaxHtlcs: r.RemoteMaxHtlcs,
1525+
MaxLocalCsv: r.MaxLocalCsv,
1526+
CommitmentType: r.CommitmentType,
1527+
ZeroConf: r.ZeroConf,
1528+
ScidAlias: r.ScidAlias,
1529+
BaseFee: r.BaseFee,
1530+
FeeRate: r.FeeRate,
1531+
UseBaseFee: r.UseBaseFee,
1532+
UseFeeRate: r.UseFeeRate,
1533+
RemoteChanReserveSat: r.RemoteChanReserveSat,
1534+
FundMax: r.FundMax,
1535+
Memo: r.Memo,
1536+
Outpoints: r.Outpoints,
1537+
}, nil
1538+
}
1539+
}
1540+
1541+
func handleChannelOpenResponse(db firewalldb.PrivacyMapDB,
1542+
flags session.PrivacyFlags) func(ctx context.Context,
1543+
r *lnrpc.ChannelPoint) (proto.Message, error) {
1544+
1545+
return func(_ context.Context, r *lnrpc.ChannelPoint) (
1546+
proto.Message, error) {
1547+
1548+
var (
1549+
txid string
1550+
index uint32
1551+
)
1552+
1553+
err := db.Update(func(tx firewalldb.PrivacyMapTx) error {
1554+
var err error
1555+
1556+
txid = r.GetFundingTxidStr()
1557+
if len(r.GetFundingTxidBytes()) != 0 {
1558+
hash, err := chainhash.NewHash(
1559+
r.GetFundingTxidBytes(),
1560+
)
1561+
if err != nil {
1562+
return err
1563+
}
1564+
1565+
txid = hash.String()
1566+
}
1567+
1568+
index = r.OutputIndex
1569+
1570+
if !flags.Contains(session.ClearChanIDs) {
1571+
txid, index, err = firewalldb.HideChanPoint(
1572+
tx, txid, index,
1573+
)
1574+
if err != nil {
1575+
return err
1576+
}
1577+
}
1578+
1579+
return nil
1580+
})
1581+
1582+
if err != nil {
1583+
return nil, err
1584+
}
1585+
1586+
switch {
1587+
case len(r.GetFundingTxidBytes()) != 0:
1588+
hash, err := chainhash.NewHashFromStr(txid)
1589+
if err != nil {
1590+
return nil, err
1591+
}
1592+
1593+
return &lnrpc.ChannelPoint{
1594+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
1595+
FundingTxidBytes: hash[:],
1596+
},
1597+
OutputIndex: index,
1598+
}, nil
1599+
1600+
case r.GetFundingTxidStr() != "":
1601+
return &lnrpc.ChannelPoint{
1602+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{
1603+
FundingTxidStr: txid,
1604+
},
1605+
OutputIndex: index,
1606+
}, nil
1607+
1608+
default:
1609+
return nil, fmt.Errorf("channel point has no funding " +
1610+
"txid")
1611+
}
1612+
}
1613+
}
1614+
14571615
// maybeHideAmount hides an amount if the privacy flag is not set.
14581616
func maybeHideAmount(flags session.PrivacyFlags, randIntn func(int) (int,
14591617
error), a int64) (int64, error) {

firewall/privacy_mapper_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,105 @@ func TestPrivacyMapper(t *testing.T) {
728728
},
729729
},
730730
},
731+
{
732+
name: "OpenChannelSync Request",
733+
uri: "/lnrpc.Lightning/OpenChannelSync",
734+
msgType: rpcperms.TypeRequest,
735+
msg: &lnrpc.OpenChannelRequest{
736+
NodePubkey: []byte{
737+
200, 19, 68, 149,
738+
},
739+
LocalFundingAmount: 1_000_000,
740+
PushSat: 1_000_000,
741+
MinHtlcMsat: 100,
742+
},
743+
expectedReplacement: &lnrpc.OpenChannelRequest{
744+
NodePubkey: []byte{
745+
1, 2, 3, 4,
746+
},
747+
LocalFundingAmount: 1_000_000,
748+
PushSat: 1_000_000,
749+
MinHtlcMsat: 100,
750+
},
751+
},
752+
{
753+
name: "OpenChannelSync Request clear",
754+
uri: "/lnrpc.Lightning/OpenChannelSync",
755+
msgType: rpcperms.TypeRequest,
756+
privacyFlags: []session.PrivacyFlag{
757+
session.ClearPubkeys,
758+
},
759+
msg: &lnrpc.OpenChannelRequest{
760+
NodePubkey: []byte{
761+
200, 19, 68, 149,
762+
},
763+
LocalFundingAmount: 1_000_000,
764+
PushSat: 1_000_000,
765+
MinHtlcMsat: 100,
766+
},
767+
expectedReplacement: &lnrpc.OpenChannelRequest{
768+
NodePubkey: []byte{
769+
200, 19, 68, 149,
770+
},
771+
LocalFundingAmount: 1_000_000,
772+
PushSat: 1_000_000,
773+
MinHtlcMsat: 100,
774+
},
775+
},
776+
{
777+
name: "OpenChannelSync Response bytes",
778+
uri: "/lnrpc.Lightning/OpenChannelSync",
779+
msgType: rpcperms.TypeResponse,
780+
msg: &lnrpc.ChannelPoint{
781+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{
782+
FundingTxidStr: clearTxID,
783+
},
784+
OutputIndex: 0,
785+
},
786+
expectedReplacement: &lnrpc.ChannelPoint{
787+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{
788+
FundingTxidStr: obfusTxID0,
789+
},
790+
OutputIndex: obfusOut0,
791+
},
792+
},
793+
{
794+
name: "OpenChannelSync Response string",
795+
uri: "/lnrpc.Lightning/OpenChannelSync",
796+
msgType: rpcperms.TypeResponse,
797+
msg: &lnrpc.ChannelPoint{
798+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
799+
FundingTxidBytes: clearTxIDReveresed[:],
800+
},
801+
OutputIndex: 0,
802+
},
803+
expectedReplacement: &lnrpc.ChannelPoint{
804+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
805+
FundingTxidBytes: obfusTxID0Reversed[:],
806+
},
807+
OutputIndex: obfusOut0,
808+
},
809+
},
810+
{
811+
name: "OpenChannelSync Response clear",
812+
uri: "/lnrpc.Lightning/OpenChannelSync",
813+
msgType: rpcperms.TypeResponse,
814+
privacyFlags: []session.PrivacyFlag{
815+
session.ClearChanIDs,
816+
},
817+
msg: &lnrpc.ChannelPoint{
818+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
819+
FundingTxidBytes: clearTxIDReveresed[:],
820+
},
821+
OutputIndex: 0,
822+
},
823+
expectedReplacement: &lnrpc.ChannelPoint{
824+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
825+
FundingTxidBytes: clearTxIDReveresed[:],
826+
},
827+
OutputIndex: 0,
828+
},
829+
},
731830
}
732831

733832
decodedID := &lnrpc.MacaroonId{

0 commit comments

Comments
 (0)