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

introduced email reporting with templates

This commit is contained in:
Massimo Candela
2019-07-09 15:23:44 +02:00
parent 4ba008786d
commit 397a3d0561
6 changed files with 141 additions and 20 deletions

View File

@@ -28,6 +28,7 @@
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
"brembo": "^2.0.3",
"event-stream": "^4.0.1",
"ip": "https://github.com/MaxCam/node-ip.git#contains-prefix",
"js-yaml": "^3.13.1",

View File

@@ -0,0 +1,15 @@
${summary}
DETAILS:
------------------------------------------------------
Monitored prefix: ${prefix}
Prefix Description: ${description}
Usual prefix origin: AS${asn}
Event type: ${type}
Now announced by: AS${neworigin}
Now announced with: ${newprefix}
When event started: ${earliest} UTC
Last event: ${latest} UTC
Detected by peers: ${peers}
See in BGPlay: ${bgplay}

View File

@@ -0,0 +1,13 @@
${summary}
DETAILS:
------------------------------------------------------
Monitored prefix: ${prefix}
Prefix Description: ${description}
Prefix origin: AS${asn}
Event type: ${type}
When event started: ${earliest} UTC
Last event: ${latest} UTC
Detected by peers: ${peers}
See in BGPlay: ${bgplay}

View File

@@ -1,11 +1,18 @@
import Report from "./report";
import brembo from "brembo";
import fs from "fs";
import moment from "moment";
import nodemailer from "nodemailer";
import path from "path";
export default class ReportEmail extends Report {
constructor(channels,params, env) {
super(channels, params, env);
this.templates = {};
this.emailBacklog = [];
this.transporter = nodemailer.createTransport({
host: this.params.smtp,
port: this.params.port,
@@ -20,6 +27,25 @@ export default class ReportEmail extends Report {
rejectUnauthorizedCertificate: this.params.rejectUnauthorizedCertificate
}
});
for (let channel of channels) {
try {
const file = path.resolve('reports/email_templates', `${channel}.txt`);
this.templates[channel] = fs.readFileSync(file, "utf8");
} catch (error){
this.logger.log({
level: 'error',
message: channel + ' template cannot be loaded'
})
}
}
setInterval(() => {
const nextEmail = this.emailBacklog.pop();
if (nextEmail) {
this._sendEmail(nextEmail);
}
}, 3000);
}
getEmails = (content) => {
@@ -48,31 +74,90 @@ export default class ReportEmail extends Report {
return [];
};
getEmailText = (message, content) => {
return content.message;
_getBGPlayLink = (prefix, start, end, instant = null, rrcs = [0,1,2,5,6,7,10,11,13,14,15,16,18,20]) => {
const bgplayTimeOffset = 5 * 60; // 5 minutes
return brembo.build("https://stat.ripe.net/", {
path: ["widget", "bgplay"],
params: {
"w.resource": prefix,
"w.ignoreReannouncements": true,
"w.starttime": moment(start).utc().unix() - bgplayTimeOffset,
"w.endtime": moment(end).utc().unix(),
"w.rrcs": rrcs.join(","),
"w.instant": null,
"w.type": "bgp",
}
}).replace("?", "#");
};
report = (message, content) => {
getEmailText = (channel, content) => {
let context = {
summary: content.message,
earliest: moment(content.earliest).utc().format("YYYY-MM-DD hh:mm:ss"),
latest: moment(content.latest).utc().format("YYYY-MM-DD hh:mm:ss"),
channel,
type: content.origin,
};
let matched = null;
switch(channel){
case "hijack":
matched = content.data[0].matchedRule;
context.prefix = matched.prefix;
context.description = matched.description;
context.asn = matched.asn;
context.peers = [...new Set(content.data.map(alert => alert.matchedMessage.peer))].length;
context.neworigin = content.data[0].matchedMessage.originAs;
context.newprefix = content.data[0].matchedMessage.prefix;
context.bgplay = this._getBGPlayLink(matched.prefix, content.earliest, content.latest);
break;
case "visibility":
matched = content.data[0].matchedRule;
context.prefix = matched.prefix;
context.description = matched.description;
context.asn = matched.asn;
context.peers = [...new Set(content.data.map(alert => alert.matchedMessage.peer))].length;
context.bgplay = this._getBGPlayLink(matched.prefix, content.earliest, content.latest);
break;
case "newprefix":
break;
}
return this.templates[channel].replace(/\${([^}]*)}/g, (r,k)=>context[k]);
};
_sendEmail = (email) => {
if (this.transporter) {
const emailGroups = this.getEmails(content);
this.transporter
.sendMail(email)
.catch(error => {
this.logger.log({
level: 'error',
message: error
});
})
}
};
for (let emails of emailGroups) {
report = (channel, content) => {
const emailGroups = this.getEmails(content);
for (let emails of emailGroups) {
const text = this.getEmailText(channel, content);
this.emailBacklog.push({
from: this.params.email,
to: emails.join(', '),
subject: 'BGP alert: ' + channel,
text: text
});
this.transporter
.sendMail({
from: this.params.email,
to: emails.join(', '),
subject: 'BGP alert: ' + message,
text: this.getEmailText(message, content)
})
.catch(error => {
this.logger.log({
level: 'error',
message: error
});
})
}
}
}
}

View File

@@ -248,7 +248,9 @@ describe("Alerting", function() {
]);
done();
process.exit()
setTimeout(function () {
process.exit()
}, 20000);
});
}).timeout(10000);

View File

@@ -790,6 +790,11 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
brembo@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/brembo/-/brembo-2.0.3.tgz#2b94bc75774b94cfa50f9c531f9115e584088524"
integrity sha512-KLapbDMsMhrsXDvNl/mzl3HHqwJFSh9fBCdvRrkDQADA/CxNMmznVQHp24I9XVg22Y+qkY6PGRcG/11/aArhWA==
browser-stdout@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"