From b550b8ae9fb7cdbd3a05a811a9f88181fba9d70c Mon Sep 17 00:00:00 2001 From: Ezri Zhu Date: Mon, 29 Jul 2024 16:50:45 -0400 Subject: [PATCH] upstream labeling and improvments --- lg.go | 63 ++++++++++++++++++++++++++++++++++++++++++++-------- main.go | 9 +++++++- prefixes.go | 25 +++++++++++++++++++++ upstreams.go | 24 ++++++++++++++++++++ vis.go | 6 +++++ 5 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 upstreams.go diff --git a/lg.go b/lg.go index f51cdf3..6a4da8e 100644 --- a/lg.go +++ b/lg.go @@ -26,6 +26,14 @@ var ( }, []string{"prefix", "city", "mux", "upstreams", "available", "origin"}, ) + ripeStatLGErr = promauto.NewCounter(prometheus.CounterOpts{ + Name: "ripestatlg_err", + Help: "error count for ripestat lg endpoint", + }) + possibleHijack = promauto.NewCounter(prometheus.CounterOpts{ + Name: "possible_hijack", + Help: "upstream mismatch, possible hijack", + }) //bgpCommunitiesGauge = promauto.NewGaugeVec(prometheus.GaugeOpts{ // Name: "bgp_communities", // Help: "BGP Communities", @@ -40,6 +48,7 @@ func (p *Prefix) checkLGState() { resp, err := http.Get(url) if err != nil { log.Error().Err(err).Msg("Fetching ripestat") + ripeStatLGErr.Inc() return } @@ -57,6 +66,7 @@ func (p *Prefix) checkLGState() { log.Error().Int("status code", statusCode). Str("status", ripeStatLookingGlassResp.Status). Msg("ripestat(lg) resp status code != 200") + ripeStatLGErr.Inc() return } @@ -65,6 +75,15 @@ func (p *Prefix) checkLGState() { availableStr = "n" } + var UFMGOrigin bool + if p.origin == 61574 { + UFMGOrigin = true + } + + if p.origin == 13335 { + return + } + origin := strconv.Itoa(p.origin) for _, rrc := range ripeStatLookingGlassResp.Data.Rrcs { @@ -76,21 +95,47 @@ func (p *Prefix) checkLGState() { asPathSplit := strings.Split(peer.AsPath, " ") upstream := "" upstream2 := "" - if len(asPathSplit) >= 4 { - upstream = asPathSplit[len(asPathSplit)-4] - if err != nil { - log.Err(err).Msg("atoi fail") - } + offset := 2 + if UFMGOrigin { + offset += 2 } - if len(asPathSplit) >= 5 { - upstream2 = asPathSplit[len(asPathSplit)-5] - if err != nil { - log.Err(err).Msg("atoi fail") + if len(asPathSplit) < offset+1 { + return + } + upstream = asPathSplit[len(asPathSplit)-offset] + if err != nil { + log.Error().Err(err).Msg("atoi fail") + return + } + matched := false + for _, dbUpstream := range dbUpstreams { + if dbUpstream.name == upstream { + matched = true + break } } + if !matched { + log.Info(). + Str("prefix", p.prefix). + Str("upstream", upstream). + Str("path", peer.AsPath). + Msg("upstream mismatch, hijack possible") + possibleHijack.Inc() + return + } if !slices.Contains(upstreams, upstream) { upstreams = append(upstreams, upstream) } + + // second upstream + if len(asPathSplit) < offset+2 { + return + } + upstream2 = asPathSplit[len(asPathSplit)-offset-1] + if err != nil { + log.Error().Err(err).Msg("atoi fail") + return + } if !slices.Contains(upstreams2, upstream2) { upstreams2 = append(upstreams2, upstream2) } diff --git a/main.go b/main.go index 11280d2..62c8208 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ import ( var port int var appId string var debug bool +var jsonLog bool const ripestatBase = "https://stat.ripe.net" @@ -33,16 +34,20 @@ func updateStates() { func init() { zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}) flag.StringVar(&appId, "appid", "exporter", "provide a unique identifier to every data call") flag.IntVar(&port, "port", 2112, "port") flag.BoolVar(&debug, "debug", false, "debug") + flag.BoolVar(&jsonLog, "json", false, "json logging") } func main() { flag.Parse() + if !jsonLog { + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}) + } + if debug { zerolog.SetGlobalLevel(zerolog.DebugLevel) log.Debug().Msg("Debug log enabled") @@ -57,6 +62,8 @@ func main() { updateStates() + setUpstreamGauge() + go func() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() diff --git a/prefixes.go b/prefixes.go index d5bd996..50ec04c 100644 --- a/prefixes.go +++ b/prefixes.go @@ -7,6 +7,31 @@ type Prefix struct { origin int } +type Upstream struct { + asn string + name string +} + +var dbUpstreams = []Upstream{ + Upstream{"Northeastern University", "156"}, + Upstream{"FABRIC Testbed", "398900"}, + Upstream{"GRNet", "5408"}, + Upstream{"Bit BV", "12859"}, + Upstream{"Netwerkvereniging Coloclue", "8283"}, + Upstream{"Stony Brook University", "5719"}, + Upstream{"Clemson University", "12148"}, + Upstream{"Utah Education Network", "210"}, + Upstream{"Georgia Institute of Technology", "2637"}, + Upstream{"University of Wisconsin - Madison", "3128"}, + Upstream{"Rede Nacional de Ensino e Pesquisa (RNP)", "1916"}, + Upstream{"Cornell University", "26"}, + Upstream{"psg.com RGNet", "3130"}, + Upstream{"Los Nettos Regional Network", "226"}, + Upstream{"UW at PNW GigaPoP", "101"}, + Upstream{"vultr", "20473"}, + Upstream{"HE", "6939"}, +} + var monitorState = []Prefix{ Prefix{prefix: "2804:269c:fe01::/48", pop: "seattle01", available: true, origin: 47065}, Prefix{prefix: "2804:269c:fe02::/48", pop: "isi01", available: true, origin: 47065}, diff --git a/upstreams.go b/upstreams.go new file mode 100644 index 0000000..8f602bf --- /dev/null +++ b/upstreams.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/rs/zerolog/log" +) + +var ( + upstreamGauge = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "defined_upstreams", + Help: "defined upstreams pulled from the db", + }, []string{"asn", "name"}) +) + +func setUpstreamGauge() { + log.Trace().Msg("setting upstreeams gauge") + for _, dbUpstream := range dbUpstreams { + upstreamGauge.WithLabelValues( + dbUpstream.asn, + dbUpstream.name, + ).Set(1) + } +} diff --git a/vis.go b/vis.go index 4921921..0975a43 100644 --- a/vis.go +++ b/vis.go @@ -17,6 +17,10 @@ var ( Name: "prefix_visibility", Help: "Visibility of the prefix", }, []string{"prefix", "city", "mux", "available", "origin"}) + ripeStatVisibilityErr = promauto.NewCounter(prometheus.CounterOpts{ + Name: "ripestatvis_err", + Help: "error count for ripestat vis endpoint", + }) ) func (p *Prefix) checkVisState() { @@ -25,6 +29,7 @@ func (p *Prefix) checkVisState() { resp, err := http.Get(url) if err != nil { log.Error().Err(err).Msg("Fetching ripestat") + ripeStatVisibilityErr.Inc() return } @@ -42,6 +47,7 @@ func (p *Prefix) checkVisState() { log.Error().Int("status code", statusCode). Str("status", ripeStatVisibilityResp.Status). Msg("ripestat(vis) resp status code != 200") + ripeStatVisibilityErr.Inc() return }