56 lines
1.7 KiB
TypeScript
56 lines
1.7 KiB
TypeScript
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
|
|
|
|
interface RpkiHistoryQuery {
|
|
asn?: string;
|
|
}
|
|
|
|
export async function rpkiHistoryRoutes(fastify: FastifyInstance): Promise<void> {
|
|
fastify.get<{ Querystring: RpkiHistoryQuery }>(
|
|
'/rpki-history',
|
|
async (request: FastifyRequest<{ Querystring: RpkiHistoryQuery }>, reply: FastifyReply) => {
|
|
let asnStr = request.query.asn || '';
|
|
const asn = asnStr.replace(/[^0-9]/g, '');
|
|
|
|
reply.header('Access-Control-Allow-Origin', '*');
|
|
reply.header('Cache-Control', 'public, max-age=3600');
|
|
|
|
if (!asn) {
|
|
return reply.status(400).send({ error: 'asn required' });
|
|
}
|
|
|
|
try {
|
|
const url = `https://stat.ripe.net/data/routing-history/data.json?resource=AS${asn}&max_rows=100`;
|
|
|
|
const controller = new AbortController();
|
|
const timeoutId = setTimeout(() => controller.abort(), 6000);
|
|
const response = await fetch(url, { signal: controller.signal });
|
|
clearTimeout(timeoutId);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`RIPE Stat returned HTTP ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
|
|
const byOrigin = (data && data.data && data.data.by_origin) || [];
|
|
const prefixes: any[] = [];
|
|
|
|
for (const orig of byOrigin) {
|
|
if (orig.prefixes) {
|
|
for (const pfx of orig.prefixes) {
|
|
prefixes.push(pfx);
|
|
}
|
|
}
|
|
}
|
|
|
|
return reply.status(200).send({
|
|
asn: asn,
|
|
prefixes: prefixes,
|
|
source: 'RIPE Stat routing-history'
|
|
});
|
|
} catch (e: any) {
|
|
return reply.status(500).send({ error: e.message });
|
|
}
|
|
}
|
|
);
|
|
}
|