From fcc2328a3bf49eb5310413058cc9ebaf8e7819f8 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Wed, 4 Dec 2019 18:04:30 +0100 Subject: WIP netiquette --- docker/netiquette/.gitignore | 1 + docker/netiquette/README.md | 24 +++++++++ docker/netiquette/index.mjs | 59 ++++++++++++++++++++ docker/netiquette/package-lock.json | 74 ++++++++++++++++++++++++++ docker/netiquette/package.json | 18 +++++++ docker/netiquette/src/catalog/consul.mjs | 30 +++++++++++ docker/netiquette/src/catalog/control_loop.mjs | 10 ++++ docker/netiquette/src/injector/iptables.mjs | 53 ++++++++++++++++++ docker/netiquette/src/injector/upnp.mjs | 0 docker/netiquette/src/io/files.mjs | 8 +++ docker/netiquette/src/io/run.mjs | 9 ++++ docker/netiquette/static.iptables | 10 ++++ docker/netiquette/test/io.mjs | 10 ++++ docker/netiquette/test/iptables.mjs | 28 ++++++++++ docker/netiquette/test/runner.mjs | 28 ++++++++++ docker/tag-config/.gitignore | 1 - docker/tag-config/README.md | 22 -------- docker/tag-config/index.mjs | 56 ------------------- docker/tag-config/package-lock.json | 74 -------------------------- docker/tag-config/package.json | 18 ------- docker/tag-config/src/catalog/consul.mjs | 30 ----------- docker/tag-config/src/injector/iptables.mjs | 53 ------------------ docker/tag-config/src/injector/upnp.mjs | 0 docker/tag-config/src/io/files.mjs | 8 --- docker/tag-config/src/io/run.mjs | 9 ---- docker/tag-config/static.iptables | 10 ---- docker/tag-config/test/io.mjs | 10 ---- docker/tag-config/test/iptables.mjs | 28 ---------- docker/tag-config/test/runner.mjs | 28 ---------- 29 files changed, 362 insertions(+), 347 deletions(-) create mode 100644 docker/netiquette/.gitignore create mode 100644 docker/netiquette/README.md create mode 100644 docker/netiquette/index.mjs create mode 100644 docker/netiquette/package-lock.json create mode 100644 docker/netiquette/package.json create mode 100644 docker/netiquette/src/catalog/consul.mjs create mode 100644 docker/netiquette/src/catalog/control_loop.mjs create mode 100644 docker/netiquette/src/injector/iptables.mjs create mode 100644 docker/netiquette/src/injector/upnp.mjs create mode 100644 docker/netiquette/src/io/files.mjs create mode 100644 docker/netiquette/src/io/run.mjs create mode 100644 docker/netiquette/static.iptables create mode 100644 docker/netiquette/test/io.mjs create mode 100644 docker/netiquette/test/iptables.mjs create mode 100644 docker/netiquette/test/runner.mjs delete mode 100644 docker/tag-config/.gitignore delete mode 100644 docker/tag-config/README.md delete mode 100644 docker/tag-config/index.mjs delete mode 100644 docker/tag-config/package-lock.json delete mode 100644 docker/tag-config/package.json delete mode 100644 docker/tag-config/src/catalog/consul.mjs delete mode 100644 docker/tag-config/src/injector/iptables.mjs delete mode 100644 docker/tag-config/src/injector/upnp.mjs delete mode 100644 docker/tag-config/src/io/files.mjs delete mode 100644 docker/tag-config/src/io/run.mjs delete mode 100644 docker/tag-config/static.iptables delete mode 100644 docker/tag-config/test/io.mjs delete mode 100644 docker/tag-config/test/iptables.mjs delete mode 100644 docker/tag-config/test/runner.mjs (limited to 'docker') diff --git a/docker/netiquette/.gitignore b/docker/netiquette/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/docker/netiquette/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/docker/netiquette/README.md b/docker/netiquette/README.md new file mode 100644 index 0000000..e4c2f27 --- /dev/null +++ b/docker/netiquette/README.md @@ -0,0 +1,24 @@ +# netiquette + +``` +npm install +npm test +``` + +You will probably need to run consul in parallel: + +``` +consul agent -dev +``` + +You can register services like that: + +``` +consul services register -name=toto -tag="public_port=4848" +``` + +You will need some arguments to run the software: + +``` +sudo npm start node=rincevent ipt_base=./static.iptables +``` diff --git a/docker/netiquette/index.mjs b/docker/netiquette/index.mjs new file mode 100644 index 0000000..6aca6e4 --- /dev/null +++ b/docker/netiquette/index.mjs @@ -0,0 +1,59 @@ +'use strict' +import consul from 'consul' +import { exec } from './src/io/run.mjs' +import { readFile } from './src/io/files.mjs' + +import ctlg_control_loop from './src/catalog/control_loop.mjs' +import ctlg_consul from './src/catalog/consul.mjs' +import inj_iptables from './src/injector/iptables.mjs' + +const get_args = () => process + .argv + .slice(2) + .map(a => a.split('=')) + .reduce((dict, tuple) => { + dict[tuple[0]] = tuple.length > 1 ? tuple[1] : null + return dict + }, {}) + +/** + * If we have multiple catalogs + * we cache the results of the other ones + */ +function* notifications_aggregator(injectors) { + const states = [] + for(let idx = 0; true; idx++) { + yield async (tag_list) => { + states[idx] = tag_list + const merged = states.reduce((acc, tag) => [...acc, ...tag], []) + await Promise.all(injectors.map(notify => notify(merged))) + } + } +} + +const main = async () => { + try { + const args = get_args() + + // Initialize all injectors + const injectors = [ + await inj_iptables(args.ipt_base, readFile, exec, console.log), + // await inj_upnp + ] + + // Initialize all catalogs and map them to the injectors + const aggr = notifications_aggregator(injectors) + const catalogs = [ + // this catalog is used to defeat deriving config due to single resource updated async. by multiple prog or by external program not tracked by catalogs + await ctlg_control_loop(setInterval, 60000, aggr.next().value), + await ctlg_consul(args.node, consul(), console.log, aggr.next().value) + ] + + console.log("[main] initialized") + } catch(e) { + console.error("initialization failed", e) + process.exit(1) + } +} + +main() diff --git a/docker/netiquette/package-lock.json b/docker/netiquette/package-lock.json new file mode 100644 index 0000000..a4d30b9 --- /dev/null +++ b/docker/netiquette/package-lock.json @@ -0,0 +1,74 @@ +{ + "name": "consul-to-igd", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "consul": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/consul/-/consul-0.34.1.tgz", + "integrity": "sha512-xCLBzPQBgnDgC2LdYnrT/Fc6PglRU6u7EBkpW0ExAx3Am/CdtKcP5o/3jfwOy7PBAwBqnJk3AYdwwGg+arriiQ==", + "requires": { + "papi": "^0.29.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "papi": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/papi/-/papi-0.29.1.tgz", + "integrity": "sha512-Y9ipSMfWuuVFO3zY9PlxOmEg+bQ7CeJ28sa9/a0veYNynLf9fwjR3+3fld5otEy7okUaEOUuCHVH62MyTmACXQ==" + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + } + } +} diff --git a/docker/netiquette/package.json b/docker/netiquette/package.json new file mode 100644 index 0000000..02fa0b3 --- /dev/null +++ b/docker/netiquette/package.json @@ -0,0 +1,18 @@ +{ + "name": "netiquette", + "version": "1.0.0", + "description": "", + "main": "index.mjs", + "dependencies": { + "consul": "^0.34.1" + }, + "devDependencies": { + "chai": "^4.2.0" + }, + "scripts": { + "start": "node --experimental-modules ./index.mjs", + "test": "node --experimental-modules ./test/runner.mjs" + }, + "author": "Quentin", + "license": "AGPL-3.0-or-later" +} 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 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}))) + diff --git a/docker/netiquette/static.iptables b/docker/netiquette/static.iptables new file mode 100644 index 0000000..d9e7d38 --- /dev/null +++ b/docker/netiquette/static.iptables @@ -0,0 +1,10 @@ +-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +-A INPUT -i docker0 -j ACCEPT +-A INPUT -s 127.0.0.0/8 -j ACCEPT +-A INPUT -s 192.168.1.2/32 -j ACCEPT +-A INPUT -s 192.168.1.3/32 -j ACCEPT +-A INPUT -s 192.168.1.4/32 -j ACCEPT +-A INPUT -p udp -m udp --dport 53 -j ACCEPT +-A INPUT -p tcp -m tcp --dport 53 -j ACCEPT +-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT +-A INPUT -p tcp -m tcp --dport 110 -j ACCEPT diff --git a/docker/netiquette/test/io.mjs b/docker/netiquette/test/io.mjs new file mode 100644 index 0000000..d88ad15 --- /dev/null +++ b/docker/netiquette/test/io.mjs @@ -0,0 +1,10 @@ +import chai from 'chai' +import { readFile } from '../src/io/files.mjs' +const expect = chai.expect + +export default [ + (async () => { + const dirname = import.meta.url.replace(/^file:\/\//g, '').replace(/io.mjs$/g, '') + expect(await readFile(`${dirname}/../package.json`, 'utf-8')).to.include('Quentin') + }) +] diff --git a/docker/netiquette/test/iptables.mjs b/docker/netiquette/test/iptables.mjs new file mode 100644 index 0000000..1ae1cb0 --- /dev/null +++ b/docker/netiquette/test/iptables.mjs @@ -0,0 +1,28 @@ +'use strict' + +import chai from 'chai' +import iptables from '../src/injector/iptables.mjs' +const expect = chai.expect + +export default [ + (async () => { + const effective_actions = [] + const expected_actions = [ + 'iptables -A INPUT -p tcp --dport 56 -j ACCEPT', + 'iptables -A INPUT -p tcp --dport 53 -j ACCEPT', + 'iptables -A INPUT -p udp --match multiport --dports 25630:25999 -j ACCEPT', + 'iptables -D INPUT -p tcp --dport 54 -j ACCEPT' + ] + + const mockLog = () => {} + const mockReadFile = (file, opt) => '-A INPUT -p tcp --dport 53 -j ACCEPT' + const mockExecCommand = (cmd, opts) => { + if (cmd.match(/^iptables -S/g)) return { stdout: '-A INPUT -p tcp --dport 54 -j ACCEPT' } + else effective_actions.push(cmd) + return { stdout: '' } } + + const fw = await iptables('static', mockReadFile, mockExecCommand, mockLog) + await fw(['public_port=56/tcp', 'public_port=25630-25999/udp', 'public_port=13', 'traefik.entrypoints=Host:im.deuxfleurs.fr;PathPrefix:/_matrix']) + expect(effective_actions).to.have.members(expected_actions) + }) +] diff --git a/docker/netiquette/test/runner.mjs b/docker/netiquette/test/runner.mjs new file mode 100644 index 0000000..b4da1de --- /dev/null +++ b/docker/netiquette/test/runner.mjs @@ -0,0 +1,28 @@ +'use strict' + +import io from './io.mjs' +import iptables from './iptables.mjs' + +(async () => { + const res = await [ + ...io, + ...iptables + ].map(async f => { + try { + await f() + return 'passed' + } + catch(e) { + console.error(e) + return 'failed' + } + }).reduce(async (acc, r) => { + const accumulator = await acc + const result = await r + accumulator.total++ + accumulator[result]++ + return accumulator + }, {total: 0, passed: 0, failed: 0}) + + console.log(`Done. passed: ${res.passed}, failed: ${res.failed}, total: ${res.total}`) +})() diff --git a/docker/tag-config/.gitignore b/docker/tag-config/.gitignore deleted file mode 100644 index 3c3629e..0000000 --- a/docker/tag-config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/docker/tag-config/README.md b/docker/tag-config/README.md deleted file mode 100644 index 0746388..0000000 --- a/docker/tag-config/README.md +++ /dev/null @@ -1,22 +0,0 @@ -``` -npm install -npm test -``` - -You will probably need to run consul in parallel: - -``` -consul agent -dev -``` - -You can register services like that: - -``` -consul services register -name=toto -tag="public_port=4848" -``` - -You will need some arguments to run the software: - -``` -sudo npm start node=rincevent ipt_base=./static.iptables -``` diff --git a/docker/tag-config/index.mjs b/docker/tag-config/index.mjs deleted file mode 100644 index a5b51fc..0000000 --- a/docker/tag-config/index.mjs +++ /dev/null @@ -1,56 +0,0 @@ -'use strict' -import consul from 'consul' -import { exec } from './src/io/run.mjs' -import { readFile } from './src/io/files.mjs' - -import ctlg_consul from './src/catalog/consul.mjs' -import inj_iptables from './src/injector/iptables.mjs' - -const get_args = () => process - .argv - .slice(2) - .map(a => a.split('=')) - .reduce((dict, tuple) => { - dict[tuple[0]] = tuple.length > 1 ? tuple[1] : null - return dict - }, {}) - -/** - * If we have multiple catalogs - * we cache the results of the other ones - */ -function* notifications_aggregator(injectors) { - const states = [] - for(let idx = 0; true; idx++) { - yield async (tag_list) => { - states[idx] = tag_list - await Promise.all( - injectors.map(notify => - notify(states.reduce((acc, tag) => [...acc, ...tag], [])))) - } - } -} - -const main = async () => { - try { - const args = get_args() - - // Initialize all injectors - const injectors = [ - await inj_iptables(args.ipt_base, readFile, exec, console.log) - ] - - // Initialize all catalogs and map them to the injectors - const aggr = notifications_aggregator(injectors) - const catalogs = [ - await ctlg_consul(args.node, consul(), console.log, aggr.next().value) - ] - - console.log("[main] initialized") - } catch(e) { - console.error("initialization failed", e) - process.exit(1) - } -} - -main() diff --git a/docker/tag-config/package-lock.json b/docker/tag-config/package-lock.json deleted file mode 100644 index a4d30b9..0000000 --- a/docker/tag-config/package-lock.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "consul-to-igd", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "consul": { - "version": "0.34.1", - "resolved": "https://registry.npmjs.org/consul/-/consul-0.34.1.tgz", - "integrity": "sha512-xCLBzPQBgnDgC2LdYnrT/Fc6PglRU6u7EBkpW0ExAx3Am/CdtKcP5o/3jfwOy7PBAwBqnJk3AYdwwGg+arriiQ==", - "requires": { - "papi": "^0.29.0" - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "papi": { - "version": "0.29.1", - "resolved": "https://registry.npmjs.org/papi/-/papi-0.29.1.tgz", - "integrity": "sha512-Y9ipSMfWuuVFO3zY9PlxOmEg+bQ7CeJ28sa9/a0veYNynLf9fwjR3+3fld5otEy7okUaEOUuCHVH62MyTmACXQ==" - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - } - } -} diff --git a/docker/tag-config/package.json b/docker/tag-config/package.json deleted file mode 100644 index 892fb87..0000000 --- a/docker/tag-config/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "consul-to-igd", - "version": "1.0.0", - "description": "", - "main": "index.mjs", - "dependencies": { - "consul": "^0.34.1" - }, - "devDependencies": { - "chai": "^4.2.0" - }, - "scripts": { - "start": "node --experimental-modules ./index.mjs", - "test": "node --experimental-modules ./test/runner.mjs" - }, - "author": "Quentin", - "license": "AGPL-3.0-or-later" -} diff --git a/docker/tag-config/src/catalog/consul.mjs b/docker/tag-config/src/catalog/consul.mjs deleted file mode 100644 index 655c61f..0000000 --- a/docker/tag-config/src/catalog/consul.mjs +++ /dev/null @@ -1,30 +0,0 @@ -'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/tag-config/src/injector/iptables.mjs b/docker/tag-config/src/injector/iptables.mjs deleted file mode 100644 index 584b560..0000000 --- a/docker/tag-config/src/injector/iptables.mjs +++ /dev/null @@ -1,53 +0,0 @@ -'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/tag-config/src/injector/upnp.mjs b/docker/tag-config/src/injector/upnp.mjs deleted file mode 100644 index e69de29..0000000 diff --git a/docker/tag-config/src/io/files.mjs b/docker/tag-config/src/io/files.mjs deleted file mode 100644 index c3eca1b..0000000 --- a/docker/tag-config/src/io/files.mjs +++ /dev/null @@ -1,8 +0,0 @@ -'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/tag-config/src/io/run.mjs b/docker/tag-config/src/io/run.mjs deleted file mode 100644 index 8774043..0000000 --- a/docker/tag-config/src/io/run.mjs +++ /dev/null @@ -1,9 +0,0 @@ -'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}))) - diff --git a/docker/tag-config/static.iptables b/docker/tag-config/static.iptables deleted file mode 100644 index d9e7d38..0000000 --- a/docker/tag-config/static.iptables +++ /dev/null @@ -1,10 +0,0 @@ --A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT --A INPUT -i docker0 -j ACCEPT --A INPUT -s 127.0.0.0/8 -j ACCEPT --A INPUT -s 192.168.1.2/32 -j ACCEPT --A INPUT -s 192.168.1.3/32 -j ACCEPT --A INPUT -s 192.168.1.4/32 -j ACCEPT --A INPUT -p udp -m udp --dport 53 -j ACCEPT --A INPUT -p tcp -m tcp --dport 53 -j ACCEPT --A INPUT -p tcp -m tcp --dport 22 -j ACCEPT --A INPUT -p tcp -m tcp --dport 110 -j ACCEPT diff --git a/docker/tag-config/test/io.mjs b/docker/tag-config/test/io.mjs deleted file mode 100644 index d88ad15..0000000 --- a/docker/tag-config/test/io.mjs +++ /dev/null @@ -1,10 +0,0 @@ -import chai from 'chai' -import { readFile } from '../src/io/files.mjs' -const expect = chai.expect - -export default [ - (async () => { - const dirname = import.meta.url.replace(/^file:\/\//g, '').replace(/io.mjs$/g, '') - expect(await readFile(`${dirname}/../package.json`, 'utf-8')).to.include('Quentin') - }) -] diff --git a/docker/tag-config/test/iptables.mjs b/docker/tag-config/test/iptables.mjs deleted file mode 100644 index 1ae1cb0..0000000 --- a/docker/tag-config/test/iptables.mjs +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' - -import chai from 'chai' -import iptables from '../src/injector/iptables.mjs' -const expect = chai.expect - -export default [ - (async () => { - const effective_actions = [] - const expected_actions = [ - 'iptables -A INPUT -p tcp --dport 56 -j ACCEPT', - 'iptables -A INPUT -p tcp --dport 53 -j ACCEPT', - 'iptables -A INPUT -p udp --match multiport --dports 25630:25999 -j ACCEPT', - 'iptables -D INPUT -p tcp --dport 54 -j ACCEPT' - ] - - const mockLog = () => {} - const mockReadFile = (file, opt) => '-A INPUT -p tcp --dport 53 -j ACCEPT' - const mockExecCommand = (cmd, opts) => { - if (cmd.match(/^iptables -S/g)) return { stdout: '-A INPUT -p tcp --dport 54 -j ACCEPT' } - else effective_actions.push(cmd) - return { stdout: '' } } - - const fw = await iptables('static', mockReadFile, mockExecCommand, mockLog) - await fw(['public_port=56/tcp', 'public_port=25630-25999/udp', 'public_port=13', 'traefik.entrypoints=Host:im.deuxfleurs.fr;PathPrefix:/_matrix']) - expect(effective_actions).to.have.members(expected_actions) - }) -] diff --git a/docker/tag-config/test/runner.mjs b/docker/tag-config/test/runner.mjs deleted file mode 100644 index b4da1de..0000000 --- a/docker/tag-config/test/runner.mjs +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' - -import io from './io.mjs' -import iptables from './iptables.mjs' - -(async () => { - const res = await [ - ...io, - ...iptables - ].map(async f => { - try { - await f() - return 'passed' - } - catch(e) { - console.error(e) - return 'failed' - } - }).reduce(async (acc, r) => { - const accumulator = await acc - const result = await r - accumulator.total++ - accumulator[result]++ - return accumulator - }, {total: 0, passed: 0, failed: 0}) - - console.log(`Done. passed: ${res.passed}, failed: ${res.failed}, total: ${res.total}`) -})() -- cgit v1.2.3