From ba269ede8dd3639e152f24bababd9235f3aa9a3c Mon Sep 17 00:00:00 2001 From: Dustyn Blackmore Date: Thu, 17 May 2018 15:42:08 +1000 Subject: [PATCH] Further NFPacket Refactor Updated src/nfpacket* Extended object Now stores mark, and verdict. Actions now includes a verdict, which returns appropriate action. Updated index.js Further utilization of the nfpacket object. --- src/index.js | 79 ++++++++++++++++++----------------------- src/nfpacket/actions.js | 34 +++++++++++++----- src/nfpacket/index.js | 2 ++ 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/index.js b/src/index.js index 9aec0e0..85334c8 100644 --- a/src/index.js +++ b/src/index.js @@ -42,12 +42,10 @@ function checkConfig (err, filename) { } // Some counters for connection analysis (Used for stdio) -let packetsAccepted = 0; -let packetsAcceptedIn = 0; -let packetsAcceptedOut = 0; -let packetsRejected = 0; -let packetsRejectedIn = 0; -let packetsRejectedOut = 0; +let packetsIn = 0; +let packetsInAccept = 0; +let packetsOut = 0; +let packetsOutAccept = 0; // An array to store our interfaces. let interfaces = []; @@ -121,11 +119,6 @@ function handleActions (action, packet) { } function handlePacket (packet) { - let verdict = { - policy: packet.enums.netfilterVerdict.NF_DROP, - mark: 0 - }; - // Check we even handle this protocol if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()]) { // Check if the global (blanket) rule applies @@ -134,7 +127,7 @@ function handlePacket (packet) { if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.action) { handleActions(rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.action, packet); if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.action === 'log') { - verdict.mark = 9999; + packet.mark = 9999; } } // Check if the global setting has any specific ports @@ -144,23 +137,25 @@ function handlePacket (packet) { // Check if the policy is allow if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.ports[packet.nfpacketDecoded.payload.dport].policy && rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.ports[packet.nfpacketDecoded.payload.dport].policy === 'allow') { // Set to accept packet. - verdict.policy = packet.enums.netfilterVerdict.NF_ACCEPT; + packet.verdict = packet.enums.netfilterVerdict.NF_ACCEPT; } // Finally - if the port is allowed, check if there's a callback to trigger. if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.ports[packet.nfpacketDecoded.payload.dport].action) { handleActions(rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.ports[packet.nfpacketDecoded.payload.dport].action, packet); if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()].global.ports[packet.nfpacketDecoded.payload.dport].action === 'log') { - verdict.mark = 9999; + packet.mark = 9999; } } // Do not further traverse ruleset, or this function ; wasted cycles. - packet.nfpacket.setVerdict(verdict.policy, verdict.mark); + return packet.actions.verdict(packet.verdict, packet.mark); + // packet.nfpacket.setVerdict(packet.verdict, packet.mark); } // The global default is enabled, yet there is no ports key.. // (Likely) means this is a port-less protocol, or a blanket 'allow' rule is in place. } else { - verdict.policy = packet.enums.netfilterVerdict.NF_ACCEPT; - packet.nfpacket.setVerdict(verdict.policy, verdict.mark); + packet.verdict = packet.enums.netfilterVerdict.NF_ACCEPT; + return packet.actions.verdict(packet.verdict, packet.mark); + //packet.nfpacket.setVerdict(packet.verdict, packet.mark); } // Else, as if globally accepted we don't need to traverse other zones. } @@ -170,80 +165,76 @@ function handlePacket (packet) { if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].action) { handleActions(rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].action, packet); if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].action === 'log') { - verdict.mark = 9999; + packet.mark = 9999; } } // Check if the protocol's zone setting has any specific ports if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports) { // Check, if there are ports, if the port is allowed. if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport] && rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport].policy && rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport].policy === 'allow') { - verdict.policy = packet.enums.netfilterVerdict.NF_ACCEPT; + packet.verdict = packet.enums.netfilterVerdict.NF_ACCEPT; // Finally - if the port is allowed, check if there's a callback to trigger. if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport].action) { handleActions(rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport].action, packet); if (rules[packet.direction][packet.nfpacketDecoded.protocol.toString()][packet.interface.zone].ports[packet.nfpacketDecoded.payload.dport].action === 'log') { - verdict.mark = 9999; + packet.mark = 9999; } } } // The global default is enabled, yet there are no ports.. which likely // Means this is a port-less protocol. } else { - verdict.policy = packet.enums.netfilterVerdict.NF_ACCEPT; + packet.verdict = packet.enums.netfilterVerdict.NF_ACCEPT; } } } - packet.nfpacket.setVerdict(verdict.policy, verdict.mark); + return packet.actions.verdict(packet.verdict, packet.mark); } function updateOutput () { process.stdout.write('\x1Bc'); - process.stdout.write('Connections - Accepted: ' + packetsAccepted + ' (I: ' + packetsAcceptedIn + ' O: ' + packetsAcceptedOut + ') - Rejected: ' + packetsRejected + ' (I: ' + packetsRejectedIn + ' O: ' + packetsRejectedOut + ')\r'); + let packetsInReject = packetsIn - packetsInAccept; + let packetsOutReject = packetsOut - packetsOutAccept; + + process.stdout.write('Packets: ' + (packetsIn + packetsOut) + ' - IN: ' + packetsIn + ' (A: ' + packetsInAccept + ' - R: ' + packetsInReject + ') - OUT: ' + packetsOut + ' (A: ' + packetsOutAccept + ' - R: ' + packetsOutReject + ')\r');// - Accepted: ' + packetsAccepted + ' (I: ' + packetsAcceptedIn + ' O: ' + packetsAcceptedOut + ') - Rejected: ' + packetsRejected + ' (I: ' + packetsRejectedIn + ' O: ' + packetsRejectedOut + ')\r'); } function bindQueueHandlers () { interfaces.forEach(interface => { interface.queueIn = nfq.createQueueHandler(parseInt(interface.number), buffer, (nfpacket) => { + packetsIn++; let thisPacket = netFilterPacket(nfpacket); thisPacket.direction = 'incoming'; thisPacket.interface = interface; - - thisPacket.encoding.decode(); - handlePacket(thisPacket); - }); + thisPacket.encoding.decode(); - interface.queueInLog = nfq.createQueueHandler(parseInt('200' + interface.number), buffer, (nfpacket) => { - let decoded = new IPv4().decode(nfpacket.payload, 0); - let stringified = nfpacket.payload.toString(); - let clonedPacket = Object.assign({}, nfpacket, { payloadDecoded: decoded, payloadStringified: stringified }); + let verdict = handlePacket(thisPacket); - handleActions('log', packet); + if (verdict.name === 'accept') { + packetsInAccept++; + } - nfpacket.setVerdict(thisVerdict.policy, 9999); + verdict(); }); interface.queueOut = nfq.createQueueHandler(parseInt('100' + interface.number), buffer, (nfpacket) => { + packetsOut++; let thisPacket = netFilterPacket(nfpacket); thisPacket.direction = 'outgoing'; thisPacket.interface = interface; - - thisPacket.encoding.decode(); - handlePacket(thisPacket); - }); + thisPacket.encoding.decode(); - interfaceLoggerQueueOut = nfq.createQueueHandler(parseInt('210' + interface.number), buffer, (nfpacket) => { - let decoded = new IPv4().decode(nfpacket.payload, 0); - let stringified = nfpacket.payload.toString(); - let clonedPacket = Object.assign({}, nfpacket, { payloadDecoded: decoded, payloadStringified: stringified }); + let verdict = handlePacket(thisPacket); - handleActions('log', packet); + if (verdict.name === 'accept') { + packetsOutAccept++; + } - nfpacket.setVerdict(thisVerdict.policy, 9999); + verdict(); }); - }); } diff --git a/src/nfpacket/actions.js b/src/nfpacket/actions.js index 24d78a3..e8867df 100644 --- a/src/nfpacket/actions.js +++ b/src/nfpacket/actions.js @@ -1,18 +1,36 @@ const actions = (dependencies) => (state) => ({ - accept: () => { + accept: (mark) => { state.nfpacket - ? state.nfpacket.setVerdict(dependencies.enums.NF_ACCEPT) + ? state.nfpacket.setVerdict(state.enums.netfilterVerdict.NF_ACCEPT, mark) : false }, - reject: () => { - state.nfpacket - ? state.nfpacket.setVerdict(dependencies.enums.NF_DROP) - : false + reject: (mark) => { + // This allows us to admin-prohibit and immediately reject outgoing, intead of droop (timeout). + if (state.direction === 'outgoing') { + state.nfpacket.setVerdict(state.enums.netfilterVerdict.NF_REPEAT, 777) + } else { + state.nfpacket + ? state.nfpacket.setVerdict(state.enums.netfilterVerdict.NF_DROP, mark) + : false + } }, - requeue: () => { + requeue: (mark) => { state.nfpacket - ? state.nfpacket.setVerdict(dependencies.enums.NF_REPEAT) + ? state.nfpacket.setVerdict(state.enums.netfilterVerdict.NF_REPEAT, mark) : false + }, + verdict: (verdict, mark) => { + switch (verdict) { + case state.enums.netfilterVerdict.NF_ACCEPT: + return state.actions.accept; + break; + case state.enums.netfilterVerdict.NF_REPEAT: + return state.actions.requeue; + break; + default: + return state.actions.reject; + break; + } } }) diff --git a/src/nfpacket/index.js b/src/nfpacket/index.js index b6c20fd..1e344a3 100644 --- a/src/nfpacket/index.js +++ b/src/nfpacket/index.js @@ -8,7 +8,9 @@ module.exports = (dependencies) => (nfpacket) => { direction: undefined, enums: enums, interface: undefined, + mark: undefined, nfpacket: nfpacket, + verdict: enums.netfilterVerdict.NF_DROP }); if (Object.keys(dependencies).includes('nfq') && Object.keys(dependencies).includes('pcapIPv4')) {