diff --git a/lib/parsers/index.js b/lib/parsers/index.js index 9c1afc0..a4ac87c 100644 --- a/lib/parsers/index.js +++ b/lib/parsers/index.js @@ -66,6 +66,7 @@ module.exports = { relpSyslogParser: wrap(require('./relpSyslogParser')), sshdParser: wrap(require('./sshdParser')), sudoParser: wrap(require('./sudoParser')), + merakiParser: wrap(require('./merakiParser')), } /** diff --git a/lib/parsers/merakiParser.js b/lib/parsers/merakiParser.js new file mode 100644 index 0000000..ef43a71 --- /dev/null +++ b/lib/parsers/merakiParser.js @@ -0,0 +1,48 @@ + +var regexes = [ + { + name: 'meraki_wap', + regex: / \S+\d+ flows (disallow|allow) src=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) dst=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) mac=(([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})) protocol=\d+/, + parts: ['action', 'src_ip', 'dst_ip', 'mac'] + }, + { + name: 'meraki_ids_alerts', + regex: /ids-alerts signature=(\d+:\d+):\d+ priority=\d+ timestamp=\d+\.\d+ shost=\S+ direction=(ingress|egress) protocol=\S+ src=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+) dst=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+) message:(.*)/, + parts: ['sid', 'direction', 'src_ip', 'src_port', 'dst_ip', 'dst_port', 'description'] + } + ] + +/** + * Parses log lines from Meraki + * + * @param {String} message Message to try and parse + * + * @returns {parserResult} + */ +module.exports = function (message) { + +var parts = [], + matched, + data = {} + +regexes.some(function (group) { + parts = group.regex.exec(message) + if (parts) { + matched = group + return true + } +}) + +if (!matched) { + return { data: void 0, error: 'No matches' } +} + +data.event = matched.name +matched.parts.forEach(function (name, index) { + data[name] = parts[index + 1].trim() +}) + +return { data: data, error: void 0 } +} + +module.exports.propertyName = 'merakiParser' \ No newline at end of file diff --git a/test/parsers/merakiParser.test.js b/test/parsers/merakiParser.test.js new file mode 100644 index 0000000..9c6e84e --- /dev/null +++ b/test/parsers/merakiParser.test.js @@ -0,0 +1,48 @@ +var StreamStash = require('../../'), + assertParserResult = require('./util').assertParserResult + +describe('merakiParser', function () { + it('Should parse action=allow Meraki WAP Logs', function() { + assertParserResult( + StreamStash.parsers.merakiParser.raw, + '[0.0 WAP12 flows allow src=0.0.0.0 dst=198.179.1.255 mac=C4:B3:01:CF:70:C7 protocol=128]', + { + event: 'meraki_wap', + action: 'allow', + src_ip: '0.0.0.0', + dst_ip: '198.179.1.255', + mac: 'C4:B3:01:CF:70:C7', + } + ) + }) + + it('Should parse action=disallow Meraki WAP logs', function() { + assertParserResult( + StreamStash.parsers.merakiParser.raw, + '[0.0 WAP12 flows disallow src=198.179.1.255 dst=198.168.1.172 mac=C4:B3:01:CF:70:C7 protocol=128]', + { + event: 'meraki_wap', + action: 'disallow', + src_ip: '198.179.1.255', + dst_ip: '198.168.1.172', + mac: 'C4:B3:01:CF:70:C7', + } + ) + }) + it('Should parse Meraki IDS logs', function() { + assertParserResult( + StreamStash.parsers.merakiParser.raw, + 'SFO_5TH_FW1 ids-alerts signature=128:1:1 priority=1 timestamp=1486600623.475848 shost=00:18:0A:78:BE:67 direction=ingress protocol=tcp/ip src=10.10.90.47:62753 dst=54.152.167.64:22 message: (spp_ssh) Challenge-Response Overflow exploit', + { + event: 'meraki_ids_alerts', + sid: '128:1', + direction: 'ingress', + src_ip: '10.10.90.47', + src_port: '62753', + dst_ip: '54.152.167.64', + dst_port: '22', + description: '(spp_ssh) Challenge-Response Overflow exploit', + } + ) + }) +}) \ No newline at end of file