mirror of
https://github.com/nttgin/BGPalerter.git
synced 2024-05-19 06:50:08 +00:00
improved accuracy rules matching
This commit is contained in:
@@ -154,6 +154,17 @@ export default class ConnectorTest extends Connector{
|
||||
path: "1,2,3,204092".split(",").map(i => parseInt(i))
|
||||
},
|
||||
type: "ris_message"
|
||||
},
|
||||
{
|
||||
data: {
|
||||
announcements: [{
|
||||
prefixes: ["2a0e:f40::/32"],
|
||||
next_hop: "124.0.0.3"
|
||||
}],
|
||||
peer: "124.0.0.3",
|
||||
path: "1,2,3,204092".split(",").map(i => parseInt(i))
|
||||
},
|
||||
type: "ris_message"
|
||||
}
|
||||
];
|
||||
break;
|
||||
@@ -180,6 +191,13 @@ export default class ConnectorTest extends Connector{
|
||||
peer: "124.0.0.2"
|
||||
},
|
||||
type: "ris_message"
|
||||
},
|
||||
{
|
||||
data: {
|
||||
withdrawals: ["2a0e:f40::/32"],
|
||||
peer: "124.0.0.2"
|
||||
},
|
||||
type: "ris_message"
|
||||
}
|
||||
];
|
||||
break;
|
||||
@@ -189,7 +207,7 @@ export default class ConnectorTest extends Connector{
|
||||
|
||||
this.timer = setInterval(() => {
|
||||
updates.forEach(update => {
|
||||
this.message(JSON.stringify(update));
|
||||
this._message(JSON.stringify(update));
|
||||
if (type === 'visibility') {
|
||||
let peer = update.data.peer.split('.');
|
||||
peer[3] = Math.min(parseInt(peer[3]) + 1, 254);
|
||||
|
||||
@@ -36,6 +36,8 @@ import ipUtils from "../ipUtils";
|
||||
export default class Input {
|
||||
|
||||
constructor(config){
|
||||
this.prefixes = [];
|
||||
this.cache = {};
|
||||
};
|
||||
|
||||
validateAS = (asn) => {
|
||||
@@ -60,4 +62,28 @@ export default class Input {
|
||||
throw new Error('The method getMonitoredPrefixes MUST be implemented');
|
||||
};
|
||||
|
||||
getMoreSpecificMatch = (prefix) => {
|
||||
|
||||
for (let p of this.prefixes) {
|
||||
if (p.prefix === prefix) {
|
||||
return p;
|
||||
} else {
|
||||
if (!this.cache[p.prefix]) {
|
||||
this.cache[p.prefix] = ipUtils.getNetmask(p.prefix);
|
||||
}
|
||||
const p2 = ipUtils.getNetmask(prefix);
|
||||
|
||||
if (ipUtils.isSubnetBinary(this.cache[p.prefix], p2)) {
|
||||
if (p.ignoreMorespecifics){
|
||||
return null;
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
import Input from "./input";
|
||||
import env from "../env";
|
||||
import ipUtils from "../ipUtils";
|
||||
|
||||
export default class InputYml extends Input {
|
||||
|
||||
@@ -70,9 +71,12 @@ export default class InputYml extends Input {
|
||||
|
||||
this.prefixes = this.prefixes.concat(monitoredPrefixes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.prefixes = this.prefixes.sort((a, b) => {
|
||||
return ipUtils.sortByPrefixLength(b.prefix, a.prefix);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
validate = (fileContent) => {
|
||||
|
||||
13
ipUtils.js
13
ipUtils.js
@@ -47,7 +47,7 @@ const ip = {
|
||||
|
||||
toDecimal: function(ip) {
|
||||
let bytes = "";
|
||||
if (ip.indexOf(":") == -1) {
|
||||
if (ip.indexOf(":") === -1) {
|
||||
bytes = ip.split(".").map(ip => parseInt(ip).toString(2).padStart(8, '0')).join("");
|
||||
} else {
|
||||
bytes = ip.split(":").filter(ip => ip !== "").map(ip => parseInt(ip, 16).toString(2).padStart(16, '0')).join("");
|
||||
@@ -63,7 +63,7 @@ const ip = {
|
||||
|
||||
let binaryRoot;
|
||||
|
||||
if (ip.indexOf(":") == -1){
|
||||
if (ip.indexOf(":") === -1){
|
||||
binaryRoot = this.toDecimal(ip).padEnd(32, '0').slice(0, bits);
|
||||
} else {
|
||||
binaryRoot = this.toDecimal(ip).padEnd(128, '0').slice(0, bits);
|
||||
@@ -73,11 +73,12 @@ const ip = {
|
||||
|
||||
},
|
||||
|
||||
isSubnet: function (prefixContainer, prefixContained) {
|
||||
prefixContained = this.getNetmask(prefixContained);
|
||||
prefixContainer = this.getNetmask(prefixContainer);
|
||||
|
||||
isSubnetBinary: (prefixContainer, prefixContained) => {
|
||||
return prefixContained != prefixContainer && prefixContained.includes(prefixContainer);
|
||||
},
|
||||
|
||||
isSubnet: function (prefixContainer, prefixContained) {
|
||||
return this.isSubnetBinary(this.getNetmask(prefixContainer), this.getNetmask(prefixContained));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -55,31 +55,20 @@ export default class MonitorHijack extends Monitor {
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
const messagePrefix = message.prefix;
|
||||
const matchedRule = this.input.getMoreSpecificMatch(messagePrefix);
|
||||
|
||||
let matches = this.monitored.filter(item => {
|
||||
const sameOrigin = item.asn.includes(message.originAs);
|
||||
return !sameOrigin &&
|
||||
(item.prefix == messagePrefix ||
|
||||
(!item.ignoreMorespecifics && ipUtils.isSubnet(item.prefix, messagePrefix)));
|
||||
});
|
||||
if (matches.length > 1) {
|
||||
matches = [matches.sort((a, b) => ipUtils.sortByPrefixLength(a.prefix, b.prefix)).pop()];
|
||||
}
|
||||
if (matchedRule && !matchedRule.asn.includes(message.originAs)) {
|
||||
const asnText = matchedRule.asn.join(", or AS");
|
||||
|
||||
if (matches.length !== 0) {
|
||||
const match = matches[0];
|
||||
|
||||
const asnText = match.asn.join(", or AS");
|
||||
|
||||
const text = (message.prefix === match.prefix) ?
|
||||
`The prefix ${match.prefix} (${match.description}) is announced by AS${message.originAs} instead of AS${asnText}` :
|
||||
const text = (message.prefix === matchedRule.prefix) ?
|
||||
`The prefix ${matchedRule.prefix} (${matchedRule.description}) is announced by AS${message.originAs} instead of AS${asnText}` :
|
||||
`A new prefix ${message.prefix} is announced by AS${message.originAs}. ` +
|
||||
`It should be instead ${match.prefix} (${match.description}) announced by AS${asnText}`;
|
||||
`It should be instead ${matchedRule.prefix} (${matchedRule.description}) announced by AS${asnText}`;
|
||||
|
||||
this.publishAlert(message.originAs + "-" + message.prefix,
|
||||
text,
|
||||
match.asn[0],
|
||||
matches[0],
|
||||
matchedRule.asn[0],
|
||||
matchedRule,
|
||||
message,
|
||||
{});
|
||||
}
|
||||
|
||||
@@ -56,27 +56,15 @@ export default class MonitorNewPrefix extends Monitor {
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
const messagePrefix = message.prefix;
|
||||
const matchedRule = this.input.getMoreSpecificMatch(messagePrefix);
|
||||
|
||||
let matches = this.monitored.filter(item => {
|
||||
const sameOrigin = item.asn.includes(message.originAs);
|
||||
|
||||
return sameOrigin &&
|
||||
item.prefix != messagePrefix &&
|
||||
ipUtils.isSubnet(item.prefix, messagePrefix);
|
||||
});
|
||||
|
||||
if (matches.length > 1) {
|
||||
matches = [matches.sort((a, b) => ipUtils.sortByPrefixLength(a.prefix, b.prefix)).pop()];
|
||||
}
|
||||
|
||||
if (matches.length !== 0) {
|
||||
const match = matches[0];
|
||||
const text = `Possible change of configuration. A new prefix ${message.prefix} is announced by AS${message.originAs}. It is a more specific of ${match.prefix} (${match.description}).`;
|
||||
if (matchedRule && matchedRule.asn.includes(message.originAs) && matchedRule.prefix !== messagePrefix) {
|
||||
const text = `Possible change of configuration. A new prefix ${message.prefix} is announced by AS${message.originAs}. It is a more specific of ${matchedRule.prefix} (${matchedRule.description}).`;
|
||||
|
||||
this.publishAlert(message.originAs + "-" + message.prefix,
|
||||
text,
|
||||
match.asn[0],
|
||||
matches[0],
|
||||
matchedRule.asn[0],
|
||||
matchedRule,
|
||||
message,
|
||||
{});
|
||||
}
|
||||
|
||||
@@ -68,22 +68,17 @@ export default class MonitorVisibility extends Monitor {
|
||||
new Promise((resolve, reject) => {
|
||||
|
||||
const messagePrefix = message.prefix;
|
||||
const matchedRule = this.input.getMoreSpecificMatch(messagePrefix);
|
||||
|
||||
let matches = this.monitored.filter(item => {
|
||||
return item.prefix == messagePrefix;
|
||||
});
|
||||
if (matches.length > 1) {
|
||||
matches = [matches.sort((a, b) => ipUtils.sortByPrefixLength(a.prefix, b.prefix)).pop()];
|
||||
}
|
||||
if (matchedRule && matchedRule.prefix === messagePrefix) {
|
||||
const text = `Possible change of configuration. A new prefix ${message.prefix} is announced by AS${message.originAs}. It is a more specific of ${matchedRule.prefix} (${matchedRule.description}).`;
|
||||
|
||||
if (matches.length !== 0) {
|
||||
const match = matches[0];
|
||||
let key = match.prefix;
|
||||
let key = matchedRule.prefix;
|
||||
|
||||
this.publishAlert(key,
|
||||
`The prefix ${match.prefix} has been withdrawn.`,
|
||||
match.asn[0],
|
||||
matches[0],
|
||||
`The prefix ${matchedRule.prefix} has been withdrawn.`,
|
||||
matchedRule.asn[0],
|
||||
matchedRule,
|
||||
message,
|
||||
{});
|
||||
}
|
||||
|
||||
@@ -22,3 +22,8 @@
|
||||
description: alarig fix test 2
|
||||
asn: 208585
|
||||
ignoreMorespecifics: false
|
||||
|
||||
2a0e:f40::/30:
|
||||
description: ignore sub test
|
||||
asn: 1234
|
||||
ignoreMorespecifics: true
|
||||
|
||||
@@ -126,7 +126,7 @@ describe("Tests", function() {
|
||||
|
||||
it("loading prefixes", function () {
|
||||
|
||||
expect(env.input.prefixes.length).to.equal(5);
|
||||
expect(env.input.prefixes.length).to.equal(6);
|
||||
expect(env.input).to
|
||||
.containSubset({
|
||||
"prefixes": [
|
||||
@@ -164,6 +164,13 @@ describe("Tests", function() {
|
||||
"ignoreMorespecifics": false,
|
||||
"prefix": "2a0e:f40::/29",
|
||||
"user": "default"
|
||||
},
|
||||
{
|
||||
"asn": [1234],
|
||||
"description": "ignore sub test",
|
||||
"ignoreMorespecifics": true,
|
||||
"prefix": "2a0e:f40::/30",
|
||||
"user": "default"
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user