diff options
Diffstat (limited to 'docker/netiquette/src')
-rw-r--r-- | docker/netiquette/src/catalog/consul.mjs | 30 | ||||
-rw-r--r-- | docker/netiquette/src/catalog/control_loop.mjs | 10 | ||||
-rw-r--r-- | docker/netiquette/src/injector/iptables.mjs | 53 | ||||
-rw-r--r-- | docker/netiquette/src/injector/upnp.mjs | 0 | ||||
-rw-r--r-- | docker/netiquette/src/io/files.mjs | 8 | ||||
-rw-r--r-- | docker/netiquette/src/io/run.mjs | 9 |
6 files changed, 110 insertions, 0 deletions
diff --git a/docker/netiquette/src/catalog/consul.mjs b/docker/netiquette/src/catalog/consul.mjs new file mode 100644 index 0000000..655c61f --- /dev/null +++ b/docker/netiquette/src/catalog/consul.mjs @@ -0,0 +1,30 @@ +'use strict' + +let l +export default l = async (node, consul, log, notify) => { + const watch = consul.watch({ method: consul.catalog.node.services, options: {node: node}}) + + const extract_tags = data => + data ? + Object + .keys(data.Services) + .map(k => data.Services[k].Tags) + .reduce((acc, v) => [...acc, ...v], []) : + [] + + watch.on('error', err => { + console.error('error', err) + }) + + watch.on('change', async (data, res) => { + try { + const tags = extract_tags(data) + log(`[consul] new update, detected ${tags.length} tags`) + await notify(tags) + } catch(e) { + console.error('failed to notify target', e) + } + }) + + log('[consul] initialized') +} diff --git a/docker/netiquette/src/catalog/control_loop.mjs b/docker/netiquette/src/catalog/control_loop.mjs new file mode 100644 index 0000000..56ad6f5 --- /dev/null +++ b/docker/netiquette/src/catalog/control_loop.mjs @@ -0,0 +1,10 @@ +'use strict' + +let l +export default l = async (timer, interval, notify) => { + timer(() => { + notify([]) + console.log(`[control_loop] actuation (triggered every ${interval} ms)`) + }, interval) + console.log("[control_loop] initialized") +} diff --git a/docker/netiquette/src/injector/iptables.mjs b/docker/netiquette/src/injector/iptables.mjs new file mode 100644 index 0000000..584b560 --- /dev/null +++ b/docker/netiquette/src/injector/iptables.mjs @@ -0,0 +1,53 @@ +'use strict' + +let l; +export default l = async (path, readFile, exec, log) => { + + const load_static_rules = async path => + (await readFile(path, 'utf-8')) + .split('\n') + .filter(e => e) + + const get_current_rules = async () => + (await exec('iptables -S INPUT')) + .stdout + .split('\n') + .filter(e => e.match(/^-A INPUT/g)) + + const compute_rules_to_add = (current, target) => + target.filter(r => !current.includes(r)) + + const compute_rules_to_del = (current, target) => + current + .filter(r => !target.includes(r)) + .map(r => r.replace(/^-A INPUT/g, '-D INPUT')) + + const update_rules = async (current, target) => + await Promise.all([ + ...compute_rules_to_del(current, target), + ...compute_rules_to_add(current, target) + ].map(r => exec(`iptables ${r}`))) + + const build_target_rules = (tag_list) => + tag_list + .map(t => /^public_port=(\d+)(-(\d+))?\/(udp|tcp)/g.exec(t)) + .filter(t => t) + .map(t => new Object({ start: t[1], stop: t[3], protocol: t[4] })) + .map(t => t.stop + ? `-A INPUT -p ${t.protocol} --match multiport --dports ${t.start}:${t.stop} -j ACCEPT` + : `-A INPUT -p ${t.protocol} --dport ${t.start} -j ACCEPT`) + + const do_log = (tag_list, r) => { + //log('[iptables]', tag_list) + log(`[iptables] ran ${r.length} commands`) + } + + const static_rules = path ? await load_static_rules(path) : [] + log(`[iptables] initialized with ${static_rules.length} static rules`) + return async tag_list => + do_log( + tag_list, + await update_rules( + await get_current_rules(), + [...static_rules, ...build_target_rules(tag_list)])) +} diff --git a/docker/netiquette/src/injector/upnp.mjs b/docker/netiquette/src/injector/upnp.mjs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/docker/netiquette/src/injector/upnp.mjs diff --git a/docker/netiquette/src/io/files.mjs b/docker/netiquette/src/io/files.mjs new file mode 100644 index 0000000..c3eca1b --- /dev/null +++ b/docker/netiquette/src/io/files.mjs @@ -0,0 +1,8 @@ +'use strict' + +import fs from 'fs' + +export const readFile = (file, opts) => + new Promise((resolve, reject) => + fs.readFile(file, opts, (err, data) => + err ? reject(err) : resolve(data))) diff --git a/docker/netiquette/src/io/run.mjs b/docker/netiquette/src/io/run.mjs new file mode 100644 index 0000000..8774043 --- /dev/null +++ b/docker/netiquette/src/io/run.mjs @@ -0,0 +1,9 @@ +'use strict' + +import child_process from 'child_process' + +export const exec = (cmd, opts) => + new Promise((resolve, reject) => + child_process.exec(cmd, opts, (error, stdout, stderr) => + error ? reject({err: error, stdout: stdout, stderr: stderr}) : resolve({stdout: stdout, stderr: stderr}))) + |