Look up IP addresses by prefix at each mask length (closes #48)
check / check (push) Successful in 3m13s
check / check (push) Successful in 3m13s
Looking up an address on /ip/ and /api/v1/ip/ read every IPv6 live route and about half of the IPv4 range index, so on a day-sized database it passed the 30-second request timeout. The lookup is now one function for both families: from the longest mask length down, it looks up the address's network prefix on the existing prefix index, and the first live route wins. The feed sends IPv6 withdrawals uncompressed, so they never matched the stored compressed prefix and never removed a route. Prefixes are now stored in the text form net/netip prints, so IPv6 withdrawals take effect. ip_start, ip_end and GetASInfoForIP are removed; nothing read them. A database from before this change must be deleted. Model: opus-5-5
This commit was merged in pull request #51.
This commit is contained in:
@@ -2,6 +2,7 @@ package routewatch
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -108,7 +109,7 @@ func (h *PrefixHandler) HandleMessage(msg *ristypes.RISMessage) {
|
||||
for _, announcement := range msg.Announcements {
|
||||
for _, prefix := range announcement.Prefixes {
|
||||
h.batch = append(h.batch, prefixUpdate{
|
||||
prefix: prefix,
|
||||
prefix: canonicalPrefix(prefix),
|
||||
originASN: originASN,
|
||||
peer: msg.Peer,
|
||||
messageType: "announcement",
|
||||
@@ -125,7 +126,7 @@ func (h *PrefixHandler) HandleMessage(msg *ristypes.RISMessage) {
|
||||
// Process withdrawals
|
||||
for _, prefix := range msg.Withdrawals {
|
||||
h.batch = append(h.batch, prefixUpdate{
|
||||
prefix: prefix,
|
||||
prefix: canonicalPrefix(prefix),
|
||||
originASN: originASN, // Use the originASN from path if available
|
||||
peer: msg.Peer,
|
||||
messageType: "withdrawal",
|
||||
@@ -264,6 +265,21 @@ func (h *PrefixHandler) flushBatchLocked() {
|
||||
h.lastFlush = time.Now()
|
||||
}
|
||||
|
||||
// canonicalPrefix returns prefix in the text form net/netip prints, the form
|
||||
// the IP lookup builds when it looks a prefix up. The feed sends IPv6
|
||||
// announcements compressed ("2001:db8::/32") but IPv6 withdrawals uncompressed
|
||||
// ("2001:db8:0:0:0:0:0:0/32"); stored as received, a withdrawal would not match
|
||||
// the route its announcement stored. A prefix that does not parse is returned
|
||||
// unchanged, and the batch flush reports it.
|
||||
func canonicalPrefix(prefix string) string {
|
||||
p, err := netip.ParsePrefix(prefix)
|
||||
if err != nil {
|
||||
return prefix
|
||||
}
|
||||
|
||||
return p.Masked().String()
|
||||
}
|
||||
|
||||
// parseCIDR extracts the mask length and IP version from a prefix string
|
||||
func parseCIDR(prefix string) (maskLength int, ipVersion int, err error) {
|
||||
_, ipNet, err := net.ParseCIDR(prefix)
|
||||
@@ -315,20 +331,6 @@ func (h *PrefixHandler) processAnnouncement(_ *database.Prefix, update prefixUpd
|
||||
LastUpdated: update.timestamp,
|
||||
}
|
||||
|
||||
// For IPv4, calculate the IP range
|
||||
if ipVersion == ipv4Version {
|
||||
start, end, err := database.CalculateIPv4Range(update.prefix)
|
||||
if err == nil {
|
||||
liveRoute.V4IPStart = &start
|
||||
liveRoute.V4IPEnd = &end
|
||||
} else {
|
||||
h.logger.Error("Failed to calculate IPv4 range",
|
||||
"prefix", update.prefix,
|
||||
"error", err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.db.UpsertLiveRoute(liveRoute); err != nil {
|
||||
h.logger.Error("Failed to upsert live route",
|
||||
"prefix", update.prefix,
|
||||
@@ -372,20 +374,6 @@ func (h *PrefixHandler) createLiveRoute(update prefixUpdate) *database.LiveRoute
|
||||
LastUpdated: update.timestamp,
|
||||
}
|
||||
|
||||
// For IPv4, calculate the IP range
|
||||
if ipVersion == ipv4Version {
|
||||
start, end, err := database.CalculateIPv4Range(update.prefix)
|
||||
if err == nil {
|
||||
liveRoute.V4IPStart = &start
|
||||
liveRoute.V4IPEnd = &end
|
||||
} else {
|
||||
h.logger.Error("Failed to calculate IPv4 range",
|
||||
"prefix", update.prefix,
|
||||
"error", err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return liveRoute
|
||||
}
|
||||
|
||||
@@ -425,20 +413,6 @@ func (h *PrefixHandler) processAnnouncementDirect(update prefixUpdate) {
|
||||
LastUpdated: update.timestamp,
|
||||
}
|
||||
|
||||
// For IPv4, calculate the IP range
|
||||
if ipVersion == ipv4Version {
|
||||
start, end, err := database.CalculateIPv4Range(update.prefix)
|
||||
if err == nil {
|
||||
liveRoute.V4IPStart = &start
|
||||
liveRoute.V4IPEnd = &end
|
||||
} else {
|
||||
h.logger.Error("Failed to calculate IPv4 range",
|
||||
"prefix", update.prefix,
|
||||
"error", err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.db.UpsertLiveRoute(liveRoute); err != nil {
|
||||
h.logger.Error("Failed to upsert live route",
|
||||
"prefix", update.prefix,
|
||||
|
||||
Reference in New Issue
Block a user