From f04482fc5326903c25f882900f8005fd7b4286f3 Mon Sep 17 00:00:00 2001 From: Dustyn Blackmore Date: Tue, 17 Apr 2018 13:55:45 +1000 Subject: [PATCH] Refactor NFT Interactions Now has an nft interface, albiet crude. Now flushes tables on init. --- index.js | 71 ++++++++++++++++++------------------------- src/nftables/index.js | 16 ++++++++++ src/nftables/rules.js | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 42 deletions(-) create mode 100644 src/nftables/index.js create mode 100644 src/nftables/rules.js diff --git a/index.js b/index.js index 398f953..ea1e0fb 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,8 @@ let rules = require('./rules.json').rules; const systemInterfaces = require('./interfaces.json').interfaces; const { exec } = require('child_process'); +const nft = require('./src/nftables')({ exec: exec }); + let ruleWatch = fs.watch('./rules.json', 'utf8', () => { setTimeout(loadRules, 500) }); function loadRules (err, filename) { @@ -56,21 +58,6 @@ function execute (command) { }); } -// Flushes all rules - entirely blank. -function flushRules () { - return execute('nft flush ruleset'); -} - -// Sets locked down (besides lo) rules. No packets accepted at all. -function lockRules () { - return execute('nft -f ./locked.rules'); -} - -// Sets base rules, with default to 'drop', but allows established and related connections. -function baseRules () { - return execute('nft -f ./base.rules'); -} - // Sets base rules, with default to 'drop', but allows established and related connections. function insertFinalCounters () { return Promise.all([ @@ -80,12 +67,10 @@ function insertFinalCounters () { } function insertInterfaceRules (interface) { - return Promise.all( - [ - execute('nft --handle --echo add rule ip filter input iif ' + interface.name + ' ct state new counter nftrace set 1 queue num ' + interface.number), - execute('nft --handle --echo add rule ip filter output oif ' + interface.name + ' ct state new counter nftrace set 1 queue num 100' + interface.number) - ] - ) + return Promise.all([ + nft.add('rule ip filter input iif ' + interface.name + ' ct state new counter nftrace set 1 queue num ' + interface.number), + nft.add('add rule ip filter output oif ' + interface.name + ' ct state new counter nftrace set 1 queue num 100' + interface.number) + ]); } function getInterfaces (path) { @@ -97,15 +82,14 @@ function getInterfaces (path) { } function setupInterfaces () { - return new Promise(function (resolve, reject) { - getInterfaces(sysClassNetInterfaces).forEach(interface => { - let newInterface = { name: interface, number: interfaces.length + 1, zone: systemInterfaces[interface].zone }; - insertInterfaceRules(newInterface); - interfaces.push(newInterface); - return resolve(true); - }); + let interfacePromises = []; + getInterfaces(sysClassNetInterfaces).forEach(interface => { + let newInterface = { name: interface, number: interfaces.length + 1, zone: systemInterfaces[interface].zone }; + interfacePromises.push(insertInterfaceRules(newInterface)) + interfaces.push(newInterface); }); -} + return Promise.all(interfacePromises); +}; function determineVerdict (interface, packet, direction) { let thisVerdict = NF_REJECT; @@ -182,16 +166,19 @@ function bindQueueHandlers () { }) } - -// flushRules().then( -baseRules().then( - setupInterfaces() - .then(insertFinalCounters() - .then(bindQueueHandlers() - ) - ) -).catch((err) => { - flushRules().then(lockRules()); -} -) -// ) +nft.flush() + .then((resolved) => { + nft.inject('./base.rules').then((resolved) => { + setupInterfaces().then((resolved) => { + bindQueueHandlers(); + + }, (rejected) => { + console.log('Rejected setup interfaces'); + }) + }, (rejected) => { + console.log('rejected inject base rules') + }) + }, (rejected) => { + console.log('rejected flush'); + }) + \ No newline at end of file diff --git a/src/nftables/index.js b/src/nftables/index.js new file mode 100644 index 0000000..4080b55 --- /dev/null +++ b/src/nftables/index.js @@ -0,0 +1,16 @@ +const rules = require('./rules'); + +const nft = (dependencies) => { + + if (Object.keys(dependencies).includes('exec')) { + return Object.assign( + {}, + nft, + rules(dependencies.exec) + ) + } + + return false; +} + +module.exports = nft; diff --git a/src/nftables/rules.js b/src/nftables/rules.js new file mode 100644 index 0000000..2b43b7e --- /dev/null +++ b/src/nftables/rules.js @@ -0,0 +1,53 @@ +function execute (exec, command) { + return new Promise((resolve, reject) => { + exec('nft ' + command, (error, stdout, stderr) => { + if (error) { + reject(error) + } else { + if (stdout) { + resolve(stdout) + } else { + resolve(stderr) + } + } + }) + }) +} + + +function executeReturnHandle (exec, command) { + return new Promise((resolve, reject) => { + exec('nft --echo --handle ' + command, (error, stdout, stderr) => { + if (error) { + reject(error) + } else { + if (stdout) { + let unparsedResult = stdout.split(' '); + resolve(unparsedResult[unparsedResult.length - 1]); + } else { + resolve(stderr) + } + } + }) + }) +} + +const rules = (exec) => ({ + add: (rule) => { + return executeReturnHandle(exec, rule); + }, + flush: () => { + return execute(exec, 'flush ruleset'); + }, + inject: (filename) => { + return execute(exec, '-f ' + filename); + }, + list: () => { + return execute(exec, 'list ruleset'); + }, + removeByTableSetChainHandle: (table, set, chain, handle) => { + return executeReturnHandle(exec, 'delete rule table ' + table + ' ' + set + ' ' + chain + ' ' + handle) + } +}) + +module.exports = rules;