From 378ade57b52c928422fe1ee4ac509c3f8514c6d1 Mon Sep 17 00:00:00 2001 From: Dustyn Blackmore Date: Tue, 24 Apr 2018 17:29:05 +1000 Subject: [PATCH] Huge Refactor Updated index.js Properly evaluate actions, currently supporting 'log' Included actions/* --- src/actions/filesystem.js | 19 ++++++++++ src/actions/index.js | 15 ++++++++ src/config/interfaces.json | 2 +- src/config/rules.json | 8 +++- src/index.js | 76 ++++++++++++++++++++++---------------- src/nfpacket/enums.js | 2 +- 6 files changed, 87 insertions(+), 35 deletions(-) create mode 100644 src/actions/filesystem.js create mode 100644 src/actions/index.js diff --git a/src/actions/filesystem.js b/src/actions/filesystem.js new file mode 100644 index 0000000..ef72426 --- /dev/null +++ b/src/actions/filesystem.js @@ -0,0 +1,19 @@ +function write (fs, content) { + return new Promise((resolve, reject) => { + fs.appendFile('./logs/test.js', content + '\n', (error) => { + if (error) { + reject(error) + } else { + resolve() + } + }) + }) +} + +const filesystem = (fs) => ({ + log: (content) => { + return write(fs, content); + } +}) + +module.exports = filesystem; diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 0000000..fa465b3 --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1,15 @@ +const filesystem = require('./filesystem'); + +const actions = (dependencies) => { + if (Object.keys(dependencies).includes('fs')) { + return Object.assign( + {}, + actions, + filesystem(dependencies.fs) + ) + } + + return false; +} + +module.exports = actions; diff --git a/src/config/interfaces.json b/src/config/interfaces.json index 7cde744..d02c421 100644 --- a/src/config/interfaces.json +++ b/src/config/interfaces.json @@ -13,4 +13,4 @@ "zone": "untrusted" } } -} \ No newline at end of file +} diff --git a/src/config/rules.json b/src/config/rules.json index 1adc762..163e87d 100644 --- a/src/config/rules.json +++ b/src/config/rules.json @@ -153,6 +153,10 @@ "acceptAction": null, "rejectAction": null }, + "1880": { + "acceptAction": null, + "rejectAction": null + }, "1900": { "acceptAction": null, "rejectAction": null @@ -177,7 +181,7 @@ "rejectAction": null, "ports": { "53": { - "acceptAction": "((packet) => { console.log(packet) })", + "acceptAction": null, "rejectAction": null }, "500": { @@ -229,4 +233,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/index.js b/src/index.js index 9380c10..619cfda 100644 --- a/src/index.js +++ b/src/index.js @@ -4,13 +4,13 @@ const nfq = require('nfqueue'); const IPv4 = require('pcap/decode/ipv4'); const pcap = require('pcap'); const { exec } = require('child_process'); -const nfpacket = require('./nfpacket')({ nfq: nfq, pcap: pcap }) - const nft = require('./nftables')({ exec: exec }); +const nfpacket = require('./nfpacket')({ nfq: nfq, pcap: pcap }) +const actions = require('./actions')({ fs: fs }) // These are the NFQUEUE result handler options. -const NF_REJECT = 0; -const NF_ACCEPT = 1; // Accept packet (but no longer seen / disowned by conntrack) +const NF_DROP = 0; // Drop the packet (There is no response or closure) +const NF_ACCEPT = 1; // Accept packet (but no longer seen / disowned by conntrack) const NF_REQUEUE = 4; // Requeue packet (Which we then use a mark to determine the action) // Protocol Numbers can be found here, however; libpcap has limited support.. @@ -32,8 +32,6 @@ let configWatch = fs.watch('./src/config', checkConfig); function checkConfig (err, filename) { setTimeout(() => { - console.log(filename); - console.log(err) switch (filename) { case 'rules.json': console.log('Rules Configuration Changed - Reloding..') @@ -95,7 +93,7 @@ function getInterfaces (path) { * @param {array} arr - promise arr * @return {Object} promise object */ -function runPromiseInSequense(arr) { +function runPromiseArrayInSequence(arr) { return arr.reduce((promiseChain, currentPromise) => { return promiseChain.then((chainedResult) => { return currentPromise(chainedResult) @@ -117,28 +115,38 @@ function setupInterfaces () { interfaces.push(newInterface); }); - return runPromiseInSequense(interfacePromises) + return runPromiseArrayInSequence(interfacePromises) }; +function handleActions(action, packet) { + switch (action) { + case 'log': + actions.log(JSON.stringify(packet)); + break; + default: + break; + } +} + function determineVerdict (interface, packet, direction) { - let thisVerdict = NF_REJECT; + let thisVerdict = NF_DROP; // Check we even handle this protocol - if (rules[direction][packet.protocol.toString()]) { + if (rules[direction][packet.payloadDecoded.protocol.toString()]) { // Check if the global (blanket) rule applies - if (rules[direction][packet.protocol.toString()].global.allowed) { + if (rules[direction][packet.payloadDecoded.protocol.toString()].global.allowed) { // Trigger the callback, if it exists.. - if (rules[direction][packet.protocol.toString()].global.acceptCallback) { - eval(rules[direction][packet.protocol.toString()].global.acceptCallback)(packet); + if (rules[direction][packet.payloadDecoded.protocol.toString()].global.acceptAction) { + handleActions(rules[direction][packet.payloadDecoded.protocol.toString()].global.acceptAction, packet); } // Check if the global setting has any specific ports - if (rules[direction][packet.protocol.toString()].global.ports) { + if (rules[direction][packet.payloadDecoded.protocol.toString()].global.ports) { // Check, if there are ports, if the port is allowed. - if (rules[direction][packet.protocol.toString()].global.ports[packet.payload.dport]) { + if (rules[direction][packet.payloadDecoded.protocol.toString()].global.ports[packet.payloadDecoded.payload.dport]) { thisVerdict = NF_ACCEPT; // Finally - if the port is allowed, check if there's a callback to trigger. - if (rules[direction][packet.protocol.toString()].global.ports[packet.payload.dport].acceptCallback) { - eval(rules[direction][packet.protocol.toString()].global.ports[packet.payload.dport].acceptCallback)(packet); + if (rules[direction][packet.payloadDecoded.protocol.toString()].global.ports[packet.payloadDecoded.payload.dport].acceptAction) { + handleActions(rules[direction][packet.payloadDecoded.protocol.toString()].global.ports[packet.payloadDecoded.payload.dport].acceptAction, packet); } return thisVerdict; } @@ -151,19 +159,19 @@ function determineVerdict (interface, packet, direction) { // Else, as if globally accepted we don't need to traverse other zones. } // Check if the protocol is zone allowed. - if (rules[direction][packet.protocol.toString()][interface.zone].allowed) { + if (rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].allowed) { // Trigger the protocol zone callback, if it exists. - if (rules[direction][packet.protocol.toString()][interface.zone].acceptCallback) { - eval(rules[direction][packet.protocol.toString()][interface.zone].acceptCallback)(packet); + if (rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].acceptAction) { + handleActions(rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].acceptAction, packet); } // Check if the protocol's zone setting has any specific ports - if (rules[direction][packet.protocol.toString()][interface.zone].ports) { + if (rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].ports) { // Check, if there are ports, if the port is allowed. - if (rules[direction][packet.protocol.toString()][interface.zone].ports[packet.payload.dport]) { + if (rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].ports[packet.payloadDecoded.payload.dport]) { thisVerdict = NF_ACCEPT; // Finally - if the port is allowed, check if there's a callback to trigger. - if (rules[direction][packet.protocol.toString()][interface.zone].ports[packet.payload.dport].acceptCallback) { - eval(rules[direction][packet.protocol.toString()][interface.zone].ports[packet.payload.dport].acceptCallback)(packet); + if (rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].ports[packet.payloadDecoded.payload.dport].acceptAction) { + handleActions(rules[direction][packet.payloadDecoded.protocol.toString()][interface.zone].ports[packet.payloadDecoded.payload.dport].acceptAction, packet); } } // The global default is enabled, yet there are no ports.. which likely @@ -185,10 +193,13 @@ function updateOutput () { function bindQueueHandlers () { interfaces.forEach(interface => { interface.queueIn = nfq.createQueueHandler(parseInt(interface.number), buffer, (nfpacket) => { - let packet = new IPv4().decode(nfpacket.payload, 0); - let thisVerdict = determineVerdict(interface, packet, 'incoming'); + let decoded = new IPv4().decode(nfpacket.payload, 0); + let stringified = nfpacket.payload.toString(); + let clonedPacket = Object.assign({}, nfpacket, { payloadDecoded: decoded, payloadStringified: stringified }); + + let thisVerdict = determineVerdict(interface, clonedPacket, 'incoming'); - if (thisVerdict === NF_REJECT) { + if (thisVerdict === NF_DROP) { packetsRejected++; packetsRejectedIn++; nfpacket.setVerdict(NF_REQUEUE, 666); @@ -200,11 +211,14 @@ function bindQueueHandlers () { }); interface.queueOut = nfq.createQueueHandler(parseInt('100' + interface.number), buffer, (nfpacket) => { - let packet = new IPv4().decode(nfpacket.payload, 0); - let thisVerdict = determineVerdict(interface, packet, 'outgoing'); + let decoded = new IPv4().decode(nfpacket.payload, 0); + let stringified = nfpacket.payload.toString(); + let clonedPacket = Object.assign({}, nfpacket, { payloadDecoded: decoded, payloadStringified: stringified }); + + let thisVerdict = determineVerdict(interface, clonedPacket, 'outgoing'); // Allow us to set a META MARK for requeue and reject. - if (thisVerdict === NF_REJECT) { + if (thisVerdict === NF_DROP) { packetsRejected++; packetsRejectedOut++; // Outgoing packets set META MARK 777 - allows use of REJECT @@ -249,4 +263,4 @@ nft.flush().then( (err) => console.log('Failed to insert final counters: ' + err) ); -const outputInterval = setInterval(updateOutput, 2500); +const outputInterval = setInterval(updateOutput, 5000); diff --git a/src/nfpacket/enums.js b/src/nfpacket/enums.js index caa88f5..08b4f0b 100644 --- a/src/nfpacket/enums.js +++ b/src/nfpacket/enums.js @@ -12,4 +12,4 @@ const protocols = { PC_IGMP: 2, PC_TCP: 6, PC_UDP: 17, -} \ No newline at end of file +}