diff options
author | Jo-Philipp Wich <jo@mein.io> | 2022-09-21 23:38:46 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2022-10-25 01:03:37 +0200 |
commit | 287775351bf39475f070ffc4ff4162f025ebfd81 (patch) | |
tree | 21a497bea4dc3058765e8c25f8a77f917c40e7d2 /applications/luci-app-upnp/root/usr/share/rpcd | |
parent | cea2c3578efe7ab36219f06985d01a4771aeb070 (diff) |
luci-app-upnp: convert rpcd backend script to ucode
Utilize the rpcd ucode plugin to reimplement the upnp backend ubus actions
in ucode, simplifying the implementation and roughly halving the processing
time for the `get_status` call.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'applications/luci-app-upnp/root/usr/share/rpcd')
-rw-r--r-- | applications/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/applications/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp b/applications/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp new file mode 100644 index 0000000000..9ee47f2968 --- /dev/null +++ b/applications/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp @@ -0,0 +1,139 @@ +// Copyright 2022 Jo-Philipp Wich <jo@mein.io> +// Licensed to the public under the Apache License 2.0. + +'use strict'; + +import { access, open, popen } from 'fs'; +import { connect } from 'ubus'; +import { cursor } from 'uci'; + +// Establish ubus connection persistently outside of the call handler scope to +// prevent premature GC'ing. Can be moved into `get_status` callback once +// https://github.com/jow-/ucode/commit/a58fe4709f661b5f28e26701ea8638efccf5aeb6 +// is merged. +const ubus = connect(); + +const methods = { + get_status: { + call: function(req) { + const uci = cursor(); + + const rules = []; + const leases = []; + + const leasefile = open(uci.get('upnpd', 'config', 'upnp_lease_file'), 'r'); + + if (leasefile) { + for (let line = leasefile.read('line'); length(line); line = leasefile.read('line')) { + const record = split(line, ':', 6); + + if (length(record) == 6) { + push(leases, { + proto: uc(record[0]), + extport: +record[1], + intaddr: arrtoip(iptoarr(record[2])), + intport: +record[3], + expiry: +record[4], + description: trim(record[5]) + }); + } + } + + leasefile.close(); + } + + const ipt = popen('iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null'); + + if (ipt) { + for (let line = ipt.read('line'); length(line); line = ipt.read('line')) { + let m = match(line, /^([0-9]+)\s+([a-z]+).+dpt:([0-9]+) to:(\S+):([0-9]+)/); + + if (m) { + push(rules, { + num: m[1], + proto: uc(m[2]), + extport: +m[3], + intaddr: arrtoip(iptoarr(m[4])), + intport: +m[5], + descr: '' + }); + } + } + + ipt.close(); + } + + const nft = popen('nft --handle list chain inet fw4 upnp_prerouting 2>/dev/null'); + + if (nft) { + for (let line = nft.read('line'), num = 1; length(line); line = nft.read('line')) { + let m = match(line, /^\t\tiif ".+" @nh,72,8 (0x6|0x11) th dport ([0-9]+) dnat ip to ([0-9.]+):([0-9]+)/); + + if (m) { + push(rules, { + num: `${num}`, + proto: (m[1] == '0x6') ? 'TCP' : 'UDP', + extport: +m[2], + intaddr: arrtoip(iptoarr(m[3])), + intport: +m[4], + descr: '' + }); + + num++; + } + } + + nft.close(); + } + + return ubus.defer('luci-rpc', 'getHostHints', {}, function(rc, host_hints) { + for (let rule in rules) { + for (let lease in leases) { + if (lease.proto == rule.proto && + lease.intaddr == rule.intaddr && + lease.intport == rule.intport && + lease.extport == rule.extport) + { + rule.descr = lease.description; + break; + } + } + + for (let mac, hint in host_hints) { + if (rule.intaddr in hint.ipaddrs) { + rule.host_hint = hint.name; + break; + } + } + } + + req.reply({ rules }); + }); + } + }, + + delete_rule: { + args: { token: 'token' }, + call: function(req) { + const idx = +req.args?.token; + + if (idx > 0) { + const uci = cursor(); + const leasefile = uci.get('upnpd', 'config', 'upnp_lease_file'); + + if (access(leasefile)) { + system(['sed', '-i', '-e', `${idx}d`, leasefile]); + system(['/etc/init.d/miniupnpd', 'restart']); + } + + return { result: 'OK' }; + } + + return { result: 'Bad request' }; + } + } +}; + +return { 'luci.upnp': methods }; + + |