1
0
mirror of https://github.com/nttgin/BGPalerter.git synced 2024-05-19 06:50:08 +00:00

added feature to monitor for disappearing ROAs

This commit is contained in:
Massimo Candela
2020-08-14 15:10:38 +02:00
parent 9e31bea194
commit 63cd9fd34a
8 changed files with 306 additions and 142 deletions

106
package-lock.json generated
View File

@@ -1346,71 +1346,71 @@
}
},
"@sentry/apm": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/apm/-/apm-5.20.1.tgz",
"integrity": "sha512-oqfyYqRR1CaM/U5qZg3KY9MxCe4OWYs3uiOvVGMOHCyx50dYsDZziM5DDVUvi6pOuokLCNbyXO9xGROSmploBQ==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/apm/-/apm-5.21.1.tgz",
"integrity": "sha512-mxMOCpeXULbQCC/f9SwPqW+g12mk3nWRNjeAUm5dyiKHY13agtQBSSYs4ROEH190YxmwTZr3vxhlR2jNSdSZcg==",
"requires": {
"@sentry/browser": "5.20.1",
"@sentry/hub": "5.20.1",
"@sentry/minimal": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"@sentry/browser": "5.21.1",
"@sentry/hub": "5.21.1",
"@sentry/minimal": "5.21.1",
"@sentry/types": "5.21.1",
"@sentry/utils": "5.21.1",
"tslib": "^1.9.3"
}
},
"@sentry/browser": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.20.1.tgz",
"integrity": "sha512-ClykuvrEsMKgAvifx5VHzRjchwYbJFX8YiIicYx+Wr3MXL2jLG6OEfHHJwJeyBL2C3vxd5O0KPK3pGMR9wPMLA==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.21.1.tgz",
"integrity": "sha512-sUxsW545klZxJE4iBAYQ8SuVS85HTOGNmIIIZWFUogB5oW3O0L+nJluXEqf/pHU82LnjDIzqsWCYQ0cRUaeYow==",
"requires": {
"@sentry/core": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"@sentry/core": "5.21.1",
"@sentry/types": "5.21.1",
"@sentry/utils": "5.21.1",
"tslib": "^1.9.3"
}
},
"@sentry/core": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.20.1.tgz",
"integrity": "sha512-gG622/UY2TePruF6iUzgVrbIX5vN8w2cjlWFo1Est8MvCfQsz8agGaLMCAyl5hCGJ6K2qTUZDOlbCNIKoMclxg==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.21.1.tgz",
"integrity": "sha512-Luulwx3GLUiY0gmHOhU+4eSga28Ce8DwoBcRq9GkGuhPu9r80057d5urxrDLp/leIZBXVvpY7tvmSN/rMtvF9w==",
"requires": {
"@sentry/hub": "5.20.1",
"@sentry/minimal": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"@sentry/hub": "5.21.1",
"@sentry/minimal": "5.21.1",
"@sentry/types": "5.21.1",
"@sentry/utils": "5.21.1",
"tslib": "^1.9.3"
}
},
"@sentry/hub": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.20.1.tgz",
"integrity": "sha512-Nv5BXf14BEc08acDguW6eSqkAJLVf8wki283FczEvTsQZZuSBHM9cJ5Hnehr6n+mr8wWpYLgUUYM0oXXigUmzQ==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.21.1.tgz",
"integrity": "sha512-x5i9Ggi5ZYMhBYL5kyTu2fUJ6owjKH2tgJL3UExoZdRyZkbLAFZb+DtfSnteWgQ6wriGfgPD3r/hAIEdaomk2A==",
"requires": {
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"@sentry/types": "5.21.1",
"@sentry/utils": "5.21.1",
"tslib": "^1.9.3"
}
},
"@sentry/minimal": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.20.1.tgz",
"integrity": "sha512-2PeJKDTHNsUd1jtSLQBJ6oRI+xrIJrYDQmsyK/qs9D7HqHfs+zNAMUjYseiVeSAFGas5IcNSuZbPRV4BnuoZ0w==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.21.1.tgz",
"integrity": "sha512-OBVPASZ+mcXMKajvJon9RjEZ+ny3+VGhOI66acoP1hmYxKvji1OC2bYEuP1r4qtHxWVLAdV7qFj3EQ9ckErZmQ==",
"requires": {
"@sentry/hub": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/hub": "5.21.1",
"@sentry/types": "5.21.1",
"tslib": "^1.9.3"
}
},
"@sentry/node": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.20.1.tgz",
"integrity": "sha512-43YFDnD7Rv+vGHV+Fmb3LaSSWrFzsPmFRu3wmf9eYMgWiuDks6c6/kWRCgkqX9Np9ImC89wcTZs/V6S4MlOm4g==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.21.1.tgz",
"integrity": "sha512-+QLqGz6+/gtShv0F16nI2+AuVEDZG2k9L25BVCNoysYzH1J1/QIKHsl7YF2trDMlWM4T7cbu5Fh8AhK6an+5/g==",
"requires": {
"@sentry/apm": "5.20.1",
"@sentry/core": "5.20.1",
"@sentry/hub": "5.20.1",
"@sentry/types": "5.20.1",
"@sentry/utils": "5.20.1",
"@sentry/apm": "5.21.1",
"@sentry/core": "5.21.1",
"@sentry/hub": "5.21.1",
"@sentry/types": "5.21.1",
"@sentry/utils": "5.21.1",
"cookie": "^0.4.1",
"https-proxy-agent": "^5.0.0",
"lru_map": "^0.3.3",
@@ -1418,16 +1418,16 @@
}
},
"@sentry/types": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.20.1.tgz",
"integrity": "sha512-OU+i/lcjGpDJv0XkNpsKrI2r1VPp8qX0H6Knq8NuZrlZe3AbvO3jRJJK0pH14xFv8Xok5jbZZpKKoQLxYfxqsw=="
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.21.1.tgz",
"integrity": "sha512-hFN4aDduMpjj6vZSIIp+9kSr8MglcKO/UmbuUXN6hKLewhxt+Zj2wjXN7ulSs5OK5mjXP9QLA5YJvVQsl2//qw=="
},
"@sentry/utils": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.20.1.tgz",
"integrity": "sha512-dhK6IdO6g7Q2CoxCbB+q8gwUapDUH5VjraFg0UBzgkrtNhtHLylqmwx0sWQvXCcp14Q/3MuzEbb4euvoh8o8oA==",
"version": "5.21.1",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.21.1.tgz",
"integrity": "sha512-p5vPuc7+GfOmW8CXxWd0samS77Q00YrN8q5TC/ztF8nBhEF18GiMeWAdQnlSwt3iWal3q3gSSrbF4c9guIugng==",
"requires": {
"@sentry/types": "5.20.1",
"@sentry/types": "5.21.1",
"tslib": "^1.9.3"
}
},
@@ -3782,9 +3782,9 @@
}
},
"ip-sub": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/ip-sub/-/ip-sub-1.0.9.tgz",
"integrity": "sha512-I0FfIJBq8XKkNNYA18xrTxstBee+sYK6fUN0SHyjBNJmn7HabKaadY1yps1XZ57reikHC3ko0km/SAX+1Wmc0Q==",
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/ip-sub/-/ip-sub-1.0.10.tgz",
"integrity": "sha512-jCoHAdI2Xx+Owpe7tZSqFGMOuFWrcIxKem0QQydp4Btxg6mCKNizayWYWntTElEsEwLUyrFkNevkJiH6b7DhvA==",
"requires": {
"ip-address": "^6.3.0"
}
@@ -6070,13 +6070,13 @@
}
},
"rpki-validator": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/rpki-validator/-/rpki-validator-2.2.0.tgz",
"integrity": "sha512-+dMZtCPVj4JHQXGWoYVSiTbWJYIIRaDN4F1/wXRKD1qwDAO8ngWlb69ItoZRmV8f/YL1gZz8zhsfHvzu8Apx7g==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/rpki-validator/-/rpki-validator-2.2.1.tgz",
"integrity": "sha512-HqH5DKY0RsUOZ5CXaEUTpP+HKaSPI+HTlfXo44TKwFHBI5uB1RmKyl4/GPLNyx98G00+zZzINrxk2WA3k6CFRw==",
"requires": {
"axios": "^0.19.2",
"brembo": "^2.0.4",
"ip-sub": "^1.0.9",
"ip-sub": "^1.0.10",
"radix-trie-js": "^1.0.5"
}
},

View File

@@ -14,7 +14,7 @@
"test-reports": "./node_modules/.bin/mocha --exit tests/reports_tests/*.js --require @babel/register",
"test-proxy": "./node_modules/.bin/mocha --exit tests/proxy_tests/*.js --require @babel/register",
"test-generate": "./node_modules/.bin/mocha --exit tests/generate_tests/*.js --require @babel/register",
"test-rpki": "./node_modules/.bin/mocha --exit tests/rpki_tests/tests.default.js --require @babel/register && ./node_modules/.bin/mocha --exit tests/rpki_tests/tests.external.js --require @babel/register",
"test-rpki": "./node_modules/.bin/mocha --exit tests/rpki_tests/tests.default.js --require @babel/register && ./node_modules/.bin/mocha --exit tests/rpki_tests/tests.external.js --require @babel/register && ./node_modules/.bin/mocha --exit tests/rpki_tests/tests.external-removed.js --require @babel/register",
"build": "./build.sh",
"watch-and-serve": "nodemon -e yml,js,json,txt --inspect --exec babel-node index.js",
"serve": "babel-node index.js",
@@ -40,20 +40,20 @@
"syslogd": "^1.1.2"
},
"dependencies": {
"@sentry/node": "^5.20.1",
"@sentry/node": "^5.21.1",
"axios": "^0.19.2",
"batch-promises": "^0.0.3",
"brembo": "^2.0.4",
"https-proxy-agent": "^5.0.0",
"inquirer": "^7.3.3",
"ip-address": "^6.3.0",
"ip-sub": "^1.0.9",
"ip-sub": "^1.0.10",
"js-yaml": "^3.14.0",
"kafka-node": "^5.0.0",
"nodemailer": "^6.4.11",
"path": "^0.12.7",
"restify": "^8.5.1",
"rpki-validator": "^2.2.0",
"rpki-validator": "^2.2.1",
"semver": "^7.3.2",
"syslog-client": "^1.1.1",
"ws": "^7.3.1",

View File

@@ -9,8 +9,9 @@ export default class MonitorRPKI extends Monitor {
this.providers = [ "ntt", "ripe", "external"]; // First provider is the default one
this.refreshVrpListMinutes = this.params.refreshVrpListMinutes || 15;
this.refreshVrpListMinutes = (!!this.params.vrpFile) ? 0 : Math.max(this.params.refreshVrpListMinutes || 0, 15);
this.preCacheROAs = this.params.preCacheROAs !== false;
this.cacheValidPrefixesSeconds = 3600 * 24 * 4 * 1000;
this.input.onChange(() => {
this.updateMonitoredResources();
@@ -19,6 +20,12 @@ export default class MonitorRPKI extends Monitor {
this.thresholdMinPeers = (params && params.thresholdMinPeers != null) ? params.thresholdMinPeers : 1;
this.validationQueue = [];
this.seenRpkiValidAnnouncementsKey = "seen-rpki-valid-announcements";
this.storage
.get(this.seenRpkiValidAnnouncementsKey)
.then(prefixes => {
this.seenRpkiValidAnnouncements = (prefixes) ? prefixes : {};
});
this.loadRpkiValidator(env);
};
@@ -76,7 +83,7 @@ export default class MonitorRPKI extends Monitor {
if (!!this.preCacheROAs) {
this.rpki
.preCache(Math.max(this.refreshVrpListMinutes, 15))
.preCache(this.refreshVrpListMinutes)
.then(() => {
this.validationTimer = setInterval(this.validateBatch, 100); // If already cached, we can validate more often
})
@@ -102,42 +109,47 @@ export default class MonitorRPKI extends Monitor {
} else {
if (fs.existsSync(vrpFile)) {
try {
const vrps = JSON.parse(fs.readFileSync(vrpFile));
let vrps = JSON.parse(fs.readFileSync(vrpFile, 'utf8'));
if (vrps.length > 0) {
if (this.validationTimer) {
clearInterval(this.validationTimer); // Stop validation cycle
if (vrps) {
if (vrps.roas && vrps.roas.length) {
vrps = vrps.roas;
}
if (vrps.length > 0) {
if (this.rpki) {
this.rpki.destroy();
}
if (this.validationTimer) {
clearInterval(this.validationTimer); // Stop validation cycle
}
this.rpki = new rpki({
connector: "external",
clientId: env.clientId
});
if (this.rpki) {
this.rpki.destroy();
}
this.rpki.setVRPs(vrps);
this.rpki
.preCache()
.then(() => {
this.validationTimer = setInterval(this.validateBatch, 100); // If already cached, we can validate more often
})
.catch(() => {
this.logger.log({
level: 'error',
message: "It was not possible to load correctly the VRPs file. Possibly there is an error in the format. The RPKI monitoring should be working anyway with one of the on-line providers."
});
this.rpki = new rpki({
connector: "external",
clientId: env.clientId
});
} else {
this.logger.log({
level: 'error',
message: "The provided VRPs file is empty. Using default vrpProvider."
});
this.rpki.setVRPs(vrps);
this.rpki
.preCache(this.refreshVrpListMinutes)
.then(() => {
this.validationTimer = setInterval(this.validateBatch, 100); // If already cached, we can validate more often
})
.catch(() => {
this.logger.log({
level: 'error',
message: "It was not possible to load correctly the VRPs file. Possibly there is an error in the format. The RPKI monitoring should be working anyway with one of the on-line providers."
});
});
} else {
this.logger.log({
level: 'error',
message: "The provided VRPs file is empty. Using default vrpProvider."
});
}
}
} catch (error) {
@@ -181,9 +193,11 @@ export default class MonitorRPKI extends Monitor {
const covering = (extra.covering && extra.covering.length) ? extra.covering.map(i => `${i.prefix}|AS${i.asn}|maxLength:${i.maxLength}`).join(", ") : false;
const coveringString = (covering) ? `Valid ROAs: ${covering}`: '';
if (extra.valid === null && this.params.checkUncovered) {
if (extra.roaDisappeared) {
return `The route ${message.prefix} announced by ${message.originAS} is no longer covered by a ROA.`;
} else if (extra.valid === null && this.params.checkUncovered) {
return `The route ${message.prefix} announced by ${message.originAS} is not covered by a ROA`;
} else {
} else if (extra.valid === false) {
return `The route ${message.prefix} announced by ${message.originAS} is not RPKI valid. ${coveringString}`;
}
}
@@ -194,41 +208,75 @@ export default class MonitorRPKI extends Monitor {
const origin = message.originAS.getValue();
this.rpki
.validate(prefix, origin.toString(), true)
.then(result => {
if (result) {
const key = "a" + [prefix, origin, result.valid]
.join("-")
.replace(/\./g, "_")
.replace(/\:/g, "_")
.replace(/\//g, "_");
.preCache(this.refreshVrpListMinutes)
.then(() => {
return this.rpki
.validate(prefix, origin.toString(), true)
.then(result => {
if (result) {
if (result.valid === false) {
this.publishAlert(key,
prefix,
matchedRule,
message,
{ covering: result.covering, valid: result.valid });
} else if (result.valid === null && this.params.checkUncovered) {
this.publishAlert(key,
prefix,
matchedRule,
message,
{ covering: null, valid: null });
}
}
})
.catch(error => {
this.logger.log({
level: 'error',
message: error
});
const cacheKey = "a" + [prefix, origin]
.join("-")
.replace(/\./g, "_")
.replace(/\:/g, "_")
.replace(/\//g, "_");
const key = `${cacheKey}-${result.valid}`;
if (result.valid === null) {
const cache = this.seenRpkiValidAnnouncements[cacheKey];
if (cache && cache.rpkiValid && cache.date + this.cacheValidPrefixesSeconds >= new Date().getTime()) { // valid cache
this.publishAlert(key,
prefix,
matchedRule,
message,
{ covering: null, valid: null, roaDisappeared: true });
} else if (this.params.checkUncovered) {
this.publishAlert(key,
prefix,
matchedRule,
message,
{ covering: null, valid: null });
}
} else if (result.valid === false) {
this.publishAlert(key,
prefix,
matchedRule,
message,
{ covering: result.covering, valid: false });
} else if (result.valid) {
// Refresh dictionary
this.seenRpkiValidAnnouncements[cacheKey] = {
date: new Date().getTime(),
rpkiValid: true
};
if (this.seenRpkiValidAnnouncementsTimer) {
clearTimeout(this.seenRpkiValidAnnouncementsTimer);
}
// Store dictionary
this.seenRpkiValidAnnouncementsTimer = setTimeout(() => {
this.storage
.set(this.seenRpkiValidAnnouncementsKey, this.seenRpkiValidAnnouncements);
}, 1000);
}
}
})
.catch(error => {
this.logger.log({
level: 'error',
message: error
});
});
});
};
monitor = (message) => {
const messageOrigin = message.originAS;
@@ -246,7 +294,4 @@ export default class MonitorRPKI extends Monitor {
return Promise.resolve(true);
};
}

View File

@@ -1,4 +1,4 @@
export default class PubSub{
export default class PubSub {
constructor() {
this.callbacks = {};
};

View File

@@ -7,7 +7,7 @@ export default class Storage {
};
set = (key, value) => {
if (/^[a-z\-]+$/i.test(key)) {
if (/^[A-Za-z0-9\-_]+$/i.test(key)) {
const envelop = {
date: new Date().getTime(),
value
@@ -21,22 +21,17 @@ export default class Storage {
};
get = (key) => {
if (/^[a-z\-]+$/i.test(key)) {
return this._get(key)
.then((data) => {
if (!!data) {
const { date, value } = data;
const now = new Date().getTime();
if (date + this.validity >= now) {
return value;
}
return this._get(key)
.then((data) => {
if (!!data) {
const { date, value } = data;
const now = new Date().getTime();
if (date + this.validity >= now) {
return value;
}
return {};
});
} else {
return Promise.reject("Not a valid key. Use only chars and dashes.");
}
}
return {};
});
};
_set = (key, value) => {

View File

@@ -31,15 +31,22 @@
*/
const chai = require("chai");
const fs = require("fs");
const chaiSubset = require('chai-subset');
const expect = chai.expect;
const asyncTimeout = 200000;
chai.use(chaiSubset);
const cacheFile = ".cache/seen-rpki-valid-announcements.json";
if (fs.existsSync(cacheFile)) {
fs.unlinkSync(cacheFile);
}
global.EXTERNAL_CONFIG_FILE = "tests/rpki_tests/config.rpki.test.default.yml";
const worker = require("../../index");
const pubSub = worker.pubSub;
describe("RPKI monitoring 1", function() {
it("default connector", function (done) {
@@ -53,8 +60,8 @@ describe("RPKI monitoring 1", function() {
message: 'The route 103.21.244.0/24 announced by AS13335 is not RPKI valid. Valid ROAs: 103.21.244.0/23|AS0|maxLength:23',
},
"a8_8_8_8_22-2914-": {
id: "a8_8_8_8_22-2914-",
"a8_8_8_8_22-2914-null": {
id: "a8_8_8_8_22-2914-null",
origin: 'rpki-monitor',
affected: '8.8.8.8/22',
message: 'The route 8.8.8.8/22 announced by AS2914 is not covered by a ROA',

View File

@@ -0,0 +1,110 @@
/*
* BSD 3-Clause License
*
* Copyright (c) 2019, NTT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
const chai = require("chai");
const chaiSubset = require('chai-subset');
const fs = require('fs');
const expect = chai.expect;
const asyncTimeout = 200000;
chai.use(chaiSubset);
global.EXTERNAL_CONFIG_FILE = "tests/rpki_tests/config.rpki.test.external.yml";
fs.copyFileSync("tests/rpki_tests/vrp.missing.json", "tests/rpki_tests/vrp.json");
const worker = require("../../index");
const pubSub = worker.pubSub;
describe("RPKI monitoring 3", function() {
it("missing roas", function (done) {
const expectedData = {
"a82_112_100_0_24-2914-null": {
id: 'a82_112_100_0_24-2914-null',
origin: 'rpki-monitor',
affected: '82.112.100.0/24',
message: 'The route 82.112.100.0/24 announced by AS2914 is no longer covered by a ROA.'
},
"a8_8_8_8_22-2914-null" : {
id: 'a8_8_8_8_22-2914-null',
origin: 'rpki-monitor',
affected: '8.8.8.8/22',
message: 'The route 8.8.8.8/22 announced by AS2914 is no longer covered by a ROA.'
},
"a103_21_244_0_24-13335-null": {
id: 'a103_21_244_0_24-13335-null',
origin: 'rpki-monitor',
affected: '103.21.244.0/24',
message: 'The route 103.21.244.0/24 announced by AS13335 is no longer covered by a ROA.'
}
};
let rpkiTestCompletedExternal = false;
pubSub.subscribe("rpki", function (type, message) {
if (!rpkiTestCompletedExternal) {
message = JSON.parse(JSON.stringify(message));
const id = message.id;
expect(Object.keys(expectedData).includes(id)).to.equal(true);
expect(expectedData[id] != null).to.equal(true);
expect(message).to.containSubset(expectedData[id]);
expect(message).to.contain
.keys([
"latest",
"earliest"
]);
delete expectedData[id];
if (Object.keys(expectedData).length === 0) {
setTimeout(() => {
rpkiTestCompletedExternal = true;
fs.unlinkSync("tests/rpki_tests/vrp.json");
done();
}, 5000);
}
}
});
setTimeout(() => { // Wait that the watcher realizes the file changed
pubSub.publish("test-type", "rpki");
}, 5000);
}).timeout(asyncTimeout);
});

View File

@@ -0,0 +1,7 @@
[
{
"asn": "13335",
"prefix": "203.21.244.0/24",
"maxLength": 24
}
]