Skip to content

Commit

Permalink
Merge pull request #6 from bmeck/queuedSpawn
Browse files Browse the repository at this point in the history
* Added queued spawn support to prevent XTables concurrency fail lock.
* Added an `iptables.dump` method to parse out `iptables-save`.
* Added an `iptablables.check` method to check the existence one or more rules from the selected chain.
  • Loading branch information
diosney committed Sep 19, 2014
2 parents 557204e + 21a9da9 commit 74c6501
Show file tree
Hide file tree
Showing 26 changed files with 540 additions and 140 deletions.
16 changes: 15 additions & 1 deletion docs/README-iptables.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,18 @@ The wrapper error codes matches (unsurprisingly) the same as iptables. They are:
if (error) {
console.log(error);
}
});
});

#### Dump

iptables.dump({
table: 'nat', // default: null == all
}, function(err, dump) {
for (var table_name in dump) {
var table_dump = dump[table];
for (var chain_name in table_dump.chains) {
var chain_dump = table_dump.chains[chain_name];
console.log(table_name, chain_name, chain_dump);
}
}
});
61 changes: 61 additions & 0 deletions lib/child_utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var processQueue = require('process-queue');

var default_queue = processQueue.createQueue({concurrency:1});

exports.exec = function (line, opts, cb) {
var stdout, stdout_length, stderr, stderr_length;

// avoid allocation
if (cb) {
stdout = [];
stdout_length = 0;
stderr = [];
stderr_length = 0;
}

var child;
var queue = opts.queue || default_queue;
if (cb) {
queue = queue.wrap({
child: function (spawned_child, next) {
child = spawned_child;
if (cb) {
child.stdout.on('data', function (data) {
if (!Buffer.isBuffer(data)) data = new Buffer(data);
stdout_length += data.length;
stdout.push(data);
});
child.stderr.on('data', function (data) {
if (!Buffer.isBuffer(data)) data = new Buffer(data);
stderr_length += data.length;
stderr.push(data);
});
}
next(null, child);
}
});
}
var cmd = {
spawnOptions: ['sh', ['-c', 'exec ' + line]]
};
function onFinish(err) {
if (!cb) return;
if (!child) {
cb(new Error('there was a problem spawning the child process'));
return;
}
if (err) {
err.killed = child.killed;
err.code = child.exitCode;
err.signal = child.signalCode;
}
cb(err,
stdout_length ? String(Buffer.concat(stdout, stdout_length)) : '',
stderr_length ? String(Buffer.concat(stderr, stderr_length)) : ''
);
}
queue.push(cmd, onFinish);

// cleanup for gc
cmd = null;
}
6 changes: 3 additions & 3 deletions lib/ipset/add.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Add a given entry to the set.
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -58,4 +58,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/create.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Create a set identified with setsetname and specified type.
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -58,4 +58,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/del.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Delete an entry from a set.
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -58,4 +58,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/destroy.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Destroy the specified set or all the sets if none is given.
Expand Down Expand Up @@ -44,7 +44,7 @@ module.exports = function (/* options?, cb */) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -56,4 +56,4 @@ module.exports = function (/* options?, cb */) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/flush.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Flush all entries from the specified set or flush all sets if none is given.
Expand Down Expand Up @@ -44,7 +44,7 @@ module.exports = function (/* options?, cb */) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -56,4 +56,4 @@ module.exports = function (/* options?, cb */) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/rename.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Rename a set.
Expand Down Expand Up @@ -35,7 +35,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -47,4 +47,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/swap.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Swap the content of two sets.
Expand Down Expand Up @@ -35,7 +35,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -47,4 +47,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/ipset/test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Test wether an entry is in a set or not.
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -58,4 +58,4 @@ module.exports = function (options, cb) {
cb(null, 0);
}
});
};
};
14 changes: 9 additions & 5 deletions lib/ipset/version.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

/**
* Print program version.
*
* @param cb
*/
module.exports = function (cb) {
if (typeof arguments[0] != 'function') {
module.exports = function (options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
}
if (typeof cb != 'function') {
throw new Error('Invalid arguments. Signature: (callback)');
}

Expand All @@ -22,7 +26,7 @@ module.exports = function (cb) {
/*
* Execute command.
*/
exec(cmd.join(' '), function (error, stdout, stderror) {
exec(cmd.join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -34,4 +38,4 @@ module.exports = function (cb) {
cb(null, stdout.split('\n')[0]);
}
});
};
};
6 changes: 3 additions & 3 deletions lib/iptables/append.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var exec = require('child_process').exec;
var exec = require('../child_utils').exec;

var tables = require('./utils').tables;
var processCommonRuleSpecs = require('./utils').processCommonRuleSpecs;
Expand Down Expand Up @@ -46,7 +46,7 @@ module.exports = function (options, cb) {
/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), function (error, stdout, stderror) {
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
Expand All @@ -58,4 +58,4 @@ module.exports = function (options, cb) {
cb(null);
}
});
};
};
66 changes: 66 additions & 0 deletions lib/iptables/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
var exec = require('../child_utils').exec;

var tables = require('./utils').tables;
var processCommonRuleSpecs = require('./utils').processCommonRuleSpecs;


/**
* Checks the existence one or more rules from the selected chain.
*
* @param options
* @param cb
*/
module.exports = function (options, cb) {
if (typeof arguments[0] != 'object') {
throw new Error('Invalid arguments. Signature: (options, callback?)');
}

var table = (typeof options.table != 'undefined')
? options.table
: tables.filter;

var ipt_cmd = (options.sudo)
? 'sudo '
: '';

ipt_cmd += (options.ipv6)
? 'ip6tables'
: 'iptables';

/*
* Build cmd to execute.
*/
var cmd = [ipt_cmd, '--table', table, '--check'];
var args = [];

/*
* Process options.
*/
if (typeof options.chain != 'undefined') {
args = args.concat(options.chain);
}

if (typeof options.rulenum != 'undefined') {
args = args.concat(options.rulenum);
}
else {
var common_rule_specs = processCommonRuleSpecs(options);
args = args.concat(common_rule_specs);
}

/*
* Execute command.
*/
exec(cmd.concat(args).join(' '), {queue: options.cmdQueue}, function (error, stdout, stderror) {
if (error && cb) {
var err = new Error(stderror.split('\n')[0]);
err.cmd = cmd.concat(args).join(' ');
err.code = error.code;

cb(err);
}
else if (cb) {
cb(null);
}
});
};
Loading

0 comments on commit 74c6501

Please sign in to comment.