From a363fadedbdfd5b4afd548e46f7014d2dc88d62f Mon Sep 17 00:00:00 2001 From: Massimo Candela Date: Mon, 4 Jan 2021 07:06:43 +0100 Subject: [PATCH] fixed include/excludeMonitor for monitorRPKI (#441) and improved tests --- src/connectors/connectorRIS.js | 3 +- src/connectors/connectorTest.js | 77 +++++++++++++++++--------- src/inputs/input.js | 2 +- src/monitors/monitor.js | 27 +++++++-- src/monitors/monitorHijack.js | 3 +- src/monitors/monitorNewPrefix.js | 6 +- src/monitors/monitorRPKI.js | 28 ++++++---- src/monitors/monitorVisibility.js | 2 +- tests/reports_tests/testsReportHttp.js | 1 + 9 files changed, 100 insertions(+), 49 deletions(-) diff --git a/src/connectors/connectorRIS.js b/src/connectors/connectorRIS.js index d8ddabb6..7821e83f 100644 --- a/src/connectors/connectorRIS.js +++ b/src/connectors/connectorRIS.js @@ -141,7 +141,7 @@ export default class ConnectorRIS extends Connector { if (monitoredPrefixes .filter( - i => (ipUtils._isEqualPrefix(i.prefix, '0:0:0:0:0:0:0:0/0') || ipUtils._isEqualPrefix(i.prefix,'0.0.0.0/0')) + i => (ipUtils.isEqualPrefix(i.prefix, '0:0:0:0:0:0:0:0/0') || ipUtils.isEqualPrefix(i.prefix,'0.0.0.0/0')) ).length === 2) { delete params.prefix; @@ -307,6 +307,5 @@ export default class ConnectorRIS extends Connector { } else if (message.type === 'ris_error') { throw new Error("Error from RIS: " + message.data.message); } - } }; diff --git a/src/connectors/connectorTest.js b/src/connectors/connectorTest.js index e73b2818..75e1d2d8 100644 --- a/src/connectors/connectorTest.js +++ b/src/connectors/connectorTest.js @@ -32,6 +32,7 @@ import Connector from "./connector"; import {AS, Path} from "../model"; +import ipUtils from "ip-sub"; export default class ConnectorTest extends Connector{ @@ -451,41 +452,65 @@ export default class ConnectorTest extends Connector{ static transform = (message) => { if (message.type === 'ris_message') { - message = message.data; - const components = []; - const announcements = message["announcements"] || []; - const withdrawals = message["withdrawals"] || []; - const aggregator = message["aggregator"] || null; - const peer = message["peer"]; + try { + message = message.data; + const components = []; + const announcements = message["announcements"] || []; + const aggregator = message["aggregator"] || null; + const withdrawals = message["withdrawals"] || []; + const peer = message["peer"]; + const communities = message["community"] || []; + const timestamp = message["timestamp"] * 1000; + let path, originAS; - for (let announcement of announcements){ - const nextHop = announcement["next_hop"]; - const prefixes = announcement["prefixes"] || []; - let path = new Path(message["path"].map(i => new AS(i))); - let originAS = path.getLast(); + if (message["path"] && message["path"].length) { + path = new Path(message["path"].map(i => new AS(i))); + originAS = path.getLast(); + } else { + path = new Path([]); + originAS = null; + } + + if (originAS && path.length()) { + for (let announcement of announcements) { + const nextHop = announcement["next_hop"]; + + if (ipUtils.isValidIP(nextHop)) { + const prefixes = (announcement["prefixes"] || []) + .filter(prefix => ipUtils.isValidPrefix(prefix)); + + for (let prefix of prefixes) { + components.push({ + type: "announcement", + prefix, + peer, + path, + originAS, + nextHop, + aggregator, + timestamp, + communities + }); + } + } + } + } - for (let prefix of prefixes){ + for (let prefix of withdrawals) { components.push({ - type: "announcement", + type: "withdrawal", prefix, peer, - path, - originAS, - nextHop, - aggregator + timestamp }) } - } - for (let prefix of withdrawals){ - components.push({ - type: "withdrawal", - prefix, - peer - }) + return components; + } catch (error) { + throw new Error(`Error during transform (${this.name}): ` + error.message); } - - return components; + } else if (message.type === 'ris_error') { + throw new Error("Error from RIS: " + message.data.message); } }; } \ No newline at end of file diff --git a/src/inputs/input.js b/src/inputs/input.js index a95fe31b..c0f86778 100644 --- a/src/inputs/input.js +++ b/src/inputs/input.js @@ -121,7 +121,7 @@ export default class Input { getMoreSpecificMatch = (prefix, includeIgnoredMorespecifics) => { for (let p of this.prefixes) { - if (ipUtils._isEqualPrefix(p.prefix, prefix)) { // Used internal method to avoid validation overhead + if (ipUtils.isEqualPrefix(p.prefix, prefix)) { return p; } else { diff --git a/src/monitors/monitor.js b/src/monitors/monitor.js index 695226e1..0e972a9e 100644 --- a/src/monitors/monitor.js +++ b/src/monitors/monitor.js @@ -253,18 +253,35 @@ export default class Monitor { return m; } } + + return null; + }; + + _included = (matched) => { + if (matched.includeMonitors.length > 0) { + return matched.includeMonitors.includes(this.name); + } else { + return !matched.excludeMonitors.includes(this.name); + } }; - getMoreSpecificMatch = (prefix, includeIgnoredMorespecifics) => { + getMoreSpecificMatch = (prefix, includeIgnoredMorespecifics, verbose=false) => { const matched = this.input.getMoreSpecificMatch(prefix, includeIgnoredMorespecifics); if (matched) { - if (matched.includeMonitors.length > 0 && !matched.includeMonitors.includes(this.name)) { - return null; - } + const included = this._included(matched); - return (matched.excludeMonitors.includes(this.name)) ? null : matched; + if (verbose) { + return { + matched, + included + }; + } else if (included) { + return matched; + } } + + return null; }; } \ No newline at end of file diff --git a/src/monitors/monitorHijack.js b/src/monitors/monitorHijack.js index a66442dd..30ce52bd 100644 --- a/src/monitors/monitorHijack.js +++ b/src/monitors/monitorHijack.js @@ -57,7 +57,7 @@ export default class MonitorHijack extends Monitor { const message = alerts[0].matchedMessage; const asnText = matchedRule.asn; - return (ipUtils._isEqualPrefix(message.prefix, matchedRule.prefix)) ? + return (ipUtils.isEqualPrefix(message.prefix, matchedRule.prefix)) ? `The prefix ${matchedRule.prefix} (${matchedRule.description}) is announced by ${message.originAS} instead of ${asnText}` : `A new prefix ${message.prefix} is announced by ${message.originAS}. ` + `It should be instead ${matchedRule.prefix} (${matchedRule.description}) announced by ${asnText}`; @@ -80,7 +80,6 @@ export default class MonitorHijack extends Monitor { } } - monitor = (message) => new Promise((resolve, reject) => { diff --git a/src/monitors/monitorNewPrefix.js b/src/monitors/monitorNewPrefix.js index 7b84e01b..e053a62b 100644 --- a/src/monitors/monitorNewPrefix.js +++ b/src/monitors/monitorNewPrefix.js @@ -31,6 +31,7 @@ */ import Monitor from "./monitor"; +import ipUtils from "ip-sub"; export default class MonitorNewPrefix extends Monitor { @@ -56,7 +57,6 @@ export default class MonitorNewPrefix extends Monitor { const matchedRule = alerts[0].matchedRule; return `Possible change of configuration. A new prefix ${message.prefix} is announced by ${message.originAS}. It is a more specific of ${matchedRule.prefix} (${matchedRule.description})`; - } return false; @@ -68,7 +68,9 @@ export default class MonitorNewPrefix extends Monitor { const messagePrefix = message.prefix; const matchedRule = this.getMoreSpecificMatch(messagePrefix, false); - if (matchedRule && !matchedRule.ignore && matchedRule.asn.includes(message.originAS) && matchedRule.prefix !== messagePrefix) { + if (matchedRule && !matchedRule.ignore && + matchedRule.asn.includes(message.originAS) && + !ipUtils.isEqualPrefix(matchedRule.prefix, messagePrefix)) { this.publishAlert(message.originAS.getId() + "-" + message.prefix, matchedRule.asn.getId(), diff --git a/src/monitors/monitorRPKI.js b/src/monitors/monitorRPKI.js index eb6974a4..5d77f135 100644 --- a/src/monitors/monitorRPKI.js +++ b/src/monitors/monitorRPKI.js @@ -179,19 +179,27 @@ export default class MonitorRPKI extends Monitor { }; monitor = (message) => { + try { + const messageOrigin = message.originAS; + const prefix = message.prefix; - const messageOrigin = message.originAS; - const prefix = message.prefix; + const matchedPrefixRule = this.getMoreSpecificMatch(prefix, false, true); - const matchedPrefixRule = this.getMoreSpecificMatch(prefix, false); - - if (matchedPrefixRule && !matchedPrefixRule.ignore) { - this.validate(message, matchedPrefixRule); - } else { - const matchedASRule = this.getMonitoredAsMatch(messageOrigin); - if (matchedASRule) { - this.validate(message, matchedASRule); + if (matchedPrefixRule.matched) { // There is a prefix match + if (!matchedPrefixRule.matched.ignore && matchedPrefixRule.included) { // The prefix match is not excluded in any way + this.validate(message, matchedPrefixRule.matched); + } + } else { // No prefix match + const matchedASRule = this.getMonitoredAsMatch(messageOrigin); // Try AS match + if (matchedASRule) { + this.validate(message, matchedASRule); + } } + } catch (error) { + this.logger.log({ + level: 'error', + message: error + }); } return Promise.resolve(true); diff --git a/src/monitors/monitorVisibility.js b/src/monitors/monitorVisibility.js index 2b9271a7..0b3c74e2 100644 --- a/src/monitors/monitorVisibility.js +++ b/src/monitors/monitorVisibility.js @@ -77,7 +77,7 @@ export default class MonitorVisibility extends Monitor { const messagePrefix = message.prefix; const matchedRule = this.getMoreSpecificMatch(messagePrefix, false); - if (matchedRule && !matchedRule.ignore && ipUtils._isEqualPrefix(matchedRule.prefix, messagePrefix)) { + if (matchedRule && !matchedRule.ignore && ipUtils.isEqualPrefix(matchedRule.prefix, messagePrefix)) { let key = matchedRule.prefix; diff --git a/tests/reports_tests/testsReportHttp.js b/tests/reports_tests/testsReportHttp.js index 3314c325..b63f1b07 100644 --- a/tests/reports_tests/testsReportHttp.js +++ b/tests/reports_tests/testsReportHttp.js @@ -50,6 +50,7 @@ describe("Reports 2", function() { server.use(restify.plugins.bodyParser({ mapParams: true })); let expectedData = [ "The prefix 2a00:5884::/32 (alarig fix test) is announced by AS15563 instead of AS204092, and AS45. Top 1 most used AS paths: [2,3,15563].", + "A new prefix 165.254.255.0/25 is announced by AS15562, and AS4. It should be instead 165.254.255.0/24 (description 2) announced by AS15562. Top 1 most used AS paths: [2,3,[15562,4]].", "A new prefix 2a00:5884:ffff::/48 is announced by AS208585. It should be instead 2a00:5884::/32 (alarig fix test) announced by AS204092, and AS45. Top 1 most used AS paths: [2,3,208585].", ];