Zero shared mutable state, no I/O -- behavior-preserving, verified via the smoke-test harness (28/28 endpoints match baseline). - server/data/*: CITY_COORDS, RIR_DELEGATION_URLS, TIER1_ASNS, IX_CITY_MAP, RIR country-code sets, UA constant - server/aspa-verification/engine.js: the RFC ASPA verification engine (hopCheck, verifyUpstream, verifyDownstream, detectValleys, etc.) - server/resilience-score.js, server/route-leak.js: pure scoring/heuristic functions server.js: 6838 -> 6454 lines. Part of the module-split plan at ~/.claude/plans/linked-riding-newell.md.
55 lines
2.0 KiB
JavaScript
55 lines
2.0 KiB
JavaScript
const { TIER1_ASNS } = require("./data/tier1-asns");
|
|
|
|
// Heuristic: detects suspicious routing relationships using RIPE Stat neighbour data.
|
|
// NOT real-time. False positives possible for large networks with many Tier-1 relationships.
|
|
// Confidence: MEDIUM — pattern-based, not path-level analysis.
|
|
function computeRouteLeakDetection(upstreams, downstreams, peers) {
|
|
const upstreamAsns = new Set(upstreams.map(n => n.asn));
|
|
const downstreamAsns = new Set(downstreams.map(n => n.asn));
|
|
|
|
const tier1Upstreams = upstreams.filter(n => TIER1_ASNS.has(n.asn));
|
|
const tier1Downstreams = downstreams.filter(n => TIER1_ASNS.has(n.asn));
|
|
|
|
const patterns = [];
|
|
|
|
// Pattern A: Tier-1 appearing as BOTH upstream AND downstream → sandwich candidate
|
|
const sandwich = tier1Upstreams.filter(n => downstreamAsns.has(n.asn));
|
|
sandwich.forEach(n => {
|
|
patterns.push({
|
|
type: "sandwich_candidate",
|
|
asn: n.asn,
|
|
name: n.name,
|
|
description: `AS${n.asn} (${n.name}) appears as both upstream and downstream — possible route leak vector`,
|
|
});
|
|
});
|
|
|
|
// Pattern B: Tier-1 as downstream (re-originating routes to Tier-1s)
|
|
tier1Downstreams.forEach(n => {
|
|
if (!upstreamAsns.has(n.asn)) {
|
|
patterns.push({
|
|
type: "tier1_downstream",
|
|
asn: n.asn,
|
|
name: n.name,
|
|
description: `AS${n.asn} (${n.name}) is a downstream — unusual for a Tier-1, may indicate leaked routes`,
|
|
});
|
|
}
|
|
});
|
|
|
|
const detected = patterns.length > 0;
|
|
|
|
return {
|
|
detected,
|
|
patterns,
|
|
tier1_upstream_count: tier1Upstreams.length,
|
|
tier1_downstream_count: tier1Downstreams.length,
|
|
_provenance: {
|
|
source: "RIPE Stat asn-neighbours",
|
|
validation: "heuristic",
|
|
confidence: "medium",
|
|
note: "Pattern-based detection only. Not real-time (15-min RIPE RIS snapshot). False positives possible for large networks with legitimate Tier-1 relationships.",
|
|
},
|
|
};
|
|
}
|
|
|
|
module.exports = { computeRouteLeakDetection };
|