123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // 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 };
|