From 94cb818dd909e532a8d6afb46761efc0d8ac1668 Mon Sep 17 00:00:00 2001 From: ErikEk Date: Sat, 11 Sep 2021 14:43:46 +0200 Subject: [PATCH] healthcheck: misconfigured bitcoind zmq --- chainreg/chainregistry.go | 94 ++++++++++++++++++++-- docs/release-notes/release-notes-0.15.0.md | 6 ++ 2 files changed, 94 insertions(+), 6 deletions(-) diff --git a/chainreg/chainregistry.go b/chainreg/chainregistry.go index 1eff0ca5b..8364b67df 100644 --- a/chainreg/chainregistry.go +++ b/chainreg/chainregistry.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net" + "net/url" "os" "strconv" "strings" @@ -485,11 +486,92 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // The api we will use for our health check depends on the // bitcoind version. - cmd, err := getBitcoindHealthCheckCmd(chainConn) + cmd, ver, err := getBitcoindHealthCheckCmd(chainConn) if err != nil { return nil, nil, err } + // If the getzmqnotifications api is available (was added in + // version 0.17.0) we make sure lnd subscribes to the correct + // zmq events. We do this to avoid a situation in which we are + // not notified of new transactions or blocks. + if ver >= 170000 { + zmqPubRawBlockURL, err := url.Parse(bitcoindMode.ZMQPubRawBlock) + if err != nil { + return nil, nil, err + } + zmqPubRawTxURL, err := url.Parse(bitcoindMode.ZMQPubRawTx) + if err != nil { + return nil, nil, err + } + + // Fetch all active zmq notifications from the bitcoind client. + resp, err := chainConn.RawRequest("getzmqnotifications", nil) + if err != nil { + return nil, nil, err + } + + zmq := []struct { + Type string `json:"type"` + Address string `json:"address"` + }{} + + if err = json.Unmarshal([]byte(resp), &zmq); err != nil { + return nil, nil, err + } + + pubRawBlockActive := false + pubRawTxActive := false + + for i := range zmq { + if zmq[i].Type == "pubrawblock" { + url, err := url.Parse(zmq[i].Address) + if err != nil { + return nil, nil, err + } + if url.Port() != zmqPubRawBlockURL.Port() { + return nil, nil, fmt.Errorf( + "unable to subscribe to zmq block events on "+ + "%s (bitcoind is running on %s)", + zmqPubRawBlockURL.Host, + url.Host, + ) + } + pubRawBlockActive = true + } + if zmq[i].Type == "pubrawtx" { + url, err := url.Parse(zmq[i].Address) + if err != nil { + return nil, nil, err + } + if url.Port() != zmqPubRawTxURL.Port() { + return nil, nil, fmt.Errorf( + "unable to subscribe to zmq tx events on "+ + "%s (bitcoind is running on %s)", + zmqPubRawTxURL.Host, + url.Host, + ) + } + pubRawTxActive = true + } + } + + // Return an error if raw tx or raw block notification over + // zmq is inactive. + if !pubRawBlockActive { + return nil, nil, errors.New( + "block notification over zmq is inactive on " + + "bitcoind", + ) + } + if !pubRawTxActive { + return nil, nil, errors.New( + "tx notification over zmq is inactive on " + + "bitcoind", + ) + } + } + cc.HealthCheck = func() error { _, err := chainConn.RawRequest(cmd, nil) return err @@ -711,11 +793,11 @@ func NewChainControl(walletConfig lnwallet.Config, // command, because it has no locking and is an inexpensive call, which was // added in version 0.15. If we are on an earlier version, we fallback to using // getblockchaininfo. -func getBitcoindHealthCheckCmd(client *rpcclient.Client) (string, error) { +func getBitcoindHealthCheckCmd(client *rpcclient.Client) (string, int64, error) { // Query bitcoind to get our current version. resp, err := client.RawRequest("getnetworkinfo", nil) if err != nil { - return "", err + return "", 0, err } // Parse the response to retrieve bitcoind's version. @@ -723,7 +805,7 @@ func getBitcoindHealthCheckCmd(client *rpcclient.Client) (string, error) { Version int64 `json:"version"` }{} if err := json.Unmarshal(resp, &info); err != nil { - return "", err + return "", 0, err } // Bitcoind returns a single value representing the semantic version: @@ -733,10 +815,10 @@ func getBitcoindHealthCheckCmd(client *rpcclient.Client) (string, error) { // The uptime call was added in version 0.15.0, so we return it for // any version value >= 150000, as per the above calculation. if info.Version >= 150000 { - return "uptime", nil + return "uptime", info.Version, nil } - return "getblockchaininfo", nil + return "getblockchaininfo", info.Version, nil } var ( diff --git a/docs/release-notes/release-notes-0.15.0.md b/docs/release-notes/release-notes-0.15.0.md index 9cb220b05..7f0d87cf4 100644 --- a/docs/release-notes/release-notes-0.15.0.md +++ b/docs/release-notes/release-notes-0.15.0.md @@ -1,5 +1,10 @@ # Release Notes +## Security + +* [Misconfigured ZMQ + setup now gets reported](https://github.com/lightningnetwork/lnd/pull/5710). + ## Misc * [An example systemd service file](https://github.com/lightningnetwork/lnd/pull/6033) @@ -15,3 +20,4 @@ # Contributors (Alphabetical Order) * Daniel McNally +* ErikEk \ No newline at end of file