mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-10 18:34:18 +08:00
5103 lines
212 KiB
Diff
5103 lines
212 KiB
Diff
--- a/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js
|
|
@@ -7,14 +7,14 @@
|
|
const callUpnpGetStatus = rpc.declare({
|
|
object: 'luci.upnp',
|
|
method: 'get_status',
|
|
- expect: { }
|
|
+ expect: {}
|
|
});
|
|
|
|
const callUpnpDeleteRule = rpc.declare({
|
|
object: 'luci.upnp',
|
|
method: 'delete_rule',
|
|
- params: [ 'token' ],
|
|
- expect: { result : "OK" },
|
|
+ params: ['token'],
|
|
+ expect: { result: 'OK' },
|
|
});
|
|
|
|
function handleDelRule(num, ev) {
|
|
@@ -35,23 +35,23 @@ return baseclass.extend({
|
|
},
|
|
|
|
render: function(data) {
|
|
- var table = E('table', { 'class': 'table', 'id': 'upnp_status_table' }, [
|
|
+ const table = E('table', { 'class': 'table', 'id': 'upnp_status_table' }, [
|
|
E('tr', { 'class': 'tr table-titles' }, [
|
|
- E('th', { 'class': 'th' }, _('Client Name')),
|
|
- E('th', { 'class': 'th' }, _('Client Address')),
|
|
- E('th', { 'class': 'th' }, _('Client Port')),
|
|
- E('th', { 'class': 'th' }, _('External Port')),
|
|
+ E('th', { 'class': 'th' }, _('Hostname')),
|
|
+ E('th', { 'class': 'th' }, _('IP address')),
|
|
+ E('th', { 'class': 'th' }, _('Port')),
|
|
+ E('th', { 'class': 'th' }, _('External port')),
|
|
E('th', { 'class': 'th' }, _('Protocol')),
|
|
E('th', { 'class': 'th right' }, _('Expires')),
|
|
- E('th', { 'class': 'th' }, _('Description')),
|
|
+ E('th', { 'class': 'th' }, _('Added via / description')),
|
|
E('th', { 'class': 'th cbi-section-actions' }, '')
|
|
])
|
|
]);
|
|
|
|
- var rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
+ const rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
|
|
- var rows = rules.map(function(rule) {
|
|
- const padnum = (num, length) => num.toString().padStart(length, "0");
|
|
+ const rows = rules.map(function(rule) {
|
|
+ const padnum = (num, length) => num.toString().padStart(length, '0');
|
|
const expires_sec = rule?.expires || 0;
|
|
const hour = Math.floor(expires_sec / 3600);
|
|
const minute = Math.floor((expires_sec % 3600) / 60);
|
|
@@ -72,8 +72,9 @@ return baseclass.extend({
|
|
'%h'.format(rule.descr),
|
|
E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
- 'click': L.bind(handleDelRule, this, rule.num)
|
|
- }, [ _('Delete') ])
|
|
+ 'click': L.bind(handleDelRule, this, rule.num),
|
|
+ 'title': _('Delete')
|
|
+ }, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 40218589d691..07ca8b0a9c62 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -3,27 +3,28 @@
|
|
'require dom';
|
|
'require poll';
|
|
'require uci';
|
|
+'require ui';
|
|
'require rpc';
|
|
'require form';
|
|
|
|
const callInitAction = rpc.declare({
|
|
object: 'luci',
|
|
method: 'setInitAction',
|
|
- params: [ 'name', 'action' ],
|
|
+ params: ['name', 'action'],
|
|
expect: { result: false }
|
|
});
|
|
|
|
const callUpnpGetStatus = rpc.declare({
|
|
object: 'luci.upnp',
|
|
method: 'get_status',
|
|
- expect: { }
|
|
+ expect: {}
|
|
});
|
|
|
|
const callUpnpDeleteRule = rpc.declare({
|
|
object: 'luci.upnp',
|
|
method: 'delete_rule',
|
|
- params: [ 'token' ],
|
|
- expect: { result : "OK" },
|
|
+ params: ['token'],
|
|
+ expect: { result: 'OK' },
|
|
});
|
|
|
|
function handleDelRule(num, ev) {
|
|
@@ -44,10 +45,10 @@ return view.extend({
|
|
|
|
poll_status: function(nodes, data) {
|
|
|
|
- var rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
+ const rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
|
|
- var rows = rules.map(function(rule) {
|
|
- const padnum = (num, length) => num.toString().padStart(length, "0");
|
|
+ const rows = rules.map(function(rule) {
|
|
+ const padnum = (num, length) => num.toString().padStart(length, '0');
|
|
const expires_sec = rule?.expires || 0;
|
|
const hour = Math.floor(expires_sec / 3600);
|
|
const minute = Math.floor((expires_sec % 3600) / 60);
|
|
@@ -68,8 +69,9 @@ return view.extend({
|
|
'%h'.format(rule.descr),
|
|
E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
- 'click': L.bind(handleDelRule, this, rule.num)
|
|
- }, [ _('Delete') ])
|
|
+ 'click': L.bind(handleDelRule, this, rule.num),
|
|
+ 'title': _('Delete')
|
|
+ }, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
@@ -80,53 +82,63 @@ return view.extend({
|
|
|
|
let m, s, o;
|
|
|
|
- var protocols = '%s & %s/%s'.format(
|
|
+ const protocols = _('%s & %s/%s', '%s & %s/%s (%s = UPnP IGD, %s = PCP, %s = NAT-PMP)').format(
|
|
'<a href="https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol" target="_blank" rel="noreferrer"><abbr title="UPnP Internet Gateway Device (Control Protocol)">UPnP IGD</abbr></a>',
|
|
'<a href="https://en.wikipedia.org/wiki/Port_Control_Protocol" target="_blank" rel="noreferrer"><abbr title="Port Control Protocol">PCP</abbr></a>',
|
|
'<a href="https://en.wikipedia.org/wiki/NAT_Port_Mapping_Protocol" target="_blank" rel="noreferrer"><abbr title="NAT Port Mapping Protocol">NAT-PMP</abbr></a>');
|
|
- m = new form.Map('upnpd', [_('UPnP IGD & PCP/NAT-PMP Service')],
|
|
+ m = new form.Map('upnpd', _('UPnP IGD & PCP/NAT-PMP Service'),
|
|
_('The %s protocols allow clients on the local network to configure port maps/forwards on the router autonomously.',
|
|
'The %s (%s = UPnP IGD & PCP/NAT-PMP) protocols allow clients on the local network to configure port maps/forwards on the router autonomously.')
|
|
- .format(protocols)
|
|
+ .format(protocols)
|
|
);
|
|
+ if (!uci.get('upnpd', 'config')) {
|
|
+ ui.addNotification(null, E('div', '<h4>' + _('No suitable configuration was found!') + '</h4><p>' +
|
|
+ _('No suitable config (LuCI app %s) found in %s. A related package update (daemon or LuCI app) may be missing.').format('v1.0', '<code>/etc/config/upnpd</code>') + '<br />' +
|
|
+ _('Use the software package manager, update lists, and install the related update. Config is migrated with the daemon package update.') + '</p>' +
|
|
+ '<a class="btn" href="/cgi-bin/luci/admin/system/package-manager?query=UPnP%20IGD%20&%20PCP/NAT-PMP">' + _('Go to package manager…') + '</a>'), 'warning');
|
|
+ m.readonly = true;
|
|
+ }
|
|
|
|
s = m.section(form.GridSection, '_active_rules');
|
|
|
|
s.render = L.bind(function(view, section_id) {
|
|
- var table = E('table', { 'class': 'table cbi-section-table', 'id': 'upnp_status_table' }, [
|
|
+ const table = E('table', { 'class': 'table cbi-section-table', 'id': 'upnp_status_table' }, [
|
|
E('tr', { 'class': 'tr table-titles' }, [
|
|
- E('th', { 'class': 'th' }, _('Client Name')),
|
|
- E('th', { 'class': 'th' }, _('Client Address')),
|
|
- E('th', { 'class': 'th' }, _('Client Port')),
|
|
- E('th', { 'class': 'th' }, _('External Port')),
|
|
+ E('th', { 'class': 'th' }, _('Hostname')),
|
|
+ E('th', { 'class': 'th' }, _('IP address')),
|
|
+ E('th', { 'class': 'th' }, _('Port')),
|
|
+ E('th', { 'class': 'th' }, _('External port')),
|
|
E('th', { 'class': 'th' }, _('Protocol')),
|
|
E('th', { 'class': 'th right' }, _('Expires')),
|
|
- E('th', { 'class': 'th' }, _('Description')),
|
|
+ E('th', { 'class': 'th' }, _('Added via / description')),
|
|
E('th', { 'class': 'th cbi-section-actions' }, '')
|
|
])
|
|
]);
|
|
|
|
- var rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
+ const rules = Array.isArray(data[0].rules) ? data[0].rules : [];
|
|
|
|
- var rows = rules.map(function(rule) {
|
|
+ const rows = rules.map(function(rule) {
|
|
return [
|
|
rule.host_hint || _('Unknown'),
|
|
rule.intaddr,
|
|
rule.intport,
|
|
rule.extport,
|
|
rule.proto,
|
|
- rule.descr,
|
|
+ '', // expires
|
|
+ '%h'.format(rule.descr),
|
|
E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
- 'click': L.bind(handleDelRule, this, rule.num)
|
|
- }, [ _('Delete') ])
|
|
+ 'click': L.bind(handleDelRule, this, rule.num),
|
|
+ 'title': _('Delete')
|
|
+ }, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
cbi_update_table(table, rows, E('em', _('There are no active port maps.')));
|
|
|
|
return E('div', { 'class': 'cbi-section cbi-tblsection' }, [
|
|
- E('h3', _('Active Service Port Maps')), table ]);
|
|
+ E('h3', _('Active Port Maps')), table
|
|
+ ]);
|
|
}, o, this);
|
|
|
|
s = m.section(form.NamedSection, 'config', 'upnpd', _('Service Settings'));
|
|
@@ -134,8 +146,8 @@ return view.extend({
|
|
s.tab('setup', _('Service Setup'));
|
|
s.tab('advanced', _('Advanced Settings'));
|
|
|
|
- o = s.taboption('setup', form.Flag, 'enabled', _('Start service'),
|
|
- _('Start autonomous port mapping service'));
|
|
+ o = s.taboption('setup', form.Flag, 'enabled', _('Enable service'),
|
|
+ _('Enable the autonomous port mapping service'));
|
|
o.rmempty = false;
|
|
|
|
o = s.taboption('setup', form.Flag, 'enable_upnp', _('Enable UPnP IGD protocol'));
|
|
@@ -152,86 +164,104 @@ return view.extend({
|
|
o.default = '1';
|
|
o.rmempty = false;
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('setup', form.Value, 'download', _('Download speed'),
|
|
_('Report maximum download speed in kByte/s'));
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('setup', form.Value, 'upload', _('Upload speed'),
|
|
_('Report maximum upload speed in kByte/s'));
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
s.taboption('advanced', form.Flag, 'use_stun', _('Use %s', 'Use %s (%s = STUN)')
|
|
- .format('<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
+ .format('<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
_('To detect the public IPv4 address for unrestricted full-cone/one-to-one NATs'));
|
|
|
|
o = s.taboption('advanced', form.Value, 'stun_host', _('STUN host'));
|
|
- o.depends('use_stun', '1');
|
|
o.datatype = 'host';
|
|
+ o.depends('use_stun', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Value, 'stun_port', _('STUN port'));
|
|
- o.depends('use_stun', '1');
|
|
o.datatype = 'port';
|
|
o.placeholder = '3478';
|
|
+ o.depends('use_stun', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Flag, 'secure_mode', _('Enable secure mode'),
|
|
_('Allow adding port maps for requesting IP addresses only'));
|
|
o.default = '1';
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
+
|
|
+ s.taboption('advanced', form.Flag, 'ipv6_disable', _('Disable IPv6 mapping'));
|
|
|
|
o = s.taboption('advanced', form.Value, 'notify_interval', _('Notify interval'),
|
|
- _('A 900s interval will result in %s notifications with the minimum max-age of 1800s', 'A 900s interval will result in %s (%s = SSDP) notifications with the minimum max-age of 1800s')
|
|
- .format('<abbr title="Simple Service Discovery Protocol">SSDP</abbr>'));
|
|
- o.datatype = 'uinteger';
|
|
+ _('A 900 s interval sends %s announcements with the minimum %s header',
|
|
+ 'A 900 s interval sends %s (%s = SSDP) announcements with the minimum %s (%s = Cache-Control: max-age=1800) header')
|
|
+ .format('<abbr title="Simple Service Discovery Protocol">SSDP</abbr>', '<code>Cache-Control: max-age=1800</code>'));
|
|
+ o.datatype = 'min(900)';
|
|
o.placeholder = '900';
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Value, 'port', _('SOAP/HTTP port'));
|
|
o.datatype = 'port';
|
|
o.placeholder = '5000';
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'presentation_url', _('Presentation URL'),
|
|
- _('Report custom router web interface (presentation) URL'));
|
|
+ o = s.taboption('advanced', form.Value, 'presentation_url', _('Router/presentation URL'),
|
|
+ _('Report custom router web interface URL'));
|
|
o.placeholder = 'http://192.168.1.1/';
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Value, 'uuid', _('Device UUID'));
|
|
- o.depends('enable_upnp', '1');
|
|
+ // o.depends('enable_upnp', '1');
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Value, 'model_number', _('Announced model number'));
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Value, 'serial_number', _('Announced serial number'));
|
|
o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
o = s.taboption('advanced', form.Flag, 'system_uptime', _('Report system instead of service uptime'));
|
|
o.default = '1';
|
|
- o.depends('enable_upnp', '1');
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o.retain = true;
|
|
|
|
s.taboption('advanced', form.Flag, 'log_output', _('Enable additional logging'),
|
|
_('Puts extra debugging information into the system log'));
|
|
|
|
o = s.taboption('advanced', form.Value, 'upnp_lease_file', _('Service lease file'));
|
|
- o.placeholder = '/var/run/miniupnpd.leases';
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o.retain = true;
|
|
|
|
s = m.section(form.GridSection, 'perm_rule', _('Service Access Control List'),
|
|
_('ACL specify which client addresses and ports can be mapped, IPv6 always allowed.'));
|
|
- s.sortable = true;
|
|
s.anonymous = true;
|
|
s.addremove = true;
|
|
+ s.sortable = true;
|
|
|
|
s.option(form.Value, 'comment', _('Comment'));
|
|
|
|
- o = s.option(form.Value, 'int_addr', _('Client Address'));
|
|
+ o = s.option(form.Value, 'int_addr', _('IP address'));
|
|
o.datatype = 'ip4addr';
|
|
o.placeholder = '0.0.0.0/0';
|
|
|
|
- o = s.option(form.Value, 'int_ports', _('Client Port'));
|
|
+ o = s.option(form.Value, 'int_ports', _('Port'));
|
|
o.datatype = 'portrange';
|
|
o.placeholder = '1-65535';
|
|
|
|
- o = s.option(form.Value, 'ext_ports', _('External Port'));
|
|
+ o = s.option(form.Value, 'ext_ports', _('External port'));
|
|
o.datatype = 'portrange';
|
|
o.placeholder = '1-65535';
|
|
|
|
diff --git a/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json b/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json
|
|
index 4611f501692a..6e1fa8fcd52c 100644
|
|
--- a/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json
|
|
+++ b/luci-app-upnp/root/usr/share/rpcd/acl.d/luci-app-upnp.json
|
|
@@ -1,6 +1,6 @@
|
|
{
|
|
"luci-app-upnp": {
|
|
- "description": "Grant access to UPnP IGD & PCP/NAT-PMP",
|
|
+ "description": "Grant access to UPnP IGD & PCP/NAT-PMP service configuration",
|
|
"read": {
|
|
"ubus": {
|
|
"luci.upnp": [ "get_status" ],
|
|
diff --git a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
index f72b57b7ba84..56ae951ceb03 100644
|
|
--- a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
+++ b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
@@ -1,3 +1,5 @@
|
|
+#!/usr/bin/env ucode
|
|
+
|
|
// Copyright 2022 Jo-Philipp Wich <jo@mein.io>
|
|
// Licensed to the public under the Apache License 2.0.
|
|
|
|
@@ -7,82 +9,73 @@ 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 ubus = connect();
|
|
const rules = [];
|
|
const leases = [];
|
|
-
|
|
- const leasefile = open(uci.get('upnpd', 'config', 'upnp_lease_file'), 'r');
|
|
-
|
|
+ const leasefile = open(uci.get('upnpd', 'config', 'upnp_lease_file') || '/var/run/miniupnpd.leases', 'r');
|
|
if (leasefile) {
|
|
for (let line = leasefile.read('line'); length(line); line = leasefile.read('line')) {
|
|
const record = split(line, ':', 6);
|
|
-
|
|
if (length(record) == 6) {
|
|
+ let descr = trim(record[5]);
|
|
+ let m = match(descr, /^PCP [A-Z]+ ([0-9a-f]{24})$/);
|
|
+ if (m) descr = 'PCP (nonce ' + m[1] + ')';
|
|
+ else if (match(descr, /^NAT-PMP \d+ \w+$/)) descr = 'NAT-PMP';
|
|
+ else if (match(descr, /^IGD2 pinhole$/)) descr = 'UPnP IGDv2 IPv6';
|
|
+ else if (!match(descr, /^UPnP IGD/)) descr = 'UPnP IGD / ' + descr;
|
|
push(leases, {
|
|
proto: uc(record[0]),
|
|
extport: +record[1],
|
|
intaddr: arrtoip(iptoarr(record[2])),
|
|
intport: +record[3],
|
|
expires: record[4] - timelocal(localtime()),
|
|
- description: trim(record[5])
|
|
+ descr: descr
|
|
});
|
|
}
|
|
}
|
|
-
|
|
leasefile.close();
|
|
}
|
|
|
|
- const ipt = popen('iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null');
|
|
-
|
|
+ // Workaround daemon bug with iptables >= 1.8.8 by parsing MINIUPNPD-POSTROUTING
|
|
+ // See https://github.com/miniupnp/miniupnp/issues/837
|
|
+ //const ipt = popen('iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null');
|
|
+ const ipt = popen('iptables --line-numbers -t nat -xnvL MINIUPNPD-POSTROUTING 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]+)/);
|
|
-
|
|
+ //let m = match(line, /^([0-9]+) .+ ([ut].p) dpt:([0-9]+) to:(\S+):([0-9]+)/);
|
|
+ let m = match(line, /^([0-9]+) .+ \* +([0-9.]+) .+ ([ut].p) spt:([0-9]+) .+ ports: ([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: ''
|
|
+ intaddr: arrtoip(iptoarr(m[2])),
|
|
+ intport: +m[4],
|
|
+ extport: +m[5],
|
|
+ proto: uc(m[3])
|
|
});
|
|
}
|
|
}
|
|
-
|
|
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]+)/);
|
|
-
|
|
+ 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: ''
|
|
+ extport: +m[2],
|
|
+ proto: (m[1] == '0x6') ? 'TCP' : 'UDP'
|
|
});
|
|
-
|
|
num++;
|
|
}
|
|
}
|
|
-
|
|
nft.close();
|
|
}
|
|
|
|
@@ -90,16 +83,14 @@ const methods = {
|
|
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;
|
|
+ lease.intaddr == rule.intaddr &&
|
|
+ lease.intport == rule.intport &&
|
|
+ lease.extport == rule.extport) {
|
|
rule.expires = lease.expires;
|
|
+ rule.descr = lease.descr;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
for (let mac, hint in host_hints) {
|
|
if (rule.intaddr in hint.ipaddrs) {
|
|
rule.host_hint = hint.name;
|
|
@@ -107,7 +98,6 @@ const methods = {
|
|
}
|
|
}
|
|
}
|
|
-
|
|
req.reply({ rules });
|
|
});
|
|
}
|
|
@@ -117,19 +107,15 @@ const methods = {
|
|
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');
|
|
-
|
|
+ const leasefile = uci.get('upnpd', 'config', 'upnp_lease_file') || '/var/run/miniupnpd.leases';
|
|
if (access(leasefile)) {
|
|
system(['sed', '-i', '-e', `${idx}d`, leasefile]);
|
|
system(['/etc/init.d/miniupnpd', 'restart']);
|
|
}
|
|
-
|
|
return { result: 'OK' };
|
|
}
|
|
-
|
|
return { result: 'Bad request' };
|
|
}
|
|
}
|
|
|
|
From e7100b61eaf00ae0e11e973ade457edc433c8daa Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 2/7] luci-app-upnp: add `UPnP IGD Adjustments` tab
|
|
|
|
And rearrange as many options
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../luci-static/resources/view/upnp/upnp.js | 71 ++++++++++---------
|
|
1 file changed, 36 insertions(+), 35 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 07ca8b0a9c62..0f8a4e84ea18 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -145,6 +145,7 @@ return view.extend({
|
|
s.addremove = false;
|
|
s.tab('setup', _('Service Setup'));
|
|
s.tab('advanced', _('Advanced Settings'));
|
|
+ s.tab('igd', _('UPnP IGD Adjustments'));
|
|
|
|
o = s.taboption('setup', form.Flag, 'enabled', _('Enable service'),
|
|
_('Enable the autonomous port mapping service'));
|
|
@@ -156,7 +157,7 @@ return view.extend({
|
|
o = s.taboption('setup', form.Flag, 'enable_natpmp', _('Enable PCP/NAT-PMP protocols'));
|
|
o.default = '1';
|
|
|
|
- s.taboption('setup', form.Flag, 'ext_allow_private_ipv4', _('Allow private IPv4'),
|
|
+ s.taboption('advanced', form.Flag, 'ext_allow_private_ipv4', _('Allow private IPv4'),
|
|
_('Enable forwarding for private/reserved IPv4 address'));
|
|
|
|
o = s.taboption('setup', form.Flag, 'igdv1', _('UPnP IGDv1 compatibility mode'),
|
|
@@ -166,16 +167,6 @@ return view.extend({
|
|
o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('setup', form.Value, 'download', _('Download speed'),
|
|
- _('Report maximum download speed in kByte/s'));
|
|
- o.depends('enable_upnp', '1');
|
|
- o.retain = true;
|
|
-
|
|
- o = s.taboption('setup', form.Value, 'upload', _('Upload speed'),
|
|
- _('Report maximum upload speed in kByte/s'));
|
|
- o.depends('enable_upnp', '1');
|
|
- o.retain = true;
|
|
-
|
|
s.taboption('advanced', form.Flag, 'use_stun', _('Use %s', 'Use %s (%s = STUN)')
|
|
.format('<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
_('To detect the public IPv4 address for unrestricted full-cone/one-to-one NATs'));
|
|
@@ -199,50 +190,60 @@ return view.extend({
|
|
|
|
s.taboption('advanced', form.Flag, 'ipv6_disable', _('Disable IPv6 mapping'));
|
|
|
|
- o = s.taboption('advanced', form.Value, 'notify_interval', _('Notify interval'),
|
|
- _('A 900 s interval sends %s announcements with the minimum %s header',
|
|
- 'A 900 s interval sends %s (%s = SSDP) announcements with the minimum %s (%s = Cache-Control: max-age=1800) header')
|
|
- .format('<abbr title="Simple Service Discovery Protocol">SSDP</abbr>', '<code>Cache-Control: max-age=1800</code>'));
|
|
- o.datatype = 'min(900)';
|
|
- o.placeholder = '900';
|
|
- o.depends('enable_upnp', '1');
|
|
+ o = s.taboption('advanced', form.Flag, 'system_uptime', _('Report system instead of service uptime'));
|
|
+ o.default = '1';
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'port', _('SOAP/HTTP port'));
|
|
- o.datatype = 'port';
|
|
- o.placeholder = '5000';
|
|
+ s.taboption('advanced', form.Flag, 'log_output', _('Enable additional logging'),
|
|
+ _('Puts extra debugging information into the system log'));
|
|
+
|
|
+ o = s.taboption('advanced', form.Value, 'upnp_lease_file', _('Service lease file'));
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.taboption('igd', form.Value, 'download', _('Download speed'),
|
|
+ _('Report maximum download speed in kByte/s'));
|
|
o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'presentation_url', _('Router/presentation URL'),
|
|
- _('Report custom router web interface URL'));
|
|
- o.placeholder = 'http://192.168.1.1/';
|
|
+ o = s.taboption('igd', form.Value, 'upload', _('Upload speed'),
|
|
+ _('Report maximum upload speed in kByte/s'));
|
|
o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'uuid', _('Device UUID'));
|
|
- // o.depends('enable_upnp', '1');
|
|
- o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o = s.taboption('igd', form.Value, 'model_number', _('Announced model number'));
|
|
+ o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'model_number', _('Announced model number'));
|
|
+ o = s.taboption('igd', form.Value, 'serial_number', _('Announced serial number'));
|
|
o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'serial_number', _('Announced serial number'));
|
|
+ o = s.taboption('igd', form.Value, 'presentation_url', _('Router/presentation URL'),
|
|
+ _('Report custom router web interface URL'));
|
|
+ o.placeholder = 'http://192.168.1.1/';
|
|
o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Flag, 'system_uptime', _('Report system instead of service uptime'));
|
|
- o.default = '1';
|
|
+ o = s.taboption('igd', form.Value, 'uuid', _('Device UUID'));
|
|
+ // o.depends('enable_upnp', '1');
|
|
o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
- s.taboption('advanced', form.Flag, 'log_output', _('Enable additional logging'),
|
|
- _('Puts extra debugging information into the system log'));
|
|
+ o = s.taboption('igd', form.Value, 'port', _('SOAP/HTTP port'));
|
|
+ o.datatype = 'port';
|
|
+ o.placeholder = '5000';
|
|
+ o.depends('enable_upnp', '1');
|
|
+ o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'upnp_lease_file', _('Service lease file'));
|
|
- o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
+ o = s.taboption('igd', form.Value, 'notify_interval', _('Notify interval'),
|
|
+ _('A 900 s interval sends %s announcements with the minimum %s header',
|
|
+ 'A 900 s interval sends %s (%s = SSDP) announcements with the minimum %s (%s = Cache-Control: max-age=1800) header')
|
|
+ .format('<abbr title="Simple Service Discovery Protocol">SSDP</abbr>', '<code>Cache-Control: max-age=1800</code>'));
|
|
+ o.datatype = 'min(900)';
|
|
+ o.placeholder = '900';
|
|
+ o.depends('enable_upnp', '1');
|
|
o.retain = true;
|
|
|
|
s = m.section(form.GridSection, 'perm_rule', _('Service Access Control List'),
|
|
|
|
From dc6910d395c2eed5b27c5f974a4db63a9253d0e3 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 3/7] luci-app-upnp: revision and adapt to new UCI options
|
|
|
|
The following settings UCI options been added or changed, and the
|
|
previous options are migrated on updating:
|
|
|
|
- Only display `Active Port Maps` if the service is enabled and `Access
|
|
Control List` if it is used
|
|
- Enable protocols (`enable_protocols`): Combined UI option added
|
|
- Allow CGNAT/STUN (`allow_cgnat`): Accept new values for IPv4 CGNAT use
|
|
and update help with newer wording of RFC 5780
|
|
- STUN server (`stun_host`): Allow port inclusion
|
|
- STUN port: Removed, as now accepted in STUN server
|
|
- Override external IPv4 (`external_ip`): UI option added for CGNAT use
|
|
- Allow third-party mapping (`allow_third_party_mapping`): Inverted from
|
|
secure mode and optionally extended to PCP
|
|
- Log level (`log_output`): Allow info log level
|
|
- UPnP IGD compatibility (`upnp_igd_compat`): Reworded/extensible
|
|
- Download/upload speed (`download_kbps`/`upload_kbps`): In kbit/s and
|
|
datatype set, now, interface link speed by default
|
|
- Router/friendly name (`friendly_name`): UI option added to set name
|
|
displayed in Windows Explorer, model/serial number removed
|
|
- Enable Networks / Access Control (`internal_network`): Section added
|
|
to select the enabled networks and their access control. By:
|
|
- Internal network (`interface`): UI option added to select the
|
|
local/internal (LAN) network interface to enable the service for
|
|
- Access defaults (`access_defaults`): UI option added to select
|
|
access defaults for ports that all devices on the network can map
|
|
- Accept extra ports (`accept_ports`): UI option added to accept these
|
|
ports or port ranges on the network as well
|
|
- Reject ports (`reject_ports`): UI option added to reject ports on
|
|
the network; overrides other settings
|
|
- Check ACL (`check_acl`): UI option added to check the ACL entries
|
|
first; these extend/override the defaults
|
|
- Slightly improve introduction text
|
|
|
|
More details on changed options can be found in the dependent package PR
|
|
|
|
Fixes: https://redirect.github.com/openwrt/luci/issues/8313
|
|
Fixes: https://redirect.github.com/openwrt/luci/issues/8677
|
|
Depends on: https://redirect.github.com/openwrt/packages/pull/28765
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
luci-app-upnp/Makefile | 2 +-
|
|
.../luci-static/resources/view/upnp/upnp.js | 202 +++++++++++++-----
|
|
.../root/usr/share/rpcd/ucode/luci.upnp | 4 +-
|
|
3 files changed, 151 insertions(+), 57 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/Makefile b/luci-app-upnp/Makefile
|
|
index 80e668764d96..601122426a89 100644
|
|
--- a/luci-app-upnp/Makefile
|
|
+++ b/luci-app-upnp/Makefile
|
|
@@ -6,7 +6,7 @@
|
|
|
|
include $(TOPDIR)/rules.mk
|
|
|
|
-LUCI_TITLE:=UPnP IGD & PCP/NAT-PMP configuration module | Universal Plug and Play
|
|
+LUCI_TITLE:=LuCI support for UPnP IGD & PCP/NAT-PMP service | originally: Universal Plug and Play
|
|
LUCI_DEPENDS:=+luci-base +miniupnpd +rpcd-mod-ucode
|
|
|
|
PKG_LICENSE:=Apache-2.0
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 0f8a4e84ea18..1dab80bef4b9 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -6,6 +6,7 @@
|
|
'require ui';
|
|
'require rpc';
|
|
'require form';
|
|
+'require tools.widgets as widgets';
|
|
|
|
const callInitAction = rpc.declare({
|
|
object: 'luci',
|
|
@@ -87,8 +88,8 @@ return view.extend({
|
|
'<a href="https://en.wikipedia.org/wiki/Port_Control_Protocol" target="_blank" rel="noreferrer"><abbr title="Port Control Protocol">PCP</abbr></a>',
|
|
'<a href="https://en.wikipedia.org/wiki/NAT_Port_Mapping_Protocol" target="_blank" rel="noreferrer"><abbr title="NAT Port Mapping Protocol">NAT-PMP</abbr></a>');
|
|
m = new form.Map('upnpd', _('UPnP IGD & PCP/NAT-PMP Service'),
|
|
- _('The %s protocols allow clients on the local network to configure port maps/forwards on the router autonomously.',
|
|
- 'The %s (%s = UPnP IGD & PCP/NAT-PMP) protocols allow clients on the local network to configure port maps/forwards on the router autonomously.')
|
|
+ _('The %s protocols/service enable permitted devices on local networks to autonomously set up IPv4/IPv6 port maps/forwards on this router.',
|
|
+ 'The %s (%s = UPnP IGD & PCP/NAT-PMP) protocols/service enable permitted devices on local networks to autonomously set up IPv4/IPv6 port maps/forwards on this router.')
|
|
.format(protocols)
|
|
);
|
|
if (!uci.get('upnpd', 'config')) {
|
|
@@ -100,6 +101,7 @@ return view.extend({
|
|
}
|
|
|
|
s = m.section(form.GridSection, '_active_rules');
|
|
+ s.disable = uci.get('upnpd', 'config', 'enabled') == '0';
|
|
|
|
s.render = L.bind(function(view, section_id) {
|
|
const table = E('table', { 'class': 'table cbi-section-table', 'id': 'upnp_status_table' }, [
|
|
@@ -151,42 +153,50 @@ return view.extend({
|
|
_('Enable the autonomous port mapping service'));
|
|
o.rmempty = false;
|
|
|
|
- o = s.taboption('setup', form.Flag, 'enable_upnp', _('Enable UPnP IGD protocol'));
|
|
- o.default = '1';
|
|
-
|
|
- o = s.taboption('setup', form.Flag, 'enable_natpmp', _('Enable PCP/NAT-PMP protocols'));
|
|
- o.default = '1';
|
|
-
|
|
- s.taboption('advanced', form.Flag, 'ext_allow_private_ipv4', _('Allow private IPv4'),
|
|
- _('Enable forwarding for private/reserved IPv4 address'));
|
|
-
|
|
- o = s.taboption('setup', form.Flag, 'igdv1', _('UPnP IGDv1 compatibility mode'),
|
|
- _('Advertise as IGDv1 (IPv4 only) device instead of IGDv2'));
|
|
- o.default = '1';
|
|
- o.rmempty = false;
|
|
- o.depends('enable_upnp', '1');
|
|
+ o = s.taboption('setup', form.ListValue, 'enable_protocols', _('Enable protocols'));
|
|
+ o.value('all', _('All protocols'));
|
|
+ o.value('upnp-igd', _('UPnP IGD'));
|
|
+ o.value('pcp+nat-pmp', _('PCP and NAT-PMP'));
|
|
+ o.default = 'all';
|
|
+ o.widget = 'radio';
|
|
+
|
|
+ o = s.taboption('setup', form.ListValue, 'upnp_igd_compat', _('UPnP IGD compatibility'),
|
|
+ _('Set compatibility mode (act as device) to workaround IGDv2-incompatible clients; %s are known to only work with %s (or) <br />Emulate/report a specific/different device to workaround/support/handle/bypass/assist/mitigate... (Alternative text welcome)').format('Sony PS, Activision CoD…', 'IGDv1'));
|
|
+ o.value('igdv1', _('IGDv1 (IPv4 only)'));
|
|
+ o.value('igdv2', _('IGDv2 (with workarounds)'));
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
- s.taboption('advanced', form.Flag, 'use_stun', _('Use %s', 'Use %s (%s = STUN)')
|
|
- .format('<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
- _('To detect the public IPv4 address for unrestricted full-cone/one-to-one NATs'));
|
|
-
|
|
- o = s.taboption('advanced', form.Value, 'stun_host', _('STUN host'));
|
|
- o.datatype = 'host';
|
|
- o.depends('use_stun', '1');
|
|
+ o = s.taboption('advanced', form.RichListValue, 'allow_cgnat', _('Allow %s/%s', 'Allow %s/%s (%s = CGNAT, %s = STUN)')
|
|
+ .format('<a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT" target="_blank" rel="noreferrer"><abbr title="Carrier-grade NAT">CGNAT</abbr></a>',
|
|
+ '<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
+ _('Allow use of unrestricted endpoint-independent (1:1) CGNATs and detect the public IPv4'));
|
|
+ o.value('', _('Disabled'), _('Manually override external IPv4 with public'));
|
|
+ o.value('1', _('Enabled'), _('Filtering test currently requires an extra firewall rule'));
|
|
+ o.value('allow-filtered', _('Enabled') + ' (' + _('allow filtered') + ')', _('Workaround filtered IPv4 CGNAT test result'));
|
|
+ o.value('report-private-ipv4', _('Disabled') + ' (' + _('report private IPv4, avoid') + ')', _('No STUN public IPv4 detection; client issues'));
|
|
+ o.optional = true;
|
|
+
|
|
+ o = s.taboption('advanced', form.Value, 'stun_host', _('STUN server'));
|
|
+ o.datatype = 'or(hostname,hostport,ip4addr("nomask"))';
|
|
+ o.placeholder = 'stun.nextcloud.com';
|
|
+ o.depends('allow_cgnat', '1');
|
|
+ o.depends('allow_cgnat', 'allow-filtered');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('advanced', form.Value, 'stun_port', _('STUN port'));
|
|
- o.datatype = 'port';
|
|
- o.placeholder = '3478';
|
|
- o.depends('use_stun', '1');
|
|
- o.retain = true;
|
|
+ o = s.taboption('advanced', form.Value, 'external_ip', _('Override external IPv4'),
|
|
+ _('Report custom public/external (WAN) IPv4 address'));
|
|
+ o.datatype = 'ip4addr("nomask")';
|
|
+ o.depends('allow_cgnat', '');
|
|
+ o.depends('allow_cgnat', 'report-private-ipv4');
|
|
|
|
- o = s.taboption('advanced', form.Flag, 'secure_mode', _('Enable secure mode'),
|
|
- _('Allow adding port maps for requesting IP addresses only'));
|
|
- o.default = '1';
|
|
- o.depends('enable_upnp', '1');
|
|
- o.retain = true;
|
|
+ o = s.taboption('advanced', form.ListValue, 'allow_third_party_mapping', _('Allow third-party mapping'),
|
|
+ _('Allow adding port maps for non-requesting IP addresses; use with care'));
|
|
+ o.value('', _('Disabled') + ' (' + _('recommended') + ')');
|
|
+ o.value('1', _('Enabled'));
|
|
+ o.value('upnp-igd', _('Enabled') + ' (' + _('UPnP IGD only') + ')');
|
|
+ o.value('pcp', _('Enabled') + ' (' + _('PCP only') + ')');
|
|
|
|
s.taboption('advanced', form.Flag, 'ipv6_disable', _('Disable IPv6 mapping'));
|
|
|
|
@@ -195,46 +205,69 @@ return view.extend({
|
|
o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
- s.taboption('advanced', form.Flag, 'log_output', _('Enable additional logging'),
|
|
- _('Puts extra debugging information into the system log'));
|
|
+ o = s.taboption('advanced', form.ListValue, 'log_output', _('Log level'));
|
|
+ o.value('default', _('Default'));
|
|
+ o.value('info', _('Info'));
|
|
+ o.value('debug', _('Debug'));
|
|
+ o.default = 'default';
|
|
+ o.widget = 'radio';
|
|
|
|
- o = s.taboption('advanced', form.Value, 'upnp_lease_file', _('Service lease file'));
|
|
+ o = s.taboption('advanced', form.Value, 'lease_file', _('Service lease file'));
|
|
o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('igd', form.Value, 'download', _('Download speed'),
|
|
- _('Report maximum download speed in kByte/s'));
|
|
- o.depends('enable_upnp', '1');
|
|
+ o = s.taboption('igd', form.Value, 'download_kbps', _('Download speed'),
|
|
+ _('Report maximum connection speed in kbit/s'));
|
|
+ o.datatype = 'uinteger';
|
|
+ o.placeholder = _('Default interface link speed');
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('igd', form.Value, 'upload', _('Upload speed'),
|
|
- _('Report maximum upload speed in kByte/s'));
|
|
- o.depends('enable_upnp', '1');
|
|
+ o = s.taboption('igd', form.Value, 'upload_kbps', _('Upload speed'),
|
|
+ _('Report maximum connection speed in kbit/s'));
|
|
+ o.datatype = 'uinteger';
|
|
+ o.placeholder = _('Default interface link speed');
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.taboption('igd', form.Value, 'friendly_name', _('Router/friendly name'));
|
|
+ o.placeholder = 'OpenWrt UPnP IGD & PCP';
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
o = s.taboption('igd', form.Value, 'model_number', _('Announced model number'));
|
|
- o.depends('enable_upnp', '1');
|
|
+ // o.depends('enable_protocols', 'upnp-igd');
|
|
+ // o.depends('enable_protocols', 'all');
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
o = s.taboption('igd', form.Value, 'serial_number', _('Announced serial number'));
|
|
- o.depends('enable_upnp', '1');
|
|
+ // o.depends('enable_protocols', 'upnp-igd');
|
|
+ // o.depends('enable_protocols', 'all');
|
|
+ o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
o = s.taboption('igd', form.Value, 'presentation_url', _('Router/presentation URL'),
|
|
_('Report custom router web interface URL'));
|
|
o.placeholder = 'http://192.168.1.1/';
|
|
- o.depends('enable_upnp', '1');
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
o = s.taboption('igd', form.Value, 'uuid', _('Device UUID'));
|
|
- // o.depends('enable_upnp', '1');
|
|
+ // o.depends('enable_protocols', 'upnp-igd');
|
|
+ // o.depends('enable_protocols', 'all');
|
|
o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
o.retain = true;
|
|
|
|
- o = s.taboption('igd', form.Value, 'port', _('SOAP/HTTP port'));
|
|
+ o = s.taboption('igd', form.Value, 'http_port', _('SOAP/HTTP port'));
|
|
o.datatype = 'port';
|
|
o.placeholder = '5000';
|
|
- o.depends('enable_upnp', '1');
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
o = s.taboption('igd', form.Value, 'notify_interval', _('Notify interval'),
|
|
@@ -243,7 +276,57 @@ return view.extend({
|
|
.format('<abbr title="Simple Service Discovery Protocol">SSDP</abbr>', '<code>Cache-Control: max-age=1800</code>'));
|
|
o.datatype = 'min(900)';
|
|
o.placeholder = '900';
|
|
- o.depends('enable_upnp', '1');
|
|
+ o.depends('enable_protocols', 'upnp-igd');
|
|
+ o.depends('enable_protocols', 'all');
|
|
+ o.retain = true;
|
|
+
|
|
+ s = m.section(form.GridSection, 'internal_network', '<h5>' + _('Enable Networks / Access Control') + '</h5>',
|
|
+ _('Select local/internal (LAN) network interfaces to enable the service for.') + ' ' +
|
|
+ _('Set access control defaults for ports that all devices on a network can map.') + ' ' +
|
|
+ _('IPv6 is currently always accepted unless disabled. (Alternative text welcome)'));
|
|
+ s.anonymous = true;
|
|
+ s.addremove = true;
|
|
+ s.cloneable = true;
|
|
+ s.sortable = true;
|
|
+ s.nodescriptions = true;
|
|
+ s.modaltitle = _('UPnP IGD & PCP/NAT-PMP') + ' - ' + _('Edit Network Access Control Settings');
|
|
+
|
|
+ o = s.option(widgets.NetworkSelect, 'interface', _('Internal network'),
|
|
+ _('Select the local/internal (LAN) network interface to enable the service for'));
|
|
+ o.nocreate = true;
|
|
+ o.editable = true;
|
|
+ o.rmempty = false;
|
|
+ o.retain = true;
|
|
+ o.filter = function(section_id, value) {
|
|
+ return (value == 'wan' || value == 'wan6') ? '' : value;
|
|
+ };
|
|
+
|
|
+ o = s.option(form.ListValue, 'access_defaults', _('Access defaults'),
|
|
+ _('Set access control defaults for ports that all devices on the network can map'));
|
|
+ o.value('', _('None / accept extra ports only'));
|
|
+ o.value('accept-high-ports', _('Accept ports >= 1024'));
|
|
+ o.value('accept-web+high-ports', _('Accept HTTP/HTTPS + ports >= 1024'));
|
|
+ o.value('accept-web-ports', _('Accept HTTP/HTTPS ports'));
|
|
+ o.value('accept-all-ports', _('Accept all ports'));
|
|
+ o.editable = true;
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.option(form.Value, 'accept_ports', _('Accept extra ports'));
|
|
+ o.datatype = 'list(portrange)';
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.option(form.Value, 'reject_ports', _('Reject ports'),
|
|
+ _('Reject unsafe/insecure/risky FTP/Telnet/DCE/NetBIOS/SMB/RDP ports on the network by default; overrides other settings; use %s for none').format('<code>0</code>'));
|
|
+ o.datatype = 'list(portrange)';
|
|
+ o.placeholder = '21 23 135 137-139 445 3389';
|
|
+ o.modalonly = true;
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.option(form.Flag, 'check_acl', _('Check ACL'),
|
|
+ _('Extend or override access defaults by device-specific permissions using the access control list (ACL)') + '<br />' +
|
|
+ _('Sequence:') + ' 1. ' + _('Reject ports') + ', 2. ' + _('ACL entries (if checked)') + ', 3. ' + _('Access defaults') + ', 4. ' + _('Accept extra ports'));
|
|
+ o.default = '1';
|
|
+ o.editable = true;
|
|
o.retain = true;
|
|
|
|
s = m.section(form.GridSection, 'perm_rule', _('Service Access Control List'),
|
|
@@ -251,6 +334,15 @@ return view.extend({
|
|
s.anonymous = true;
|
|
s.addremove = true;
|
|
s.sortable = true;
|
|
+ // To do: ACL part of extra tab with dependency on option as immediately, and network section part of service setup tab
|
|
+ let acl_used = false;
|
|
+ for (let ifnr = 0; uci.get('upnpd', `@internal_network[${ifnr}]`, 'interface'); ifnr++) {
|
|
+ if (uci.get('upnpd', `@internal_network[${ifnr}]`, 'check_acl') != '0') {
|
|
+ acl_used = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ s.disable = !acl_used;
|
|
|
|
s.option(form.Value, 'comment', _('Comment'));
|
|
|
|
@@ -271,11 +363,13 @@ return view.extend({
|
|
o.value('deny', _('Deny'));
|
|
|
|
return m.render().then(L.bind(function(m, nodes) {
|
|
- poll.add(L.bind(function() {
|
|
- return Promise.all([
|
|
- callUpnpGetStatus()
|
|
- ]).then(L.bind(this.poll_status, this, nodes));
|
|
- }, this), 5);
|
|
+ if (uci.get('upnpd', 'config', 'enabled') != '0') {
|
|
+ poll.add(L.bind(function() {
|
|
+ return Promise.all([
|
|
+ callUpnpGetStatus()
|
|
+ ]).then(L.bind(this.poll_status, this, nodes));
|
|
+ }, this), 5);
|
|
+ }
|
|
return nodes;
|
|
}, this, m));
|
|
}
|
|
diff --git a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
index 56ae951ceb03..a7bf8e6f5d86 100644
|
|
--- a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
+++ b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
@@ -16,7 +16,7 @@ const methods = {
|
|
const ubus = connect();
|
|
const rules = [];
|
|
const leases = [];
|
|
- const leasefile = open(uci.get('upnpd', 'config', 'upnp_lease_file') || '/var/run/miniupnpd.leases', 'r');
|
|
+ const leasefile = open(uci.get('upnpd', 'config', 'lease_file') || '/var/run/miniupnpd.leases', 'r');
|
|
if (leasefile) {
|
|
for (let line = leasefile.read('line'); length(line); line = leasefile.read('line')) {
|
|
const record = split(line, ':', 6);
|
|
@@ -109,7 +109,7 @@ const methods = {
|
|
const idx = +req.args?.token;
|
|
if (idx > 0) {
|
|
const uci = cursor();
|
|
- const leasefile = uci.get('upnpd', 'config', 'upnp_lease_file') || '/var/run/miniupnpd.leases';
|
|
+ const leasefile = uci.get('upnpd', 'config', 'lease_file') || '/var/run/miniupnpd.leases';
|
|
if (access(leasefile)) {
|
|
system(['sed', '-i', '-e', `${idx}d`, leasefile]);
|
|
system(['/etc/init.d/miniupnpd', 'restart']);
|
|
|
|
From e203add9f4372d85f97b4222abe69066a08cb571 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 4/7] luci-app-upnp: rename UCI section to settings v2.0
|
|
|
|
Rename UCI section `config` (v1.0) -> `settings` (v2.0), helps on
|
|
migration and to distinguish the updated config from the previous one
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../htdocs/luci-static/resources/view/upnp/upnp.js | 10 +++++-----
|
|
.../luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp | 4 ++--
|
|
2 files changed, 7 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 1dab80bef4b9..e5f1245636af 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -92,16 +92,16 @@ return view.extend({
|
|
'The %s (%s = UPnP IGD & PCP/NAT-PMP) protocols/service enable permitted devices on local networks to autonomously set up IPv4/IPv6 port maps/forwards on this router.')
|
|
.format(protocols)
|
|
);
|
|
- if (!uci.get('upnpd', 'config')) {
|
|
+ if (!uci.get('upnpd', 'settings')) {
|
|
ui.addNotification(null, E('div', '<h4>' + _('No suitable configuration was found!') + '</h4><p>' +
|
|
- _('No suitable config (LuCI app %s) found in %s. A related package update (daemon or LuCI app) may be missing.').format('v1.0', '<code>/etc/config/upnpd</code>') + '<br />' +
|
|
+ _('No suitable config (LuCI app %s) found in %s. A related package update (daemon or LuCI app) may be missing.').format('v2.0', '<code>/etc/config/upnpd</code>') + '<br />' +
|
|
_('Use the software package manager, update lists, and install the related update. Config is migrated with the daemon package update.') + '</p>' +
|
|
'<a class="btn" href="/cgi-bin/luci/admin/system/package-manager?query=UPnP%20IGD%20&%20PCP/NAT-PMP">' + _('Go to package manager…') + '</a>'), 'warning');
|
|
m.readonly = true;
|
|
}
|
|
|
|
s = m.section(form.GridSection, '_active_rules');
|
|
- s.disable = uci.get('upnpd', 'config', 'enabled') == '0';
|
|
+ s.disable = uci.get('upnpd', 'settings', 'enabled') == '0';
|
|
|
|
s.render = L.bind(function(view, section_id) {
|
|
const table = E('table', { 'class': 'table cbi-section-table', 'id': 'upnp_status_table' }, [
|
|
@@ -143,7 +143,7 @@ return view.extend({
|
|
]);
|
|
}, o, this);
|
|
|
|
- s = m.section(form.NamedSection, 'config', 'upnpd', _('Service Settings'));
|
|
+ s = m.section(form.NamedSection, 'settings', 'upnpd', _('Service Settings'));
|
|
s.addremove = false;
|
|
s.tab('setup', _('Service Setup'));
|
|
s.tab('advanced', _('Advanced Settings'));
|
|
@@ -363,7 +363,7 @@ return view.extend({
|
|
o.value('deny', _('Deny'));
|
|
|
|
return m.render().then(L.bind(function(m, nodes) {
|
|
- if (uci.get('upnpd', 'config', 'enabled') != '0') {
|
|
+ if (uci.get('upnpd', 'settings', 'enabled') != '0') {
|
|
poll.add(L.bind(function() {
|
|
return Promise.all([
|
|
callUpnpGetStatus()
|
|
diff --git a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
index a7bf8e6f5d86..e38f5a26352d 100644
|
|
--- a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
+++ b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
@@ -16,7 +16,7 @@ const methods = {
|
|
const ubus = connect();
|
|
const rules = [];
|
|
const leases = [];
|
|
- const leasefile = open(uci.get('upnpd', 'config', 'lease_file') || '/var/run/miniupnpd.leases', 'r');
|
|
+ const leasefile = open(uci.get('upnpd', 'settings', 'lease_file') || '/var/run/miniupnpd.leases', 'r');
|
|
if (leasefile) {
|
|
for (let line = leasefile.read('line'); length(line); line = leasefile.read('line')) {
|
|
const record = split(line, ':', 6);
|
|
@@ -109,7 +109,7 @@ const methods = {
|
|
const idx = +req.args?.token;
|
|
if (idx > 0) {
|
|
const uci = cursor();
|
|
- const leasefile = uci.get('upnpd', 'config', 'lease_file') || '/var/run/miniupnpd.leases';
|
|
+ const leasefile = uci.get('upnpd', 'settings', 'lease_file') || '/var/run/miniupnpd.leases';
|
|
if (access(leasefile)) {
|
|
system(['sed', '-i', '-e', `${idx}d`, leasefile]);
|
|
system(['/etc/init.d/miniupnpd', 'restart']);
|
|
|
|
From 88c8ccce976eb54ed4d3e6cea00b18660eb3eec7 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 5/7] luci-app-upnp: update ACL options, migrate section
|
|
|
|
- Disableable and cloneable ACL entries, always translated `Action`
|
|
- Improve UI with direct editability, clearer help wording, and rename
|
|
to `Access Control List`
|
|
- The ACL is now rejected last if not accepted by access defaults. Add
|
|
(disabled) ACL template entries on migration
|
|
- Migrate ACL entries to the new section name `acl_entry`
|
|
- The following ACL UCI options been added or changed, and the previous
|
|
options are migrated on updating:
|
|
|
|
acl_entry UCI options | Change | Previous name
|
|
----------------------------|----------------------------|--------------
|
|
action | New/updated values (1) |
|
|
int_port | Remove colon separator (2) | int_ports
|
|
ext_port | Remove colon separator (2) | ext_ports
|
|
descr_filter | New option (3) |
|
|
|
|
1. Allow disabled, and update action option to use the nftables terms
|
|
(allow/deny -> accept/reject). To avoid adding inverted actions when
|
|
changing via LuCI, ensure any missing are set, as LuCI and UCI had
|
|
not matching action defaults. Missing actions are now ignored/logged
|
|
2. Ensure that the hyphen (-) is only used as a port range separator by
|
|
migration, as the colon (:) is not valid in LuCI
|
|
3. Add missing UCI option to set a regular expression to check for a
|
|
UPnP IGD IPv4 port map description, and fix the current collision
|
|
with the comment field which was not noticed due to a daemon bug
|
|
https://redirect.github.com/openwrt/packages/pull/24495
|
|
https://redirect.github.com/miniupnp/miniupnp/pull/853
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../luci-static/resources/view/upnp/upnp.js | 46 +++++++++++++++----
|
|
1 file changed, 36 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index e5f1245636af..87c7c2a25fe0 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -329,11 +329,14 @@ return view.extend({
|
|
o.editable = true;
|
|
o.retain = true;
|
|
|
|
- s = m.section(form.GridSection, 'perm_rule', _('Service Access Control List'),
|
|
- _('ACL specify which client addresses and ports can be mapped, IPv6 always allowed.'));
|
|
+ s = m.section(form.GridSection, 'acl_entry', '<h5>' + _('Access Control List') + '</h5>',
|
|
+ _('The access control list (ACL) specifies which IP addresses and ports can be mapped.') + ' ' +
|
|
+ _('ACL entries are checked in order, then rejected if not matched and not accepted by access defaults. (should be part of extra tab)'));
|
|
s.anonymous = true;
|
|
s.addremove = true;
|
|
+ s.cloneable = true;
|
|
s.sortable = true;
|
|
+ s.modaltitle = _('UPnP IGD & PCP/NAT-PMP') + ' - ' + _('Edit ACL Entry');
|
|
// To do: ACL part of extra tab with dependency on option as immediately, and network section part of service setup tab
|
|
let acl_used = false;
|
|
for (let ifnr = 0; uci.get('upnpd', `@internal_network[${ifnr}]`, 'interface'); ifnr++) {
|
|
@@ -344,23 +347,46 @@ return view.extend({
|
|
}
|
|
s.disable = !acl_used;
|
|
|
|
- s.option(form.Value, 'comment', _('Comment'));
|
|
+ o = s.option(form.Value, 'comment', _('Comment'));
|
|
+ o.default = _('unspecified');
|
|
|
|
o = s.option(form.Value, 'int_addr', _('IP address'));
|
|
o.datatype = 'ip4addr';
|
|
- o.placeholder = '0.0.0.0/0';
|
|
+ o.rmempty = false;
|
|
+ o.editable = true;
|
|
+ o.retain = true;
|
|
+ o.modalonly = false;
|
|
+
|
|
+ o = s.option(form.Value, 'int_addr', _('IP address'),
|
|
+ _('Enter device\'s IPv4 address, or an address with netmask'));
|
|
+ o.datatype = 'ip4addr';
|
|
+ o.rmempty = false;
|
|
+ o.retain = true;
|
|
+ o.modalonly = true;
|
|
|
|
- o = s.option(form.Value, 'int_ports', _('Port'));
|
|
+ o = s.option(form.Value, 'int_port', _('Port'));
|
|
o.datatype = 'portrange';
|
|
- o.placeholder = '1-65535';
|
|
+ o.placeholder = '1-65535 (' + _('any port') + ')';
|
|
+ o.editable = true;
|
|
+ o.retain = true;
|
|
|
|
- o = s.option(form.Value, 'ext_ports', _('External port'));
|
|
+ o = s.option(form.Value, 'ext_port', _('External port'));
|
|
o.datatype = 'portrange';
|
|
- o.placeholder = '1-65535';
|
|
+ o.placeholder = '1-65535 (' + _('any port') + ')';
|
|
+ o.editable = true;
|
|
+ o.retain = true;
|
|
+
|
|
+ o = s.option(form.Value, 'descr_filter', _('Description filter'),
|
|
+ _('Regular expression to check description of UPnP IGD IPv4 port maps'));
|
|
+ o.placeholder = '.* (' + _('any description') + ')';
|
|
+ o.modalonly = true;
|
|
|
|
o = s.option(form.ListValue, 'action', _('Action'));
|
|
- o.value('allow', _('Allow'));
|
|
- o.value('deny', _('Deny'));
|
|
+ o.value('accept', _('Accept'));
|
|
+ o.value('reject', _('Reject'));
|
|
+ o.value('disabled', _('Disabled'));
|
|
+ o.editable = true;
|
|
+ o.retain = true;
|
|
|
|
return m.render().then(L.bind(function(m, nodes) {
|
|
if (uci.get('upnpd', 'settings', 'enabled') != '0') {
|
|
|
|
From 095283e5b52745251d12f8254f3257f4c4cfe7f8 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 6/7] luci-app-upnp: list active IPv6 port maps
|
|
|
|
Supports nftables and ip6tables; IPv6 port maps not yet deletable, as
|
|
not parsing extra IPv6 lease file
|
|
|
|
(Note: Daemon's IPv6 lease file differs from the IPv4 format in order
|
|
and separator. With IPv4, the remote IP field is missing and not
|
|
retained during daemon restarts. IMHO, it would be better to have a
|
|
complete/combined IPv4/IPv6 lease file upstream, with unique mapping IDs
|
|
for reliable deletion in the 1st field, with a standardised order and
|
|
more fields, and then use it without rewriting the parsing.)
|
|
|
|
(to merge with prior)
|
|
|
|
Fixes: https://redirect.github.com/openwrt/luci/issues/2985
|
|
Fixes: https://redirect.github.com/openwrt/luci/issues/5197
|
|
Fixes: https://redirect.github.com/openwrt/luci/pull/8567
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../resources/view/status/include/80_upnp.js | 8 +++-
|
|
.../luci-static/resources/view/upnp/upnp.js | 16 ++++++--
|
|
.../root/usr/share/rpcd/ucode/luci.upnp | 40 ++++++++++++++++++-
|
|
3 files changed, 57 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js
|
|
index c82a108232de..7d06b2a56d6d 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/status/include/80_upnp.js
|
|
@@ -70,15 +70,19 @@ return baseclass.extend({
|
|
rule.proto,
|
|
expires_str,
|
|
'%h'.format(rule.descr),
|
|
- E('button', {
|
|
+ rule.num != '0' ? E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
'click': L.bind(handleDelRule, this, rule.num),
|
|
'title': _('Delete')
|
|
+ }, [_('Delete')]) : E('button', {
|
|
+ 'class': 'btn cbi-button-remove',
|
|
+ 'title': _('Not yet deletable; UPnP IGDv2 IPv6 port maps expire sooner, have no description'),
|
|
+ 'style': 'cursor: not-allowed'
|
|
}, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
- cbi_update_table(table, rows, E('em', _('There are no active port maps.')));
|
|
+ cbi_update_table(table, rows, E('em', _('There are no active IPv4/IPv6 port maps')));
|
|
|
|
return table;
|
|
}
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 87c7c2a25fe0..2f790e6c4a12 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -68,15 +68,19 @@ return view.extend({
|
|
rule.proto,
|
|
expires_str,
|
|
'%h'.format(rule.descr),
|
|
- E('button', {
|
|
+ rule.num != '0' ? E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
'click': L.bind(handleDelRule, this, rule.num),
|
|
'title': _('Delete')
|
|
+ }, [_('Delete')]) : E('button', {
|
|
+ 'class': 'btn cbi-button-remove',
|
|
+ 'title': _('Not yet deletable; UPnP IGDv2 IPv6 port maps expire sooner, have no description'),
|
|
+ 'style': 'cursor: not-allowed'
|
|
}, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
- cbi_update_table(nodes.querySelector('#upnp_status_table'), rows, E('em', _('There are no active port maps.')));
|
|
+ cbi_update_table(nodes.querySelector('#upnp_status_table'), rows, E('em', _('There are no active IPv4/IPv6 port maps')));
|
|
},
|
|
|
|
render: function(data) {
|
|
@@ -128,15 +132,19 @@ return view.extend({
|
|
rule.proto,
|
|
'', // expires
|
|
'%h'.format(rule.descr),
|
|
- E('button', {
|
|
+ rule.num != '0' ? E('button', {
|
|
'class': 'btn cbi-button-remove',
|
|
'click': L.bind(handleDelRule, this, rule.num),
|
|
'title': _('Delete')
|
|
+ }, [_('Delete')]) : E('button', {
|
|
+ 'class': 'btn cbi-button-remove',
|
|
+ 'title': _('Not yet deletable; UPnP IGDv2 IPv6 port maps expire sooner, have no description'),
|
|
+ 'style': 'cursor: not-allowed'
|
|
}, [_('Delete')])
|
|
];
|
|
});
|
|
|
|
- cbi_update_table(table, rows, E('em', _('There are no active port maps.')));
|
|
+ cbi_update_table(table, rows, E('em', _('There are no active IPv4/IPv6 port maps')));
|
|
|
|
return E('div', { 'class': 'cbi-section cbi-tblsection' }, [
|
|
E('h3', _('Active Port Maps')), table
|
|
diff --git a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
index e38f5a26352d..b9bf72809f66 100644
|
|
--- a/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
+++ b/luci-app-upnp/root/usr/share/rpcd/ucode/luci.upnp
|
|
@@ -59,6 +59,23 @@ const methods = {
|
|
}
|
|
}
|
|
ipt.close();
|
|
+
|
|
+ const iptipv6 = popen('ip6tables --line-numbers -xnvL MINIUPNPD 2>/dev/null');
|
|
+ if (iptipv6) {
|
|
+ for (let line = iptipv6.read('line'); length(line); line = iptipv6.read('line')) {
|
|
+ let m = match(line, /^([0-9]+) .+ ([0-9a-f:]+) ([ut].p) dpt:([0-9]+)/);
|
|
+ if (m) {
|
|
+ push(rules, {
|
|
+ num: '0',
|
|
+ intaddr: arrtoip(iptoarr(m[2])),
|
|
+ intport: +m[4],
|
|
+ extport: +m[4],
|
|
+ proto: uc(m[3])
|
|
+ });
|
|
+ }
|
|
+ }
|
|
+ iptipv6.close();
|
|
+ }
|
|
}
|
|
|
|
const nft = popen('nft --handle list chain inet fw4 upnp_prerouting 2>/dev/null');
|
|
@@ -77,6 +94,27 @@ const methods = {
|
|
}
|
|
}
|
|
nft.close();
|
|
+
|
|
+ const nftipv6 = popen('nft --handle list chain inet fw4 upnp_forward 2>/dev/null');
|
|
+ if (nftipv6) {
|
|
+ for (let line = nftipv6.read('line'), num = 1; length(line); line = nftipv6.read('line')) {
|
|
+ let m = match(line, /^\t\tiif ".+" th dport ([0-9]+) @nh,192,128 0x([0-9a-f]+) @nh,48,8 (0x6|0x11) accept/);
|
|
+ if (m) {
|
|
+ push(rules, {
|
|
+ num: '0',
|
|
+ intaddr: arrtoip(iptoarr(join(':', [substr(m[2], 0, 4),
|
|
+ substr(m[2], 4, 4), substr(m[2], 8, 4), substr(m[2], 12, 4), substr(m[2], 16, 4),
|
|
+ substr(m[2], 20, 4), substr(m[2], 24, 4), substr(m[2], 28, 4)
|
|
+ ]))),
|
|
+ intport: +m[1],
|
|
+ extport: +m[1],
|
|
+ proto: (m[3] == '0x6') ? 'TCP' : 'UDP'
|
|
+ });
|
|
+ num++;
|
|
+ }
|
|
+ }
|
|
+ nftipv6.close();
|
|
+ }
|
|
}
|
|
|
|
return ubus.defer('luci-rpc', 'getHostHints', {}, function(rc, host_hints) {
|
|
@@ -92,7 +130,7 @@ const methods = {
|
|
}
|
|
}
|
|
for (let mac, hint in host_hints) {
|
|
- if (rule.intaddr in hint.ipaddrs) {
|
|
+ if (rule.intaddr in hint.ipaddrs || rule.intaddr in hint.ip6addrs) {
|
|
rule.host_hint = hint.name;
|
|
break;
|
|
}
|
|
|
|
From 5550b4a056860acd9ba6509b80f52ebeda47dbce Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 7/7] luci-app-upnp: service-wide access control settings
|
|
|
|
This implements variant B
|
|
|
|
upnpd.settings UCI options | Change | Previous name
|
|
-----------------------------|---------------------------|--------------
|
|
access_defaults | New option (1) |
|
|
accept_ports | New option (1) |
|
|
reject_ports | New option (2) |
|
|
check_acl | New option (1) |
|
|
|
|
Notes:
|
|
1. New options added for default ports that all devices can map,
|
|
client-specific permissions using the access control list (ACL) can
|
|
extend/override the defaults. Access defaults: accept-high-ports
|
|
accept-web+high-ports/accept-web-ports/accept-all-ports
|
|
2. Reject ports; overrides other settings. By default reject unsafe:
|
|
FTP (21), Telnet (23), DCE/NetBIOS/SMB (135/137-139/445), RDP (3389)
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../luci-static/resources/view/upnp/upnp.js | 106 ++++++++----------
|
|
1 file changed, 45 insertions(+), 61 deletions(-)
|
|
|
|
diff --git a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
index 2f790e6c4a12..68de0e56a807 100644
|
|
--- a/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
+++ b/luci-app-upnp/htdocs/luci-static/resources/view/upnp/upnp.js
|
|
@@ -154,6 +154,7 @@ return view.extend({
|
|
s = m.section(form.NamedSection, 'settings', 'upnpd', _('Service Settings'));
|
|
s.addremove = false;
|
|
s.tab('setup', _('Service Setup'));
|
|
+ s.tab('access_control', _('Access Control'));
|
|
s.tab('advanced', _('Advanced Settings'));
|
|
s.tab('igd', _('UPnP IGD Adjustments'));
|
|
|
|
@@ -168,6 +169,18 @@ return view.extend({
|
|
o.default = 'all';
|
|
o.widget = 'radio';
|
|
|
|
+ o = s.taboption('setup', widgets.NetworkSelect, 'internal_iface', _('Enable networks'),
|
|
+ _('Select local/internal (LAN) network interfaces to enable the service for'));
|
|
+ o.nocreate = true;
|
|
+ o.multiple = true;
|
|
+ o.rmempty = false;
|
|
+ o.filter = function(section_id, value) {
|
|
+ return (value == 'wan' || value == 'wan6') ? '' : value;
|
|
+ };
|
|
+ o.write = function(section_id, formvalue) {
|
|
+ uci.set('upnpd', section_id, 'internal_iface', Array.isArray(formvalue) ? formvalue.join(' ') : formvalue);
|
|
+ };
|
|
+
|
|
o = s.taboption('setup', form.ListValue, 'upnp_igd_compat', _('UPnP IGD compatibility'),
|
|
_('Set compatibility mode (act as device) to workaround IGDv2-incompatible clients; %s are known to only work with %s (or) <br />Emulate/report a specific/different device to workaround/support/handle/bypass/assist/mitigate... (Alternative text welcome)').format('Sony PS, Activision CoD…', 'IGDv1'));
|
|
o.value('igdv1', _('IGDv1 (IPv4 only)'));
|
|
@@ -176,6 +189,35 @@ return view.extend({
|
|
o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
+ o = s.taboption('access_control', form.ListValue, 'access_defaults', _('Access defaults'),
|
|
+ _('Set access control defaults for ports that all devices can map'));
|
|
+ o.value('', _('None / accept extra ports only'));
|
|
+ o.value('accept-high-ports', _('Accept ports >= 1024'));
|
|
+ o.value('accept-web+high-ports', _('Accept HTTP/HTTPS + ports >= 1024'));
|
|
+ o.value('accept-web-ports', _('Accept HTTP/HTTPS ports'));
|
|
+ o.value('accept-all-ports', _('Accept all ports'));
|
|
+
|
|
+ o = s.taboption('access_control', form.Value, 'accept_ports', _('Accept extra ports'));
|
|
+ o.datatype = 'list(portrange)';
|
|
+
|
|
+ o = s.taboption('access_control', form.Value, 'reject_ports', _('Reject ports'),
|
|
+ _('Reject unsafe/insecure/risky FTP/Telnet/DCE/NetBIOS/SMB/RDP ports by default; overrides other settings; use %s for none').format('<code>0</code>'));
|
|
+ o.datatype = 'list(portrange)';
|
|
+ o.placeholder = '21 23 135 137-139 445 3389';
|
|
+ o.modalonly = true;
|
|
+
|
|
+ o = s.taboption('access_control', form.Flag, 'check_acl', _('Check ACL'),
|
|
+ _('Extend or override access defaults by device-specific permissions using the access control list (ACL)') + '<br />' +
|
|
+ _('Sequence:') + ' 1. ' + _('Reject ports') + ', 2. ' + _('ACL entries (if checked)') + ', 3. ' + _('Access defaults') + ', 4. ' + _('Accept extra ports'));
|
|
+ o.default = '1';
|
|
+ o.onchange = function(ev, section_id, value) {
|
|
+ let acl = document.getElementById('cbi-upnpd-acl_entry');
|
|
+ value == 0 ? acl.style.display = 'none' : acl.style.display = 'block';
|
|
+ };
|
|
+
|
|
+ s.taboption('access_control', form.Flag, 'ipv6_disable', _('Disable IPv6 mapping'),
|
|
+ _('IPv6 is currently always accepted unless disabled'));
|
|
+
|
|
o = s.taboption('advanced', form.RichListValue, 'allow_cgnat', _('Allow %s/%s', 'Allow %s/%s (%s = CGNAT, %s = STUN)')
|
|
.format('<a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT" target="_blank" rel="noreferrer"><abbr title="Carrier-grade NAT">CGNAT</abbr></a>',
|
|
'<a href="https://en.wikipedia.org/wiki/STUN" target="_blank" rel="noreferrer"><abbr title="Session Traversal Utilities for NAT">STUN</abbr></a>'),
|
|
@@ -206,8 +248,6 @@ return view.extend({
|
|
o.value('upnp-igd', _('Enabled') + ' (' + _('UPnP IGD only') + ')');
|
|
o.value('pcp', _('Enabled') + ' (' + _('PCP only') + ')');
|
|
|
|
- s.taboption('advanced', form.Flag, 'ipv6_disable', _('Disable IPv6 mapping'));
|
|
-
|
|
o = s.taboption('advanced', form.Flag, 'system_uptime', _('Report system instead of service uptime'));
|
|
o.default = '1';
|
|
o.depends('keep-translation', 'to-disable-as-rare-use');
|
|
@@ -288,72 +328,16 @@ return view.extend({
|
|
o.depends('enable_protocols', 'all');
|
|
o.retain = true;
|
|
|
|
- s = m.section(form.GridSection, 'internal_network', '<h5>' + _('Enable Networks / Access Control') + '</h5>',
|
|
- _('Select local/internal (LAN) network interfaces to enable the service for.') + ' ' +
|
|
- _('Set access control defaults for ports that all devices on a network can map.') + ' ' +
|
|
- _('IPv6 is currently always accepted unless disabled. (Alternative text welcome)'));
|
|
- s.anonymous = true;
|
|
- s.addremove = true;
|
|
- s.cloneable = true;
|
|
- s.sortable = true;
|
|
- s.nodescriptions = true;
|
|
- s.modaltitle = _('UPnP IGD & PCP/NAT-PMP') + ' - ' + _('Edit Network Access Control Settings');
|
|
-
|
|
- o = s.option(widgets.NetworkSelect, 'interface', _('Internal network'),
|
|
- _('Select the local/internal (LAN) network interface to enable the service for'));
|
|
- o.nocreate = true;
|
|
- o.editable = true;
|
|
- o.rmempty = false;
|
|
- o.retain = true;
|
|
- o.filter = function(section_id, value) {
|
|
- return (value == 'wan' || value == 'wan6') ? '' : value;
|
|
- };
|
|
-
|
|
- o = s.option(form.ListValue, 'access_defaults', _('Access defaults'),
|
|
- _('Set access control defaults for ports that all devices on the network can map'));
|
|
- o.value('', _('None / accept extra ports only'));
|
|
- o.value('accept-high-ports', _('Accept ports >= 1024'));
|
|
- o.value('accept-web+high-ports', _('Accept HTTP/HTTPS + ports >= 1024'));
|
|
- o.value('accept-web-ports', _('Accept HTTP/HTTPS ports'));
|
|
- o.value('accept-all-ports', _('Accept all ports'));
|
|
- o.editable = true;
|
|
- o.retain = true;
|
|
-
|
|
- o = s.option(form.Value, 'accept_ports', _('Accept extra ports'));
|
|
- o.datatype = 'list(portrange)';
|
|
- o.retain = true;
|
|
-
|
|
- o = s.option(form.Value, 'reject_ports', _('Reject ports'),
|
|
- _('Reject unsafe/insecure/risky FTP/Telnet/DCE/NetBIOS/SMB/RDP ports on the network by default; overrides other settings; use %s for none').format('<code>0</code>'));
|
|
- o.datatype = 'list(portrange)';
|
|
- o.placeholder = '21 23 135 137-139 445 3389';
|
|
- o.modalonly = true;
|
|
- o.retain = true;
|
|
-
|
|
- o = s.option(form.Flag, 'check_acl', _('Check ACL'),
|
|
- _('Extend or override access defaults by device-specific permissions using the access control list (ACL)') + '<br />' +
|
|
- _('Sequence:') + ' 1. ' + _('Reject ports') + ', 2. ' + _('ACL entries (if checked)') + ', 3. ' + _('Access defaults') + ', 4. ' + _('Accept extra ports'));
|
|
- o.default = '1';
|
|
- o.editable = true;
|
|
- o.retain = true;
|
|
-
|
|
s = m.section(form.GridSection, 'acl_entry', '<h5>' + _('Access Control List') + '</h5>',
|
|
_('The access control list (ACL) specifies which IP addresses and ports can be mapped.') + ' ' +
|
|
- _('ACL entries are checked in order, then rejected if not matched and not accepted by access defaults. (should be part of extra tab)'));
|
|
+ _('ACL entries are checked in order, then rejected if not matched and not accepted by access defaults. (To do: should be part of access control tab)'));
|
|
s.anonymous = true;
|
|
s.addremove = true;
|
|
s.cloneable = true;
|
|
s.sortable = true;
|
|
s.modaltitle = _('UPnP IGD & PCP/NAT-PMP') + ' - ' + _('Edit ACL Entry');
|
|
- // To do: ACL part of extra tab with dependency on option as immediately, and network section part of service setup tab
|
|
- let acl_used = false;
|
|
- for (let ifnr = 0; uci.get('upnpd', `@internal_network[${ifnr}]`, 'interface'); ifnr++) {
|
|
- if (uci.get('upnpd', `@internal_network[${ifnr}]`, 'check_acl') != '0') {
|
|
- acl_used = true;
|
|
- break;
|
|
- }
|
|
- }
|
|
- s.disable = !acl_used;
|
|
+ // To do: ACL part of access control tab and hide (or dependency on option) instead of disable as immediately, and to not break onchange function
|
|
+ s.disable = uci.get('upnpd', 'settings', 'check_acl') == '0';
|
|
|
|
o = s.option(form.Value, 'comment', _('Comment'));
|
|
o.default = _('unspecified');
|
|
|
|
--- a/miniupnpd/Makefile
|
|
+++ b/miniupnpd/Makefile
|
|
@@ -8,12 +8,12 @@
|
|
include $(TOPDIR)/rules.mk
|
|
|
|
PKG_NAME:=miniupnpd
|
|
-PKG_VERSION:=2.3.9
|
|
-PKG_RELEASE:=3
|
|
+PKG_VERSION:=2.3.10
|
|
+PKG_RELEASE:=1
|
|
|
|
PKG_SOURCE_URL:=https://github.com/miniupnp/miniupnp/releases/download/miniupnpd_$(subst .,_,$(PKG_VERSION))
|
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
|
-PKG_HASH:=66cb3c3d697ab2bb3a61d3c48628166d6ba328d7c2dbeb95898fdf2a3202af7b
|
|
+PKG_HASH:=f9c34ed3632fb60cd248dd5897bd98479a103a75688b056ca2f069e68ab32987
|
|
|
|
PKG_MAINTAINER:=Alexandru Ardelean <ardeleanalex@gmail.com>
|
|
PKG_LICENSE:=BSD-3-Clause
|
|
|
|
From 1bca0ee5caa52f493a4e6cef12d2665ba246ecbe Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 02/10] miniupnpd: patch for UPnP IGDv2 Microsoft/Apple
|
|
compatibility
|
|
|
|
- Add workaround to list port maps with the Windows IGDv2-incompatible
|
|
client by returning an infinite (0) lease duration. To fix listing and
|
|
editing via GUI (Explorer/Network), if daemon was compiled with IGDv2
|
|
- Extend detection to older versions of Windows and add Xbox
|
|
- Detect Apple IGDv2-incompatible clients and apply existing workaround,
|
|
that only caused problems if PCP/NAT-PMP (prioritised) was disabled
|
|
|
|
(to merge with prior)
|
|
|
|
Link: https://github.com/Self-Hosting-Group/miniupnp/tree/upnp-igdv2-compat
|
|
Link: https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Overview#compatibility-issues
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../patches/10-upnp-igdv2-compat.patch | 80 +++++++++++++++++++
|
|
1 file changed, 80 insertions(+)
|
|
create mode 100644 miniupnpd/patches/10-upnp-igdv2-compat.patch
|
|
|
|
diff --git a/miniupnpd/patches/10-upnp-igdv2-compat.patch b/miniupnpd/patches/10-upnp-igdv2-compat.patch
|
|
new file mode 100644
|
|
index 00000000000000..2307aeb83ceb74
|
|
--- /dev/null
|
|
+++ b/miniupnpd/patches/10-upnp-igdv2-compat.patch
|
|
@@ -0,0 +1,80 @@
|
|
+From 38e01919d585b0fd663d2b3249963b336061cbd3 Mon Sep 17 00:00:00 2001
|
|
+From: Self-Hosting-Group
|
|
+ <155233284+Self-Hosting-Group@users.noreply.github.com>
|
|
+Date: Wed, 25 Mar 2026 00:00:00 +0000
|
|
+Subject: [PATCH] miniupnpd: UPnP IGDv2 Microsoft/Apple compatibility
|
|
+
|
|
+* Add workaround to list port maps with the Windows IGDv2-incompatible
|
|
+ client by returning an infinite (0) lease duration. To fix listing and
|
|
+ editing via GUI (Explorer/Network), if daemon was compiled with IGDv2
|
|
+* Extend detection to older versions of Windows and add Xbox
|
|
+* Detect Apple IGDv2-incompatible clients and apply existing workaround,
|
|
+ that only caused problems if PCP/NAT-PMP (prioritised) was disabled
|
|
+
|
|
+Link: https://github.com/Self-Hosting-Group/miniupnp/tree/upnp-igdv2-compat
|
|
+Link: https://github.com/Self-Hosting-Group/wiki/wiki/Port-Mapping-Protocols-Overview#compatibility-issues
|
|
+---
|
|
+ upnphttp.c | 19 ++++++++++++++++---
|
|
+ upnpsoap.c | 16 ++++++++++++++++
|
|
+ 2 files changed, 32 insertions(+), 3 deletions(-)
|
|
+
|
|
+--- a/upnphttp.c
|
|
++++ b/upnphttp.c
|
|
+@@ -304,9 +304,22 @@ ParseHttpHeaders(struct upnphttp * h)
|
|
+ }
|
|
+ else if(strncasecmp(line, "user-agent:", 11) == 0)
|
|
+ {
|
|
+- /* - User-Agent: Microsoft-Windows/10.0 UPnP/1.0
|
|
+- * - User-Agent: FDSSDP */
|
|
+- if(strcasestr(line + 11, "microsoft") != NULL || strstr(line + 11, "FDSSDP") != NULL) {
|
|
++ /* Detect Microsoft UPnP IGDv2-incompatible clients that only support IGDv1 routers,
|
|
++ * and Windows requires extra UDA 1.x (Win XP 1.0), via User-Agent SOAP/HTTP header:
|
|
++ * - Microsoft-Windows/10.0 UPnP/1.0 (Win >=10)
|
|
++ * - Microsoft-Windows/6.1 UPnP/1.0 (Win 7)
|
|
++ * - FDSSDP (Win >=Vista for GET)
|
|
++ * - Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1) (Win XP/Vista for GET)
|
|
++ * - Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x) (Win XP/Vista for POST)
|
|
++ * - Xbox/2.0.17559.0 UPnP/1.0 Xbox/2.0.17559.0
|
|
++ * Detect Apple UPnP IGDv2-incompatible clients that only support IGDv1 routers:
|
|
++ * - Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1) (for GET)
|
|
++ * - Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x) (for POST) */
|
|
++ if (((strstr(line + 11, "Microsoft-Windows/") != NULL ||
|
|
++ strstr(line + 11, "Xbox/") != NULL) &&
|
|
++ strstr(line + 11, " UPnP/1.0") != NULL) ||
|
|
++ strstr(line + 11, "FDSSDP") != NULL ||
|
|
++ strstr(line + 11, "Mozilla/4.0 (compatible; UPnP/1.0; Windows") != NULL) {
|
|
+ h->respflags |= FLAG_MS_CLIENT;
|
|
+ }
|
|
+ }
|
|
+--- a/upnpsoap.c
|
|
++++ b/upnpsoap.c
|
|
+@@ -854,6 +854,14 @@ GetSpecificPortMappingEntry(struct upnph
|
|
+ #ifdef ENABLE_PCP
|
|
+ hide_pcp_nonce(desc);
|
|
+ #endif
|
|
++#ifdef IGD_V2
|
|
++ /* Workaround to list port maps with the Windows IGDv2-incompatible client
|
|
++ * by returning an infinite (0) lease duration. To fix listing and editing
|
|
++ * via GUI (Explorer/Network), if daemon was compiled with IGDv2 */
|
|
++ if (h->respflags & FLAG_MS_CLIENT) {
|
|
++ leaseduration = 0;
|
|
++ }
|
|
++#endif
|
|
+ bodylen = snprintf(body, sizeof(body), resp,
|
|
+ action, ns/*SERVICE_TYPE_WANIPC*/,
|
|
+ (unsigned int)iport, int_ip, desc, leaseduration,
|
|
+@@ -1124,6 +1132,14 @@ GetGenericPortMappingEntry(struct upnpht
|
|
+ #ifdef ENABLE_PCP
|
|
+ hide_pcp_nonce(desc);
|
|
+ #endif
|
|
++#ifdef IGD_V2
|
|
++ /* Workaround to list port maps with the Windows IGDv2-incompatible client
|
|
++ * by returning an infinite (0) lease duration. To fix listing and editing
|
|
++ * via GUI (Explorer/Network), if daemon was compiled with IGDv2 */
|
|
++ if (h->respflags & FLAG_MS_CLIENT) {
|
|
++ leaseduration = 0;
|
|
++ }
|
|
++#endif
|
|
+ bodylen = snprintf(body, sizeof(body), resp,
|
|
+ action, ns, /*SERVICE_TYPE_WANIPC,*/ rhost,
|
|
+ (unsigned int)eport, protocol, (unsigned int)iport, iaddr, desc,
|
|
|
|
From 4606783f9fa877e5fd6da150ee96067a71f60966 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 03/10] miniupnpd: patch to improve logging
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
- Clearer logging of enabled protocols/ports, IPv6 mapping, and UPnP IGD
|
|
compatibility mode… in start banner
|
|
- Log warnings with an enabled allow third-party mapping option
|
|
- Less verbose logging by changing the log level of many normally
|
|
occurring, internal messages, or those not relevant to users, to debug
|
|
or info
|
|
- Comment out log filling messages when internal interfaces lose link,
|
|
and for e.g. `rule with label '%s' is not a IGD pinhole`, as normally
|
|
occurring
|
|
|
|
(to merge with prior)
|
|
|
|
Fixes: https://redirect.github.com/openwrt/packages/issues/17601
|
|
Fixes: https://redirect.github.com/openwrt/packages/issues/26483
|
|
Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
.../patches/20-improve-logging.patch | 1186 +++++++++++++++++
|
|
1 file changed, 1186 insertions(+)
|
|
create mode 100644 miniupnpd/patches/20-improve-logging.patch
|
|
|
|
diff --git a/miniupnpd/patches/20-improve-logging.patch b/miniupnpd/patches/20-improve-logging.patch
|
|
new file mode 100644
|
|
index 00000000000000..ee0673535c5cef
|
|
--- /dev/null
|
|
+++ b/miniupnpd/patches/20-improve-logging.patch
|
|
@@ -0,0 +1,1186 @@
|
|
+From 38e01919d585b0fd663d2b3249963b336061cbd3 Mon Sep 17 00:00:00 2001
|
|
+From: Self-Hosting-Group
|
|
+ <155233284+Self-Hosting-Group@users.noreply.github.com>
|
|
+Date: Tue, 12 May 2026 00:00:00 +0000
|
|
+Subject: [PATCH] miniupnpd: Improve logging
|
|
+
|
|
+* Clearer logging of enabled protocols/ports, IPv6 mapping, and UPnP IGD
|
|
+ compatibility mode… in start banner
|
|
+* Log warnings with an enabled allow third-party mapping option
|
|
+* Less verbose logging by changing the log level of many normally
|
|
+ occurring or internal messages, or those not relevant to users, to
|
|
+ debug or info
|
|
+* Comment out log-filling messages when internal interfaces lose link,
|
|
+ and for e.g. `rule with label '%s' is not a IGD pinhole`, as normally
|
|
+ occurring
|
|
+
|
|
+Fixes: https://redirect.github.com/openwrt/packages/issues/17601
|
|
+Fixes: https://redirect.github.com/openwrt/packages/issues/26483
|
|
+Link: https://github.com/Self-Hosting-Group/miniupnp/tree/improve-logging
|
|
+---
|
|
+ asyncsendto.c | 4 +--
|
|
+ getifaddr.c | 4 +--
|
|
+ minissdp.c | 24 ++++++-------
|
|
+ miniupnpd.c | 20 +++++------
|
|
+ natpmp.c | 16 ++++-----
|
|
+ netfilter/iptcrdr.c | 10 +++---
|
|
+ netfilter/iptpinhole.c | 4 +--
|
|
+ netfilter_nft/nftnlrdr.c | 2 +-
|
|
+ netfilter_nft/nftnlrdr_misc.c | 8 ++---
|
|
+ netfilter_nft/nftpinhole.c | 10 +++---
|
|
+ pcpserver.c | 18 +++++-----
|
|
+ pf/pfpinhole.c | 8 ++---
|
|
+ upnphttp.c | 6 ++--
|
|
+ upnppinhole.c | 48 ++++++++++++-------------
|
|
+ upnpredirect.c | 20 +++++------
|
|
+ upnpsoap.c | 28 +++++++--------
|
|
+ 16 files changed, 115 insertions(+), 115 deletions(-)
|
|
+
|
|
+--- a/asyncsendto.c
|
|
++++ b/asyncsendto.c
|
|
+@@ -254,9 +254,9 @@ int try_sendto(fd_set * writefds)
|
|
+ /* uncatched error */
|
|
+ if(sockaddr_to_string(elt->dest_addr, addr_str, sizeof(addr_str)) <= 0)
|
|
+ addr_str[0] = '\0';
|
|
+- syslog(LOG_ERR, "%s(sock=%d, len=%u, dest=%s): sendto: %m",
|
|
++ /*syslog(LOG_DEBUG, "%s(sock=%d, len=%u, dest=%s): sendto: %m",
|
|
+ "try_sendto", elt->sockfd, (unsigned)elt->len,
|
|
+- addr_str);
|
|
++ addr_str);*/
|
|
+ ret--;
|
|
+ }
|
|
+ } else if((int)n != (int)elt->len) {
|
|
+--- a/getifaddr.c
|
|
++++ b/getifaddr.c
|
|
+@@ -74,7 +74,7 @@ getifaddr(const char * ifname, char * bu
|
|
+ } else {
|
|
+ r = GETIFADDR_IOCTL_ERROR;
|
|
+ }
|
|
+- syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
|
++ syslog(LOG_DEBUG, "ioctl(s, SIOCGIFADDR, ...): %m");
|
|
+ close(s);
|
|
+ return r;
|
|
+ }
|
|
+@@ -149,7 +149,7 @@ getifaddr(const char * ifname, char * bu
|
|
+ if(addr) *addr = ((struct sockaddr_in *)candidate->ifa_addr)->sin_addr;
|
|
+ if(mask) *mask = ((struct sockaddr_in *)candidate->ifa_netmask)->sin_addr;
|
|
+ } else {
|
|
+- syslog(LOG_WARNING, "no AF_INET address found for %s", ifname);
|
|
++ syslog(LOG_DEBUG, "no AF_INET address found for %s", ifname);
|
|
+ freeifaddrs(ifap);
|
|
+ return GETIFADDR_NO_ADDRESS;
|
|
+ }
|
|
+--- a/minissdp.c
|
|
++++ b/minissdp.c
|
|
+@@ -741,8 +741,8 @@ SendSSDPNotify(int s, const struct socka
|
|
+ }
|
|
+ n = sendto_or_schedule(s, bufr, l, 0, dest, dest_len);
|
|
+ if(n < 0) {
|
|
+- syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
|
+- host ? host : "NULL");
|
|
++ /*syslog(LOG_DEBUG, "sendto(udp_notify=%d, %s): %m", s,
|
|
++ host ? host : "NULL");*/
|
|
+ } else if(n != l) {
|
|
+ syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l);
|
|
+ }
|
|
+@@ -752,8 +752,8 @@ SendSSDPNotify(int s, const struct socka
|
|
+ * discovery messages SHOULD NOT be sent more than three times. */
|
|
+ n = sendto_schedule(s, bufr, l, 0, dest, dest_len, 250);
|
|
+ if(n < 0) {
|
|
+- syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
|
+- host ? host : "NULL");
|
|
++ /*syslog(LOG_DEBUG, "sendto(udp_notify=%d, %s): %m", s,
|
|
++ host ? host : "NULL");*/
|
|
+ }
|
|
+ }
|
|
+
|
|
+@@ -1058,7 +1058,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ }
|
|
+ if(lan_addr == NULL)
|
|
+ {
|
|
+- syslog(LOG_WARNING, "SSDP packet sender %s (if_index=%d) not from a LAN, ignoring",
|
|
++ syslog(LOG_DEBUG, "SSDP packet sender %s (if_index=%d) not from a LAN, ignoring",
|
|
+ sender_str, source_if);
|
|
+ return;
|
|
+ }
|
|
+@@ -1161,7 +1161,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ sender_str );*/
|
|
+ if(st && (st_len > 0))
|
|
+ {
|
|
+- syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
|
|
++ syslog(LOG_DEBUG, "SSDP M-SEARCH from %s ST: %.*s",
|
|
+ sender_str, st_len, st);
|
|
+ /* find in which sub network the client is */
|
|
+ #ifdef ENABLE_IPV6
|
|
+@@ -1274,7 +1274,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ else
|
|
+ snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
|
|
+ #endif
|
|
+- syslog(LOG_INFO, "Single search found");
|
|
++ syslog(LOG_DEBUG, "Single search found");
|
|
+ #ifdef DELAY_MSEARCH_RESPONSE
|
|
+ delay = random() / (1 + RAND_MAX / (1000 * mx_value));
|
|
+ #ifdef DEBUG
|
|
+@@ -1303,7 +1303,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ #ifdef DELAY_MSEARCH_RESPONSE
|
|
+ unsigned int delay_increment = (mx_value * 1000) / 15;
|
|
+ #endif
|
|
+- syslog(LOG_INFO, "ssdp:all found");
|
|
++ syslog(LOG_DEBUG, "ssdp:all found");
|
|
+ for(i=0; known_service_types[i].s; i++)
|
|
+ {
|
|
+ #ifdef DELAY_MSEARCH_RESPONSE
|
|
+@@ -1361,7 +1361,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ #endif
|
|
+ if(0 == memcmp(st, uuidvalue_igd, l))
|
|
+ {
|
|
+- syslog(LOG_INFO, "ssdp:uuid (IGD) found");
|
|
++ syslog(LOG_DEBUG, "ssdp:uuid (IGD) found");
|
|
+ SendSSDPResponse(s, sender, st, st_len, "",
|
|
+ announced_host, http_port,
|
|
+ #ifdef ENABLE_HTTPS
|
|
+@@ -1371,7 +1371,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ }
|
|
+ else if(0 == memcmp(st, uuidvalue_wan, l))
|
|
+ {
|
|
+- syslog(LOG_INFO, "ssdp:uuid (WAN) found");
|
|
++ syslog(LOG_DEBUG, "ssdp:uuid (WAN) found");
|
|
+ SendSSDPResponse(s, sender, st, st_len, "",
|
|
+ announced_host, http_port,
|
|
+ #ifdef ENABLE_HTTPS
|
|
+@@ -1381,7 +1381,7 @@ ProcessSSDPData(int s, const char *bufr,
|
|
+ }
|
|
+ else if(0 == memcmp(st, uuidvalue_wcd, l))
|
|
+ {
|
|
+- syslog(LOG_INFO, "ssdp:uuid (WCD) found");
|
|
++ syslog(LOG_DEBUG, "ssdp:uuid (WCD) found");
|
|
+ SendSSDPResponse(s, sender, st, st_len, "",
|
|
+ announced_host, http_port,
|
|
+ #ifdef ENABLE_HTTPS
|
|
+@@ -1442,7 +1442,7 @@ SendSSDPbyebye(int s, const struct socka
|
|
+ n = sendto_or_schedule(s, bufr, l, 0, dest, destlen);
|
|
+ if(n < 0)
|
|
+ {
|
|
+- syslog(LOG_ERR, "sendto(udp_shutdown=%d) to %s: %m", s, dest_str);
|
|
++ syslog(LOG_DEBUG, "sendto(udp_shutdown=%d) to %s: %m", s, dest_str);
|
|
+ return -1;
|
|
+ }
|
|
+ else if(n != l)
|
|
+--- a/miniupnpd.c
|
|
++++ b/miniupnpd.c
|
|
+@@ -489,7 +489,7 @@ ProcessIncomingHTTP(int shttpl, const ch
|
|
+ if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL)
|
|
+ {
|
|
+ /* The peer is not a LAN ! */
|
|
+- syslog(LOG_WARNING,
|
|
++ syslog(LOG_DEBUG,
|
|
+ "%s peer %s is not from a LAN, closing the connection",
|
|
+ protocol, addr_str);
|
|
+ close(shttp);
|
|
+@@ -859,7 +859,7 @@ set_startup_time(void)
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_INFO, "system uptime is %lu seconds", uptime);
|
|
++ syslog(LOG_DEBUG, "system uptime is %lu seconds", uptime);
|
|
+ }
|
|
+ fclose(f);
|
|
+ startup_time -= uptime;
|
|
+@@ -2109,6 +2109,22 @@ init(int argc, char * * argv, struct run
|
|
+ pidfilename = NULL;
|
|
+ #endif
|
|
+
|
|
++syslog(LOG_NOTICE, "MiniUPnP daemon " MINIUPNPD_VERSION " starting, enable protocols %s%s%s, ext_ifname=%s BOOTID=%u",
|
|
++ GETFLAG(ENABLEUPNPMASK) ? "UPnP IGD" : "",
|
|
++#ifdef ENABLE_NATPMP
|
|
++ GETFLAG(ENABLEUPNPMASK) && GETFLAG(ENABLENATPMPMASK) ? " & " : "",
|
|
++#ifdef ENABLE_PCP
|
|
++ GETFLAG(ENABLENATPMPMASK) ? "PCP/NAT-PMP" : "",
|
|
++#else
|
|
++ GETFLAG(ENABLENATPMPMASK) ? "NAT-PMP" : "",
|
|
++#endif
|
|
++#else
|
|
++ "", "",
|
|
++#endif
|
|
++ ext_if_name, upnp_bootid);
|
|
++syslog(LOG_INFO, "More information at https://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/");
|
|
++syslog(LOG_NOTICE, "Extra logging with log level info (-v) or debug (-v -v)");
|
|
++
|
|
+ #ifdef USE_SYSTEMD
|
|
+ if (systemd_flag) {
|
|
+ int r = sd_notify(0,
|
|
+@@ -2121,7 +2137,7 @@ init(int argc, char * * argv, struct run
|
|
+
|
|
+ #ifdef ENABLE_LEASEFILE
|
|
+ /*remove(lease_file);*/
|
|
+- syslog(LOG_INFO, "Reloading rules from lease file");
|
|
++ syslog(LOG_INFO, "Reloading port maps from lease file");
|
|
+ reload_from_lease_file();
|
|
+ #ifdef ENABLE_UPNPPINHOLE
|
|
+ reload_from_lease_file6();
|
|
+@@ -2409,21 +2425,9 @@ main(int argc, char * * argv)
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+- syslog(LOG_INFO, "version " MINIUPNPD_VERSION " starting%s%sext if %s BOOTID=%u",
|
|
+-#ifdef ENABLE_NATPMP
|
|
+-#ifdef ENABLE_PCP
|
|
+- GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP/PCP " : " ",
|
|
+-#else
|
|
+- GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP " : " ",
|
|
+-#endif
|
|
+-#else
|
|
+- " ",
|
|
+-#endif
|
|
+- GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "",
|
|
+- ext_if_name, upnp_bootid);
|
|
+ #ifdef ENABLE_IPV6
|
|
+ if (strcmp(ext_if_name6, ext_if_name) != 0) {
|
|
+- syslog(LOG_INFO, "specific IPv6 ext if %s", ext_if_name6);
|
|
++ syslog(LOG_INFO, "Separate ext_ifname6=%s set", ext_if_name6);
|
|
+ }
|
|
+ #endif
|
|
+
|
|
+@@ -2467,7 +2471,7 @@ main(int argc, char * * argv)
|
|
+ return 1;
|
|
+ }
|
|
+ v.port = listen_port;
|
|
+- syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
|
|
++ syslog(LOG_NOTICE, "Listening for UPnP IGD (SOAP/HTTP) traffic on port %d/TCP, SSDP 1900/UDP", v.port);
|
|
+ #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
|
+ if(!GETFLAG(IPV6DISABLEDMASK))
|
|
+ {
|
|
+@@ -2493,7 +2497,7 @@ main(int argc, char * * argv)
|
|
+ return 1;
|
|
+ }
|
|
+ v.https_port = listen_port;
|
|
+- syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port);
|
|
++ syslog(LOG_NOTICE, "Listening for UPnP IGD (SOAP/HTTPS) traffic on port %d/TCP", v.https_port);
|
|
+ #if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
|
+ shttpsl_v4 = OpenAndConfHTTPSocket(&listen_port, 0);
|
|
+ if(shttpsl_v4 < 0)
|
|
+@@ -2507,11 +2511,11 @@ main(int argc, char * * argv)
|
|
+ if(!GETFLAG(IPV6DISABLEDMASK)) {
|
|
+ if(find_ipv6_addr(lan_addrs.lh_first ? lan_addrs.lh_first->ifname : NULL,
|
|
+ ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
|
|
+- syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
|
|
++ syslog(LOG_NOTICE, "IPv6 address given to UPnP IGD clients: %s",
|
|
+ ipv6_addr_for_http_with_brackets);
|
|
+ } else {
|
|
+ memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6);
|
|
+- syslog(LOG_WARNING, "no HTTP IPv6 address, disabling IPv6");
|
|
++ syslog(LOG_DEBUG, "no HTTP IPv6 address, disabling IPv6");
|
|
+ SETFLAG(IPV6DISABLEDMASK);
|
|
+ }
|
|
+ }
|
|
+@@ -2563,7 +2567,7 @@ main(int argc, char * * argv)
|
|
+ if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
|
|
+ #endif
|
|
+ {
|
|
+- syslog(LOG_WARNING, "Failed to broadcast good-bye notifications");
|
|
++ syslog(LOG_DEBUG, "Failed to broadcast good-bye notifications");
|
|
+ }
|
|
+ }
|
|
+ #endif /* UPNP_STRICT */
|
|
+@@ -2588,16 +2592,16 @@ main(int argc, char * * argv)
|
|
+ if(OpenAndConfNATPMPSockets(snatpmp) < 0)
|
|
+ #ifdef ENABLE_PCP
|
|
+ {
|
|
+- syslog(LOG_ERR, "Failed to open sockets for NAT-PMP/PCP.");
|
|
++ syslog(LOG_ERR, "Failed to open port 5351/UDP for PCP/NAT-PMP");
|
|
+ } else {
|
|
+- syslog(LOG_NOTICE, "Listening for NAT-PMP/PCP traffic on port %u",
|
|
++ syslog(LOG_NOTICE, "Listening for PCP/NAT-PMP traffic on port %u/UDP",
|
|
+ NATPMP_PORT);
|
|
+ }
|
|
+ #else
|
|
+ {
|
|
+- syslog(LOG_ERR, "Failed to open sockets for NAT PMP.");
|
|
++ syslog(LOG_ERR, "Failed to open port 5351/UDP for NAT-PMP");
|
|
+ } else {
|
|
+- syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
|
|
++ syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u/UDP",
|
|
+ NATPMP_PORT);
|
|
+ }
|
|
+ #endif
|
|
+@@ -2706,6 +2710,30 @@ main(int argc, char * * argv)
|
|
+ }
|
|
+ #endif /* HAS_LIBCAP_NG */
|
|
+
|
|
++if (GETFLAG(ENABLEUPNPMASK) && !GETFLAG(SECUREMODEMASK))
|
|
++ syslog(LOG_WARNING, "WARNING: Allow adding port maps for non-requesting IP addresses via UPnP IGD, as secure_mode=no set");
|
|
++#ifdef ENABLE_PCP
|
|
++if (GETFLAG(ENABLENATPMPMASK) && GETFLAG(PCP_ALLOWTHIRDPARTYMASK))
|
|
++ syslog(LOG_WARNING, "WARNING: Allow adding port maps for non-requesting IP addresses via PCP, as pcp_allow_thirdparty=yes set");
|
|
++#endif
|
|
++#ifdef ENABLE_IPV6
|
|
++if (GETFLAG(IPV6DISABLEDMASK))
|
|
++ syslog(LOG_NOTICE, "IPv6 mapping disabled");
|
|
++#else
|
|
++syslog(LOG_NOTICE, "IPv6 mapping disabled");
|
|
++#endif
|
|
++if (GETFLAG(ENABLEUPNPMASK)) {
|
|
++#ifdef IGD_V2
|
|
++ if (GETFLAG(FORCEIGDDESCV1MASK)) {
|
|
++ syslog(LOG_NOTICE, "UPnP IGD compatibility mode set to IGDv1 (IPv4 only)");
|
|
++ } else {
|
|
++ syslog(LOG_NOTICE, "UPnP IGD compatibility mode set to IGDv2 (with workarounds)");
|
|
++ }
|
|
++#else
|
|
++ syslog(LOG_NOTICE, "UPnP IGD compatibility mode set to IGDv1 (IPv4 only)");
|
|
++#endif
|
|
++}
|
|
++
|
|
+ #ifdef USE_SYSTEMD
|
|
+ if (v.systemd_notify) {
|
|
+ upnp_update_status();
|
|
+@@ -3016,7 +3044,7 @@ main(int argc, char * * argv)
|
|
+ }
|
|
+ i = try_sendto(&writeset);
|
|
+ if(i < 0) {
|
|
+- syslog(LOG_ERR, "try_sendto failed to send %d packets", -i);
|
|
++ /*syslog(LOG_DEBUG, "try_sendto failed to send %d packets", -i);*/
|
|
+ }
|
|
+ #ifdef USE_MINIUPNPDCTL
|
|
+ for(ectl = ctllisthead.lh_first; ectl;)
|
|
+@@ -3116,7 +3144,7 @@ main(int argc, char * * argv)
|
|
+ if(lan_addr == NULL) {
|
|
+ char sender_str[64];
|
|
+ sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str));
|
|
+- syslog(LOG_WARNING, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
|
++ syslog(LOG_DEBUG, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
|
+ sender_str);
|
|
+ continue;
|
|
+ }
|
|
+@@ -3139,7 +3167,7 @@ main(int argc, char * * argv)
|
|
+ if(lan_addr == NULL) {
|
|
+ char sender_str[64];
|
|
+ sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str));
|
|
+- syslog(LOG_WARNING, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
|
++ syslog(LOG_DEBUG, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
|
+ sender_str);
|
|
+ continue;
|
|
+ }
|
|
+@@ -3173,7 +3201,7 @@ main(int argc, char * * argv)
|
|
+ /* process SSDP packets */
|
|
+ if(sudp >= 0 && FD_ISSET(sudp, &readset))
|
|
+ {
|
|
+- /*syslog(LOG_INFO, "Received UDP Packet");*/
|
|
++ /*syslog(LOG_DEBUG, "Received UDP Packet");*/
|
|
+ #ifdef ENABLE_HTTPS
|
|
+ ProcessSSDPRequest(sudp, (unsigned short)v.port, (unsigned short)v.https_port);
|
|
+ #else
|
|
+@@ -3183,7 +3211,7 @@ main(int argc, char * * argv)
|
|
+ #ifdef ENABLE_IPV6
|
|
+ if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset))
|
|
+ {
|
|
+- syslog(LOG_INFO, "Received UDP Packet (IPv6)");
|
|
++ /*syslog(LOG_DEBUG, "Received UDP Packet (IPv6)");*/
|
|
+ #ifdef ENABLE_HTTPS
|
|
+ ProcessSSDPRequest(sudpv6, (unsigned short)v.port, (unsigned short)v.https_port);
|
|
+ #else
|
|
+@@ -3285,7 +3313,7 @@ main(int argc, char * * argv)
|
|
+
|
|
+ shutdown:
|
|
+
|
|
+- syslog(LOG_NOTICE, "shutting down MiniUPnPd");
|
|
++ syslog(LOG_NOTICE, "Shutting down MiniUPnPd");
|
|
+ #ifdef USE_SYSTEMD
|
|
+ if (v.systemd_notify) {
|
|
+ sd_notify(0,
|
|
+@@ -3304,7 +3332,7 @@ shutdown:
|
|
+ if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
|
|
+ #endif
|
|
+ {
|
|
+- syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
|
|
++ syslog(LOG_DEBUG, "Failed to broadcast good-bye notifications");
|
|
+ }
|
|
+ }
|
|
+ /* try to send pending packets */
|
|
+--- a/natpmp.c
|
|
++++ b/natpmp.c
|
|
+@@ -106,7 +106,7 @@ static void FillPublicAddressResponse(un
|
|
+ resp[3] = 3; /* Network Failure (e.g. NAT box itself
|
|
+ * has not obtained a DHCP lease) */
|
|
+ } else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, &addr, NULL) < 0) {
|
|
+- syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name);
|
|
++ syslog(LOG_DEBUG, "Failed to get IP for interface %s", ext_if_name);
|
|
+ resp[3] = 3; /* Network Failure (e.g. NAT box itself
|
|
+ * has not obtained a DHCP lease) */
|
|
+ } else if (!GETFLAG(ALLOWPRIVATEIPV4MASK) && addr_is_reserved(&addr)) {
|
|
+@@ -231,7 +231,7 @@ void ProcessIncomingNATPMPPacket(int s,
|
|
+ syslog(LOG_ERR, "inet_ntop(natpmp): %m");
|
|
+ }
|
|
+
|
|
+- syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
|
|
++ syslog(LOG_DEBUG, "NAT-PMP request received from %s:%hu %d bytes",
|
|
+ senderaddrstr, ntohs(senderaddr->sin_port), n);
|
|
+
|
|
+ if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
|
|
+@@ -260,7 +260,7 @@ void ProcessIncomingNATPMPPacket(int s,
|
|
+ resp[3] = 1; /* unsupported version */
|
|
+ } else switch(req[1]) {
|
|
+ case 0: /* Public address request */
|
|
+- syslog(LOG_INFO, "NAT-PMP public address request");
|
|
++ syslog(LOG_DEBUG, "NAT-PMP public address request");
|
|
+ FillPublicAddressResponse(resp, senderaddr->sin_addr.s_addr);
|
|
+ resplen = 12;
|
|
+ break;
|
|
+@@ -319,7 +319,7 @@ void ProcessIncomingNATPMPPacket(int s,
|
|
+ resp[3] = 2; /* Not Authorized/Refused */
|
|
+ break;
|
|
+ } else {
|
|
+- syslog(LOG_INFO, "NAT-PMP %s port %hu mapping removed",
|
|
++ syslog(LOG_DEBUG, "NAT-PMP %s port %hu mapping removed",
|
|
+ proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
|
|
+ index--;
|
|
+ }
|
|
+@@ -340,7 +340,7 @@ void ProcessIncomingNATPMPPacket(int s,
|
|
+ eport_first = eport;
|
|
+ } else if(eport == eport_first) { /* no eport available */
|
|
+ if(any_eport_allowed == 0) { /* all eports rejected by permissions */
|
|
+- syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu",
|
|
++ syslog(LOG_INFO, "No allowed eport for NAT-PMP %hu %s->%s:%hu",
|
|
+ eport, proto_itoa(proto), senderaddrstr, iport);
|
|
+ resp[3] = 2; /* Not Authorized/Refused */
|
|
+ } else { /* at least one eport allowed (but none available) */
|
|
+@@ -443,7 +443,7 @@ void SendNATPMPPublicAddressChangeNotifi
|
|
+ FillPublicAddressResponse(notif, 0);
|
|
+ if(notif[3])
|
|
+ {
|
|
+- syslog(LOG_WARNING, "%s: cannot get public IP address, stopping",
|
|
++ syslog(LOG_DEBUG, "%s: cannot get public IP address, stopping",
|
|
+ "SendNATPMPPublicAddressChangeNotification");
|
|
+ return;
|
|
+ }
|
|
+@@ -471,7 +471,7 @@ void SendNATPMPPublicAddressChangeNotifi
|
|
+ (struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
|
+ if(n < 0)
|
|
+ {
|
|
+- syslog(LOG_ERR, "%s: sendto(s_udp=%d, port=%d): %m",
|
|
++ syslog(LOG_DEBUG, "%s: sendto(s_udp=%d, port=%d): %m",
|
|
+ "SendNATPMPPublicAddressChangeNotification", sockets[j], NATPMP_PORT);
|
|
+ return;
|
|
+ }
|
|
+@@ -481,7 +481,7 @@ void SendNATPMPPublicAddressChangeNotifi
|
|
+ (struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
|
+ if(n < 0)
|
|
+ {
|
|
+- syslog(LOG_ERR, "%s: sendto(s_udp=%d, port=%d): %m",
|
|
++ syslog(LOG_DEBUG, "%s: sendto(s_udp=%d, port=%d): %m",
|
|
+ "SendNATPMPPublicAddressChangeNotification", sockets[j], NATPMP_NOTIF_PORT);
|
|
+ return;
|
|
+ }
|
|
+--- a/netfilter/iptcrdr.c
|
|
++++ b/netfilter/iptcrdr.c
|
|
+@@ -711,7 +711,7 @@ delete_filter_rule(const char * ifname,
|
|
+ continue;
|
|
+ }
|
|
+ index = i;
|
|
+- /*syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);*/
|
|
++ /*syslog(LOG_DEBUG, "Trying to delete filter rule at index %u", index);*/
|
|
+ r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
|
|
+ h = NULL;
|
|
+ break;
|
|
+@@ -804,7 +804,7 @@ delete_redirect_and_filter_rules(unsigne
|
|
+ #endif
|
|
+ if(r == 0)
|
|
+ {
|
|
+- syslog(LOG_INFO, "Trying to delete nat rule at index %u", index);
|
|
++ syslog(LOG_DEBUG, "Trying to delete nat rule at index %u", index);
|
|
+ /* Now delete both rules */
|
|
+ /* first delete the nat rule */
|
|
+ h = iptc_init("nat");
|
|
+@@ -848,7 +848,7 @@ delete_redirect_and_filter_rules(unsigne
|
|
+ if(iaddr != e->ip.dst.s_addr)
|
|
+ continue;
|
|
+ index = i;
|
|
+- syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);
|
|
++ syslog(LOG_DEBUG, "Trying to delete filter rule at index %u", index);
|
|
+ r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule");
|
|
+ h = NULL;
|
|
+ break;
|
|
+@@ -906,7 +906,7 @@ delete_redirect_and_filter_rules(unsigne
|
|
+ }
|
|
+
|
|
+ index = i;
|
|
+- syslog(LOG_INFO, "Trying to delete peer rule at index %u", index);
|
|
++ syslog(LOG_DEBUG, "Trying to delete peer rule at index %u", index);
|
|
+ r2 = delete_rule_and_commit(index, h, miniupnpd_nat_postrouting_chain, "delete_peer_rule");
|
|
+ h = NULL;
|
|
+ break;
|
|
+@@ -958,7 +958,7 @@ delete_redirect_and_filter_rules(unsigne
|
|
+ if(iaddr != e->ip.src.s_addr)
|
|
+ continue;
|
|
+ index = i;
|
|
+- syslog(LOG_INFO, "Trying to delete dscp rule at index %u", index);
|
|
++ syslog(LOG_DEBUG, "Trying to delete dscp rule at index %u", index);
|
|
+ r2 = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_dscp_rule");
|
|
+ h = NULL;
|
|
+ break;
|
|
+--- a/netfilter/iptpinhole.c
|
|
++++ b/netfilter/iptpinhole.c
|
|
+@@ -295,14 +295,14 @@ find_pinhole(const char * ifname,
|
|
+
|
|
+ if(rem_host && (rem_host[0] != '\0')) {
|
|
+ if (inet_pton(AF_INET6, rem_host, &saddr) < 1) {
|
|
+- syslog(LOG_WARNING, "Failed to parse INET6 address \"%s\"", rem_host);
|
|
++ syslog(LOG_INFO, "Failed to parse INET6 address \"%s\"", rem_host);
|
|
+ memset(&saddr, 0, sizeof(struct in6_addr));
|
|
+ }
|
|
+ } else {
|
|
+ memset(&saddr, 0, sizeof(struct in6_addr));
|
|
+ }
|
|
+ if (inet_pton(AF_INET6, int_client, &daddr) < 1) {
|
|
+- syslog(LOG_WARNING, "Failed to parse INET6 address \"%s\"", int_client);
|
|
++ syslog(LOG_INFO, "Failed to parse INET6 address \"%s\"", int_client);
|
|
+ memset(&daddr, 0, sizeof(struct in6_addr));
|
|
+ }
|
|
+ for(p = pinhole_list.lh_first; p != NULL; p = p->entries.le_next) {
|
|
+--- a/netfilter_nft/nftnlrdr.c
|
|
++++ b/netfilter_nft/nftnlrdr.c
|
|
+@@ -353,7 +353,7 @@ delete_redirect_and_filter_rules(unsigne
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+- syslog(LOG_WARNING, "%s: redirect rule with eport=%hu proto %d NOT FOUND",
|
|
++ syslog(LOG_INFO, "%s: redirect rule with eport=%hu proto %d NOT FOUND",
|
|
+ "delete_redirect_and_filter_rules", eport, proto);
|
|
+ }
|
|
+
|
|
+--- a/netfilter_nft/nftnlrdr_misc.c
|
|
++++ b/netfilter_nft/nftnlrdr_misc.c
|
|
+@@ -104,7 +104,7 @@ nft_mnl_connect(void)
|
|
+ return -1;
|
|
+ }
|
|
+ mnl_portid = mnl_socket_get_portid(mnl_sock);
|
|
+- syslog(LOG_INFO, "mnl_socket bound, port_id=%u", mnl_portid);
|
|
++ syslog(LOG_DEBUG, "mnl_socket bound, port_id=%u", mnl_portid);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+@@ -745,7 +745,7 @@ refresh_nft_cache(struct rule_list *head
|
|
+ errno = 0;
|
|
+ ret = mnl_cb_run(buf, n, mnl_seq, mnl_portid, table_cb, &data);
|
|
+ if (ret <= -1 /*== MNL_CB_ERROR*/) {
|
|
+- syslog(LOG_ERR, "%s: mnl_cb_run returned %d: %m",
|
|
++ syslog(LOG_DEBUG, "%s: mnl_cb_run returned %d: %m",
|
|
+ "refresh_nft_cache", ret);
|
|
+ return -1;
|
|
+ }
|
|
+@@ -1279,7 +1279,7 @@ nft_send_rule(struct nftnl_rule * rule,
|
|
+
|
|
+ result = send_batch(batch);
|
|
+ if (result < 0) {
|
|
+- syslog(LOG_ERR, "%s(%p, %d, %d) send_batch failed %d",
|
|
++ syslog(LOG_DEBUG, "%s(%p, %d, %d) send_batch failed %d",
|
|
+ "nft_send_rule", rule, (int)cmd, (int)chain_type, result);
|
|
+ }
|
|
+ }
|
|
+@@ -1462,7 +1462,7 @@ send_batch(struct mnl_nlmsg_batch *batch
|
|
+ errno = 0;
|
|
+ ret = mnl_cb_run(buf, n, 0, mnl_portid, NULL, NULL);
|
|
+ if (ret <= -1 /*== MNL_CB_ERROR*/) {
|
|
+- syslog(LOG_ERR, "%s: mnl_cb_run returned %d: %m",
|
|
++ syslog(LOG_DEBUG, "%s: mnl_cb_run returned %d: %m",
|
|
+ "send_batch", ret);
|
|
+ return -4;
|
|
+ }
|
|
+--- a/netfilter_nft/nftpinhole.c
|
|
++++ b/netfilter_nft/nftpinhole.c
|
|
+@@ -129,7 +129,7 @@ find_pinhole(const char * ifname,
|
|
+
|
|
+ if (rem_host && rem_host[0] != '\0' && rem_host[0] != '*') {
|
|
+ if (inet_pton(AF_INET6, rem_host, &saddr) < 1) {
|
|
+- syslog(LOG_WARNING, "Failed to parse INET6 address \"%s\"", rem_host);
|
|
++ syslog(LOG_INFO, "Failed to parse INET6 address \"%s\"", rem_host);
|
|
+ memset(&saddr, 0, sizeof(struct in6_addr));
|
|
+ }
|
|
+ } else {
|
|
+@@ -137,7 +137,7 @@ find_pinhole(const char * ifname,
|
|
+ }
|
|
+
|
|
+ if (inet_pton(AF_INET6, int_client, &daddr) < 1) {
|
|
+- syslog(LOG_WARNING, "Failed to parse INET6 address \"%s\"", int_client);
|
|
++ syslog(LOG_INFO, "Failed to parse INET6 address \"%s\"", int_client);
|
|
+ memset(&daddr, 0, sizeof(struct in6_addr));
|
|
+ }
|
|
+
|
|
+@@ -159,7 +159,7 @@ find_pinhole(const char * ifname,
|
|
+ (0 == memcmp(&daddr, &p->daddr6, sizeof(struct in6_addr)))) {
|
|
+
|
|
+ if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);*/
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+@@ -396,7 +396,7 @@ get_pinhole_info(unsigned short uid,
|
|
+ if (timestamp) {
|
|
+ int uid_temp;
|
|
+ if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid_temp, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);*/
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+@@ -460,7 +460,7 @@ clean_pinhole_list(unsigned int * next_t
|
|
+ continue;
|
|
+
|
|
+ if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc);*/
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+--- a/pcpserver.c
|
|
++++ b/pcpserver.c
|
|
+@@ -1086,7 +1086,7 @@ static void CreatePCPMap(pcp_info_t *pcp
|
|
+ else
|
|
+ r = CreatePCPMap_NAT(pcp_msg_info);
|
|
+ pcp_msg_info->result_code = r;
|
|
+- syslog(r == PCP_SUCCESS ? LOG_INFO : LOG_ERR,
|
|
++ syslog(LOG_INFO,
|
|
+ "PCP MAP: %s mapping %s %hu->%s:%hu '%s'",
|
|
+ r == PCP_SUCCESS ? "added" : "failed to add",
|
|
+ proto_itoa(pcp_msg_info->protocol),
|
|
+@@ -1128,7 +1128,7 @@ static void DeletePCPMap(pcp_info_t *pcp
|
|
+ if(0 != strcmp(desc, pcp_msg_info->desc)) {
|
|
+ /* nonce does not match */
|
|
+ pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED;
|
|
+- syslog(LOG_ERR, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
|
|
++ syslog(LOG_INFO, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
|
|
+ iport, proto_itoa(pcp_msg_info->protocol));
|
|
+ return;
|
|
+ } else {
|
|
+@@ -1146,14 +1146,14 @@ static void DeletePCPMap(pcp_info_t *pcp
|
|
+ desc, sizeof(desc),
|
|
+ NULL /* lifetime */);
|
|
+ if (uid < 0) {
|
|
+- syslog(LOG_ERR, "Failed to find mapping to %s:%hu, protocol %s",
|
|
++ syslog(LOG_INFO, "Failed to find mapping to %s:%hu, protocol %s",
|
|
+ pcp_msg_info->mapped_str, iport, proto_itoa(pcp_msg_info->protocol));
|
|
+ return;
|
|
+ } else {
|
|
+ if(0 != strcmp(desc, pcp_msg_info->desc)) {
|
|
+ /* nonce does not match */
|
|
+ pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED;
|
|
+- syslog(LOG_ERR, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
|
|
++ syslog(LOG_INFO, "Unauthorized to remove PCP mapping internal port %hu, protocol %s",
|
|
+ iport, proto_itoa(pcp_msg_info->protocol));
|
|
+ return;
|
|
+ } else {
|
|
+@@ -1168,7 +1168,7 @@ static void DeletePCPMap(pcp_info_t *pcp
|
|
+ syslog(LOG_INFO, "PCP: %s port %hu mapping removed",
|
|
+ proto==IPPROTO_TCP?"TCP":"UDP", (pcp_msg_info->is_fw ? iport : eport2));
|
|
+ } else {
|
|
+- syslog(LOG_ERR, "Failed to remove PCP mapping to %s:%hu %s",
|
|
++ syslog(LOG_INFO, "Failed to remove PCP mapping to %s:%hu %s",
|
|
+ pcp_msg_info->mapped_str, iport, proto_itoa(proto));
|
|
+ pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES;
|
|
+ }
|
|
+@@ -1391,7 +1391,7 @@ static int processPCPRequest(void * req,
|
|
+ CreatePCPMap(pcp_msg_info);
|
|
+ }
|
|
+ } else {
|
|
+- syslog(LOG_ERR, "PCP: Invalid PCP v2 MAP message.");
|
|
++ syslog(LOG_DEBUG, "PCP: Invalid PCP v2 MAP message.");
|
|
+ return pcp_msg_info->result_code;
|
|
+ }
|
|
+
|
|
+@@ -1601,7 +1601,7 @@ int ProcessIncomingPCPPacket(int s, unsi
|
|
+ if (!GETFLAG(PCP_ALLOWTHIRDPARTYMASK)) {
|
|
+ lan_addr = get_lan_for_peer(senderaddr);
|
|
+ if(lan_addr == NULL) {
|
|
+- syslog(LOG_WARNING, "PCP packet sender %s not from a LAN, ignoring",
|
|
++ syslog(LOG_DEBUG, "PCP packet sender %s not from a LAN, ignoring",
|
|
+ addr_str);
|
|
+ return 0;
|
|
+ }
|
|
+@@ -1722,7 +1722,7 @@ void PCPSendUnsolicitedAnnounce(int * so
|
|
+ }
|
|
+ len = sendto_or_schedule(sockets[i], buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
|
+ if( len < 0 ) {
|
|
+- syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce(sockets[%d]) sendto(): %m", i);
|
|
++ syslog(LOG_DEBUG, "PCPSendUnsolicitedAnnounce(sockets[%d]) sendto(): %m", i);
|
|
+ }
|
|
+ }
|
|
+ #ifdef ENABLE_IPV6
|
|
+@@ -1733,7 +1733,7 @@ void PCPSendUnsolicitedAnnounce(int * so
|
|
+ addr6.sin6_port = htons(5350);
|
|
+ len = sendto_or_schedule(socket6, buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6));
|
|
+ if( len < 0 ) {
|
|
+- syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() IPv6 sendto(): %m");
|
|
++ syslog(LOG_DEBUG, "PCPSendUnsolicitedAnnounce() IPv6 sendto(): %m");
|
|
+ }
|
|
+ }
|
|
+ #endif /* ENABLE_IPV6 */
|
|
+--- a/pf/pfpinhole.c
|
|
++++ b/pf/pfpinhole.c
|
|
+@@ -246,12 +246,12 @@ int find_pinhole(const char * ifname,
|
|
+ (0 == memcmp(&daddr, &RULE.dst.addr.v.a.addr.v6, sizeof(struct in6_addr)))) {
|
|
+ #ifdef USE_LIBPFCTL
|
|
+ if(sscanf(RULE.label[0], PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label[0]);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label[0]);*/
|
|
+ continue;
|
|
+ }
|
|
+ #else /* USE_LIBPFCTL */
|
|
+ if(sscanf(RULE.label, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label);*/
|
|
+ continue;
|
|
+ }
|
|
+ #endif /* USE_LIBPFCTL */
|
|
+@@ -565,7 +565,7 @@ int clean_pinhole_list(unsigned int * ne
|
|
+ return -1;
|
|
+ }
|
|
+ if(sscanf(RULE.label[0], PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label[0]);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label[0]);*/
|
|
+ continue;
|
|
+ }
|
|
+ #else /* USE_LIBPFCTL */
|
|
+@@ -576,7 +576,7 @@ int clean_pinhole_list(unsigned int * ne
|
|
+ return -1;
|
|
+ }
|
|
+ if(sscanf(RULE.label, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) {
|
|
+- syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label);
|
|
++ /*syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", RULE.label);*/
|
|
+ continue;
|
|
+ }
|
|
+ #endif /* USE_LIBPFCTL */
|
|
+--- a/upnphttp.c
|
|
++++ b/upnphttp.c
|
|
+@@ -514,7 +514,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp
|
|
+ if(h->req_soapActionOff > 0)
|
|
+ {
|
|
+ /* we can process the request */
|
|
+- syslog(LOG_INFO, "SOAPAction: %.*s",
|
|
++ syslog(LOG_DEBUG, "SOAPAction: %.*s",
|
|
+ h->req_soapActionLen, h->req_buf + h->req_soapActionOff);
|
|
+ ExecuteSoapAction(h,
|
|
+ h->req_buf + h->req_soapActionOff,
|
|
+@@ -819,7 +819,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt
|
|
+ for(i = 0; i<15 && *p != '\r'; i++)
|
|
+ HttpVer[i] = *(p++);
|
|
+ HttpVer[i] = '\0';
|
|
+- syslog(LOG_INFO, "HTTP REQUEST from %s : %s %s (%s)",
|
|
++ syslog(LOG_DEBUG, "HTTP REQUEST from %s : %s %s (%s)",
|
|
+ h->clientaddr_str, HttpCommand, HttpUrl, HttpVer);
|
|
+ ParseHttpHeaders(h);
|
|
+ if(h->req_HostOff > 0 && h->req_HostLen > 0) {
|
|
+@@ -899,7 +899,7 @@ ProcessHttpQuery_upnphttp(struct upnphtt
|
|
+ return;
|
|
+ }
|
|
+ #endif
|
|
+- syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
|
|
++ syslog(LOG_DEBUG, "%s not found, responding ERROR 404", HttpUrl);
|
|
+ Send404(h);
|
|
+ }
|
|
+ #ifdef ENABLE_EVENTS
|
|
+--- a/upnppinhole.c
|
|
++++ b/upnppinhole.c
|
|
+@@ -110,7 +110,7 @@ lease_file6_add(const char * rem_client,
|
|
+
|
|
+ fd = fopen( lease_file6, "a");
|
|
+ if (fd==NULL) {
|
|
+- syslog(LOG_ERR, "could not open lease file: %s", lease_file);
|
|
++ syslog(LOG_DEBUG, "could not open lease file: %s", lease_file);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+@@ -189,13 +189,13 @@ lease_file6_update(int uid, unsigned int
|
|
+ proto = line;
|
|
+ p = strchr(line, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+@@ -203,13 +203,13 @@ lease_file6_update(int uid, unsigned int
|
|
+ int_client = p;
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+@@ -217,20 +217,20 @@ lease_file6_update(int uid, unsigned int
|
|
+ rem_client = p;
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+ desc = strchr(p2, ';');
|
|
+ uid_rule = atoi(p);
|
|
+ if(!desc) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(desc++) = '\0';
|
|
+@@ -385,49 +385,49 @@ int lease_file6_expire(void)
|
|
+ // Internal Host
|
|
+ p = strchr(line, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ // Internal Port
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+ // External Host
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ // External Port
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+ // uid
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ // Timestamp
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+ // descr
|
|
+ desc = strchr(p2, ';');
|
|
+ if(!desc) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(desc++) = '\0';
|
|
+@@ -476,7 +476,7 @@ int reload_from_lease_file6(void)
|
|
+ if(!lease_file6) return -1;
|
|
+ fd = fopen( lease_file6, "r");
|
|
+ if (fd==NULL) {
|
|
+- syslog(LOG_ERR, "could not open lease file: %s", lease_file6);
|
|
++ syslog(LOG_DEBUG, "could not open lease file: %s", lease_file6);
|
|
+ return -1;
|
|
+ }
|
|
+ if(unlink(lease_file6) < 0) {
|
|
+@@ -491,13 +491,13 @@ int reload_from_lease_file6(void)
|
|
+ proto = line;
|
|
+ p = strchr(line, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+@@ -505,13 +505,13 @@ int reload_from_lease_file6(void)
|
|
+ int_client = p;
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+@@ -519,20 +519,20 @@ int reload_from_lease_file6(void)
|
|
+ rem_client = p;
|
|
+ p = strchr(p2, ';');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ p2 = strchr(p, ';');
|
|
+ if(!p2) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p2++) = '\0';
|
|
+ desc = strchr(p2, ';');
|
|
+ uid = atoi(p);
|
|
+ if(!desc) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(desc++) = '\0';
|
|
+@@ -549,7 +549,7 @@ int reload_from_lease_file6(void)
|
|
+
|
|
+ if(timestamp > 0) {
|
|
+ if(timestamp <= (unsigned int)current_unix_time) {
|
|
+- syslog(LOG_NOTICE, "already expired lease in lease file");
|
|
++ syslog(LOG_INFO, "already expired lease in lease file");
|
|
+ continue;
|
|
+ } else {
|
|
+ leaseduration = timestamp - current_unix_time;
|
|
+--- a/upnpredirect.c
|
|
++++ b/upnpredirect.c
|
|
+@@ -66,7 +66,7 @@ lease_file_add(unsigned short eport,
|
|
+
|
|
+ fd = fopen( lease_file, "a");
|
|
+ if (fd==NULL) {
|
|
+- syslog(LOG_ERR, "could not open lease file: %s", lease_file);
|
|
++ syslog(LOG_DEBUG, "could not open lease file: %s", lease_file);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+@@ -168,7 +168,7 @@ int reload_from_lease_file(void)
|
|
+ if(!lease_file) return -1;
|
|
+ fd = fopen( lease_file, "r");
|
|
+ if (fd==NULL) {
|
|
+- syslog(LOG_ERR, "could not open lease file: %s", lease_file);
|
|
++ syslog(LOG_DEBUG, "could not open lease file: %s", lease_file);
|
|
+ return -1;
|
|
+ }
|
|
+ if(unlink(lease_file) < 0) {
|
|
+@@ -184,33 +184,33 @@ int reload_from_lease_file(void)
|
|
+ proto = line;
|
|
+ p = strchr(line, ':');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ iaddr = strchr(p, ':');
|
|
+ if(!iaddr) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(iaddr++) = '\0';
|
|
+ eport = (unsigned short)atoi(p);
|
|
+ p = strchr(iaddr, ':');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ iport = (unsigned short)atoi(p);
|
|
+ p = strchr(p, ':');
|
|
+ if(!p) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(p++) = '\0';
|
|
+ desc = strchr(p, ':');
|
|
+ if(!desc) {
|
|
+- syslog(LOG_ERR, "unrecognized data in lease file");
|
|
++ syslog(LOG_DEBUG, "unrecognized data in lease file");
|
|
+ continue;
|
|
+ }
|
|
+ *(desc++) = '\0';
|
|
+@@ -231,7 +231,7 @@ int reload_from_lease_file(void)
|
|
+ timestamp += current_time; /* convert to our time */
|
|
+ #else
|
|
+ if(timestamp <= (unsigned int)current_unix_time) {
|
|
+- syslog(LOG_NOTICE, "already expired lease in lease file (%hu=>%s:%hu %s)",
|
|
++ syslog(LOG_INFO, "already expired lease in lease file (%hu=>%s:%hu %s)",
|
|
+ eport, iaddr, iport, proto);
|
|
+ continue;
|
|
+ } else {
|
|
+@@ -391,7 +391,7 @@ upnp_redirect(const char * rhost, unsign
|
|
+ #endif /* CHECK_PORTINUSE */
|
|
+ } else {
|
|
+ timestamp = (leaseduration > 0) ? upnp_time() + leaseduration : 0;
|
|
+- syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
|
|
++ syslog(LOG_DEBUG, "redirecting port %hu to %s:%hu protocol %s for: %s",
|
|
+ eport, iaddr, iport, protocol, desc);
|
|
+ return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
|
|
+ desc, timestamp);
|
|
+@@ -641,7 +641,7 @@ get_upnp_rules_state_list(int max_rules_
|
|
+ {
|
|
+ if(tmp->to_remove)
|
|
+ {
|
|
+- syslog(LOG_NOTICE, "remove port mapping %hu %s because it has expired",
|
|
++ syslog(LOG_INFO, "remove port mapping %hu %s because it has expired",
|
|
+ tmp->eport, proto_itoa(tmp->proto));
|
|
+ _upnp_delete_redir(tmp->eport, tmp->proto);
|
|
+ *p = tmp->next;
|
|
+--- a/upnpsoap.c
|
|
++++ b/upnpsoap.c
|
|
+@@ -491,7 +491,7 @@ AddPortMapping(struct upnphttp * h, cons
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
|
|
++ syslog(LOG_INFO, "Failed to convert hostname '%s' to ip address", int_ip);
|
|
+ ClearNameValueList(&data);
|
|
+ SoapError(h, 402, "Invalid Args");
|
|
+ return;
|
|
+@@ -690,7 +690,7 @@ AddAnyPortMapping(struct upnphttp * h, c
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip);
|
|
++ syslog(LOG_INFO, "Failed to convert hostname '%s' to ip address", int_ip);
|
|
+ ClearNameValueList(&data);
|
|
+ SoapError(h, 402, "Invalid Args");
|
|
+ return;
|
|
+@@ -847,7 +847,7 @@ GetSpecificPortMappingEntry(struct upnph
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s' duration=%u",
|
|
++ syslog(LOG_DEBUG, "%s: rhost='%s' %s %s found => %s:%u desc='%s' duration=%u",
|
|
+ action,
|
|
+ r_host ? r_host : "NULL", ext_port, protocol, int_ip,
|
|
+ (unsigned int)iport, desc, leaseduration);
|
|
+@@ -931,7 +931,7 @@ DeletePortMapping(struct upnphttp * h, c
|
|
+ return;
|
|
+ }
|
|
+
|
|
+- syslog(LOG_INFO, "%s: external port: %hu, protocol: %s",
|
|
++ syslog(LOG_DEBUG, "%s: external port: %hu, protocol: %s",
|
|
+ action, eport, protocol);
|
|
+
|
|
+ /* if in secure mode, check the IP
|
|
+@@ -1047,7 +1047,7 @@ DeletePortMappingRange(struct upnphttp *
|
|
+ for(i = 0; i < number; i++)
|
|
+ {
|
|
+ r = upnp_delete_redirection(port_list[i], protocol);
|
|
+- syslog(LOG_INFO, "%s: deleting external port: %hu, protocol: %s: %s",
|
|
++ syslog(LOG_DEBUG, "%s: deleting external port: %hu, protocol: %s: %s",
|
|
+ action, port_list[i], protocol, r < 0 ? "failed" : "ok");
|
|
+ }
|
|
+ free(port_list);
|
|
+@@ -1112,7 +1112,7 @@ GetGenericPortMappingEntry(struct upnpht
|
|
+ return;
|
|
+ }
|
|
+
|
|
+- syslog(LOG_INFO, "%s: index=%d", action, (int)index);
|
|
++ syslog(LOG_DEBUG, "%s: index=%d", action, (int)index);
|
|
+
|
|
+ rhost[0] = '\0';
|
|
+ r = upnp_get_redirection_infos_by_index((int)index, &eport, protocol, &iport,
|
|
+@@ -1635,7 +1635,7 @@ PinholeVerification(struct upnphttp * h,
|
|
+ int r;
|
|
+ struct addrinfo hints, *ai, *p;
|
|
+
|
|
+- syslog(LOG_INFO, "%s: InternalClient %s is not an IPv6, assume hostname and convert",
|
|
++ syslog(LOG_DEBUG, "%s: InternalClient %s is not an IPv6, assume hostname and convert",
|
|
+ "PinholeVerification", int_ip);
|
|
+
|
|
+ memset(&hints, 0, sizeof(hints));
|
|
+@@ -1655,8 +1655,8 @@ PinholeVerification(struct upnphttp * h,
|
|
+ {
|
|
+ result_ip = ((struct sockaddr_in6 *)p->ai_addr)->sin6_addr;
|
|
+ if (inet_ntop(AF_INET6, &result_ip, int_ip, sizeof(struct in6_addr)) == NULL)
|
|
+- syslog(LOG_WARNING, "%s: inet_ntop(): %m", "PinholeVerification");
|
|
+- syslog(LOG_INFO, "%s: InternalClient resolved as %s",
|
|
++ syslog(LOG_DEBUG, "%s: inet_ntop(): %m", "PinholeVerification");
|
|
++ syslog(LOG_DEBUG, "%s: InternalClient resolved as %s",
|
|
+ "PinholeVerification", int_ip);
|
|
+ found = 1;
|
|
+ }
|
|
+@@ -1672,7 +1672,7 @@ PinholeVerification(struct upnphttp * h,
|
|
+ freeaddrinfo(ai);
|
|
+ if (!found)
|
|
+ {
|
|
+- syslog(LOG_NOTICE, "%s: No IPv6 address for hostname '%s'",
|
|
++ syslog(LOG_INFO, "%s: No IPv6 address for hostname '%s'",
|
|
+ "PinholeVerification", int_ip);
|
|
+ SoapError(h, 402, "Invalid Args");
|
|
+ return -1;
|
|
+@@ -1680,7 +1680,7 @@ PinholeVerification(struct upnphttp * h,
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_WARNING, "%s: Failed to convert hostname '%s' to IP address : %s",
|
|
++ syslog(LOG_INFO, "%s: Failed to convert hostname '%s' to IP address : %s",
|
|
+ "PinholeVerification", int_ip, gai_strerror(r));
|
|
+ SoapError(h, 402, "Invalid Args");
|
|
+ return -1;
|
|
+@@ -1813,7 +1813,7 @@ AddPinhole(struct upnphttp * h, const ch
|
|
+ inet_ntop(AF_INET6,
|
|
+ &(((struct sockaddr_in6 *)p->ai_addr)->sin6_addr),
|
|
+ rem_ip, sizeof(rem_ip));
|
|
+- syslog(LOG_INFO, "resolved '%s' to '%s'", rem_host, rem_ip);
|
|
++ syslog(LOG_DEBUG, "resolved '%s' to '%s'", rem_host, rem_ip);
|
|
+ rem_host = rem_ip;
|
|
+ break;
|
|
+ }
|
|
+@@ -1822,7 +1822,7 @@ AddPinhole(struct upnphttp * h, const ch
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+- syslog(LOG_WARNING, "AddPinhole : getaddrinfo(%s) : %s",
|
|
++ syslog(LOG_INFO, "AddPinhole : getaddrinfo(%s) : %s",
|
|
+ rem_host, gai_strerror(err));
|
|
+ #if 0
|
|
+ SoapError(h, 402, "Invalid Args");
|
|
+@@ -2481,7 +2481,7 @@ SoapError(struct upnphttp * h, int errCo
|
|
+ char body[2048];
|
|
+ int bodylen;
|
|
+
|
|
+- syslog(LOG_INFO, "Returning UPnPError %d: %s", errCode, errDesc);
|
|
++ syslog(LOG_DEBUG, "Returning UPnPError %d: %s", errCode, errDesc);
|
|
+ bodylen = snprintf(body, sizeof(body), resp, errCode, errDesc);
|
|
+ BuildResp2_upnphttp(h, 500, "Internal Server Error", body, bodylen);
|
|
+ SendRespAndClose_upnphttp(h);
|
|
|
|
From 159e795432dd4da1ef464156570d5447c401ea5c Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 04/10] miniupnpd: package revision and new UCI options
|
|
|
|
The following settings UCI options been added or changed, and the
|
|
previous options are migrated on updating:
|
|
|
|
upnpd.config UCI options | Change | Previous name
|
|
-----------------------------|---------------------------|--------------
|
|
enabled | Match default (1) |
|
|
enable_protocols=upnp-igd | Combined option | enable_upnp=1
|
|
enable_protocols=pcp+nat-pmp | Combined option | enable_natpmp=1
|
|
allow_cgnat | Accept extra values (2) | use_stun
|
|
stun_host | Accept port inclusion (3) |
|
|
stun_port | Removed, included in host |
|
|
allow_third_party_mapping=0 | Inverted/extended to PCP | secure_mode=1
|
|
log_output | Allow info log level |
|
|
lease_file | Set by default + IPv6 (4) | upnp_lease_file
|
|
upnp_igd_compat=igdv1 | Renamed/match default (1) | igdv1=1
|
|
download_kbps | In kbit/s and renamed (5) | download
|
|
upload_kbps | In kbit/s and renamed (5) | upload
|
|
friendly_name | New option, router name |
|
|
http_port | Renamed, rem. if default | port
|
|
notify_interval | Removed if <900s, minimum |
|
|
internal_iface | Migrated, new section |
|
|
|
|
internal_network UCI options | Change | Previous name
|
|
-----------------------------|---------------------------|--------------
|
|
interface | New option |
|
|
access_defaults | New option (6) |
|
|
accept_ports | New option (6) |
|
|
reject_ports | New option (7) |
|
|
check_acl | New option (6) |
|
|
|
|
Notes:
|
|
1. Init UCI default now matches LuCI and initial config file defaults
|
|
for: enabled=0 and upnp_igd_compat=igdv1
|
|
2. Accept extra values for IPv4 CGNAT use, migrate option from X-Wrt and
|
|
only use STUN when necessary with a private/CGNAT external IPv4
|
|
3. Remove known unsupported STUN servers and set compatible by default
|
|
4. Configure undocumented daemon option `lease_file6=${lease_file}-ipv6`
|
|
so that active IPv6 port maps are not lost when service restarts,
|
|
e.g. by deleting an active port map. Remove option if UCI default set
|
|
5. Gets converted, config file now defaults to interface link speed
|
|
instead of 8/4 Mbit/s, which is removed on migration
|
|
6. New options added for default ports that all devices on a network can
|
|
map, client-specific permissions using the access control list (ACL)
|
|
can extend/override the defaults. Access defaults: accept-high-ports
|
|
accept-web+high-ports/accept-web-ports/accept-all-ports
|
|
7. Reject ports; overrides other settings. By default reject unsafe:
|
|
FTP (21), Telnet (23), DCE/NetBIOS/SMB (135/137-139/445), RDP (3389)
|
|
|
|
Code refactoring:
|
|
- Add a function for logging and output to stderr, and extend logging
|
|
- Revise daemon init/config-gen slightly by declare all UCI options
|
|
(incl. booleans) according to the same principle and remove
|
|
`upnpd_write_bool`
|
|
- Document and reformat default `/etc/config/upnpd` UCI config file
|
|
- Don't configure/flush unnecessary `upnp_postrouting` nftables chain
|
|
|
|
Fixes: https://redirect.github.com/openwrt/packages/issues/17413
|
|
Fixes: https://redirect.github.com/openwrt/packages/issues/29314
|
|
Depends on: https://redirect.github.com/openwrt/luci/pull/8415
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/Makefile | 2 +
|
|
miniupnpd/files/miniupnpd.init | 213 ++++++++++++------
|
|
.../chain-post/srcnat/20-miniupnpd.nft | 1 -
|
|
.../nftables.d/table-post/20-miniupnpd.nft | 1 -
|
|
.../files/upnpd-migration.uci-defaults | 159 +++++++++++++
|
|
miniupnpd/files/upnpd.config | 56 +++--
|
|
6 files changed, 335 insertions(+), 97 deletions(-)
|
|
delete mode 100644 miniupnpd/files/nftables.d/chain-post/srcnat/20-miniupnpd.nft
|
|
create mode 100644 miniupnpd/files/upnpd-migration.uci-defaults
|
|
|
|
diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile
|
|
index 042a49faf32803..33c27862b309a4 100644
|
|
--- a/miniupnpd/Makefile
|
|
+++ b/miniupnpd/Makefile
|
|
@@ -98,8 +98,10 @@ define Package/miniupnpd/install/Default
|
|
$(INSTALL_DIR) $(1)/etc/init.d
|
|
$(INSTALL_DIR) $(1)/etc/config
|
|
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
|
|
+ $(INSTALL_DIR) $(1)/etc/uci-defaults
|
|
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/miniupnpd $(1)/usr/sbin/miniupnpd
|
|
$(INSTALL_BIN) ./files/miniupnpd.init $(1)/etc/init.d/miniupnpd
|
|
+ $(INSTALL_BIN) ./files/upnpd-migration.uci-defaults $(1)/etc/uci-defaults/99-miniupnpd-upnpd-migration
|
|
$(INSTALL_CONF) ./files/upnpd.config $(1)/etc/config/upnpd
|
|
$(INSTALL_DATA) ./files/miniupnpd.hotplug $(1)/etc/hotplug.d/iface/50-miniupnpd
|
|
endef
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index 861bec0d3124f9..5dd786a50462d5 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -42,53 +42,44 @@ conf_rule_add() {
|
|
echo "$action $ext_start${ext_end:+-}$ext_end $int_addr $int_start${int_end:+-}$int_end #$comment"
|
|
}
|
|
|
|
-upnpd_write_bool() {
|
|
- local opt="$1"
|
|
- local def="${2:-0}"
|
|
- local alt="${3:-$opt}"
|
|
- local val
|
|
-
|
|
- config_get_bool val config "$opt" "$def"
|
|
- if [ "$val" -eq 0 ]; then
|
|
- echo "$alt=no"
|
|
- else
|
|
- echo "$alt=yes"
|
|
- fi
|
|
-}
|
|
-
|
|
upnpd() {
|
|
config_load "upnpd"
|
|
- local external_iface external_iface6 external_zone external_ip internal_iface
|
|
- local upload download log_output port config_file serial_number model_number
|
|
- local use_stun stun_host stun_port uuid notify_interval presentation_url
|
|
- local upnp_lease_file upnp_lease_file6 ipv6_disable ext_allow_private_ipv4
|
|
+ local external_iface external_iface6 external_zone external_ip
|
|
+ local upload_kbps download_kbps log_output http_port config_file serial_number model_number
|
|
+ local allow_cgnat stun_host uuid notify_interval presentation_url
|
|
+ local lease_file ipv6_disable
|
|
+ local enable_protocols allow_third_party_mapping system_uptime upnp_igd_compat
|
|
+ local friendly_name
|
|
|
|
local enabled
|
|
- config_get_bool enabled config enabled 1
|
|
- [ "$enabled" -eq 0 ] && return 1
|
|
-
|
|
+ config_get enabled config enabled 0
|
|
+ if [ "$enabled" != "1" ]; then
|
|
+ log "Service disabled, enabled UCI option not set"
|
|
+ return 1
|
|
+ fi
|
|
config_get external_iface config external_iface
|
|
config_get external_iface6 config external_iface6
|
|
config_get external_zone config external_zone
|
|
config_get external_ip config external_ip
|
|
- config_get internal_iface config internal_iface
|
|
- config_get port config port 5000
|
|
- config_get upload config upload
|
|
- config_get download config download
|
|
- config_get_bool log_output config log_output 0
|
|
+ config_get http_port config http_port 5000
|
|
+ config_get upload_kbps config upload_kbps
|
|
+ config_get download_kbps config download_kbps
|
|
+ config_get log_output config log_output
|
|
config_get config_file config config_file
|
|
config_get serial_number config serial_number
|
|
config_get model_number config model_number
|
|
config_get uuid config uuid
|
|
- config_get use_stun config use_stun 0
|
|
- config_get stun_host config stun_host
|
|
- config_get stun_port config stun_port
|
|
+ config_get allow_cgnat config allow_cgnat 0
|
|
+ config_get stun_host config stun_host stun.nextcloud.com
|
|
config_get notify_interval config notify_interval
|
|
config_get presentation_url config presentation_url
|
|
- config_get upnp_lease_file config upnp_lease_file
|
|
- config_get upnp_lease_file6 config upnp_lease_file6
|
|
+ config_get lease_file config lease_file /var/run/miniupnpd.leases
|
|
config_get ipv6_disable config ipv6_disable 0
|
|
- config_get ext_allow_private_ipv4 config ext_allow_private_ipv4 0
|
|
+ config_get enable_protocols config enable_protocols all
|
|
+ config_get allow_third_party_mapping config allow_third_party_mapping 0
|
|
+ config_get system_uptime config system_uptime 1
|
|
+ config_get upnp_igd_compat config upnp_igd_compat igdv1
|
|
+ config_get friendly_name config friendly_name "OpenWrt UPnP IGD & PCP"
|
|
|
|
local conf ifname ifname6
|
|
|
|
@@ -121,55 +112,66 @@ upnpd() {
|
|
local tmpconf="/var/etc/miniupnpd.conf"
|
|
conf="$tmpconf"
|
|
mkdir -p /var/etc
|
|
-
|
|
+ if [ "$ifname" = "" ]; then
|
|
+ log "No external network interface found, not starting" daemon.err
|
|
+ return 1
|
|
+ fi
|
|
+ if ! uci -q get upnpd.@internal_network[0].interface >/dev/null; then
|
|
+ log "No internal networks configured, not starting" daemon.err
|
|
+ return 1
|
|
+ fi
|
|
{
|
|
echo "ext_ifname=$ifname"
|
|
echo "ext_ifname6=$ifname6"
|
|
[ -n "$external_ip" ] && echo "ext_ip=$external_ip"
|
|
|
|
- local iface
|
|
- for iface in ${internal_iface:-lan}; do
|
|
- local device
|
|
- network_get_device device "$iface" && echo "listening_ip=$device"
|
|
- done
|
|
-
|
|
- config_load "upnpd"
|
|
- upnpd_write_bool enable_natpmp 1
|
|
- upnpd_write_bool enable_upnp 1
|
|
- upnpd_write_bool secure_mode 1
|
|
- upnpd_write_bool system_uptime 1
|
|
- upnpd_write_bool igdv1 0 force_igd_desc_v1
|
|
- upnpd_write_bool use_stun 0 ext_perform_stun
|
|
- upnpd_write_bool ipv6_disable $ipv6_disable
|
|
- upnpd_write_bool ext_allow_private_ipv4 $ext_allow_private_ipv4
|
|
-
|
|
- [ "$use_stun" -eq 0 ] || {
|
|
- [ -n "$stun_host" ] && echo "ext_stun_host=$stun_host"
|
|
- [ -n "$stun_port" ] && echo "ext_stun_port=$stun_port"
|
|
- }
|
|
+ [ "$enable_protocols" = "all" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=yes"
|
|
+ [ "$enable_protocols" = "upnp-igd" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=no"
|
|
+ [ "$enable_protocols" = "pcp+nat-pmp" ] && echo "enable_upnp=no" && echo "enable_pcp_pmp=yes"
|
|
+ [ "$allow_third_party_mapping" = "0" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=no"
|
|
+ [ "$allow_third_party_mapping" = "1" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=yes"
|
|
+ [ "$allow_third_party_mapping" = "upnp-igd" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=no"
|
|
+ [ "$allow_third_party_mapping" = "pcp" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=yes"
|
|
+ [ "$system_uptime" = "0" ] && echo "system_uptime=no" || echo "system_uptime=yes"
|
|
+ [ "$upnp_igd_compat" = "igdv1" ] && echo "force_igd_desc_v1=yes" || echo "force_igd_desc_v1=no"
|
|
+ # Only perform an STUN CGNAT test if necessary, with a private/CGNAT-reserved external IPv4
|
|
+ local extipv4 extipv4private
|
|
+ extipv4="$(ip -4 addr show dev "$ifname" | grep inet | head -1 | sed -E "s/.*inet ([0-9.]+).*/\1/")"
|
|
+ case "$extipv4" in
|
|
+ 10.* | 100.6[4-9].* | 100.[7-9][0-9].* | 100.1[0-1][0-9].* | 100.12[0-7].* | 172.1[6-9].* | \
|
|
+ 172.2[0-9].* | 172.3[0-1].* | 192.0.0.[1-6] | 192.168.* | 198.1[89].*) extipv4private=1 ;;
|
|
+ esac
|
|
+ [ "$extipv4private" = "1" ] && log "Private/CGNAT-reserved external IPv4 detected ($extipv4)"
|
|
+ if [ "$extipv4private" = "1" ] && [ "$allow_cgnat" != "0" ]; then
|
|
+ [ "$allow_cgnat" = "1" ] && echo "ext_perform_stun=yes"
|
|
+ [ "$allow_cgnat" = "allow-filtered" ] && echo "ext_perform_stun=allow-filtered"
|
|
+ # Avoid next option, as no STUN public IPv4 detection, required by clients (PCP/NAT-PMP among others)
|
|
+ [ "$allow_cgnat" = "report-private-ipv4" ] && echo "ext_allow_private_ipv4=yes"
|
|
+ echo "ext_stun_host=${stun_host%%:*}"
|
|
+ [ "${stun_host%%:*}" != "${stun_host##*:}" ] && echo "ext_stun_port=${stun_host##*:}"
|
|
+ fi
|
|
+ [ "$ipv6_disable" = "0" ] && echo "ipv6_disable=no" || echo "ipv6_disable=yes"
|
|
|
|
- [ -n "$upload" ] && [ -n "$download" ] && {
|
|
- echo "bitrate_down=$((download * 1024 * 8))"
|
|
- echo "bitrate_up=$((upload * 1024 * 8))"
|
|
- }
|
|
+ [ -n "$download_kbps" ] && echo "bitrate_down=$((download_kbps * 1000))"
|
|
+ [ -n "$upload_kbps" ] && echo "bitrate_up=$((upload_kbps * 1000))"
|
|
|
|
- [ -n "$upnp_lease_file" ] && touch "$upnp_lease_file" && echo "lease_file=$upnp_lease_file"
|
|
- [ -n "$upnp_lease_file6" ] && touch "$upnp_lease_file6" && echo "lease_file6=$upnp_lease_file6"
|
|
+ touch "$lease_file" && echo "lease_file=$lease_file"
|
|
+ [ "$ipv6_disable" = "0" ] && touch "${lease_file}-ipv6" && echo "lease_file6=${lease_file}-ipv6"
|
|
+ [ -n "$friendly_name" ] && echo "friendly_name=$friendly_name"
|
|
[ -n "$presentation_url" ] && echo "presentation_url=$presentation_url"
|
|
[ -n "$notify_interval" ] && echo "notify_interval=$notify_interval"
|
|
- [ -n "$serial_number" ] && echo "serial=$serial_number"
|
|
- [ -n "$model_number" ] && echo "model_number=$model_number"
|
|
- [ -n "$port" ] && echo "port=$port"
|
|
+ echo "serial=$serial_number"
|
|
+ echo "model_number=$model_number"
|
|
+ echo "http_port=$http_port"
|
|
|
|
[ -z "$uuid" ] && {
|
|
+ log "Generate UPnP IGD UUID"
|
|
uuid="$(cat /proc/sys/kernel/random/uuid)"
|
|
uci set upnpd.config.uuid="$uuid"
|
|
uci commit upnpd
|
|
}
|
|
|
|
- [ "$uuid" = "nocli" ] || echo "uuid=$uuid"
|
|
-
|
|
- config_foreach conf_rule_add perm_rule
|
|
+ [ "$uuid" != "nocli" ] && echo "uuid=$uuid" || log "uuid=nocli deprecated, set to 00000000-0000-0000-0000-000000000000 instead"
|
|
|
|
if [ "$FW" = "fw4" ]; then
|
|
#When using nftables configure miniupnpd to use its own table and chains
|
|
@@ -177,9 +179,14 @@ upnpd() {
|
|
echo "upnp_nat_table_name=fw4"
|
|
echo "upnp_forward_chain=upnp_forward"
|
|
echo "upnp_nat_chain=upnp_prerouting"
|
|
- echo "upnp_nat_postrouting_chain=upnp_postrouting"
|
|
+ #echo "upnp_nat_postrouting_chain=upnp_postrouting"
|
|
fi
|
|
|
|
+ echo "# Enable internal networks / access control"
|
|
+ config_foreach upnpd_add_int_network_and_defaults internal_network pre-acl
|
|
+ config_foreach conf_rule_add perm_rule
|
|
+ config_foreach upnpd_add_int_network_and_defaults internal_network post-acl
|
|
+
|
|
} > "$tmpconf"
|
|
fi
|
|
|
|
@@ -190,15 +197,14 @@ upnpd() {
|
|
else
|
|
iptables -L MINIUPNPD >/dev/null 2>&1 || fw3 reload
|
|
fi
|
|
- else
|
|
- logger -t "upnp daemon" "external interface not found, not starting"
|
|
fi
|
|
|
|
procd_open_instance
|
|
procd_set_param file "$conf" "/etc/config/firewall"
|
|
procd_set_param command "$PROG"
|
|
procd_append_param command -f "$conf"
|
|
- [ "$log_output" = "1" ] && procd_append_param command -d
|
|
+ [ "$log_output" = "info" ] && procd_append_param command -v
|
|
+ [ "$log_output" = "debug" ] && procd_append_param command -v -v
|
|
procd_close_instance
|
|
}
|
|
|
|
@@ -211,7 +217,7 @@ stop_service() {
|
|
else
|
|
nft flush chain inet fw4 upnp_forward 2>/dev/null
|
|
nft flush chain inet fw4 upnp_prerouting 2>/dev/null
|
|
- nft flush chain inet fw4 upnp_postrouting 2>/dev/null
|
|
+ #nft flush chain inet fw4 upnp_postrouting 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
@@ -223,3 +229,70 @@ start_service() {
|
|
service_triggers() {
|
|
procd_add_reload_trigger "upnpd"
|
|
}
|
|
+
|
|
+log() {
|
|
+ logger -s -p "${2:-daemon.notice}" -t "miniupnpd-init" "$1" || echo "miniupnpd-init: $1" >&2
|
|
+}
|
|
+
|
|
+upnpd_add_int_network_and_defaults() {
|
|
+ local cfg="$1"
|
|
+ local interface access_defaults accept_ports reject_ports check_acl
|
|
+ config_get interface "$cfg" interface
|
|
+ config_get access_defaults "$cfg" access_defaults none
|
|
+ config_get accept_ports "$cfg" accept_ports
|
|
+ config_get reject_ports "$cfg" reject_ports "21 23 135 137-139 445 3389"
|
|
+ config_get check_acl "$cfg" check_acl 1
|
|
+ local device subnet rejectport accessdefaultsports acceptport
|
|
+ network_get_device device "$interface"
|
|
+ network_get_subnet subnet "$interface"
|
|
+ [ "$subnet" = "" ] && log "Cannot get IPv4 subnet for network $interface, network ignored" daemon.warn && return 0
|
|
+ if [ "$2" = "pre-acl" ]; then
|
|
+ echo "# Enable internal network $interface ($device) with access defaults $access_defaults and check ACL $check_acl"
|
|
+ echo "listening_ip=$device"
|
|
+ for rejectport in $reject_ports; do
|
|
+ if [ "$rejectport" -ge "1" ] 2>/dev/null && [ "$rejectport" -le "65535" ] 2>/dev/null ||
|
|
+ {
|
|
+ [ "${rejectport%%-*}" -ge "1" ] 2>/dev/null &&
|
|
+ [ "${rejectport%%-*}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${rejectport##*-}" -ge "1" ] 2>/dev/null &&
|
|
+ [ "${rejectport##*-}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${rejectport##*-}" -ge "${rejectport%%-*}" ] 2>/dev/null
|
|
+ }; then
|
|
+ echo "deny $rejectport $subnet $rejectport # Reject port $rejectport on $interface"
|
|
+ else
|
|
+ log "Invalid port or port range ($rejectport) in reject_ports ignored" daemon.warn
|
|
+ fi
|
|
+ done
|
|
+ fi
|
|
+ if { [ "$2" = "post-acl" ] && [ "$check_acl" = "1" ]; } ||
|
|
+ { [ "$2" = "pre-acl" ] && [ "$check_acl" = "0" ]; }; then
|
|
+ if [ "$access_defaults" = "accept-high-ports" ]; then
|
|
+ accessdefaultsports="1024-65535"
|
|
+ elif [ "$access_defaults" = "accept-web+high-ports" ]; then
|
|
+ accessdefaultsports="80 443 1024-65535"
|
|
+ elif [ "$access_defaults" = "accept-web-ports" ]; then
|
|
+ accessdefaultsports="80 443"
|
|
+ elif [ "$access_defaults" = "accept-all-ports" ]; then
|
|
+ accessdefaultsports="1-65535"
|
|
+ elif [ "$access_defaults" != "none" ]; then
|
|
+ log "Invalid access_defaults ($access_defaults) ignored" daemon.warn
|
|
+ fi
|
|
+ for acceptport in $accessdefaultsports $accept_ports; do
|
|
+ if [ "$acceptport" -ge "1" ] 2>/dev/null && [ "$acceptport" -le "65535" ] 2>/dev/null ||
|
|
+ {
|
|
+ [ "${acceptport%%-*}" -ge "1" ] 2>/dev/null &&
|
|
+ [ "${acceptport%%-*}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${acceptport##*-}" -ge "1" ] 2>/dev/null &&
|
|
+ [ "${acceptport##*-}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${acceptport##*-}" -ge "${acceptport%%-*}" ] 2>/dev/null
|
|
+ }; then
|
|
+ echo "allow $acceptport $subnet $acceptport # Accept port $acceptport on $interface"
|
|
+ else
|
|
+ log "Invalid port or port range ($acceptport) in accept_ports ignored" daemon.warn
|
|
+ fi
|
|
+ done
|
|
+ fi
|
|
+ if [ "$2" = "pre-acl" ] && [ "$check_acl" = "0" ]; then
|
|
+ echo "deny 1-65535 $subnet 1-65535 # Reject ACL by default on $interface"
|
|
+ fi
|
|
+}
|
|
diff --git a/miniupnpd/files/nftables.d/chain-post/srcnat/20-miniupnpd.nft b/miniupnpd/files/nftables.d/chain-post/srcnat/20-miniupnpd.nft
|
|
deleted file mode 100644
|
|
index 2d0051e202f7b1..00000000000000
|
|
--- a/miniupnpd/files/nftables.d/chain-post/srcnat/20-miniupnpd.nft
|
|
+++ /dev/null
|
|
@@ -1 +0,0 @@
|
|
-jump upnp_postrouting comment "Hook into miniupnpd postrouting chain";
|
|
diff --git a/miniupnpd/files/nftables.d/table-post/20-miniupnpd.nft b/miniupnpd/files/nftables.d/table-post/20-miniupnpd.nft
|
|
index 7d914e5c84fdf3..3d787fba88d0da 100644
|
|
--- a/miniupnpd/files/nftables.d/table-post/20-miniupnpd.nft
|
|
+++ b/miniupnpd/files/nftables.d/table-post/20-miniupnpd.nft
|
|
@@ -1,3 +1,2 @@
|
|
chain upnp_forward {}
|
|
chain upnp_prerouting {}
|
|
-chain upnp_postrouting {}
|
|
diff --git a/miniupnpd/files/upnpd-migration.uci-defaults b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
new file mode 100644
|
|
index 00000000000000..19445c9198994b
|
|
--- /dev/null
|
|
+++ b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
@@ -0,0 +1,159 @@
|
|
+#!/bin/sh
|
|
+
|
|
+log() {
|
|
+ logger -s -p "${2:-daemon.notice}" -t "upnpd" "$1" || echo "upnpd: $1" >&2
|
|
+}
|
|
+
|
|
+log "Check UCI options in /etc/config/upnpd to be migrated to v2.0"
|
|
+
|
|
+# Set missing enabled option to fix previously different defaults in LuCI/config (0) and init UCI (1)
|
|
+if ! uci -q get upnpd.config.enabled >/dev/null; then
|
|
+ uci -q set upnpd.config.enabled="1"
|
|
+fi
|
|
+
|
|
+# Migrate boolean options to only use 0/1 for LuCI support
|
|
+for option in enabled ipv6_disable system_uptime; do
|
|
+ if uci -q get upnpd.config.$option >/dev/null; then
|
|
+ uci get upnpd.config.$option | grep -q -E -x "0|off|false|no|disabled" && uci set upnpd.config.$option="0"
|
|
+ uci get upnpd.config.$option | grep -q -E -x "1|on|true|yes|enabled" && uci set upnpd.config.$option="1"
|
|
+ fi
|
|
+done
|
|
+
|
|
+# Migrate enable_upnp/enable_natpmp -> enable_protocols: Combined option
|
|
+if uci -q get upnpd.config.enable_upnp >/dev/null || uci -q get upnpd.config.enable_natpmp >/dev/null; then
|
|
+ log "enable_upnp/enable_natpmp -> enable_protocols: Combined option"
|
|
+ if ! uci -q get upnpd.config.enable_upnp | grep -q -E -x "0|off|false|no|disabled"; then
|
|
+ uci -q get upnpd.config.enable_natpmp | grep -q -E -x "0|off|false|no|disabled" &&
|
|
+ uci set upnpd.config.enable_protocols="upnp-igd" ||
|
|
+ uci set upnpd.config.enable_protocols="all"
|
|
+ elif ! uci -q get upnpd.config.enable_natpmp | grep -q -E -x "0|off|false|no|disabled"; then
|
|
+ uci set upnpd.config.enable_protocols="pcp+nat-pmp"
|
|
+ else
|
|
+ uci set upnpd.config.enable_protocols="all"
|
|
+ uci set upnpd.config.enabled="0"
|
|
+ fi
|
|
+ uci -q delete upnpd.config.enable_upnp
|
|
+ uci -q delete upnpd.config.enable_natpmp
|
|
+fi
|
|
+
|
|
+# Rename use_stun -> allow_cgnat
|
|
+if uci -q get upnpd.config.use_stun >/dev/null; then
|
|
+ log "use_stun -> allow_cgnat"
|
|
+ uci rename upnpd.config.use_stun="allow_cgnat"
|
|
+fi
|
|
+
|
|
+# Migrate force_forwarding=1 (in X-Wrt since 2021) to new similar option allow_cgnat=allow-filtered for cross-upgrades
|
|
+if uci -q get upnpd.config.force_forwarding >/dev/null; then
|
|
+ log "force_forwarding=1 -> allow_cgnat=allow-filtered: New option"
|
|
+ uci get upnpd.config.force_forwarding | grep -q -E -x "1|on|true|yes|enabled" &&
|
|
+ uci set upnpd.config.allow_cgnat="allow-filtered"
|
|
+ uci delete upnpd.config.force_forwarding
|
|
+fi
|
|
+
|
|
+# Remove known unsupported (not CGNAT filtering test capable) STUN servers and include stun_port in stun_host
|
|
+if uci -q get upnpd.config.stun_host | grep -q -E "stun[0-9]?.l.google.com|stun.cloudflare.com"; then
|
|
+ log "stun_host: Unsupported STUN server ($(uci -q get upnpd.config.stun_host)) set, remove to set default"
|
|
+ uci delete upnpd.config.stun_host
|
|
+ # Workaround for false negative filtered STUN CGNAT test results for unsupported servers before daemon 2.3.10
|
|
+ uci set upnpd.config.allow_cgnat="allow-filtered"
|
|
+ uci -q delete upnpd.config.stun_port
|
|
+elif uci -q get upnpd.config.stun_port >/dev/null; then
|
|
+ uci -q get upnpd.config.stun_host >/dev/null && [ "$(uci -q get upnpd.config.stun_port)" != "3478" ] &&
|
|
+ log "stun_port: Include stun_port in stun_host, and remove option" &&
|
|
+ uci set upnpd.config.stun_host="$(uci -q get upnpd.config.stun_host | cut -d ":" -f 1):$(uci -q get upnpd.config.stun_port)"
|
|
+ uci delete upnpd.config.stun_port
|
|
+fi
|
|
+
|
|
+# Migrate secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd: Invert and extend to PCP
|
|
+if uci -q get upnpd.config.secure_mode >/dev/null; then
|
|
+ log "secure_mode=1/0 -> allow_third_party_mapping=0/upnp-igd: Invert and extend to PCP"
|
|
+ uci get upnpd.config.secure_mode | grep -q -E -x "0|off|false|no|disabled" &&
|
|
+ uci set upnpd.config.allow_third_party_mapping="upnp-igd" ||
|
|
+ uci set upnpd.config.allow_third_party_mapping="0"
|
|
+ uci delete upnpd.config.secure_mode
|
|
+fi
|
|
+
|
|
+# Migrate log_output=0/1 -> log_output=default/debug: Now info also allowed
|
|
+if uci -q get upnpd.config.log_output >/dev/null; then
|
|
+ log "log_output=0/1 -> log_output=default/debug: Now info also allowed"
|
|
+ uci get upnpd.config.log_output | grep -q -E -x "1|on|true|yes|enabled" &&
|
|
+ uci set upnpd.config.log_output="debug"
|
|
+ uci get upnpd.config.log_output | grep -q -E -x "0|off|false|no|disabled" &&
|
|
+ uci set upnpd.config.log_output="default"
|
|
+fi
|
|
+
|
|
+# Rename upnp_lease_file -> lease_file: To original daemon name, and remove if UCI default set
|
|
+if uci -q get upnpd.config.upnp_lease_file >/dev/null; then
|
|
+ if [ "$(uci -q get upnpd.config.upnp_lease_file)" = "/var/run/miniupnpd.leases" ]; then
|
|
+ log "upnp_lease_file -> lease_file: Remove option as UCI default set"
|
|
+ uci delete upnpd.config.upnp_lease_file
|
|
+ else
|
|
+ log "upnp_lease_file -> lease_file"
|
|
+ uci rename upnpd.config.upnp_lease_file="lease_file"
|
|
+ fi
|
|
+fi
|
|
+if uci -q get upnpd.config.upnp_lease_file6 >/dev/null; then
|
|
+ uci delete upnpd.config.upnp_lease_file6
|
|
+fi
|
|
+
|
|
+# Migrate igdv1=1/0 -> upnp_igd_compat=igdv1/igdv2: Extensible/clearer
|
|
+if uci -q get upnpd.config.igdv1 >/dev/null; then
|
|
+ log "igdv1=1/0 -> upnp_igd_compat=igdv1/igdv2"
|
|
+ uci get upnpd.config.igdv1 | grep -q -E -x "1|on|true|yes|enabled" &&
|
|
+ uci set upnpd.config.upnp_igd_compat="igdv1" ||
|
|
+ uci set upnpd.config.upnp_igd_compat="igdv2"
|
|
+ uci delete upnpd.config.igdv1
|
|
+fi
|
|
+
|
|
+# Migrate download/upload -> download_kbps/upload_kbps: Convert to kbit/s
|
|
+if uci -q get upnpd.config.download >/dev/null; then
|
|
+ download="$(uci -q get upnpd.config.download)"
|
|
+ if [ "$download" != "1024" ] && [ "$download" -ge "1" ] 2>/dev/null; then
|
|
+ log "download -> download_kbps: Convert to kbit/s"
|
|
+ download_kbps="$((download * 8 * 1000 / 1024))"
|
|
+ uci set upnpd.config.download_kbps="$download_kbps"
|
|
+ fi
|
|
+ uci delete upnpd.config.download
|
|
+fi
|
|
+if uci -q get upnpd.config.upload >/dev/null; then
|
|
+ upload="$(uci -q get upnpd.config.upload)"
|
|
+ if [ "$upload" != "512" ] && [ "$upload" -ge "1" ] 2>/dev/null; then
|
|
+ log "upload -> upload_kbps: Convert to kbit/s"
|
|
+ upload_kbps="$((upload * 8 * 1000 / 1024))"
|
|
+ uci set upnpd.config.upload_kbps="$upload_kbps"
|
|
+ fi
|
|
+ uci delete upnpd.config.upload
|
|
+fi
|
|
+
|
|
+# Rename port -> http_port: Remove if UCI default set
|
|
+if uci -q get upnpd.config.port >/dev/null; then
|
|
+ if [ "$(uci -q get upnpd.config.port)" = "5000" ]; then
|
|
+ log "port -> http_port: Remove option as UCI default set"
|
|
+ uci delete upnpd.config.port
|
|
+ else
|
|
+ log "port -> http_port"
|
|
+ uci rename upnpd.config.port="http_port"
|
|
+ fi
|
|
+fi
|
|
+
|
|
+# Migrate notify_interval <= 900 s: Remove to set minimum of 900 (default)
|
|
+if [ "$(uci -q get upnpd.config.notify_interval)" -le "900" ] 2>/dev/null; then
|
|
+ log "notify_interval <= 900 s: Remove to set minimum of 900 (default)"
|
|
+ uci delete upnpd.config.notify_interval
|
|
+fi
|
|
+
|
|
+# Migrate internal_iface option to new internal_network section
|
|
+if ! uci -q get upnpd.@internal_network[0] >/dev/null; then
|
|
+ ifnr=0
|
|
+ for interface in $(uci -q get upnpd.config.internal_iface || echo lan); do
|
|
+ log "Create new internal_network section for $interface"
|
|
+ uci add upnpd internal_network >/dev/null
|
|
+ uci set upnpd.@internal_network[$ifnr].interface="$interface"
|
|
+ ifnr=$((ifnr + 1))
|
|
+ done
|
|
+ uci -q delete upnpd.config.internal_iface
|
|
+fi
|
|
+
|
|
+uci commit upnpd >/dev/null
|
|
+
|
|
+exit 0
|
|
diff --git a/miniupnpd/files/upnpd.config b/miniupnpd/files/upnpd.config
|
|
index c4546e018f5de7..6344a60071bd72 100644
|
|
--- a/miniupnpd/files/upnpd.config
|
|
+++ b/miniupnpd/files/upnpd.config
|
|
@@ -1,29 +1,35 @@
|
|
-config upnpd config
|
|
- option enabled 0
|
|
- option enable_natpmp 1
|
|
- option enable_upnp 1
|
|
- option secure_mode 1
|
|
- option log_output 0
|
|
- option download 1024
|
|
- option upload 512
|
|
-#by default, looked up dynamically from ubus
|
|
-# option external_iface wan
|
|
- option internal_iface lan
|
|
- option port 5000
|
|
- option upnp_lease_file /var/run/miniupnpd.leases
|
|
- option upnp_lease_file6 /var/run/miniupnpd.leases6
|
|
- option igdv1 1
|
|
+# UPnP IGD & PCP/NAT-PMP Service Settings (v2.0)
|
|
+
|
|
+config upnpd 'config'
|
|
+ option enabled '0'
|
|
+ # Can be set to all/upnp-igd/pcp+nat-pmp
|
|
+ option enable_protocols 'all'
|
|
+ #option ipv6_disable '0'
|
|
+ #option allow_third_party_mapping '0'
|
|
+ # Extra logging by setting to info or debug (previously 1)
|
|
+ option log_output 'default'
|
|
+ option upnp_igd_compat 'igdv1'
|
|
+
|
|
+# Enable Networks / Access Control
|
|
+
|
|
+config internal_network
|
|
+ option interface 'lan'
|
|
+ option access_defaults 'accept-high-ports' # default none
|
|
+ option check_acl '0' # default 1
|
|
+
|
|
+# Access Control List
|
|
+# Empty ACL rejected alone, IPv6 accepted unless disabled
|
|
|
|
config perm_rule
|
|
- option action allow
|
|
- option ext_ports 1024-65535
|
|
- option int_addr 0.0.0.0/0 # Does not override secure_mode
|
|
- option int_ports 1024-65535
|
|
- option comment "Allow high ports"
|
|
+ option comment 'Allow high ports'
|
|
+ option int_addr '0.0.0.0/0'
|
|
+ option int_ports '1024-65535'
|
|
+ option ext_ports '1024-65535'
|
|
+ option action 'allow'
|
|
|
|
config perm_rule
|
|
- option action deny
|
|
- option ext_ports 0-65535
|
|
- option int_addr 0.0.0.0/0
|
|
- option int_ports 0-65535
|
|
- option comment "Default deny"
|
|
+ option comment 'Default deny'
|
|
+ option int_addr '0.0.0.0/0'
|
|
+ option int_ports '1-65535'
|
|
+ option ext_ports '1-65535'
|
|
+ option action 'deny'
|
|
|
|
From 39860c186473551ec4a0156cbf8cc1f73b139b12 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 05/10] miniupnpd: group/rearrange config-gen, refactoring
|
|
|
|
- Group and rearrange UCI option declaration and config-gen by
|
|
function/LuCI UI, and comment
|
|
- Encode required XML entities of text UPnP IGD config options until the
|
|
daemon does so using the created function `xml_encode`
|
|
- Only generate UPnP IGD config if the protocol is enabled
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/miniupnpd.hotplug | 2 +-
|
|
miniupnpd/files/miniupnpd.init | 125 +++++++++++++-------------
|
|
2 files changed, 66 insertions(+), 61 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/miniupnpd.hotplug b/miniupnpd/files/miniupnpd.hotplug
|
|
index 607a32bdc6885b..5d34c441a829ea 100644
|
|
--- a/miniupnpd/files/miniupnpd.hotplug
|
|
+++ b/miniupnpd/files/miniupnpd.hotplug
|
|
@@ -40,6 +40,6 @@ fi
|
|
|
|
[ "$DEVICE" != "$ifname" ] && [ "$DEVICE" != "$ifname6" ] && exit 0
|
|
|
|
-grep -qs "^ext_ifname=$ifname" "$tmpconf" && grep -qs "^ext_ifname6=$ifname6" "$tmpconf" && exit 0
|
|
+grep -qs "^ext_ifname=$ifname" "$tmpconf" && grep -qs "^ext_ifname6=${ifname6:-$ifname}" "$tmpconf" && exit 0
|
|
|
|
/etc/init.d/miniupnpd restart
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index 5dd786a50462d5..969b22e60cacc4 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -29,7 +29,6 @@ conf_rule_add() {
|
|
local cfg="$1"
|
|
local action int_addr
|
|
local ext_start ext_end int_start int_end comment
|
|
-
|
|
config_get action "$cfg" action "deny" # allow or deny
|
|
upnpd_get_port_range "ext" "$cfg" ext_ports "0-65535" # external ports: x, x-y, x:y
|
|
config_get int_addr "$cfg" int_addr "0.0.0.0/0" # ip or network and subnet mask (internal)
|
|
@@ -44,45 +43,45 @@ conf_rule_add() {
|
|
|
|
upnpd() {
|
|
config_load "upnpd"
|
|
- local external_iface external_iface6 external_zone external_ip
|
|
- local upload_kbps download_kbps log_output http_port config_file serial_number model_number
|
|
- local allow_cgnat stun_host uuid notify_interval presentation_url
|
|
- local lease_file ipv6_disable
|
|
- local enable_protocols allow_third_party_mapping system_uptime upnp_igd_compat
|
|
- local friendly_name
|
|
-
|
|
local enabled
|
|
config_get enabled config enabled 0
|
|
if [ "$enabled" != "1" ]; then
|
|
log "Service disabled, enabled UCI option not set"
|
|
return 1
|
|
fi
|
|
- config_get external_iface config external_iface
|
|
- config_get external_iface6 config external_iface6
|
|
- config_get external_zone config external_zone
|
|
- config_get external_ip config external_ip
|
|
- config_get http_port config http_port 5000
|
|
- config_get upload_kbps config upload_kbps
|
|
- config_get download_kbps config download_kbps
|
|
- config_get log_output config log_output
|
|
- config_get config_file config config_file
|
|
- config_get serial_number config serial_number
|
|
- config_get model_number config model_number
|
|
- config_get uuid config uuid
|
|
+ # Daemon
|
|
+ local enable_protocols allow_cgnat stun_host allow_third_party_mapping ipv6_disable system_uptime log_output lease_file config_file
|
|
+ config_get enable_protocols config enable_protocols all
|
|
config_get allow_cgnat config allow_cgnat 0
|
|
config_get stun_host config stun_host stun.nextcloud.com
|
|
- config_get notify_interval config notify_interval
|
|
- config_get presentation_url config presentation_url
|
|
- config_get lease_file config lease_file /var/run/miniupnpd.leases
|
|
- config_get ipv6_disable config ipv6_disable 0
|
|
- config_get enable_protocols config enable_protocols all
|
|
config_get allow_third_party_mapping config allow_third_party_mapping 0
|
|
+ config_get ipv6_disable config ipv6_disable 0
|
|
config_get system_uptime config system_uptime 1
|
|
+ config_get log_output config log_output
|
|
+ config_get lease_file config lease_file /var/run/miniupnpd.leases
|
|
+ config_get config_file config config_file
|
|
+
|
|
+ # UPnP IGD
|
|
+ local upnp_igd_compat download_kbps upload_kbps friendly_name model_number serial_number presentation_url uuid http_port notify_interval
|
|
config_get upnp_igd_compat config upnp_igd_compat igdv1
|
|
+ config_get download_kbps config download_kbps
|
|
+ config_get upload_kbps config upload_kbps
|
|
config_get friendly_name config friendly_name "OpenWrt UPnP IGD & PCP"
|
|
+ config_get model_number config model_number
|
|
+ config_get serial_number config serial_number
|
|
+ config_get presentation_url config presentation_url
|
|
+ config_get uuid config uuid
|
|
+ config_get http_port config http_port 5000
|
|
+ config_get notify_interval config notify_interval
|
|
|
|
- local conf ifname ifname6
|
|
+ # External network interface
|
|
+ local external_iface external_iface6 external_zone external_ip
|
|
+ config_get external_iface config external_iface
|
|
+ config_get external_iface6 config external_iface6
|
|
+ config_get external_zone config external_zone
|
|
+ config_get external_ip config external_ip
|
|
|
|
+ local conf ifname ifname6
|
|
. /lib/functions/network.sh
|
|
|
|
if [ -n "$external_iface" ] ; then
|
|
@@ -120,20 +119,6 @@ upnpd() {
|
|
log "No internal networks configured, not starting" daemon.err
|
|
return 1
|
|
fi
|
|
- {
|
|
- echo "ext_ifname=$ifname"
|
|
- echo "ext_ifname6=$ifname6"
|
|
- [ -n "$external_ip" ] && echo "ext_ip=$external_ip"
|
|
-
|
|
- [ "$enable_protocols" = "all" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=yes"
|
|
- [ "$enable_protocols" = "upnp-igd" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=no"
|
|
- [ "$enable_protocols" = "pcp+nat-pmp" ] && echo "enable_upnp=no" && echo "enable_pcp_pmp=yes"
|
|
- [ "$allow_third_party_mapping" = "0" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=no"
|
|
- [ "$allow_third_party_mapping" = "1" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=yes"
|
|
- [ "$allow_third_party_mapping" = "upnp-igd" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=no"
|
|
- [ "$allow_third_party_mapping" = "pcp" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=yes"
|
|
- [ "$system_uptime" = "0" ] && echo "system_uptime=no" || echo "system_uptime=yes"
|
|
- [ "$upnp_igd_compat" = "igdv1" ] && echo "force_igd_desc_v1=yes" || echo "force_igd_desc_v1=no"
|
|
# Only perform an STUN CGNAT test if necessary, with a private/CGNAT-reserved external IPv4
|
|
local extipv4 extipv4private
|
|
extipv4="$(ip -4 addr show dev "$ifname" | grep inet | head -1 | sed -E "s/.*inet ([0-9.]+).*/\1/")"
|
|
@@ -142,6 +127,11 @@ upnpd() {
|
|
172.2[0-9].* | 172.3[0-1].* | 192.0.0.[1-6] | 192.168.* | 198.1[89].*) extipv4private=1 ;;
|
|
esac
|
|
[ "$extipv4private" = "1" ] && log "Private/CGNAT-reserved external IPv4 detected ($extipv4)"
|
|
+ {
|
|
+ echo "# Daemon"
|
|
+ [ "$enable_protocols" = "all" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=yes"
|
|
+ [ "$enable_protocols" = "upnp-igd" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=no"
|
|
+ [ "$enable_protocols" = "pcp+nat-pmp" ] && echo "enable_upnp=no" && echo "enable_pcp_pmp=yes"
|
|
if [ "$extipv4private" = "1" ] && [ "$allow_cgnat" != "0" ]; then
|
|
[ "$allow_cgnat" = "1" ] && echo "ext_perform_stun=yes"
|
|
[ "$allow_cgnat" = "allow-filtered" ] && echo "ext_perform_stun=allow-filtered"
|
|
@@ -150,31 +140,37 @@ upnpd() {
|
|
echo "ext_stun_host=${stun_host%%:*}"
|
|
[ "${stun_host%%:*}" != "${stun_host##*:}" ] && echo "ext_stun_port=${stun_host##*:}"
|
|
fi
|
|
+ [ "$allow_third_party_mapping" = "0" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=no"
|
|
+ [ "$allow_third_party_mapping" = "1" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=yes"
|
|
+ [ "$allow_third_party_mapping" = "upnp-igd" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=no"
|
|
+ [ "$allow_third_party_mapping" = "pcp" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=yes"
|
|
[ "$ipv6_disable" = "0" ] && echo "ipv6_disable=no" || echo "ipv6_disable=yes"
|
|
-
|
|
- [ -n "$download_kbps" ] && echo "bitrate_down=$((download_kbps * 1000))"
|
|
- [ -n "$upload_kbps" ] && echo "bitrate_up=$((upload_kbps * 1000))"
|
|
-
|
|
+ [ "$system_uptime" = "0" ] && echo "system_uptime=no" || echo "system_uptime=yes"
|
|
touch "$lease_file" && echo "lease_file=$lease_file"
|
|
[ "$ipv6_disable" = "0" ] && touch "${lease_file}-ipv6" && echo "lease_file6=${lease_file}-ipv6"
|
|
- [ -n "$friendly_name" ] && echo "friendly_name=$friendly_name"
|
|
- [ -n "$presentation_url" ] && echo "presentation_url=$presentation_url"
|
|
- [ -n "$notify_interval" ] && echo "notify_interval=$notify_interval"
|
|
- echo "serial=$serial_number"
|
|
- echo "model_number=$model_number"
|
|
- echo "http_port=$http_port"
|
|
-
|
|
- [ -z "$uuid" ] && {
|
|
- log "Generate UPnP IGD UUID"
|
|
- uuid="$(cat /proc/sys/kernel/random/uuid)"
|
|
- uci set upnpd.config.uuid="$uuid"
|
|
- uci commit upnpd
|
|
- }
|
|
|
|
- [ "$uuid" != "nocli" ] && echo "uuid=$uuid" || log "uuid=nocli deprecated, set to 00000000-0000-0000-0000-000000000000 instead"
|
|
+ if [ "$enable_protocols" = "upnp-igd" ] || [ "$enable_protocols" = "all" ]; then
|
|
+ echo "# UPnP IGD"
|
|
+ [ "$upnp_igd_compat" = "igdv1" ] && echo "force_igd_desc_v1=yes" || echo "force_igd_desc_v1=no"
|
|
+ [ -n "$download_kbps" ] && echo "bitrate_down=$((download_kbps * 1000))"
|
|
+ [ -n "$upload_kbps" ] && echo "bitrate_up=$((upload_kbps * 1000))"
|
|
+ [ -n "$friendly_name" ] && echo "friendly_name=$(xml_encode "$friendly_name")"
|
|
+ [ -n "$model_number" ] && echo "model_number=$(xml_encode "$model_number")" || echo "model_number="
|
|
+ [ -n "$serial_number" ] && echo "serial=$(xml_encode "$serial_number")" || echo "serial="
|
|
+ [ -n "$presentation_url" ] && echo "presentation_url=$presentation_url"
|
|
+ [ -z "$uuid" ] && {
|
|
+ log "Generate UPnP IGD UUID"
|
|
+ uuid="$(cat /proc/sys/kernel/random/uuid)"
|
|
+ uci set upnpd.config.uuid="$uuid"
|
|
+ uci commit upnpd
|
|
+ }
|
|
+ [ "$uuid" != "nocli" ] && echo "uuid=$uuid" || log "uuid=nocli deprecated, set to 00000000-0000-0000-0000-000000000000 instead"
|
|
+ echo "http_port=$http_port"
|
|
+ [ -n "$notify_interval" ] && echo "notify_interval=$notify_interval"
|
|
+ fi
|
|
|
|
if [ "$FW" = "fw4" ]; then
|
|
- #When using nftables configure miniupnpd to use its own table and chains
|
|
+ echo "# Firewall backend"
|
|
echo "upnp_table_name=fw4"
|
|
echo "upnp_nat_table_name=fw4"
|
|
echo "upnp_forward_chain=upnp_forward"
|
|
@@ -182,6 +178,11 @@ upnpd() {
|
|
#echo "upnp_nat_postrouting_chain=upnp_postrouting"
|
|
fi
|
|
|
|
+ echo "# External network interface"
|
|
+ echo "ext_ifname=$ifname"
|
|
+ echo "ext_ifname6=${ifname6:-$ifname}"
|
|
+ [ -n "$external_ip" ] && echo "ext_ip=$external_ip"
|
|
+
|
|
echo "# Enable internal networks / access control"
|
|
config_foreach upnpd_add_int_network_and_defaults internal_network pre-acl
|
|
config_foreach conf_rule_add perm_rule
|
|
@@ -191,7 +192,6 @@ upnpd() {
|
|
fi
|
|
|
|
if [ -n "$ifname" ]; then
|
|
- # start firewall
|
|
if [ "$FW" = "fw4" ]; then
|
|
nft -s -t -n list chain inet fw4 upnp_forward >/dev/null 2>&1 || fw4 reload
|
|
else
|
|
@@ -234,6 +234,11 @@ log() {
|
|
logger -s -p "${2:-daemon.notice}" -t "miniupnpd-init" "$1" || echo "miniupnpd-init: $1" >&2
|
|
}
|
|
|
|
+xml_encode() {
|
|
+ # Encode required XML entities of text UPnP IGD config options until the daemon does so
|
|
+ echo "$1" | sed "s/&/\&/g; s/</\</g; s/>/\>/g"
|
|
+}
|
|
+
|
|
upnpd_add_int_network_and_defaults() {
|
|
local cfg="$1"
|
|
local interface access_defaults accept_ports reject_ports check_acl
|
|
|
|
From dde9664570cac7236cb243b663ca0ce2c61f5c35 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 06/10] miniupnpd: rename UCI section to settings v2.0
|
|
|
|
Rename UCI section `config` (v1.0) -> `settings` (v2.0), helps on
|
|
migration and to distinguish the updated config from the previous one
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/firewall3.include | 4 +-
|
|
miniupnpd/files/miniupnpd.hotplug | 6 +--
|
|
miniupnpd/files/miniupnpd.init | 50 +++++++++----------
|
|
.../files/upnpd-migration.uci-defaults | 13 +++++
|
|
miniupnpd/files/upnpd.config | 2 +-
|
|
5 files changed, 44 insertions(+), 31 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/firewall3.include b/miniupnpd/files/firewall3.include
|
|
index 4fd483974306c1..53ca8dc716cc2f 100644
|
|
--- a/miniupnpd/files/firewall3.include
|
|
+++ b/miniupnpd/files/firewall3.include
|
|
@@ -48,11 +48,11 @@ add_extzone_rules() {
|
|
|
|
# By default, user configuration is king.
|
|
|
|
-for ext_iface in $(uci -q get upnpd.config.external_iface); do
|
|
+for ext_iface in $(uci -q get upnpd.settings.external_iface); do
|
|
add_extzone_rules $(fw3 -q network "$ext_iface")
|
|
done
|
|
|
|
-add_extzone_rules $(uci -q get upnpd.config.external_zone)
|
|
+add_extzone_rules $(uci -q get upnpd.settings.external_zone)
|
|
|
|
[ "$ADDED" -ne 0 ] && exit 0
|
|
|
|
diff --git a/miniupnpd/files/miniupnpd.hotplug b/miniupnpd/files/miniupnpd.hotplug
|
|
index 5d34c441a829ea..20ee344c9a0e72 100644
|
|
--- a/miniupnpd/files/miniupnpd.hotplug
|
|
+++ b/miniupnpd/files/miniupnpd.hotplug
|
|
@@ -10,9 +10,9 @@
|
|
[ "$ACTION" != "ifup" ] && /etc/init.d/miniupnpd running && exit 0
|
|
|
|
tmpconf="/var/etc/miniupnpd.conf"
|
|
-external_iface=$(uci -q get upnpd.config.external_iface)
|
|
-external_iface6=$(uci -q get upnpd.config.external_iface6)
|
|
-external_zone=$(uci -q get upnpd.config.external_zone)
|
|
+external_iface=$(uci -q get upnpd.settings.external_iface)
|
|
+external_iface6=$(uci -q get upnpd.settings.external_iface6)
|
|
+external_zone=$(uci -q get upnpd.settings.external_zone)
|
|
[ -x "$(command -v nft)" ] && FW="fw4" || FW="fw3"
|
|
|
|
. /lib/functions/network.sh
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index 969b22e60cacc4..80aa789c039803 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -44,42 +44,42 @@ conf_rule_add() {
|
|
upnpd() {
|
|
config_load "upnpd"
|
|
local enabled
|
|
- config_get enabled config enabled 0
|
|
+ config_get enabled settings enabled 0
|
|
if [ "$enabled" != "1" ]; then
|
|
log "Service disabled, enabled UCI option not set"
|
|
return 1
|
|
fi
|
|
# Daemon
|
|
local enable_protocols allow_cgnat stun_host allow_third_party_mapping ipv6_disable system_uptime log_output lease_file config_file
|
|
- config_get enable_protocols config enable_protocols all
|
|
- config_get allow_cgnat config allow_cgnat 0
|
|
- config_get stun_host config stun_host stun.nextcloud.com
|
|
- config_get allow_third_party_mapping config allow_third_party_mapping 0
|
|
- config_get ipv6_disable config ipv6_disable 0
|
|
- config_get system_uptime config system_uptime 1
|
|
- config_get log_output config log_output
|
|
- config_get lease_file config lease_file /var/run/miniupnpd.leases
|
|
- config_get config_file config config_file
|
|
+ config_get enable_protocols settings enable_protocols all
|
|
+ config_get allow_cgnat settings allow_cgnat 0
|
|
+ config_get stun_host settings stun_host stun.nextcloud.com
|
|
+ config_get allow_third_party_mapping settings allow_third_party_mapping 0
|
|
+ config_get ipv6_disable settings ipv6_disable 0
|
|
+ config_get system_uptime settings system_uptime 1
|
|
+ config_get log_output settings log_output
|
|
+ config_get lease_file settings lease_file /var/run/miniupnpd.leases
|
|
+ config_get config_file settings config_file
|
|
|
|
# UPnP IGD
|
|
local upnp_igd_compat download_kbps upload_kbps friendly_name model_number serial_number presentation_url uuid http_port notify_interval
|
|
- config_get upnp_igd_compat config upnp_igd_compat igdv1
|
|
- config_get download_kbps config download_kbps
|
|
- config_get upload_kbps config upload_kbps
|
|
- config_get friendly_name config friendly_name "OpenWrt UPnP IGD & PCP"
|
|
- config_get model_number config model_number
|
|
- config_get serial_number config serial_number
|
|
- config_get presentation_url config presentation_url
|
|
- config_get uuid config uuid
|
|
- config_get http_port config http_port 5000
|
|
- config_get notify_interval config notify_interval
|
|
+ config_get upnp_igd_compat settings upnp_igd_compat igdv1
|
|
+ config_get download_kbps settings download_kbps
|
|
+ config_get upload_kbps settings upload_kbps
|
|
+ config_get friendly_name settings friendly_name "OpenWrt UPnP IGD & PCP"
|
|
+ config_get model_number settings model_number
|
|
+ config_get serial_number settings serial_number
|
|
+ config_get presentation_url settings presentation_url
|
|
+ config_get uuid settings uuid
|
|
+ config_get http_port settings http_port 5000
|
|
+ config_get notify_interval settings notify_interval
|
|
|
|
# External network interface
|
|
local external_iface external_iface6 external_zone external_ip
|
|
- config_get external_iface config external_iface
|
|
- config_get external_iface6 config external_iface6
|
|
- config_get external_zone config external_zone
|
|
- config_get external_ip config external_ip
|
|
+ config_get external_iface settings external_iface
|
|
+ config_get external_iface6 settings external_iface6
|
|
+ config_get external_zone settings external_zone
|
|
+ config_get external_ip settings external_ip
|
|
|
|
local conf ifname ifname6
|
|
. /lib/functions/network.sh
|
|
@@ -161,7 +161,7 @@ upnpd() {
|
|
[ -z "$uuid" ] && {
|
|
log "Generate UPnP IGD UUID"
|
|
uuid="$(cat /proc/sys/kernel/random/uuid)"
|
|
- uci set upnpd.config.uuid="$uuid"
|
|
+ uci set upnpd.settings.uuid="$uuid"
|
|
uci commit upnpd
|
|
}
|
|
[ "$uuid" != "nocli" ] && echo "uuid=$uuid" || log "uuid=nocli deprecated, set to 00000000-0000-0000-0000-000000000000 instead"
|
|
diff --git a/miniupnpd/files/upnpd-migration.uci-defaults b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
index 19445c9198994b..efde6ca1232212 100644
|
|
--- a/miniupnpd/files/upnpd-migration.uci-defaults
|
|
+++ b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
@@ -4,7 +4,12 @@ log() {
|
|
logger -s -p "${2:-daemon.notice}" -t "upnpd" "$1" || echo "upnpd: $1" >&2
|
|
}
|
|
|
|
+# Skip migration with existing settings (v2.0) or with no config (v1.0) UCI section
|
|
+# Enables the creation of a merged v1.0/v2.0 config file
|
|
+{ uci -q get upnpd.settings >/dev/null || ! uci -q get upnpd.config >/dev/null; } && exit 0
|
|
+
|
|
log "Check UCI options in /etc/config/upnpd to be migrated to v2.0"
|
|
+cp /etc/config/upnpd /tmp
|
|
|
|
# Set missing enabled option to fix previously different defaults in LuCI/config (0) and init UCI (1)
|
|
if ! uci -q get upnpd.config.enabled >/dev/null; then
|
|
@@ -154,6 +159,14 @@ if ! uci -q get upnpd.@internal_network[0] >/dev/null; then
|
|
uci -q delete upnpd.config.internal_iface
|
|
fi
|
|
|
|
+# Rename UCI section config -> settings (v2.0)
|
|
+if uci -q get upnpd.config >/dev/null; then
|
|
+ log "Rename UCI section config -> settings (v2.0)" && uci rename upnpd.config="settings" ||
|
|
+ log "Error renaming the UCI section" daemon.err
|
|
+fi
|
|
+
|
|
uci commit upnpd >/dev/null
|
|
|
|
+log "Previous v1.0 config file copied to /tmp/upnpd (kept until reboot)"
|
|
+
|
|
exit 0
|
|
diff --git a/miniupnpd/files/upnpd.config b/miniupnpd/files/upnpd.config
|
|
index 6344a60071bd72..2245b0a6f015f8 100644
|
|
--- a/miniupnpd/files/upnpd.config
|
|
+++ b/miniupnpd/files/upnpd.config
|
|
@@ -1,6 +1,6 @@
|
|
# UPnP IGD & PCP/NAT-PMP Service Settings (v2.0)
|
|
|
|
-config upnpd 'config'
|
|
+config upnpd 'settings'
|
|
option enabled '0'
|
|
# Can be set to all/upnp-igd/pcp+nat-pmp
|
|
option enable_protocols 'all'
|
|
|
|
From 19bbb0dd7e9c878e39fe830e173dc54c150dd2a1 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 07/10] miniupnpd: update ACL options, migrate section
|
|
|
|
- The ACL is now rejected last if not accepted by access defaults. Add
|
|
(disabled) ACL template entries on migration
|
|
- Migrate ACL entries to the new section name `acl_entry`
|
|
- The following ACL UCI options been added or changed, and the previous
|
|
options are migrated on updating:
|
|
|
|
acl_entry UCI options | Change | Previous name
|
|
----------------------------|----------------------------|--------------
|
|
action | New/updated values (1) |
|
|
int_port | Remove colon separator (2) | int_ports
|
|
ext_port | Remove colon separator (2) | ext_ports
|
|
descr_filter | New option (3) |
|
|
|
|
1. Allow disabled, and update action option to use the nftables terms
|
|
(allow/deny -> accept/reject). To avoid adding inverted actions when
|
|
changing via LuCI, ensure any missing are set, as LuCI and UCI had
|
|
not matching action defaults. Missing actions are now ignored/logged
|
|
2. Ensure that the hyphen (-) is only used as a port range separator by
|
|
migration, as the colon (:) is not valid in LuCI
|
|
3. Add missing UCI option to set a regular expression to check for a
|
|
UPnP IGD IPv4 port map description, and fix the current collision
|
|
with the comment field which was not noticed due to a daemon bug
|
|
https://redirect.github.com/openwrt/packages/pull/24495
|
|
https://redirect.github.com/miniupnp/miniupnp/pull/853
|
|
|
|
- Refactoring by adding a more universal usable `is_port_or_range`
|
|
function instead of `upnpd_get_port_range` and check if it has a valid
|
|
range, and removes a shellcheck warning
|
|
- Rename `conf_rule_add` function to `upnpd_add_acl_entry`
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/miniupnpd.init | 86 ++++++++-----------
|
|
.../files/upnpd-migration.uci-defaults | 86 +++++++++++++++++++
|
|
miniupnpd/files/upnpd.config | 22 ++---
|
|
3 files changed, 131 insertions(+), 63 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index 80aa789c039803..b4e09eb84067db 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -7,38 +7,39 @@ USE_PROCD=1
|
|
PROG=/usr/sbin/miniupnpd
|
|
[ -x "$(command -v nft)" ] && FW="fw4" || FW="fw3"
|
|
|
|
-upnpd_get_port_range() {
|
|
- local var="$1"; shift
|
|
- local val
|
|
-
|
|
- config_get val "$@"
|
|
-
|
|
- case "$val" in
|
|
- [0-9]*[:-][0-9]*)
|
|
- export -n -- "${var}_start=${val%%[:-]*}"
|
|
- export -n -- "${var}_end=${val##*[:-]}"
|
|
- ;;
|
|
- [0-9]*)
|
|
- export -n -- "${var}_start=$val"
|
|
- export -n -- "${var}_end="
|
|
- ;;
|
|
- esac
|
|
+is_port_or_range() {
|
|
+ [ "$1" = "0" ] && [ "$2" != "allowport0" ] && return 1
|
|
+ [ "$1" -ge "1" ] 2>/dev/null && [ "$1" -le "65535" ] 2>/dev/null && return 0
|
|
+ [ "$2" = "allowport0" ] && local minport=0 || local minport=1
|
|
+ [ "${1%%-*}" -ge "$minport" ] 2>/dev/null && [ "${1%%-*}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${1##*-}" -ge "$minport" ] 2>/dev/null && [ "${1##*-}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${1##*-}" -ge "${1%%-*}" ] 2>/dev/null && return 0 || return 1
|
|
}
|
|
|
|
-conf_rule_add() {
|
|
+upnpd_add_acl_entry() {
|
|
local cfg="$1"
|
|
- local action int_addr
|
|
- local ext_start ext_end int_start int_end comment
|
|
- config_get action "$cfg" action "deny" # allow or deny
|
|
- upnpd_get_port_range "ext" "$cfg" ext_ports "0-65535" # external ports: x, x-y, x:y
|
|
- config_get int_addr "$cfg" int_addr "0.0.0.0/0" # ip or network and subnet mask (internal)
|
|
- upnpd_get_port_range "int" "$cfg" int_ports "0-65535" # internal ports: x, x-y, x:y or range
|
|
- config_get comment "$cfg" comment "ACL" # comment
|
|
-
|
|
- # Make a single IP IP/32 so that miniupnpd.conf can use it.
|
|
- [ "${int_addr%/*}" = "$int_addr" ] && int_addr="$int_addr/32"
|
|
-
|
|
- echo "$action $ext_start${ext_end:+-}$ext_end $int_addr $int_start${int_end:+-}$int_end #$comment"
|
|
+ local comment int_addr int_port ext_port descr_filter action
|
|
+ config_get comment "$cfg" comment "unspecified" # comment
|
|
+ config_get int_addr "$cfg" int_addr "0.0.0.0/0" # IPv4 or network and subnet mask (internal)
|
|
+ config_get int_port "$cfg" int_port "1-65535" # internal port/range: x or x-y
|
|
+ config_get ext_port "$cfg" ext_port "1-65535" # external port/range: x or x-y
|
|
+ config_get descr_filter "$cfg" descr_filter # description regex filter (must be built in)
|
|
+ config_get action "$cfg" action # accept/reject/disabled
|
|
+ ! is_port_or_range "$int_port" allowport0 &&
|
|
+ log "ACL entry: Invalid port or port range ($int_port) in int_port ignored" daemon.warn && int_port=1-65535
|
|
+ ! is_port_or_range "$ext_port" allowport0 &&
|
|
+ log "ACL entry: Invalid port or port range ($ext_port) in ext_port ignored" daemon.warn && ext_port=1-65535
|
|
+ [ "$descr_filter" != "" ] && descr_filter=" \"$descr_filter\""
|
|
+ if [ "$action" = "accept" ]; then
|
|
+ action=allow
|
|
+ elif [ "$action" = "reject" ]; then
|
|
+ action=deny
|
|
+ elif [ "$action" != "disabled" ]; then
|
|
+ log "ACL entry: Entry with invalid action ($action) ignored" daemon.warn
|
|
+ action=disabled
|
|
+ fi
|
|
+ [ "$action" = "disabled" ] && return 0
|
|
+ echo "$action $ext_port $int_addr $int_port${descr_filter} # $comment"
|
|
}
|
|
|
|
upnpd() {
|
|
@@ -185,8 +186,9 @@ upnpd() {
|
|
|
|
echo "# Enable internal networks / access control"
|
|
config_foreach upnpd_add_int_network_and_defaults internal_network pre-acl
|
|
- config_foreach conf_rule_add perm_rule
|
|
+ config_foreach upnpd_add_acl_entry acl_entry
|
|
config_foreach upnpd_add_int_network_and_defaults internal_network post-acl
|
|
+ echo "deny 1-65535 0.0.0.0/0 1-65535 # Reject ACL by default"
|
|
|
|
} > "$tmpconf"
|
|
fi
|
|
@@ -255,18 +257,8 @@ upnpd_add_int_network_and_defaults() {
|
|
echo "# Enable internal network $interface ($device) with access defaults $access_defaults and check ACL $check_acl"
|
|
echo "listening_ip=$device"
|
|
for rejectport in $reject_ports; do
|
|
- if [ "$rejectport" -ge "1" ] 2>/dev/null && [ "$rejectport" -le "65535" ] 2>/dev/null ||
|
|
- {
|
|
- [ "${rejectport%%-*}" -ge "1" ] 2>/dev/null &&
|
|
- [ "${rejectport%%-*}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${rejectport##*-}" -ge "1" ] 2>/dev/null &&
|
|
- [ "${rejectport##*-}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${rejectport##*-}" -ge "${rejectport%%-*}" ] 2>/dev/null
|
|
- }; then
|
|
- echo "deny $rejectport $subnet $rejectport # Reject port $rejectport on $interface"
|
|
- else
|
|
+ is_port_or_range "$rejectport" allowport0 && echo "deny $rejectport $subnet $rejectport # Reject port $rejectport on $interface" ||
|
|
log "Invalid port or port range ($rejectport) in reject_ports ignored" daemon.warn
|
|
- fi
|
|
done
|
|
fi
|
|
if { [ "$2" = "post-acl" ] && [ "$check_acl" = "1" ]; } ||
|
|
@@ -283,18 +275,8 @@ upnpd_add_int_network_and_defaults() {
|
|
log "Invalid access_defaults ($access_defaults) ignored" daemon.warn
|
|
fi
|
|
for acceptport in $accessdefaultsports $accept_ports; do
|
|
- if [ "$acceptport" -ge "1" ] 2>/dev/null && [ "$acceptport" -le "65535" ] 2>/dev/null ||
|
|
- {
|
|
- [ "${acceptport%%-*}" -ge "1" ] 2>/dev/null &&
|
|
- [ "${acceptport%%-*}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${acceptport##*-}" -ge "1" ] 2>/dev/null &&
|
|
- [ "${acceptport##*-}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${acceptport##*-}" -ge "${acceptport%%-*}" ] 2>/dev/null
|
|
- }; then
|
|
- echo "allow $acceptport $subnet $acceptport # Accept port $acceptport on $interface"
|
|
- else
|
|
+ is_port_or_range "$acceptport" && echo "allow $acceptport $subnet $acceptport # Accept port $acceptport on $interface" ||
|
|
log "Invalid port or port range ($acceptport) in accept_ports ignored" daemon.warn
|
|
- fi
|
|
done
|
|
fi
|
|
if [ "$2" = "pre-acl" ] && [ "$check_acl" = "0" ]; then
|
|
diff --git a/miniupnpd/files/upnpd-migration.uci-defaults b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
index efde6ca1232212..ac0c8d3245c175 100644
|
|
--- a/miniupnpd/files/upnpd-migration.uci-defaults
|
|
+++ b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
@@ -147,6 +147,90 @@ if [ "$(uci -q get upnpd.config.notify_interval)" -le "900" ] 2>/dev/null; then
|
|
uci delete upnpd.config.notify_interval
|
|
fi
|
|
|
|
+# Migrate ACL to new section, note that an empty ACL is now rejected alone
|
|
+# a) Empty/unmodified ACL: Set access defaults, add/update template entries
|
|
+# b) Modified ACL:
|
|
+# - Add missing entry action to avoid adding inverted actions when changing via LuCI
|
|
+# - Update entry action allow/deny -> accept/reject
|
|
+# - Update entry port options to only use the LuCI (and daemon) supported hyphen (-) as port range separator
|
|
+# - Not using access defaults, add template entries
|
|
+if uci -q get upnpd.@acl_entry[0] >/dev/null; then
|
|
+ log "Error migrating ACL, as the new UCI section already exists" daemon.err
|
|
+elif ! uci -q get upnpd.@perm_rule[0] >/dev/null; then
|
|
+ log "Empty ACL: Set access defaults, add templates, empty ACL rejected alone"
|
|
+ access_defaults=accept-all-ports
|
|
+ check_acl=0
|
|
+ addtemplateentries=1
|
|
+elif ! uci -q get upnpd.@perm_rule[2] >/dev/null &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[0].int_addr)" = "0.0.0.0/0" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[0].int_ports)" = "1024-65535" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[0].ext_ports)" = "1024-65535" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[0].action)" = "allow" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[1].int_addr)" = "0.0.0.0/0" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[1].int_ports)" = "0-65535" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[1].ext_ports)" = "0-65535" ] &&
|
|
+ [ "$(uci -q get upnpd.@perm_rule[1].action)" = "deny" ]; then
|
|
+ log "Unmodified ACL: Set access defaults, empty ACL rejected alone"
|
|
+ access_defaults=accept-high-ports
|
|
+ check_acl=0
|
|
+ addtemplateentries=1
|
|
+ uci delete upnpd.@perm_rule[-1]
|
|
+ uci delete upnpd.@perm_rule[-1]
|
|
+else
|
|
+ log "Modified ACL: Migrate entries/section, empty ACL rejected alone"
|
|
+ addtemplateentries=1
|
|
+ entrynr=0
|
|
+ while uci -q get upnpd.@perm_rule[$entrynr] >/dev/null; do
|
|
+ comment="$(uci -q get upnpd.@perm_rule[$entrynr].comment)"
|
|
+ int_addr="$(uci -q get upnpd.@perm_rule[$entrynr].int_addr)"
|
|
+ int_port="$(uci -q get upnpd.@perm_rule[$entrynr].int_ports)"
|
|
+ ext_port="$(uci -q get upnpd.@perm_rule[$entrynr].ext_ports)"
|
|
+ action="$(uci -q get upnpd.@perm_rule[$entrynr].action)"
|
|
+ echo "$int_port" | grep -q ":" &&
|
|
+ log "ACL entry: Update int_port to use hyphen (-) as port range separator" &&
|
|
+ int_port="$(echo "$int_port" | tr ":" "-")"
|
|
+ echo "$ext_port" | grep -q ":" &&
|
|
+ log "ACL entry: Update ext_port to use hyphen (-) as port range separator" &&
|
|
+ ext_port="$(echo "$ext_port" | tr ":" "-")"
|
|
+ [ "$action" = "" ] && log "ACL entry: Add missing action option" && action=reject
|
|
+ [ "$action" = "allow" ] && action=accept
|
|
+ [ "$action" = "deny" ] && action=reject
|
|
+ uci batch >/dev/null <<-EOF
|
|
+ add upnpd acl_entry
|
|
+ set upnpd.@acl_entry[-1].comment="${comment:-unspecified}"
|
|
+ set upnpd.@acl_entry[-1].int_addr="${int_addr:-0.0.0.0/0}"
|
|
+ set upnpd.@acl_entry[-1].int_port="$int_port"
|
|
+ set upnpd.@acl_entry[-1].ext_port="$ext_port"
|
|
+ set upnpd.@acl_entry[-1].action="$action"
|
|
+ EOF
|
|
+ entrynr=$((entrynr + 1))
|
|
+ done
|
|
+ if [ "${int_addr:-0.0.0.0/0}" = "0.0.0.0/0" ] && [ "${int_port:-0-65535}" = "0-65535" ] &&
|
|
+ [ "${ext_port:-0-65535}" = "0-65535" ] && [ "$action" = "reject" ]; then
|
|
+ log "ACL entry: Remove no longer useful reject by default entry"
|
|
+ uci delete upnpd.@acl_entry[-1]
|
|
+ fi
|
|
+ while uci -q delete upnpd.@perm_rule[-1]; do :; done
|
|
+fi
|
|
+if [ "$addtemplateentries" = "1" ]; then
|
|
+ uci batch >/dev/null <<-EOF
|
|
+ add upnpd acl_entry
|
|
+ add upnpd acl_entry
|
|
+ set upnpd.@acl_entry[-2].comment="High ports"
|
|
+ set upnpd.@acl_entry[-2].int_addr="0.0.0.0/0"
|
|
+ set upnpd.@acl_entry[-2].int_port="1024-65535"
|
|
+ set upnpd.@acl_entry[-2].ext_port="1024-65535"
|
|
+ set upnpd.@acl_entry[-2].action="disabled"
|
|
+ set upnpd.@acl_entry[-1].comment="Low/system ports"
|
|
+ set upnpd.@acl_entry[-1].int_addr="0.0.0.0/0"
|
|
+ set upnpd.@acl_entry[-1].int_port="1-1023"
|
|
+ set upnpd.@acl_entry[-1].ext_port="1-1023"
|
|
+ set upnpd.@acl_entry[-1].action="disabled"
|
|
+ EOF
|
|
+ uci -q get upnpd.@acl_entry[-3] >/dev/null &&
|
|
+ uci reorder upnpd.@acl_entry[-2]=0 && uci reorder upnpd.@acl_entry[-1]=1
|
|
+fi
|
|
+
|
|
# Migrate internal_iface option to new internal_network section
|
|
if ! uci -q get upnpd.@internal_network[0] >/dev/null; then
|
|
ifnr=0
|
|
@@ -154,6 +238,8 @@ if ! uci -q get upnpd.@internal_network[0] >/dev/null; then
|
|
log "Create new internal_network section for $interface"
|
|
uci add upnpd internal_network >/dev/null
|
|
uci set upnpd.@internal_network[$ifnr].interface="$interface"
|
|
+ [ "$access_defaults" != "" ] && uci set upnpd.@internal_network[$ifnr].access_defaults="$access_defaults"
|
|
+ [ "$check_acl" = "0" ] && uci set upnpd.@internal_network[$ifnr].check_acl="0"
|
|
ifnr=$((ifnr + 1))
|
|
done
|
|
uci -q delete upnpd.config.internal_iface
|
|
diff --git a/miniupnpd/files/upnpd.config b/miniupnpd/files/upnpd.config
|
|
index 2245b0a6f015f8..74fc64b58e9bf6 100644
|
|
--- a/miniupnpd/files/upnpd.config
|
|
+++ b/miniupnpd/files/upnpd.config
|
|
@@ -18,18 +18,18 @@ config internal_network
|
|
option check_acl '0' # default 1
|
|
|
|
# Access Control List
|
|
-# Empty ACL rejected alone, IPv6 accepted unless disabled
|
|
+# Empty ACL rejected alone, IPv6 accepted unless disabled, action: accept/reject
|
|
|
|
-config perm_rule
|
|
- option comment 'Allow high ports'
|
|
+config acl_entry
|
|
+ option comment 'High ports'
|
|
option int_addr '0.0.0.0/0'
|
|
- option int_ports '1024-65535'
|
|
- option ext_ports '1024-65535'
|
|
- option action 'allow'
|
|
+ option int_port '1024-65535'
|
|
+ option ext_port '1024-65535'
|
|
+ option action 'disabled'
|
|
|
|
-config perm_rule
|
|
- option comment 'Default deny'
|
|
+config acl_entry
|
|
+ option comment 'Low/system ports'
|
|
option int_addr '0.0.0.0/0'
|
|
- option int_ports '1-65535'
|
|
- option ext_ports '1-65535'
|
|
- option action 'deny'
|
|
+ option int_port '1-1023'
|
|
+ option ext_port '1-1023'
|
|
+ option action 'disabled'
|
|
|
|
From b58735acf4c5419987bde2d8947e67d14bcd7b9e Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 08/10] miniupnpd: separate service start and config-gen
|
|
|
|
- Remove `config_foreach upnpd "upnpd"` and replace it with regular
|
|
function call, as init was not designed for a multi-instance setup, as
|
|
the same `tmpconf` will be used/overwritten, and non-anonymous section
|
|
- Move code to make the custom vs. config file generation decision
|
|
earlier, and only perform external interface detection with the second
|
|
one, and rename function `upnpd` to `upnpd_generate_config`
|
|
- Replace unnecessary `if` cases with `elif` in init/hotplug
|
|
- Exit with 1 on errors to get an inactive service status
|
|
- Use `procd_add_reload_trigger "firewall"` instead of listening
|
|
`/etc/config/firewall`
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/miniupnpd.hotplug | 33 +++---
|
|
miniupnpd/files/miniupnpd.init | 146 +++++++++++++-------------
|
|
2 files changed, 86 insertions(+), 93 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/miniupnpd.hotplug b/miniupnpd/files/miniupnpd.hotplug
|
|
index 20ee344c9a0e72..e86097e86010a7 100644
|
|
--- a/miniupnpd/files/miniupnpd.hotplug
|
|
+++ b/miniupnpd/files/miniupnpd.hotplug
|
|
@@ -1,11 +1,9 @@
|
|
+#!/bin/sh
|
|
/etc/init.d/miniupnpd enabled || exit 0
|
|
|
|
-# If miniupnpd is not running:
|
|
-# - check on _any_ event (event updates may contribute to network_find_wan*)
|
|
-
|
|
-# If miniupnpd _is_ running:
|
|
-# - check only on ifup (otherwise lease updates etc would cause
|
|
-# miniupnpd state loss)
|
|
+# If daemon is:
|
|
+# - not running: check on any event (event updates may contribute to network_find_wan*)
|
|
+# - running: check only on ifup (otherwise lease updates etc. would cause daemon state loss)
|
|
|
|
[ "$ACTION" != "ifup" ] && /etc/init.d/miniupnpd running && exit 0
|
|
|
|
@@ -16,26 +14,19 @@ external_zone=$(uci -q get upnpd.settings.external_zone)
|
|
[ -x "$(command -v nft)" ] && FW="fw4" || FW="fw3"
|
|
|
|
. /lib/functions/network.sh
|
|
-
|
|
-if [ -n "$external_iface" ] ; then
|
|
+if [ -n "$external_iface" ]; then
|
|
network_get_device ifname "$external_iface"
|
|
+elif [ -n "$external_zone" ]; then
|
|
+ ifname=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
else
|
|
- if [ -n "$external_zone" ] ; then
|
|
- ifname=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
- else
|
|
- network_find_wan external_iface && \
|
|
- network_get_device ifname "$external_iface"
|
|
- fi
|
|
+ network_find_wan external_iface && network_get_device ifname "$external_iface"
|
|
fi
|
|
-if [ -n "$external_iface6" ] ; then
|
|
+if [ -n "$external_iface6" ]; then
|
|
network_get_device ifname6 "$external_iface6"
|
|
+elif [ -n "$external_zone" ]; then
|
|
+ ifname6=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
else
|
|
- if [ -n "$external_zone" ] ; then
|
|
- ifname6=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
- else
|
|
- network_find_wan6 external_iface6 && \
|
|
- network_get_device ifname6 "$external_iface6"
|
|
- fi
|
|
+ network_find_wan6 external_iface6 && network_get_device ifname6 "$external_iface6"
|
|
fi
|
|
|
|
[ "$DEVICE" != "$ifname" ] && [ "$DEVICE" != "$ifname6" ] && exit 0
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index b4e09eb84067db..a66587153d2706 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -42,25 +42,16 @@ upnpd_add_acl_entry() {
|
|
echo "$action $ext_port $int_addr $int_port${descr_filter} # $comment"
|
|
}
|
|
|
|
-upnpd() {
|
|
- config_load "upnpd"
|
|
- local enabled
|
|
- config_get enabled settings enabled 0
|
|
- if [ "$enabled" != "1" ]; then
|
|
- log "Service disabled, enabled UCI option not set"
|
|
- return 1
|
|
- fi
|
|
+upnpd_generate_config() {
|
|
# Daemon
|
|
- local enable_protocols allow_cgnat stun_host allow_third_party_mapping ipv6_disable system_uptime log_output lease_file config_file
|
|
+ local enable_protocols allow_cgnat stun_host allow_third_party_mapping ipv6_disable system_uptime lease_file
|
|
config_get enable_protocols settings enable_protocols all
|
|
config_get allow_cgnat settings allow_cgnat 0
|
|
config_get stun_host settings stun_host stun.nextcloud.com
|
|
config_get allow_third_party_mapping settings allow_third_party_mapping 0
|
|
config_get ipv6_disable settings ipv6_disable 0
|
|
config_get system_uptime settings system_uptime 1
|
|
- config_get log_output settings log_output
|
|
config_get lease_file settings lease_file /var/run/miniupnpd.leases
|
|
- config_get config_file settings config_file
|
|
|
|
# UPnP IGD
|
|
local upnp_igd_compat download_kbps upload_kbps friendly_name model_number serial_number presentation_url uuid http_port notify_interval
|
|
@@ -82,53 +73,51 @@ upnpd() {
|
|
config_get external_zone settings external_zone
|
|
config_get external_ip settings external_ip
|
|
|
|
- local conf ifname ifname6
|
|
+ local ifname ifname6
|
|
. /lib/functions/network.sh
|
|
-
|
|
- if [ -n "$external_iface" ] ; then
|
|
+ if [ -n "$external_iface" ]; then
|
|
network_get_device ifname "$external_iface"
|
|
+ elif [ -n "$external_zone" ]; then
|
|
+ ifname=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
else
|
|
- if [ -n "$external_zone" ] ; then
|
|
- ifname=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
- else
|
|
- network_find_wan external_iface && \
|
|
- network_get_device ifname "$external_iface"
|
|
- fi
|
|
+ network_find_wan external_iface && network_get_device ifname "$external_iface"
|
|
fi
|
|
- if [ -n "$external_iface6" ] ; then
|
|
+ if [ -n "$external_iface6" ]; then
|
|
network_get_device ifname6 "$external_iface6"
|
|
+ elif [ -n "$external_zone" ]; then
|
|
+ ifname6=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
else
|
|
- if [ -n "$external_zone" ] ; then
|
|
- ifname6=$($FW -q zone "$external_zone" 2>/dev/null | head -1)
|
|
- else
|
|
- network_find_wan6 external_iface6 && \
|
|
- network_get_device ifname6 "$external_iface6"
|
|
- fi
|
|
+ network_find_wan6 external_iface6 && network_get_device ifname6 "$external_iface6"
|
|
+ fi
|
|
+ if [ "$ifname" = "" ]; then
|
|
+ log "No external network interface found, not starting" daemon.err
|
|
+ return 1
|
|
+ fi
|
|
+ # Workaround for daemon bug with UPnP IGDv2 if IPv6 is not ready at start
|
|
+ if [ "$ipv6_disable" = "0" ] && [ "$(uci -q get firewall.@defaults[0].disable_ipv6)" != "1" ] &&
|
|
+ [ "$(uci -q get network.wan6.disabled)" != "1" ]; then
|
|
+ local pass=0
|
|
+ while ! ip -6 addr show dev "${ifname6:-$ifname}" | grep -q "inet6 [23]"; do
|
|
+ log "IPv6 not ready yet; delay start"
|
|
+ sleep 5
|
|
+ pass=$((pass + 1))
|
|
+ [ "$pass" = "4" ] && log "IPv6 GUA not yet available, UPnP IGD mapping not possible" && break
|
|
+ done
|
|
+ fi
|
|
+ if ! uci -q get upnpd.@internal_network[0].interface >/dev/null; then
|
|
+ log "No internal networks configured, not starting" daemon.err
|
|
+ return 1
|
|
fi
|
|
+ # Only perform an STUN CGNAT test if necessary, with a private/CGNAT-reserved external IPv4
|
|
+ local extipv4 extipv4private
|
|
+ extipv4="$(ip -4 addr show dev "$ifname" | grep inet | head -1 | sed -E "s/.*inet ([0-9.]+).*/\1/")"
|
|
+ case "$extipv4" in
|
|
+ 10.* | 100.6[4-9].* | 100.[7-9][0-9].* | 100.1[0-1][0-9].* | 100.12[0-7].* | 172.1[6-9].* | \
|
|
+ 172.2[0-9].* | 172.3[0-1].* | 192.0.0.[1-6] | 192.168.* | 198.1[89].*) extipv4private=1 ;;
|
|
+ esac
|
|
+ [ "$extipv4private" = "1" ] && log "Private/CGNAT-reserved external IPv4 detected ($extipv4)"
|
|
|
|
- if [ -n "$config_file" ]; then
|
|
- conf="$config_file"
|
|
- else
|
|
- local tmpconf="/var/etc/miniupnpd.conf"
|
|
- conf="$tmpconf"
|
|
- mkdir -p /var/etc
|
|
- if [ "$ifname" = "" ]; then
|
|
- log "No external network interface found, not starting" daemon.err
|
|
- return 1
|
|
- fi
|
|
- if ! uci -q get upnpd.@internal_network[0].interface >/dev/null; then
|
|
- log "No internal networks configured, not starting" daemon.err
|
|
- return 1
|
|
- fi
|
|
- # Only perform an STUN CGNAT test if necessary, with a private/CGNAT-reserved external IPv4
|
|
- local extipv4 extipv4private
|
|
- extipv4="$(ip -4 addr show dev "$ifname" | grep inet | head -1 | sed -E "s/.*inet ([0-9.]+).*/\1/")"
|
|
- case "$extipv4" in
|
|
- 10.* | 100.6[4-9].* | 100.[7-9][0-9].* | 100.1[0-1][0-9].* | 100.12[0-7].* | 172.1[6-9].* | \
|
|
- 172.2[0-9].* | 172.3[0-1].* | 192.0.0.[1-6] | 192.168.* | 198.1[89].*) extipv4private=1 ;;
|
|
- esac
|
|
- [ "$extipv4private" = "1" ] && log "Private/CGNAT-reserved external IPv4 detected ($extipv4)"
|
|
- {
|
|
+ {
|
|
echo "# Daemon"
|
|
[ "$enable_protocols" = "all" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=yes"
|
|
[ "$enable_protocols" = "upnp-igd" ] && echo "enable_upnp=yes" && echo "enable_pcp_pmp=no"
|
|
@@ -190,32 +179,15 @@ upnpd() {
|
|
config_foreach upnpd_add_int_network_and_defaults internal_network post-acl
|
|
echo "deny 1-65535 0.0.0.0/0 1-65535 # Reject ACL by default"
|
|
|
|
- } > "$tmpconf"
|
|
- fi
|
|
-
|
|
- if [ -n "$ifname" ]; then
|
|
- if [ "$FW" = "fw4" ]; then
|
|
- nft -s -t -n list chain inet fw4 upnp_forward >/dev/null 2>&1 || fw4 reload
|
|
- else
|
|
- iptables -L MINIUPNPD >/dev/null 2>&1 || fw3 reload
|
|
- fi
|
|
- fi
|
|
-
|
|
- procd_open_instance
|
|
- procd_set_param file "$conf" "/etc/config/firewall"
|
|
- procd_set_param command "$PROG"
|
|
- procd_append_param command -f "$conf"
|
|
- [ "$log_output" = "info" ] && procd_append_param command -v
|
|
- [ "$log_output" = "debug" ] && procd_append_param command -v -v
|
|
- procd_close_instance
|
|
+ } >"$1"
|
|
}
|
|
|
|
stop_service() {
|
|
if [ "$FW" = "fw3" ]; then
|
|
- iptables -t nat -F MINIUPNPD 2>/dev/null
|
|
- iptables -t nat -F MINIUPNPD-POSTROUTING 2>/dev/null
|
|
iptables -t filter -F MINIUPNPD 2>/dev/null
|
|
[ -x /usr/sbin/ip6tables ] && ip6tables -t filter -F MINIUPNPD 2>/dev/null
|
|
+ iptables -t nat -F MINIUPNPD 2>/dev/null
|
|
+ iptables -t nat -F MINIUPNPD-POSTROUTING 2>/dev/null
|
|
else
|
|
nft flush chain inet fw4 upnp_forward 2>/dev/null
|
|
nft flush chain inet fw4 upnp_prerouting 2>/dev/null
|
|
@@ -225,11 +197,41 @@ stop_service() {
|
|
|
|
start_service() {
|
|
config_load "upnpd"
|
|
- config_foreach upnpd "upnpd"
|
|
+ local enabled config_file log_output conf
|
|
+ config_get enabled settings enabled 0
|
|
+ config_get config_file settings config_file
|
|
+ config_get log_output settings log_output
|
|
+ if [ "$enabled" != "1" ]; then
|
|
+ log "Service disabled, enabled UCI option not set"
|
|
+ return 1
|
|
+ fi
|
|
+
|
|
+ if [ -n "$config_file" ]; then
|
|
+ conf="$config_file"
|
|
+ else
|
|
+ local tmpconf="/var/etc/miniupnpd.conf"
|
|
+ conf="$tmpconf"
|
|
+ mkdir -p /var/etc
|
|
+ upnpd_generate_config "$tmpconf" || return 1
|
|
+ fi
|
|
+
|
|
+ if [ "$FW" = "fw4" ]; then
|
|
+ nft -s -t -n list chain inet fw4 upnp_forward >/dev/null 2>&1 || fw4 reload
|
|
+ else
|
|
+ iptables -L MINIUPNPD >/dev/null 2>&1 || fw3 reload
|
|
+ fi
|
|
+
|
|
+ procd_open_instance
|
|
+ procd_set_param file "$conf"
|
|
+ procd_set_param command "$PROG"
|
|
+ procd_append_param command -f "$conf"
|
|
+ [ "$log_output" = "info" ] && procd_append_param command -v
|
|
+ [ "$log_output" = "debug" ] && procd_append_param command -v -v
|
|
+ procd_close_instance
|
|
}
|
|
|
|
service_triggers() {
|
|
- procd_add_reload_trigger "upnpd"
|
|
+ procd_add_reload_trigger "upnpd" "firewall"
|
|
}
|
|
|
|
log() {
|
|
|
|
From 562d07c55e1e8d46e6ec45f4397c9a02ba5429c5 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 09/10] miniupnpd: rearrange init, format `firewall3.include`
|
|
|
|
- Arrange `start_service` and main init functions first
|
|
- Format `firewall3.include` using shfmt
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/firewall3.include | 44 +++----
|
|
miniupnpd/files/miniupnpd.init | 164 +++++++++++++-------------
|
|
2 files changed, 104 insertions(+), 104 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/firewall3.include b/miniupnpd/files/firewall3.include
|
|
index 53ca8dc716cc2f..8fc2144db31932 100644
|
|
--- a/miniupnpd/files/firewall3.include
|
|
+++ b/miniupnpd/files/firewall3.include
|
|
@@ -20,36 +20,36 @@ iptables_prepend_rule() {
|
|
local chain="$3"
|
|
local target="$4"
|
|
|
|
- $iptables "$IPTARGS" -t "$table" -I "$chain" $($iptables "$IPTARGS" -t "$table" --line-numbers -nL "$chain" | \
|
|
+ $iptables "$IPTARGS" -t "$table" -I "$chain" $($iptables "$IPTARGS" -t "$table" --line-numbers -nL "$chain" |
|
|
sed -ne '$s/[^0-9].*//p') -j "$target"
|
|
}
|
|
|
|
ADDED=0
|
|
|
|
add_extzone_rules() {
|
|
- local ext_zone="$1"
|
|
-
|
|
- [ -z "$ext_zone" ] && return
|
|
-
|
|
- # IPv4 - due to NAT, need to add both to nat and filter table
|
|
- # need to insert as penultimate rule for input & forward & postrouting since final rule might be a fw3 REJECT
|
|
- iptables_prepend_rule "$IPTABLES" filter "zone_${ext_zone}_input" MINIUPNPD
|
|
- iptables_prepend_rule "$IPTABLES" filter "zone_${ext_zone}_forward" MINIUPNPD
|
|
- $IPTABLES -t nat -A "zone_${ext_zone}_prerouting" -j MINIUPNPD
|
|
- iptables_prepend_rule "$IPTABLES" nat "zone_${ext_zone}_postrouting" MINIUPNPD-POSTROUTING
|
|
-
|
|
- # IPv6 if available - filter only
|
|
- [ -x $IP6TABLES ] && {
|
|
- iptables_prepend_rule "$IP6TABLES" filter "zone_${ext_zone}_input" MINIUPNPD
|
|
- iptables_prepend_rule "$IP6TABLES" filter "zone_${ext_zone}_forward" MINIUPNPD
|
|
- }
|
|
- ADDED=$(($ADDED + 1))
|
|
+ local ext_zone="$1"
|
|
+
|
|
+ [ -z "$ext_zone" ] && return
|
|
+
|
|
+ # IPv4 - due to NAT, need to add both to nat and filter table
|
|
+ # need to insert as penultimate rule for input & forward & postrouting since final rule might be a fw3 REJECT
|
|
+ iptables_prepend_rule "$IPTABLES" filter "zone_${ext_zone}_input" MINIUPNPD
|
|
+ iptables_prepend_rule "$IPTABLES" filter "zone_${ext_zone}_forward" MINIUPNPD
|
|
+ $IPTABLES -t nat -A "zone_${ext_zone}_prerouting" -j MINIUPNPD
|
|
+ iptables_prepend_rule "$IPTABLES" nat "zone_${ext_zone}_postrouting" MINIUPNPD-POSTROUTING
|
|
+
|
|
+ # IPv6 if available - filter only
|
|
+ [ -x $IP6TABLES ] && {
|
|
+ iptables_prepend_rule "$IP6TABLES" filter "zone_${ext_zone}_input" MINIUPNPD
|
|
+ iptables_prepend_rule "$IP6TABLES" filter "zone_${ext_zone}_forward" MINIUPNPD
|
|
+ }
|
|
+ ADDED=$(($ADDED + 1))
|
|
}
|
|
|
|
# By default, user configuration is king.
|
|
|
|
for ext_iface in $(uci -q get upnpd.settings.external_iface); do
|
|
- add_extzone_rules $(fw3 -q network "$ext_iface")
|
|
+ add_extzone_rules $(fw3 -q network "$ext_iface")
|
|
done
|
|
|
|
add_extzone_rules $(uci -q get upnpd.settings.external_zone)
|
|
@@ -66,7 +66,7 @@ network_find_wan wan_iface
|
|
network_find_wan6 wan6_iface
|
|
|
|
for ext_iface in $wan_iface $wan6_iface; do
|
|
- # fw3 -q network fails on sub-interfaces => map to device first
|
|
- network_get_device ext_device $ext_iface
|
|
- add_extzone_rules $(fw3 -q device "$ext_device")
|
|
+ # fw3 -q network fails on sub-interfaces => map to device first
|
|
+ network_get_device ext_device $ext_iface
|
|
+ add_extzone_rules $(fw3 -q device "$ext_device")
|
|
done
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index a66587153d2706..a6611c0e732e0d 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -7,39 +7,56 @@ USE_PROCD=1
|
|
PROG=/usr/sbin/miniupnpd
|
|
[ -x "$(command -v nft)" ] && FW="fw4" || FW="fw3"
|
|
|
|
-is_port_or_range() {
|
|
- [ "$1" = "0" ] && [ "$2" != "allowport0" ] && return 1
|
|
- [ "$1" -ge "1" ] 2>/dev/null && [ "$1" -le "65535" ] 2>/dev/null && return 0
|
|
- [ "$2" = "allowport0" ] && local minport=0 || local minport=1
|
|
- [ "${1%%-*}" -ge "$minport" ] 2>/dev/null && [ "${1%%-*}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${1##*-}" -ge "$minport" ] 2>/dev/null && [ "${1##*-}" -le "65535" ] 2>/dev/null &&
|
|
- [ "${1##*-}" -ge "${1%%-*}" ] 2>/dev/null && return 0 || return 1
|
|
+start_service() {
|
|
+ config_load "upnpd"
|
|
+ local enabled config_file log_output conf
|
|
+ config_get enabled settings enabled 0
|
|
+ config_get config_file settings config_file
|
|
+ config_get log_output settings log_output
|
|
+ if [ "$enabled" != "1" ]; then
|
|
+ log "Service disabled, enabled UCI option not set"
|
|
+ return 1
|
|
+ fi
|
|
+
|
|
+ if [ -n "$config_file" ]; then
|
|
+ conf="$config_file"
|
|
+ else
|
|
+ local tmpconf="/var/etc/miniupnpd.conf"
|
|
+ conf="$tmpconf"
|
|
+ mkdir -p /var/etc
|
|
+ upnpd_generate_config "$tmpconf" || return 1
|
|
+ fi
|
|
+
|
|
+ if [ "$FW" = "fw4" ]; then
|
|
+ nft -s -t -n list chain inet fw4 upnp_forward >/dev/null 2>&1 || fw4 reload
|
|
+ else
|
|
+ iptables -L MINIUPNPD >/dev/null 2>&1 || fw3 reload
|
|
+ fi
|
|
+
|
|
+ procd_open_instance
|
|
+ procd_set_param file "$conf"
|
|
+ procd_set_param command "$PROG"
|
|
+ procd_append_param command -f "$conf"
|
|
+ [ "$log_output" = "info" ] && procd_append_param command -v
|
|
+ [ "$log_output" = "debug" ] && procd_append_param command -v -v
|
|
+ procd_close_instance
|
|
}
|
|
|
|
-upnpd_add_acl_entry() {
|
|
- local cfg="$1"
|
|
- local comment int_addr int_port ext_port descr_filter action
|
|
- config_get comment "$cfg" comment "unspecified" # comment
|
|
- config_get int_addr "$cfg" int_addr "0.0.0.0/0" # IPv4 or network and subnet mask (internal)
|
|
- config_get int_port "$cfg" int_port "1-65535" # internal port/range: x or x-y
|
|
- config_get ext_port "$cfg" ext_port "1-65535" # external port/range: x or x-y
|
|
- config_get descr_filter "$cfg" descr_filter # description regex filter (must be built in)
|
|
- config_get action "$cfg" action # accept/reject/disabled
|
|
- ! is_port_or_range "$int_port" allowport0 &&
|
|
- log "ACL entry: Invalid port or port range ($int_port) in int_port ignored" daemon.warn && int_port=1-65535
|
|
- ! is_port_or_range "$ext_port" allowport0 &&
|
|
- log "ACL entry: Invalid port or port range ($ext_port) in ext_port ignored" daemon.warn && ext_port=1-65535
|
|
- [ "$descr_filter" != "" ] && descr_filter=" \"$descr_filter\""
|
|
- if [ "$action" = "accept" ]; then
|
|
- action=allow
|
|
- elif [ "$action" = "reject" ]; then
|
|
- action=deny
|
|
- elif [ "$action" != "disabled" ]; then
|
|
- log "ACL entry: Entry with invalid action ($action) ignored" daemon.warn
|
|
- action=disabled
|
|
+stop_service() {
|
|
+ if [ "$FW" = "fw3" ]; then
|
|
+ iptables -t filter -F MINIUPNPD 2>/dev/null
|
|
+ [ -x /usr/sbin/ip6tables ] && ip6tables -t filter -F MINIUPNPD 2>/dev/null
|
|
+ iptables -t nat -F MINIUPNPD 2>/dev/null
|
|
+ iptables -t nat -F MINIUPNPD-POSTROUTING 2>/dev/null
|
|
+ else
|
|
+ nft flush chain inet fw4 upnp_forward 2>/dev/null
|
|
+ nft flush chain inet fw4 upnp_prerouting 2>/dev/null
|
|
+ #nft flush chain inet fw4 upnp_postrouting 2>/dev/null
|
|
fi
|
|
- [ "$action" = "disabled" ] && return 0
|
|
- echo "$action $ext_port $int_addr $int_port${descr_filter} # $comment"
|
|
+}
|
|
+
|
|
+service_triggers() {
|
|
+ procd_add_reload_trigger "upnpd" "firewall"
|
|
}
|
|
|
|
upnpd_generate_config() {
|
|
@@ -182,58 +199,6 @@ upnpd_generate_config() {
|
|
} >"$1"
|
|
}
|
|
|
|
-stop_service() {
|
|
- if [ "$FW" = "fw3" ]; then
|
|
- iptables -t filter -F MINIUPNPD 2>/dev/null
|
|
- [ -x /usr/sbin/ip6tables ] && ip6tables -t filter -F MINIUPNPD 2>/dev/null
|
|
- iptables -t nat -F MINIUPNPD 2>/dev/null
|
|
- iptables -t nat -F MINIUPNPD-POSTROUTING 2>/dev/null
|
|
- else
|
|
- nft flush chain inet fw4 upnp_forward 2>/dev/null
|
|
- nft flush chain inet fw4 upnp_prerouting 2>/dev/null
|
|
- #nft flush chain inet fw4 upnp_postrouting 2>/dev/null
|
|
- fi
|
|
-}
|
|
-
|
|
-start_service() {
|
|
- config_load "upnpd"
|
|
- local enabled config_file log_output conf
|
|
- config_get enabled settings enabled 0
|
|
- config_get config_file settings config_file
|
|
- config_get log_output settings log_output
|
|
- if [ "$enabled" != "1" ]; then
|
|
- log "Service disabled, enabled UCI option not set"
|
|
- return 1
|
|
- fi
|
|
-
|
|
- if [ -n "$config_file" ]; then
|
|
- conf="$config_file"
|
|
- else
|
|
- local tmpconf="/var/etc/miniupnpd.conf"
|
|
- conf="$tmpconf"
|
|
- mkdir -p /var/etc
|
|
- upnpd_generate_config "$tmpconf" || return 1
|
|
- fi
|
|
-
|
|
- if [ "$FW" = "fw4" ]; then
|
|
- nft -s -t -n list chain inet fw4 upnp_forward >/dev/null 2>&1 || fw4 reload
|
|
- else
|
|
- iptables -L MINIUPNPD >/dev/null 2>&1 || fw3 reload
|
|
- fi
|
|
-
|
|
- procd_open_instance
|
|
- procd_set_param file "$conf"
|
|
- procd_set_param command "$PROG"
|
|
- procd_append_param command -f "$conf"
|
|
- [ "$log_output" = "info" ] && procd_append_param command -v
|
|
- [ "$log_output" = "debug" ] && procd_append_param command -v -v
|
|
- procd_close_instance
|
|
-}
|
|
-
|
|
-service_triggers() {
|
|
- procd_add_reload_trigger "upnpd" "firewall"
|
|
-}
|
|
-
|
|
log() {
|
|
logger -s -p "${2:-daemon.notice}" -t "miniupnpd-init" "$1" || echo "miniupnpd-init: $1" >&2
|
|
}
|
|
@@ -243,6 +208,15 @@ xml_encode() {
|
|
echo "$1" | sed "s/&/\&/g; s/</\</g; s/>/\>/g"
|
|
}
|
|
|
|
+is_port_or_range() {
|
|
+ [ "$1" = "0" ] && [ "$2" != "allowport0" ] && return 1
|
|
+ [ "$1" -ge "1" ] 2>/dev/null && [ "$1" -le "65535" ] 2>/dev/null && return 0
|
|
+ [ "$2" = "allowport0" ] && local minport=0 || local minport=1
|
|
+ [ "${1%%-*}" -ge "$minport" ] 2>/dev/null && [ "${1%%-*}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${1##*-}" -ge "$minport" ] 2>/dev/null && [ "${1##*-}" -le "65535" ] 2>/dev/null &&
|
|
+ [ "${1##*-}" -ge "${1%%-*}" ] 2>/dev/null && return 0 || return 1
|
|
+}
|
|
+
|
|
upnpd_add_int_network_and_defaults() {
|
|
local cfg="$1"
|
|
local interface access_defaults accept_ports reject_ports check_acl
|
|
@@ -285,3 +259,29 @@ upnpd_add_int_network_and_defaults() {
|
|
echo "deny 1-65535 $subnet 1-65535 # Reject ACL by default on $interface"
|
|
fi
|
|
}
|
|
+
|
|
+upnpd_add_acl_entry() {
|
|
+ local cfg="$1"
|
|
+ local comment int_addr int_port ext_port descr_filter action
|
|
+ config_get comment "$cfg" comment "unspecified" # comment
|
|
+ config_get int_addr "$cfg" int_addr "0.0.0.0/0" # IPv4 or network and subnet mask (internal)
|
|
+ config_get int_port "$cfg" int_port "1-65535" # internal port/range: x or x-y
|
|
+ config_get ext_port "$cfg" ext_port "1-65535" # external port/range: x or x-y
|
|
+ config_get descr_filter "$cfg" descr_filter # description regex filter (must be built in)
|
|
+ config_get action "$cfg" action # accept/reject/disabled
|
|
+ ! is_port_or_range "$int_port" allowport0 &&
|
|
+ log "ACL entry: Invalid port or port range ($int_port) in int_port ignored" daemon.warn && int_port=1-65535
|
|
+ ! is_port_or_range "$ext_port" allowport0 &&
|
|
+ log "ACL entry: Invalid port or port range ($ext_port) in ext_port ignored" daemon.warn && ext_port=1-65535
|
|
+ [ "$descr_filter" != "" ] && descr_filter=" \"$descr_filter\""
|
|
+ if [ "$action" = "accept" ]; then
|
|
+ action=allow
|
|
+ elif [ "$action" = "reject" ]; then
|
|
+ action=deny
|
|
+ elif [ "$action" != "disabled" ]; then
|
|
+ log "ACL entry: Entry with invalid action ($action) ignored" daemon.warn
|
|
+ action=disabled
|
|
+ fi
|
|
+ [ "$action" = "disabled" ] && return 0
|
|
+ echo "$action $ext_port $int_addr $int_port${descr_filter} # $comment"
|
|
+}
|
|
|
|
From 397f547a4cda0a6ed83ecbb9dfd6a3f0252294a7 Mon Sep 17 00:00:00 2001
|
|
From: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
Date: Tue, 14 Jul 2026 00:00:00 +0000
|
|
Subject: [PATCH 10/10] miniupnpd: service-wide access control settings
|
|
|
|
This implements variant B
|
|
|
|
upnpd.settings UCI options | Change | Previous name
|
|
-----------------------------|---------------------------|--------------
|
|
access_defaults | New option (1) |
|
|
accept_ports | New option (1) |
|
|
reject_ports | New option (2) |
|
|
check_acl | New option (1) |
|
|
|
|
Notes:
|
|
1. New options added for default ports that all devices can map,
|
|
client-specific permissions using the access control list (ACL) can
|
|
extend/override the defaults. Access defaults: accept-high-ports
|
|
accept-web+high-ports/accept-web-ports/accept-all-ports
|
|
2. Reject ports; overrides other settings. By default reject unsafe:
|
|
FTP (21), Telnet (23), DCE/NetBIOS/SMB (135/137-139/445), RDP (3389)
|
|
|
|
(to merge with prior)
|
|
|
|
Signed-off-by: Self Hosting Group <selfhostinggroup-git+openwrt@shost.ing>
|
|
---
|
|
miniupnpd/files/miniupnpd.init | 98 ++++++++-----------
|
|
.../files/upnpd-migration.uci-defaults | 16 +--
|
|
miniupnpd/files/upnpd.config | 11 +--
|
|
3 files changed, 49 insertions(+), 76 deletions(-)
|
|
|
|
diff --git a/miniupnpd/files/miniupnpd.init b/miniupnpd/files/miniupnpd.init
|
|
index a6611c0e732e0d..d7256603f0c34c 100644
|
|
--- a/miniupnpd/files/miniupnpd.init
|
|
+++ b/miniupnpd/files/miniupnpd.init
|
|
@@ -61,15 +61,22 @@ service_triggers() {
|
|
|
|
upnpd_generate_config() {
|
|
# Daemon
|
|
- local enable_protocols allow_cgnat stun_host allow_third_party_mapping ipv6_disable system_uptime lease_file
|
|
+ local enable_protocols allow_cgnat stun_host allow_third_party_mapping system_uptime lease_file
|
|
config_get enable_protocols settings enable_protocols all
|
|
config_get allow_cgnat settings allow_cgnat 0
|
|
config_get stun_host settings stun_host stun.nextcloud.com
|
|
config_get allow_third_party_mapping settings allow_third_party_mapping 0
|
|
- config_get ipv6_disable settings ipv6_disable 0
|
|
config_get system_uptime settings system_uptime 1
|
|
config_get lease_file settings lease_file /var/run/miniupnpd.leases
|
|
|
|
+ # Access control
|
|
+ local access_defaults accept_ports reject_ports check_acl ipv6_disable
|
|
+ config_get access_defaults settings access_defaults none
|
|
+ config_get accept_ports settings accept_ports
|
|
+ config_get reject_ports settings reject_ports "21 23 135 137-139 445 3389"
|
|
+ config_get check_acl settings check_acl 1
|
|
+ config_get ipv6_disable settings ipv6_disable 0
|
|
+
|
|
# UPnP IGD
|
|
local upnp_igd_compat download_kbps upload_kbps friendly_name model_number serial_number presentation_url uuid http_port notify_interval
|
|
config_get upnp_igd_compat settings upnp_igd_compat igdv1
|
|
@@ -83,12 +90,13 @@ upnpd_generate_config() {
|
|
config_get http_port settings http_port 5000
|
|
config_get notify_interval settings notify_interval
|
|
|
|
- # External network interface
|
|
- local external_iface external_iface6 external_zone external_ip
|
|
+ # Network interfaces
|
|
+ local external_iface external_iface6 external_zone external_ip internal_iface
|
|
config_get external_iface settings external_iface
|
|
config_get external_iface6 settings external_iface6
|
|
config_get external_zone settings external_zone
|
|
config_get external_ip settings external_ip
|
|
+ config_get internal_iface settings internal_iface lan
|
|
|
|
local ifname ifname6
|
|
. /lib/functions/network.sh
|
|
@@ -121,10 +129,6 @@ upnpd_generate_config() {
|
|
[ "$pass" = "4" ] && log "IPv6 GUA not yet available, UPnP IGD mapping not possible" && break
|
|
done
|
|
fi
|
|
- if ! uci -q get upnpd.@internal_network[0].interface >/dev/null; then
|
|
- log "No internal networks configured, not starting" daemon.err
|
|
- return 1
|
|
- fi
|
|
# Only perform an STUN CGNAT test if necessary, with a private/CGNAT-reserved external IPv4
|
|
local extipv4 extipv4private
|
|
extipv4="$(ip -4 addr show dev "$ifname" | grep inet | head -1 | sed -E "s/.*inet ([0-9.]+).*/\1/")"
|
|
@@ -151,7 +155,6 @@ upnpd_generate_config() {
|
|
[ "$allow_third_party_mapping" = "1" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=yes"
|
|
[ "$allow_third_party_mapping" = "upnp-igd" ] && echo "secure_mode=no" && echo "pcp_allow_thirdparty=no"
|
|
[ "$allow_third_party_mapping" = "pcp" ] && echo "secure_mode=yes" && echo "pcp_allow_thirdparty=yes"
|
|
- [ "$ipv6_disable" = "0" ] && echo "ipv6_disable=no" || echo "ipv6_disable=yes"
|
|
[ "$system_uptime" = "0" ] && echo "system_uptime=no" || echo "system_uptime=yes"
|
|
touch "$lease_file" && echo "lease_file=$lease_file"
|
|
[ "$ipv6_disable" = "0" ] && touch "${lease_file}-ipv6" && echo "lease_file6=${lease_file}-ipv6"
|
|
@@ -191,9 +194,37 @@ upnpd_generate_config() {
|
|
[ -n "$external_ip" ] && echo "ext_ip=$external_ip"
|
|
|
|
echo "# Enable internal networks / access control"
|
|
- config_foreach upnpd_add_int_network_and_defaults internal_network pre-acl
|
|
- config_foreach upnpd_add_acl_entry acl_entry
|
|
- config_foreach upnpd_add_int_network_and_defaults internal_network post-acl
|
|
+ [ "$ipv6_disable" = "0" ] && echo "ipv6_disable=no" || echo "ipv6_disable=yes"
|
|
+ local rejectport
|
|
+ for rejectport in $reject_ports; do
|
|
+ is_port_or_range "$rejectport" allowport0 && echo "deny $rejectport 0.0.0.0/0 $rejectport # Reject port $rejectport" ||
|
|
+ log "Invalid port or port range ($rejectport) in reject_ports ignored" daemon.warn
|
|
+ done
|
|
+ [ "$check_acl" = "1" ] && echo "# Access control list" && config_foreach upnpd_add_acl_entry acl_entry
|
|
+ local iface
|
|
+ for iface in $internal_iface; do
|
|
+ local device subnet accessdefaultsports acceptport
|
|
+ network_get_device device "$iface"
|
|
+ network_get_subnet subnet "$iface"
|
|
+ [ "$subnet" = "" ] && log "Cannot get IPv4 subnet for network $iface, network ignored" daemon.warn && continue
|
|
+ echo "# Enable internal network $iface ($device) with access defaults $access_defaults and check ACL $check_acl"
|
|
+ echo "listening_ip=$device"
|
|
+ if [ "$access_defaults" = "accept-high-ports" ]; then
|
|
+ accessdefaultsports="1024-65535"
|
|
+ elif [ "$access_defaults" = "accept-web+high-ports" ]; then
|
|
+ accessdefaultsports="80 443 1024-65535"
|
|
+ elif [ "$access_defaults" = "accept-web-ports" ]; then
|
|
+ accessdefaultsports="80 443"
|
|
+ elif [ "$access_defaults" = "accept-all-ports" ]; then
|
|
+ accessdefaultsports="1-65535"
|
|
+ elif [ "$access_defaults" != "none" ]; then
|
|
+ log "Invalid access_defaults ($access_defaults) ignored" daemon.warn
|
|
+ fi
|
|
+ for acceptport in $accessdefaultsports $accept_ports; do
|
|
+ is_port_or_range "$acceptport" && echo "allow $acceptport $subnet $acceptport # Accept port $acceptport on $iface" ||
|
|
+ log "Invalid port or port range ($acceptport) in accept_ports ignored" daemon.warn
|
|
+ done
|
|
+ done
|
|
echo "deny 1-65535 0.0.0.0/0 1-65535 # Reject ACL by default"
|
|
|
|
} >"$1"
|
|
@@ -217,49 +248,6 @@ is_port_or_range() {
|
|
[ "${1##*-}" -ge "${1%%-*}" ] 2>/dev/null && return 0 || return 1
|
|
}
|
|
|
|
-upnpd_add_int_network_and_defaults() {
|
|
- local cfg="$1"
|
|
- local interface access_defaults accept_ports reject_ports check_acl
|
|
- config_get interface "$cfg" interface
|
|
- config_get access_defaults "$cfg" access_defaults none
|
|
- config_get accept_ports "$cfg" accept_ports
|
|
- config_get reject_ports "$cfg" reject_ports "21 23 135 137-139 445 3389"
|
|
- config_get check_acl "$cfg" check_acl 1
|
|
- local device subnet rejectport accessdefaultsports acceptport
|
|
- network_get_device device "$interface"
|
|
- network_get_subnet subnet "$interface"
|
|
- [ "$subnet" = "" ] && log "Cannot get IPv4 subnet for network $interface, network ignored" daemon.warn && return 0
|
|
- if [ "$2" = "pre-acl" ]; then
|
|
- echo "# Enable internal network $interface ($device) with access defaults $access_defaults and check ACL $check_acl"
|
|
- echo "listening_ip=$device"
|
|
- for rejectport in $reject_ports; do
|
|
- is_port_or_range "$rejectport" allowport0 && echo "deny $rejectport $subnet $rejectport # Reject port $rejectport on $interface" ||
|
|
- log "Invalid port or port range ($rejectport) in reject_ports ignored" daemon.warn
|
|
- done
|
|
- fi
|
|
- if { [ "$2" = "post-acl" ] && [ "$check_acl" = "1" ]; } ||
|
|
- { [ "$2" = "pre-acl" ] && [ "$check_acl" = "0" ]; }; then
|
|
- if [ "$access_defaults" = "accept-high-ports" ]; then
|
|
- accessdefaultsports="1024-65535"
|
|
- elif [ "$access_defaults" = "accept-web+high-ports" ]; then
|
|
- accessdefaultsports="80 443 1024-65535"
|
|
- elif [ "$access_defaults" = "accept-web-ports" ]; then
|
|
- accessdefaultsports="80 443"
|
|
- elif [ "$access_defaults" = "accept-all-ports" ]; then
|
|
- accessdefaultsports="1-65535"
|
|
- elif [ "$access_defaults" != "none" ]; then
|
|
- log "Invalid access_defaults ($access_defaults) ignored" daemon.warn
|
|
- fi
|
|
- for acceptport in $accessdefaultsports $accept_ports; do
|
|
- is_port_or_range "$acceptport" && echo "allow $acceptport $subnet $acceptport # Accept port $acceptport on $interface" ||
|
|
- log "Invalid port or port range ($acceptport) in accept_ports ignored" daemon.warn
|
|
- done
|
|
- fi
|
|
- if [ "$2" = "pre-acl" ] && [ "$check_acl" = "0" ]; then
|
|
- echo "deny 1-65535 $subnet 1-65535 # Reject ACL by default on $interface"
|
|
- fi
|
|
-}
|
|
-
|
|
upnpd_add_acl_entry() {
|
|
local cfg="$1"
|
|
local comment int_addr int_port ext_port descr_filter action
|
|
diff --git a/miniupnpd/files/upnpd-migration.uci-defaults b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
index ac0c8d3245c175..60f80d54fffa28 100644
|
|
--- a/miniupnpd/files/upnpd-migration.uci-defaults
|
|
+++ b/miniupnpd/files/upnpd-migration.uci-defaults
|
|
@@ -212,6 +212,8 @@ else
|
|
fi
|
|
while uci -q delete upnpd.@perm_rule[-1]; do :; done
|
|
fi
|
|
+[ "$access_defaults" != "" ] && uci set upnpd.config.access_defaults="$access_defaults"
|
|
+[ "$check_acl" = "0" ] && uci set upnpd.config.check_acl="0"
|
|
if [ "$addtemplateentries" = "1" ]; then
|
|
uci batch >/dev/null <<-EOF
|
|
add upnpd acl_entry
|
|
@@ -231,20 +233,6 @@ if [ "$addtemplateentries" = "1" ]; then
|
|
uci reorder upnpd.@acl_entry[-2]=0 && uci reorder upnpd.@acl_entry[-1]=1
|
|
fi
|
|
|
|
-# Migrate internal_iface option to new internal_network section
|
|
-if ! uci -q get upnpd.@internal_network[0] >/dev/null; then
|
|
- ifnr=0
|
|
- for interface in $(uci -q get upnpd.config.internal_iface || echo lan); do
|
|
- log "Create new internal_network section for $interface"
|
|
- uci add upnpd internal_network >/dev/null
|
|
- uci set upnpd.@internal_network[$ifnr].interface="$interface"
|
|
- [ "$access_defaults" != "" ] && uci set upnpd.@internal_network[$ifnr].access_defaults="$access_defaults"
|
|
- [ "$check_acl" = "0" ] && uci set upnpd.@internal_network[$ifnr].check_acl="0"
|
|
- ifnr=$((ifnr + 1))
|
|
- done
|
|
- uci -q delete upnpd.config.internal_iface
|
|
-fi
|
|
-
|
|
# Rename UCI section config -> settings (v2.0)
|
|
if uci -q get upnpd.config >/dev/null; then
|
|
log "Rename UCI section config -> settings (v2.0)" && uci rename upnpd.config="settings" ||
|
|
diff --git a/miniupnpd/files/upnpd.config b/miniupnpd/files/upnpd.config
|
|
index 74fc64b58e9bf6..1ae67365486063 100644
|
|
--- a/miniupnpd/files/upnpd.config
|
|
+++ b/miniupnpd/files/upnpd.config
|
|
@@ -4,19 +4,16 @@ config upnpd 'settings'
|
|
option enabled '0'
|
|
# Can be set to all/upnp-igd/pcp+nat-pmp
|
|
option enable_protocols 'all'
|
|
+ # Enable networks, multiple can be specified, separated by a space
|
|
+ option internal_iface 'lan'
|
|
+ option access_defaults 'accept-high-ports' # default none
|
|
+ option check_acl '0' # default 1
|
|
#option ipv6_disable '0'
|
|
#option allow_third_party_mapping '0'
|
|
# Extra logging by setting to info or debug (previously 1)
|
|
option log_output 'default'
|
|
option upnp_igd_compat 'igdv1'
|
|
|
|
-# Enable Networks / Access Control
|
|
-
|
|
-config internal_network
|
|
- option interface 'lan'
|
|
- option access_defaults 'accept-high-ports' # default none
|
|
- option check_acl '0' # default 1
|
|
-
|
|
# Access Control List
|
|
# Empty ACL rejected alone, IPv6 accepted unless disabled, action: accept/reject
|
|
|