From 01cddb8013d9eb05d38db6f699a9adfafcbb053b Mon Sep 17 00:00:00 2001 From: Ben Ritcey Date: Tue, 28 Nov 2023 11:56:47 -0500 Subject: [PATCH] Added firewall.rules.hash metric (#1010) * Added firewall.rules.hash metric Added a FNV-1 hash of the firewall rules as a Prometheus value. * Switch FNV has to int64, include both hashes in log messages * Use a uint32 for the FNV hash Let go-metrics cast the uint32 to a int64, so it won't be lossy when it eventually emits a float64 Prometheus metric. --- firewall.go | 14 ++++++++++++++ interface.go | 8 ++++---- main.go | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/firewall.go b/firewall.go index bdda18c..64fada3 100644 --- a/firewall.go +++ b/firewall.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "hash/fnv" "net" "reflect" "strconv" @@ -278,6 +279,18 @@ func (f *Firewall) GetRuleHash() string { return hex.EncodeToString(sum[:]) } +// GetRuleHashFNV returns a uint32 FNV-1 hash representation the rules, for use as a metric value +func (f *Firewall) GetRuleHashFNV() uint32 { + h := fnv.New32a() + h.Write([]byte(f.rules)) + return h.Sum32() +} + +// GetRuleHashes returns both the sha256 and FNV-1 hashes, suitable for logging +func (f *Firewall) GetRuleHashes() string { + return "SHA:" + f.GetRuleHash() + ",FNV:" + strconv.FormatUint(uint64(f.GetRuleHashFNV()), 10) +} + func AddFirewallRulesFromConfig(l *logrus.Logger, inbound bool, c *config.C, fw FirewallInterface) error { var table string if inbound { @@ -449,6 +462,7 @@ func (f *Firewall) EmitStats() { conntrack.Unlock() metrics.GetOrRegisterGauge("firewall.conntrack.count", nil).Update(int64(conntrackCount)) metrics.GetOrRegisterGauge("firewall.rules.version", nil).Update(int64(f.rulesVersion)) + metrics.GetOrRegisterGauge("firewall.rules.hash", nil).Update(int64(f.GetRuleHashFNV())) } func (f *Firewall) inConns(packet []byte, fp firewall.Packet, incoming bool, h *HostInfo, caPool *cert.NebulaCAPool, localCache firewall.ConntrackCache) bool { diff --git a/interface.go b/interface.go index a86b6f0..d16348a 100644 --- a/interface.go +++ b/interface.go @@ -332,8 +332,8 @@ func (f *Interface) reloadFirewall(c *config.C) { // If rulesVersion is back to zero, we have wrapped all the way around. Be // safe and just reset conntrack in this case. if fw.rulesVersion == 0 { - f.l.WithField("firewallHash", fw.GetRuleHash()). - WithField("oldFirewallHash", oldFw.GetRuleHash()). + f.l.WithField("firewallHashes", fw.GetRuleHashes()). + WithField("oldFirewallHashes", oldFw.GetRuleHashes()). WithField("rulesVersion", fw.rulesVersion). Warn("firewall rulesVersion has overflowed, resetting conntrack") } else { @@ -343,8 +343,8 @@ func (f *Interface) reloadFirewall(c *config.C) { f.firewall = fw oldFw.Destroy() - f.l.WithField("firewallHash", fw.GetRuleHash()). - WithField("oldFirewallHash", oldFw.GetRuleHash()). + f.l.WithField("firewallHashes", fw.GetRuleHashes()). + WithField("oldFirewallHashes", oldFw.GetRuleHashes()). WithField("rulesVersion", fw.rulesVersion). Info("New firewall has been installed") } diff --git a/main.go b/main.go index 26f47eb..fd3b687 100644 --- a/main.go +++ b/main.go @@ -65,7 +65,7 @@ func Main(c *config.C, configTest bool, buildVersion string, logger *logrus.Logg if err != nil { return nil, util.ContextualizeIfNeeded("Error while loading firewall rules", err) } - l.WithField("firewallHash", fw.GetRuleHash()).Info("Firewall started") + l.WithField("firewallHashes", fw.GetRuleHashes()).Info("Firewall started") // TODO: make sure mask is 4 bytes tunCidr := certificate.Details.Ips[0]