aboutsummaryrefslogtreecommitdiff
path: root/docker/netiquette/src
diff options
context:
space:
mode:
Diffstat (limited to 'docker/netiquette/src')
-rw-r--r--docker/netiquette/src/catalog/consul.mjs30
-rw-r--r--docker/netiquette/src/catalog/control_loop.mjs10
-rw-r--r--docker/netiquette/src/injector/iptables.mjs53
-rw-r--r--docker/netiquette/src/injector/upnp.mjs0
-rw-r--r--docker/netiquette/src/io/files.mjs8
-rw-r--r--docker/netiquette/src/io/run.mjs9
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})))
+