fix: bgp.he.net name+country fallback for unregistered ASNs
For ASNs with no PeeringDB entry and no RIPE Stat holder (e.g. reserved or unannounced ASNs), extract name from bgp.he.net page title and country code from the /country/XX href. Eliminates the last 2 CRITICAL audit failures (AS34465 → 'RIPE NCC ASN block'/GB, AS59947 → 'LLHOST INC. SRL'/RO). Audit result: 80/82 PERFECT, 0 CRITICAL. v0.6.8.
This commit is contained in:
parent
9012d2931f
commit
9038e280fa
@ -118,3 +118,12 @@ All notable changes to PeerCortex are documented here.
|
||||
|
||||
### Added
|
||||
- **Name search with autocomplete**: Type any network or organization name in the search bar to get live suggestions. Results are sourced from both RIPE Stat and PeeringDB — covering thousands of registered networks worldwide. Use arrow keys to navigate, Enter or click to select.
|
||||
|
||||
## [0.6.8] — 2026-04-03
|
||||
|
||||
### Fixed
|
||||
- **Name fallback via bgp.he.net title**: ASNs without a PeeringDB entry and no RIPE Stat holder
|
||||
now extract their name from bgp.he.net page title (e.g. LLHOST INC. SRL, RIPE NCC ASN block)
|
||||
- **Country code fallback via bgp.he.net**: ASNs with no country in rir-stats-country
|
||||
now derive their 2-letter country code from bgp.he.net href (e.g. /country/RO, /country/GB)
|
||||
- Zero CRITICAL data errors across 82 of 103 audited ASNs (21 large Tier-1 ASNs exceed 15s cold-cache)
|
||||
|
||||
22
server.js
22
server.js
@ -1546,6 +1546,18 @@ async function fetchBgpHeNet(asn) {
|
||||
if (peerMatch) result.peer_count = parseInt(peerMatch[1].replace(/,/g, ''));
|
||||
const countryMatch = html.match(/Country[^<]*<[^>]*>[^<]*<[^>]*>\s*<[^>]*>([^<]+)/i);
|
||||
if (countryMatch) result.country = countryMatch[1].trim();
|
||||
// Extract 2-letter country code from href="/country/XX"
|
||||
const ccMatch = html.match(/href="\/country\/([A-Z]{2})"/i);
|
||||
if (ccMatch) result.country_code = ccMatch[1].toUpperCase();
|
||||
// Extract clean AS name from title: "AS12345 Some Name - bgp.he.net" → "Some Name"
|
||||
if (titleMatch) {
|
||||
const rawTitle = titleMatch[1].trim();
|
||||
const nameFromTitle = rawTitle.replace(/^AS\d+\s+/i, '').replace(/\s+-\s+bgp\.he\.net.*$/i, '').trim();
|
||||
if (nameFromTitle && !nameFromTitle.toLowerCase().includes('bgp.he.net')) {
|
||||
result.name_from_title = nameFromTitle;
|
||||
}
|
||||
}
|
||||
|
||||
const lgMatch = html.match(/Looking\s+Glass[^<]*<[^>]*href="([^"]+)"/i);
|
||||
if (lgMatch) result.looking_glass = lgMatch[1];
|
||||
const descMatch = html.match(/AS\s+Name[^<]*<[^>]*>[^<]*<[^>]*>([^<]+)/i);
|
||||
@ -2089,7 +2101,7 @@ const server = http.createServer(async (req, res) => {
|
||||
JSON.stringify({
|
||||
status,
|
||||
service: "PeerCortex",
|
||||
version: "0.6.7",
|
||||
version: "0.6.8",
|
||||
timestamp: new Date().toISOString(),
|
||||
uptime_seconds: Math.floor(process.uptime()),
|
||||
memory_mb: Math.round(mem.heapUsed / 1024 / 1024),
|
||||
@ -3338,6 +3350,10 @@ const server = http.createServer(async (req, res) => {
|
||||
else if (selfLink.includes("lacnic")) rir = "LACNIC";
|
||||
else if (selfLink.includes("afrinic")) rir = "AFRINIC";
|
||||
}
|
||||
// bgp.he.net country_code fallback (for unannounced/reserve ASNs)
|
||||
if (!country && bgpHeData && bgpHeData.country_code) {
|
||||
country = bgpHeData.country_code;
|
||||
}
|
||||
// Last resort: derive RIR from country code (common assignments)
|
||||
if (!rir && country) {
|
||||
const ARIN_CC = new Set(["US","CA","AI","AG","BS","BB","BZ","VG","KY","DM","DO","GD","GP","HT","JM","MQ","MS","PR","KN","LC","VC","TT","TC","VI","UM"]);
|
||||
@ -3535,7 +3551,7 @@ const server = http.createServer(async (req, res) => {
|
||||
const result = {
|
||||
meta: {
|
||||
service: "PeerCortex",
|
||||
version: "0.6.7",
|
||||
version: "0.6.8",
|
||||
query: "AS" + asn,
|
||||
duration_ms: duration,
|
||||
sources: ["PeeringDB", "RIPE Stat", "bgp.he.net", "Cloudflare RPKI", "RIPE RPKI Validator", "Route Views"],
|
||||
@ -3545,7 +3561,7 @@ const server = http.createServer(async (req, res) => {
|
||||
},
|
||||
network: {
|
||||
asn: parseInt(asn),
|
||||
name: net.name || overview?.holder || "Unknown",
|
||||
name: net.name || overview?.holder || (bgpHeData && bgpHeData.name_from_title) || "Unknown",
|
||||
aka: net.aka || "",
|
||||
org_name: (net.org && net.org.name) ? net.org.name : "",
|
||||
website: net.website || "",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user