The 662-line handler (the largest in the file) split into one function per data-source/merge stage: facility+IX-location coordinate resolution (facilities.js), neighbour name-resolution + threat-intel enrichment (enrich-neighbours.js), RIR/country derivation cascade (rir-country.js), visibility/prefix-size computation (routing-info.js), multi-source cross-checks + data-quality scoring (cross-check.js), and a slim orchestrator (index.js) running Phase 0/1 fetch and final result assembly. Verified via node --check, eslint no-undef (2 known bugs remain: compare, webhooks), and smoke-test harness (28/28 match, including a byte-for-byte match on /api/lookup's own large response body -- the strongest possible confirmation this, the most complex handler in the file, was decomposed without changing behavior). server.js: 2917 -> 1734 lines (6838 originally -- 75% reduction so far).
52 lines
2.3 KiB
JavaScript
52 lines
2.3 KiB
JavaScript
const { ARIN_CC, APNIC_CC, LACNIC_CC, AFRINIC_CC } = require("../../data/rir-country-codes");
|
|
|
|
// Derive RIR and country through a cascade of fallback sources: RIPE Stat
|
|
// rir-stats-country, RDAP port43, RDAP self-link, bgp.he.net country_code,
|
|
// then a country-code-to-RIR table as a last resort.
|
|
function deriveRirAndCountry(rirEntries, rirData, rdapData, bgpHeData) {
|
|
let rir = "";
|
|
let country = "";
|
|
// RIPE Stat rir-stats-country uses 'location' field (not 'country' or 'rir')
|
|
if (Array.isArray(rirEntries) && rirEntries.length > 0) {
|
|
country = rirEntries[0]?.location || rirEntries[0]?.country || "";
|
|
rir = rirEntries[0]?.rir || "";
|
|
}
|
|
if (!rir && rirData?.data) {
|
|
const rirField = rirData.data.rirs || [];
|
|
if (rirField.length > 0) rir = rirField[0]?.rir || "";
|
|
}
|
|
// Derive RIR from rdapData.port43 (e.g. "whois.ripe.net" → "RIPE")
|
|
if (!rir && rdapData && rdapData.port43) {
|
|
const p43 = (rdapData.port43 || "").toLowerCase();
|
|
if (p43.includes("ripe")) rir = "RIPE";
|
|
else if (p43.includes("arin")) rir = "ARIN";
|
|
else if (p43.includes("apnic")) rir = "APNIC";
|
|
else if (p43.includes("lacnic")) rir = "LACNIC";
|
|
else if (p43.includes("afrinic")) rir = "AFRINIC";
|
|
}
|
|
// Also derive RIR from RDAP links (URL of the RDAP endpoint that responded)
|
|
if (!rir && rdapData && rdapData.links) {
|
|
const selfLink = (rdapData.links.find(l => l.rel === "self") || {}).href || "";
|
|
if (selfLink.includes("ripe")) rir = "RIPE";
|
|
else if (selfLink.includes("arin")) rir = "ARIN";
|
|
else if (selfLink.includes("apnic")) rir = "APNIC";
|
|
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) {
|
|
if (ARIN_CC.has(country)) rir = "ARIN";
|
|
else if (APNIC_CC.has(country)) rir = "APNIC";
|
|
else if (LACNIC_CC.has(country)) rir = "LACNIC";
|
|
else if (AFRINIC_CC.has(country)) rir = "AFRINIC";
|
|
else rir = "RIPE"; // Europe + rest = RIPE NCC
|
|
}
|
|
return { rir, country };
|
|
}
|
|
|
|
module.exports = { deriveRirAndCountry };
|