'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)])) }