netmetrics.go 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package p2p
  2. import (
  3. "math"
  4. "regexp"
  5. "strconv"
  6. gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
  7. "github.com/certusone/wormhole/node/pkg/version"
  8. "github.com/ethereum/go-ethereum/common"
  9. "github.com/libp2p/go-libp2p/core/peer"
  10. "github.com/prometheus/client_golang/prometheus"
  11. "github.com/prometheus/client_golang/prometheus/promauto"
  12. "github.com/wormhole-foundation/wormhole/sdk/vaa"
  13. )
  14. var (
  15. wormholeNetworkNodeHeight = promauto.NewGaugeVec(
  16. prometheus.GaugeOpts{
  17. Name: "wormhole_network_node_height",
  18. Help: "Network height of the given guardian node per network",
  19. }, []string{"guardian_addr", "node_id", "node_name", "network"})
  20. wormholeNetworkNodeErrors = promauto.NewGaugeVec(
  21. prometheus.GaugeOpts{
  22. Name: "wormhole_network_node_errors_count",
  23. Help: "Number of errors the given guardian node encountered per network",
  24. }, []string{"guardian_addr", "node_id", "node_name", "network"})
  25. wormholeNetworkVersion = promauto.NewGaugeVec(
  26. prometheus.GaugeOpts{
  27. Name: "wormhole_network_node_version",
  28. Help: "Network version of the given guardian node per network",
  29. }, []string{"guardian_addr", "node_id", "node_name", "network", "version"})
  30. )
  31. func collectNodeMetrics(addr common.Address, peerId peer.ID, hb *gossipv1.Heartbeat) {
  32. for _, n := range hb.Networks {
  33. if n == nil {
  34. continue
  35. }
  36. chain := vaa.ChainID(n.Id) // #nosec G115 -- This is safe as chain id is constrained in SetNetworkStats
  37. wormholeNetworkNodeHeight.WithLabelValues(
  38. addr.Hex(), peerId.String(), hb.NodeName, chain.String()).Set(float64(n.Height))
  39. wormholeNetworkNodeErrors.WithLabelValues(
  40. addr.Hex(), peerId.String(), hb.NodeName, chain.String()).Set(float64(n.ErrorCount))
  41. wormholeNetworkVersion.WithLabelValues(
  42. addr.Hex(), peerId.String(), hb.NodeName, chain.String(),
  43. sanitizeVersion(hb.Version, version.Version())).Set(1)
  44. }
  45. }
  46. var (
  47. // Parse version string using regular expression.
  48. // The version string should be in the format of "vX.Y.Z"
  49. // where X, Y and Z are integers. Suffixes are ignored.
  50. reVersion = regexp.MustCompile(`^v(\d+)\.(\d+)\.(\d+)`)
  51. )
  52. // sanitizeVersion cleans up the version string to prevent an attacker from executing a cardinality attack.
  53. func sanitizeVersion(versionStr string, reference string) string {
  54. // Match groups of reVersion
  55. components := reVersion.FindStringSubmatch(versionStr)
  56. referenceComponents := reVersion.FindStringSubmatch(reference)
  57. // Compare components of the version string with the reference and ensure
  58. // that the distance is less than 5.
  59. for i, c := range components {
  60. if len(referenceComponents) <= i {
  61. return "other"
  62. }
  63. cInt, _ := strconv.Atoi(c)
  64. cRefInt, _ := strconv.Atoi(referenceComponents[i])
  65. if math.Abs(float64(cInt-cRefInt)) > 5 {
  66. return "other"
  67. }
  68. }
  69. v := reVersion.FindString(versionStr)
  70. if v == "" {
  71. return "other"
  72. }
  73. return v
  74. }