check / check (push) Successful in 2m55s
Looking up an address read every IPv6 live route and, for IPv4, about half of the range index. Both families now look the address's prefix up at each mask length, longest first, on the prefix index: at most 33 or 129 indexed lookups, however many routes are live. The feed sends IPv6 withdrawals uncompressed but announcements compressed, so the prefix handler now stores every prefix in the text form net/netip prints, the form the lookup builds. IPv6 withdrawals now remove their routes. The IPv4 range columns, their index and the code that fills them are removed, and so are the unused GetASInfoForIP lookups. Model: opus-5-5
147 lines
4.8 KiB
Go
147 lines
4.8 KiB
Go
// Package database provides SQLite storage for BGP routing data.
|
|
package database
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ASN represents an Autonomous System Number with its metadata including
|
|
// handle, description, WHOIS data, and first/last seen timestamps.
|
|
type ASN struct {
|
|
ASN int `json:"asn"`
|
|
Handle string `json:"handle"`
|
|
Description string `json:"description"`
|
|
// WHOIS parsed fields
|
|
ASName string `json:"as_name,omitempty"`
|
|
OrgName string `json:"org_name,omitempty"`
|
|
OrgID string `json:"org_id,omitempty"`
|
|
Address string `json:"address,omitempty"`
|
|
CountryCode string `json:"country_code,omitempty"`
|
|
AbuseEmail string `json:"abuse_email,omitempty"`
|
|
AbusePhone string `json:"abuse_phone,omitempty"`
|
|
TechEmail string `json:"tech_email,omitempty"`
|
|
TechPhone string `json:"tech_phone,omitempty"`
|
|
RIR string `json:"rir,omitempty"` // ARIN, RIPE, APNIC, LACNIC, AFRINIC
|
|
RIRRegDate *time.Time `json:"rir_registration_date,omitempty"`
|
|
RIRLastMod *time.Time `json:"rir_last_modified,omitempty"`
|
|
WHOISRaw string `json:"whois_raw,omitempty"`
|
|
// Timestamps
|
|
FirstSeen time.Time `json:"first_seen"`
|
|
LastSeen time.Time `json:"last_seen"`
|
|
WHOISUpdatedAt *time.Time `json:"whois_updated_at,omitempty"`
|
|
}
|
|
|
|
// Prefix represents an IP prefix (CIDR block) with its IP version (4 or 6)
|
|
// and first/last seen timestamps.
|
|
type Prefix struct {
|
|
ID uuid.UUID `json:"id"`
|
|
Prefix string `json:"prefix"`
|
|
IPVersion int `json:"ip_version"` // 4 or 6
|
|
FirstSeen time.Time `json:"first_seen"`
|
|
LastSeen time.Time `json:"last_seen"`
|
|
}
|
|
|
|
// Announcement represents a BGP announcement or withdrawal event,
|
|
// containing the prefix, AS path, origin ASN, peer ASN, next hop, and timestamp.
|
|
type Announcement struct {
|
|
ID uuid.UUID `json:"id"`
|
|
PrefixID uuid.UUID `json:"prefix_id"`
|
|
PeerASN int `json:"peer_asn"`
|
|
OriginASN int `json:"origin_asn"`
|
|
Path string `json:"path"` // JSON-encoded AS path
|
|
NextHop string `json:"next_hop"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
IsWithdrawal bool `json:"is_withdrawal"`
|
|
}
|
|
|
|
// ASNPeering represents a peering relationship between two ASNs,
|
|
// stored with the lower ASN as ASA and the higher as ASB.
|
|
type ASNPeering struct {
|
|
ID uuid.UUID `json:"id"`
|
|
ASA int `json:"as_a"`
|
|
ASB int `json:"as_b"`
|
|
FirstSeen time.Time `json:"first_seen"`
|
|
LastSeen time.Time `json:"last_seen"`
|
|
}
|
|
|
|
// LiveRoute represents a route in the live routing table
|
|
type LiveRoute struct {
|
|
ID uuid.UUID `json:"id"`
|
|
Prefix string `json:"prefix"`
|
|
MaskLength int `json:"mask_length"`
|
|
IPVersion int `json:"ip_version"`
|
|
OriginASN int `json:"origin_asn"`
|
|
PeerIP string `json:"peer_ip"`
|
|
ASPath []int `json:"as_path"`
|
|
NextHop string `json:"next_hop"`
|
|
LastUpdated time.Time `json:"last_updated"`
|
|
}
|
|
|
|
// PrefixDistribution represents the distribution of prefixes by mask length
|
|
type PrefixDistribution struct {
|
|
MaskLength int `json:"mask_length"`
|
|
Count int `json:"count"`
|
|
}
|
|
|
|
// IPInfo represents comprehensive IP information for the /ip endpoint
|
|
type IPInfo struct {
|
|
IP string `json:"ip"`
|
|
PTR []string `json:"ptr,omitempty"`
|
|
Netblock string `json:"netblock"`
|
|
MaskLength int `json:"mask_length"`
|
|
IPVersion int `json:"ip_version"`
|
|
NumPeers int `json:"num_peers"`
|
|
// AS information
|
|
ASN int `json:"asn"`
|
|
ASName string `json:"as_name,omitempty"`
|
|
Handle string `json:"handle,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
OrgName string `json:"org_name,omitempty"`
|
|
OrgID string `json:"org_id,omitempty"`
|
|
Address string `json:"address,omitempty"`
|
|
CountryCode string `json:"country_code,omitempty"`
|
|
AbuseEmail string `json:"abuse_email,omitempty"`
|
|
RIR string `json:"rir,omitempty"`
|
|
// Timestamps
|
|
FirstSeen time.Time `json:"first_seen"`
|
|
LastSeen time.Time `json:"last_seen"`
|
|
// Indicates if WHOIS data needs refresh (not serialized)
|
|
NeedsWHOISRefresh bool `json:"-"`
|
|
}
|
|
|
|
// LiveRouteDeletion represents parameters for deleting a live route
|
|
type LiveRouteDeletion struct {
|
|
Prefix string
|
|
OriginASN int
|
|
PeerIP string
|
|
IPVersion int
|
|
}
|
|
|
|
// PeerUpdate represents parameters for updating a peer
|
|
type PeerUpdate struct {
|
|
PeerIP string
|
|
PeerASN int
|
|
MessageType string
|
|
Timestamp time.Time
|
|
}
|
|
|
|
// ASNWHOISUpdate contains WHOIS data for updating an ASN record.
|
|
type ASNWHOISUpdate struct {
|
|
ASN int
|
|
ASName string
|
|
OrgName string
|
|
OrgID string
|
|
Address string
|
|
CountryCode string
|
|
AbuseEmail string
|
|
AbusePhone string
|
|
TechEmail string
|
|
TechPhone string
|
|
RIR string
|
|
RIRRegDate *time.Time
|
|
RIRLastMod *time.Time
|
|
WHOISRaw string
|
|
}
|