From 63cd9fd34a5d95893b54efc351fb86e1c0b12838 Mon Sep 17 00:00:00 2001 From: Massimo Candela Date: Fri, 14 Aug 2020 15:10:38 +0200 Subject: [PATCH] added feature to monitor for disappearing ROAs --- package-lock.json | 106 ++++++------ package.json | 8 +- src/monitors/monitorRPKI.js | 177 +++++++++++++-------- src/utils/pubSub.js | 2 +- src/utils/storage.js | 27 ++-- tests/rpki_tests/tests.default.js | 11 +- tests/rpki_tests/tests.external-removed.js | 110 +++++++++++++ tests/rpki_tests/vrp.missing.json | 7 + 8 files changed, 306 insertions(+), 142 deletions(-) create mode 100644 tests/rpki_tests/tests.external-removed.js create mode 100644 tests/rpki_tests/vrp.missing.json diff --git a/package-lock.json b/package-lock.json index 052d939..a78e780 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" } }, diff --git a/package.json b/package.json index 41c7bbc..fb26245 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/monitors/monitorRPKI.js b/src/monitors/monitorRPKI.js index 57feccd..fb02aaa 100644 --- a/src/monitors/monitorRPKI.js +++ b/src/monitors/monitorRPKI.js @@ -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); }; - - - } diff --git a/src/utils/pubSub.js b/src/utils/pubSub.js index 1ac3396..70d2a46 100644 --- a/src/utils/pubSub.js +++ b/src/utils/pubSub.js @@ -1,4 +1,4 @@ -export default class PubSub{ +export default class PubSub { constructor() { this.callbacks = {}; }; diff --git a/src/utils/storage.js b/src/utils/storage.js index 2f31033..fb2b8e5 100644 --- a/src/utils/storage.js +++ b/src/utils/storage.js @@ -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) => { diff --git a/tests/rpki_tests/tests.default.js b/tests/rpki_tests/tests.default.js index 1166b3a..86a2e3b 100644 --- a/tests/rpki_tests/tests.default.js +++ b/tests/rpki_tests/tests.default.js @@ -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', diff --git a/tests/rpki_tests/tests.external-removed.js b/tests/rpki_tests/tests.external-removed.js new file mode 100644 index 0000000..324ea56 --- /dev/null +++ b/tests/rpki_tests/tests.external-removed.js @@ -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); +}); \ No newline at end of file diff --git a/tests/rpki_tests/vrp.missing.json b/tests/rpki_tests/vrp.missing.json new file mode 100644 index 0000000..15dc037 --- /dev/null +++ b/tests/rpki_tests/vrp.missing.json @@ -0,0 +1,7 @@ +[ + { + "asn": "13335", + "prefix": "203.21.244.0/24", + "maxLength": 24 + } +] \ No newline at end of file