// 11. Bogon Detection (local check, no external API calls) function checkBogonPrefix(prefix) { var bogonV4 = [ { net: "0.0.0.0", mask: 8 }, { net: "10.0.0.0", mask: 8 }, { net: "100.64.0.0", mask: 10 }, { net: "127.0.0.0", mask: 8 }, { net: "169.254.0.0", mask: 16 }, { net: "172.16.0.0", mask: 12 }, { net: "192.0.2.0", mask: 24 }, { net: "192.168.0.0", mask: 16 }, { net: "198.51.100.0", mask: 24 }, { net: "203.0.113.0", mask: 24 }, { net: "240.0.0.0", mask: 4 }, ]; if (prefix.includes(":")) return { prefix: prefix, is_bogon: false, reason: "IPv6 bogon check skipped" }; var split = prefix.split("/"); var addr = split[0]; var mask = parseInt(split[1] || "0"); var parts = addr.split(".").map(Number); var ip = ((parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0; for (var bi = 0; bi < bogonV4.length; bi++) { var b = bogonV4[bi]; var bParts = b.net.split(".").map(Number); var bIp = ((bParts[0] << 24) | (bParts[1] << 16) | (bParts[2] << 8) | bParts[3]) >>> 0; var bMask = (~((1 << (32 - b.mask)) - 1)) >>> 0; if ((ip & bMask) === (bIp & bMask) && mask >= b.mask) { return { prefix: prefix, is_bogon: true, reason: "Matches bogon " + b.net + "/" + b.mask }; } } return { prefix: prefix, is_bogon: false }; } function checkBogonAsn(asnNum) { if (asnNum === 0 || asnNum === 23456 || asnNum === 65535) return true; if (asnNum >= 64496 && asnNum <= 64511) return true; if (asnNum >= 64512 && asnNum <= 65534) return true; return false; } // "pass" must mean prefixes/neighbours were actually fetched and checked clean -- // not that the upstream source failed and left nothing to check. A source is // unavailable if it's falsy (fetchRipeStatCached network failure) OR if it's a // truthy object with status:"error" (local-db-client.js's DB-error signal -- // see the 2026-07-16 audit; that object is NOT null, so a plain `!x` check // alone misses this case and would show "pass" on 0 checked prefixes). function isSourceUnavailable(x) { return !x || x.status === "error"; } function computeBogonResult(allPrefixes, neighbours, prefixData, neighbourData) { var bogonPrefixResults = allPrefixes.map(checkBogonPrefix); var bogonPrefixes = bogonPrefixResults.filter(function(r) { return r.is_bogon; }); var asnInPaths = neighbours.map(function(n) { return n.asn; }); var bogonAsns = asnInPaths.filter(checkBogonAsn); var prefixesUnavailable = isSourceUnavailable(prefixData); var neighboursUnavailable = isSourceUnavailable(neighbourData); var bogonDataUnavailable = prefixesUnavailable && neighboursUnavailable; return { status: bogonDataUnavailable ? "info" : (bogonPrefixes.length === 0 && bogonAsns.length === 0 ? "pass" : "fail"), bogon_prefixes: bogonPrefixes, bogon_asns_in_paths: bogonAsns, total_prefixes_checked: allPrefixes.length, prefixes_source_unavailable: prefixesUnavailable, neighbours_source_unavailable: neighboursUnavailable, }; } module.exports = { computeBogonResult };