/** * @module mcp-server/tools/security * MCP Tool: BGP security — hijack detection, route leak analysis (ASPA-based), * bogon filtering, and blacklist checks. * * Provides security-focused analysis of BGP routing using RPKI ROV and ASPA * validation from bgproutes.io, combined with historical data from RIPE Stat * and other sources. */ import { z } from "zod"; import type { ASN, AnomalySeverity } from "../../types/common.js"; // ── Tool Schemas ───────────────────────────────────────── /** Input schema for hijack detection */ export const hijackDetectionSchema = z.object({ prefix: z .string() .describe("IP prefix to check for hijacks (e.g., '1.1.1.0/24')"), expectedOriginAsn: z .number() .optional() .describe("Expected origin ASN (if known)"), includeHistory: z .boolean() .optional() .default(true) .describe("Include historical hijack events"), }); /** Input schema for ASPA-based route leak detection */ export const routeLeakDetectionSchema = z.object({ asn: z .union([z.string(), z.number()]) .describe("ASN to check for route leaks involving their prefixes"), prefixes: z .array(z.string()) .optional() .describe("Specific prefixes to check (default: all announced by ASN)"), timeRange: z .object({ start: z.string().describe("Start time (ISO 8601)"), end: z.string().describe("End time (ISO 8601)"), }) .optional() .describe("Time range to search for leaks"), }); /** Input schema for bogon check */ export const bogonCheckSchema = z.object({ asn: z .union([z.string(), z.number()]) .describe("ASN to check for bogon origination or path issues"), includeReserved: z .boolean() .optional() .default(true) .describe("Check for reserved/unallocated prefix announcements"), includeBogonAsns: z .boolean() .optional() .default(true) .describe("Check for bogon ASNs in AS paths"), }); /** Input schema for blacklist check */ export const blacklistCheckSchema = z.object({ resource: z .string() .describe("IP address, prefix, or ASN to check against blacklists"), lists: z .array(z.string()) .optional() .describe("Specific blacklists to check (default: all known)"), }); // ── Result Types ───────────────────────────────────────── /** Detected BGP hijack */ export interface HijackEvent { readonly prefix: string; readonly legitimateOrigin: ASN; readonly hijackerAsn: ASN; readonly hijackerName: string; readonly type: "exact-match" | "sub-prefix" | "squat"; readonly severity: AnomalySeverity; readonly rpkiStatus: "valid" | "invalid" | "not-found" | "unknown"; readonly firstSeen: string; readonly lastSeen: string; readonly affectedPaths: number; readonly description: string; } /** Hijack detection result */ export interface HijackDetectionResult { readonly prefix: string; readonly expectedOriginAsn: ASN | null; readonly currentOrigins: ReadonlyArray<{ readonly asn: ASN; readonly name: string; readonly rpkiValid: boolean; }>; readonly activeHijacks: ReadonlyArray; readonly historicalHijacks: ReadonlyArray; readonly riskLevel: AnomalySeverity; readonly recommendations: ReadonlyArray; } /** ASPA-based route leak event */ export interface RouteLeakEvent { readonly prefix: string; readonly leakerAsn: ASN; readonly leakerName: string; readonly leakedTo: ReadonlyArray; readonly aspaValidation: { readonly state: "invalid"; readonly violatingHop: { readonly asn: ASN; readonly position: number; readonly reason: string; }; }; readonly severity: AnomalySeverity; readonly firstSeen: string; readonly lastSeen: string; readonly description: string; } /** Route leak detection result */ export interface RouteLeakDetectionResult { readonly asn: ASN; readonly name: string; readonly prefixesChecked: number; readonly activeLeaks: ReadonlyArray; readonly historicalLeaks: ReadonlyArray; readonly aspaStatus: { readonly hasAspaObjects: boolean; readonly aspaObjectCount: number; readonly coveragePercent: number; }; readonly riskLevel: AnomalySeverity; readonly recommendations: ReadonlyArray; } /** Bogon check finding */ export interface BogonFinding { readonly type: "bogon_prefix" | "bogon_asn" | "reserved_prefix" | "unallocated_prefix"; readonly resource: string; readonly severity: AnomalySeverity; readonly description: string; readonly asPath: ReadonlyArray; } /** Bogon check result */ export interface BogonCheckResult { readonly asn: ASN; readonly findings: ReadonlyArray; readonly bogonPrefixCount: number; readonly bogonAsnInPathCount: number; readonly clean: boolean; readonly recommendations: ReadonlyArray; } /** Blacklist check result */ export interface BlacklistCheckResult { readonly resource: string; readonly listed: boolean; readonly listings: ReadonlyArray<{ readonly list: string; readonly listedSince: string; readonly reason: string; readonly delistUrl: string; }>; readonly clean: boolean; } // ── Tool Handlers ──────────────────────────────────────── /** * Detect active and historical BGP hijacks for a prefix. * * Checks for unauthorized origin ASes, sub-prefix hijacks, and route * squatting using RPKI ROV validation and MOAS conflict detection. * * @param input - Validated detection parameters * @returns Hijack detection result with active/historical events * * @example * ``` * > Check if 1.1.1.0/24 is being hijacked * * Returns: Current origins, RPKI validation, any MOAS conflicts, * and historical hijack events. * ``` */ export async function handleHijackDetection( input: z.infer ): Promise { // TODO: Query bgproutes.io RIB for current origins of this prefix // TODO: Validate each origin via RPKI ROV // TODO: Compare with expected origin if provided // TODO: Check for sub-prefix announcements (more-specific hijacks) // TODO: Query historical data from RIPE Stat BGP updates return { prefix: input.prefix, expectedOriginAsn: input.expectedOriginAsn ?? null, currentOrigins: [], activeHijacks: [], historicalHijacks: [], riskLevel: "info", recommendations: [ "Create ROAs for all your prefixes to enable RPKI-based hijack protection", "Monitor BGP announcements in real-time for early hijack detection", "Register ASPA objects to protect against route leaks", ], }; } /** * Detect route leaks using ASPA validation. * * Analyzes BGP paths for ASPA validation failures, which indicate * potential route leaks where a customer or peer re-announces routes * to unauthorized neighbors. * * ASPA (Autonomous System Provider Authorization) objects declare which * ASes are authorized providers. A path that violates these declarations * indicates a route leak. * * @param input - Validated detection parameters * @returns Route leak detection result with ASPA analysis * * @example * ``` * > Detect route leaks using ASPA validation for prefixes of AS13335 * * Returns: Prefixes with ASPA-invalid paths, the leaking AS, severity, * and recommendations for deploying ASPA objects. * ``` */ export async function handleRouteLeakDetection( input: z.infer ): Promise { // TODO: Get all announced prefixes for the ASN (or use provided list) // TODO: For each prefix, query bgproutes.io RIB entries with ASPA validation // TODO: Filter for entries where aspaValidation.state === "invalid" // TODO: Identify the leaking AS (the hop that violates ASPA) // TODO: Query historical updates for past leak events // TODO: Check if the ASN has registered ASPA objects const _input = input; return { asn: 0, // TODO: parseASN(input.asn) name: "", prefixesChecked: 0, activeLeaks: [], historicalLeaks: [], aspaStatus: { hasAspaObjects: false, aspaObjectCount: 0, coveragePercent: 0, }, riskLevel: "info", recommendations: [ "Register ASPA objects to declare your authorized upstream providers", "Monitor ASPA validation results for your prefixes in real-time", "Coordinate with your upstreams to ensure they also deploy ASPA", "Use bgproutes.io real-time stream for immediate leak alerting", ], }; } /** * Check for bogon prefixes and bogon ASNs in routing. * * @param input - Validated check parameters * @returns Bogon check result with findings */ export async function handleBogonCheck( input: z.infer ): Promise { // TODO: Get all announced prefixes for the ASN // TODO: Check against IANA reserved/special-purpose ranges // TODO: Check AS paths for bogon ASNs (reserved, documentation, private) // TODO: Check for unallocated prefixes from RIR data const _input = input; return { asn: 0, findings: [], bogonPrefixCount: 0, bogonAsnInPathCount: 0, clean: true, recommendations: [], }; } /** * Check a resource against known blacklists and reputation databases. * * @param input - Validated check parameters * @returns Blacklist check result with listings */ export async function handleBlacklistCheck( input: z.infer ): Promise { // TODO: Check against Spamhaus (DROP, EDROP, ASN-DROP) // TODO: Check against Team Cymru bogon lists // TODO: Check against various DNSBL services // TODO: Aggregate results from specified or all lists return { resource: input.resource, listed: false, listings: [], clean: true, }; }