- Connects to RIPE RIS Live stream to receive real-time BGP updates - Stores BGP data in SQLite database: - ASNs with first/last seen timestamps - Prefixes with IPv4/IPv6 classification - BGP announcements and withdrawals - AS-to-AS peering relationships from AS paths - Live routing table tracking active routes - HTTP server with statistics endpoints - Metrics tracking with go-metrics - Custom JSON unmarshaling to handle nested AS sets in paths - Dependency injection with uber/fx - Pure Go implementation (no CGO) - Includes streamdumper utility for debugging raw messages
82 lines
2.5 KiB
Go
82 lines
2.5 KiB
Go
// Package ristypes defines the data structures for RIS Live BGP messages and announcements.
|
|
package ristypes
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// ASPath represents an AS path that may contain nested AS sets
|
|
type ASPath []int
|
|
|
|
// UnmarshalJSON implements custom JSON unmarshaling to flatten nested arrays
|
|
func (p *ASPath) UnmarshalJSON(data []byte) error {
|
|
// First try to unmarshal as a simple array of integers
|
|
var simple []int
|
|
if err := json.Unmarshal(data, &simple); err == nil {
|
|
*p = ASPath(simple)
|
|
|
|
return nil
|
|
}
|
|
|
|
// If that fails, unmarshal as array of interfaces and flatten
|
|
var raw []interface{}
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Flatten the array
|
|
result := make([]int, 0)
|
|
for _, item := range raw {
|
|
switch v := item.(type) {
|
|
case float64:
|
|
result = append(result, int(v))
|
|
case []interface{}:
|
|
// Nested array - flatten it
|
|
for _, nested := range v {
|
|
if num, ok := nested.(float64); ok {
|
|
result = append(result, int(num))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*p = ASPath(result)
|
|
|
|
return nil
|
|
}
|
|
|
|
// RISLiveMessage represents the outer wrapper from the RIS Live stream
|
|
type RISLiveMessage struct {
|
|
Type string `json:"type"`
|
|
Data RISMessage `json:"data"`
|
|
}
|
|
|
|
// RISMessage represents a message from the RIS Live stream
|
|
type RISMessage struct {
|
|
Type string `json:"type"`
|
|
Timestamp float64 `json:"timestamp"`
|
|
ParsedTimestamp time.Time `json:"-"` // Parsed from Timestamp field
|
|
Peer string `json:"peer"`
|
|
PeerASN string `json:"peer_asn"`
|
|
ID string `json:"id"`
|
|
Host string `json:"host"`
|
|
RRC string `json:"rrc,omitempty"`
|
|
MrtTime float64 `json:"mrt_time,omitempty"`
|
|
SocketTime float64 `json:"socket_time,omitempty"`
|
|
Path ASPath `json:"path,omitempty"`
|
|
Community [][]int `json:"community,omitempty"`
|
|
Origin string `json:"origin,omitempty"`
|
|
MED *int `json:"med,omitempty"`
|
|
LocalPref *int `json:"local_pref,omitempty"`
|
|
Announcements []RISAnnouncement `json:"announcements,omitempty"`
|
|
Withdrawals []string `json:"withdrawals,omitempty"`
|
|
Raw string `json:"raw,omitempty"`
|
|
}
|
|
|
|
// RISAnnouncement represents announcement data within a RIS message
|
|
type RISAnnouncement struct {
|
|
NextHop string `json:"next_hop"`
|
|
Prefixes []string `json:"prefixes"`
|
|
}
|