2019-08-15 11:26:14 +02:00
import axios from "axios" ;
import brembo from "brembo" ;
import yaml from "js-yaml" ;
import fs from "fs" ;
2019-09-14 21:00:20 +02:00
const batchPromises = require ( 'batch-promises' ) ;
2019-08-15 11:26:14 +02:00
2019-10-27 13:39:54 +01:00
module . exports = function generatePrefixes ( asnList , outputFile , exclude , excludeDelegated , prefixes ) {
2019-09-15 20:40:51 +02:00
const generateList = { } ;
let someNotValidatedPrefixes = false ;
2019-08-15 11:26:14 +02:00
2019-10-27 13:39:54 +01:00
if ( ! asnList && ! prefixes ) {
throw new Error ( "You need to specify at least an AS number or a list of prefixes." ) ;
}
if ( asnList && prefixes ) {
throw new Error ( "You can specify an AS number or a list of prefixes, not both." ) ;
2019-09-15 20:40:51 +02:00
}
2019-08-15 11:26:14 +02:00
2019-09-15 20:40:51 +02:00
if ( ! outputFile ) {
throw new Error ( "Output file not specified" ) ;
}
2019-08-15 11:26:14 +02:00
2019-09-18 21:55:54 +02:00
const getMultipleOrigins = ( prefix ) => {
const url = brembo . build ( "https://stat.ripe.net" , {
path : [ "data" , "prefix-overview" , "data.json" ] ,
params : {
resource : prefix
}
} ) ;
return axios ( {
url ,
method : 'GET' ,
responseType : 'json'
} )
. then ( data => {
let asns = [ ] ;
if ( data . data && data . data . data && data . data . data . asns ) {
asns = data . data . data . asns . map ( i => i . asn ) ;
}
return asns ;
} )
} ;
2019-09-15 20:40:51 +02:00
const getAnnouncedMoreSpecifics = ( prefix ) => {
const url = brembo . build ( "https://stat.ripe.net" , {
path : [ "data" , "related-prefixes" , "data.json" ] ,
params : {
resource : prefix
2019-09-14 21:00:20 +02:00
}
2019-09-15 20:40:51 +02:00
} ) ;
2019-09-14 21:00:20 +02:00
2019-09-15 20:40:51 +02:00
return axios ( {
url ,
method : 'GET' ,
responseType : 'json'
2019-09-14 21:00:20 +02:00
} )
2019-09-15 20:40:51 +02:00
. then ( data => {
let prefixes = [ ] ;
if ( data . data && data . data . data && data . data . data . prefixes ) {
prefixes = data . data . data . prefixes
. filter ( i => i . relationship === "Overlap - More Specific" )
. map ( i => {
return {
asn : i . origin _asn ,
2019-09-17 19:20:25 +02:00
description : i . asn _name ,
2019-09-15 20:40:51 +02:00
prefix : i . prefix
}
} ) ;
}
2019-09-14 21:00:20 +02:00
2019-09-15 20:40:51 +02:00
return prefixes ;
} )
2019-09-14 21:00:20 +02:00
2019-09-15 20:40:51 +02:00
} ;
2019-09-14 21:00:20 +02:00
2019-09-18 21:55:54 +02:00
const generateRule = ( prefix , asn , ignoreMorespecifics , description , excludeDelegated ) =>
getMultipleOrigins ( prefix )
. then ( asns => {
const origin = ( asns && asns . length ) ? asns : [ asn ] ;
generateList [ prefix ] = {
description : description || "No description provided" ,
asn : origin . map ( i => parseInt ( i ) ) ,
ignoreMorespecifics : ignoreMorespecifics ,
ignore : excludeDelegated
} ;
} ) ;
2019-08-15 11:26:14 +02:00
2019-09-15 20:40:51 +02:00
const getAnnouncedPrefixes = ( asn ) => {
const url = brembo . build ( "https://stat.ripe.net" , {
path : [ "data" , "announced-prefixes" , "data.json" ] ,
params : {
resource : asn
2019-08-15 11:26:14 +02:00
}
2019-09-15 20:40:51 +02:00
} ) ;
2019-09-14 21:00:20 +02:00
2019-09-15 20:40:51 +02:00
return axios ( {
url ,
method : 'GET' ,
responseType : 'json'
2019-08-15 11:26:14 +02:00
} )
2019-09-15 20:40:51 +02:00
. then ( data => {
if ( data . data && data . data . data && data . data . data . prefixes ) {
return data . data . data . prefixes
. filter ( item => {
const latest = item . timelines
. map ( t => ( t . endtime ) ? new Date ( t . endtime ) : new Date ( ) )
. sort ( ( a , b ) => a - b )
. pop ( ) ;
return latest . getTime ( ) + ( 3600 * 24 * 1000 ) > new Date ( ) . getTime ( ) ;
} )
}
return [ ] ;
} )
2019-09-18 21:55:54 +02:00
. then ( list => list . filter ( i => ! exclude . includes ( i . prefix ) ) )
. then ( list => {
return Promise . all ( list . map ( i => generateRule ( i . prefix , asn , false , null , false ) ) )
. then ( ( ) => list . map ( i => i . prefix ) )
2019-09-15 20:40:51 +02:00
} )
2019-10-04 21:03:51 +02:00
2019-09-15 20:40:51 +02:00
} ;
const validatePrefix = ( asn , prefix ) => {
const url = brembo . build ( "https://stat.ripe.net" , {
path : [ "data" , "rpki-validation" , "data.json" ] ,
params : {
resource : asn ,
prefix
2019-08-15 11:26:14 +02:00
}
2019-09-15 20:40:51 +02:00
} ) ;
2019-09-14 21:00:20 +02:00
2019-09-15 20:40:51 +02:00
return axios ( {
url ,
method : 'GET' ,
responseType : 'json'
2019-08-15 11:26:14 +02:00
} )
2019-09-15 20:40:51 +02:00
. then ( data => {
if ( data . data && data . data . data && data . data . data . validating _roas ) {
return data . data . data . validating _roas . map ( i => i . validity ) . some ( i => i === 'valid' ) ;
}
return false ;
} )
. then ( ( isValid ) => {
if ( isValid ) {
generateList [ prefix ] . description += ' (valid ROA available)' ;
} else {
someNotValidatedPrefixes = true ;
}
} )
} ;
2019-10-27 13:39:54 +01:00
const getBaseRules = ( ) => {
if ( prefixes ) {
return Promise
. all ( prefixes . map ( p => generateRule ( p , null , false , null , false ) ) )
. then ( ( ) => prefixes ) ;
} else {
return Promise . all ( asnList . map ( getAnnouncedPrefixes ) ) ;
}
} ;
return getBaseRules ( )
2019-09-18 21:55:54 +02:00
. then ( items => [ ] . concat . apply ( [ ] , items ) )
. then ( prefixes => {
return batchPromises ( 20 , prefixes , prefix => {
return getAnnouncedMoreSpecifics ( prefix )
. then ( ( items ) => Promise
2019-10-04 21:03:51 +02:00
. all ( items . map ( item => generateRule ( item . prefix , item . asn , true , item . description , excludeDelegated ) ) ) )
. catch ( ( e ) => {
console . log ( "Cannot download more specific prefixes of" , prefix , e ) ;
} )
2019-09-18 21:55:54 +02:00
} )
2019-10-04 21:03:51 +02:00
. catch ( ( e ) => {
console . log ( "Cannot download more specific prefixes" , e ) ;
} )
2019-09-18 21:55:54 +02:00
} )
. then ( ( ) => {
return Promise . all ( Object . keys ( generateList ) . map ( prefix => validatePrefix ( generateList [ prefix ] . asn [ 0 ] , prefix ) ) )
2019-10-04 21:03:51 +02:00
. catch ( ( e ) => {
console . log ( "ROA check failed due to error" , e ) ;
} )
2019-09-18 21:55:54 +02:00
} )
. then ( ( ) => {
2019-09-15 20:40:51 +02:00
const yamlContent = yaml . dump ( generateList ) ;
fs . writeFileSync ( outputFile , yamlContent ) ;
if ( someNotValidatedPrefixes ) {
2019-10-27 13:39:54 +01:00
console . log ( "WARNING: The generated configuration is a snapshot of what is currently announced. Some of the prefixes don't have ROA objects associated or are RPKI invalid. Please, verify the config file by hand!" ) ;
2019-09-15 20:40:51 +02:00
}
console . log ( "Done!" ) ;
2019-10-04 21:03:51 +02:00
} )
. catch ( ( e ) => {
console . log ( "Something went wrong" , e ) ;
} )
2019-08-15 11:26:14 +02:00
2019-10-04 21:03:51 +02:00
} ;