From: Dirk Brenken Date: Mon, 12 Jan 2026 22:04:39 +0000 (+0100) Subject: luci-app-banip: sync with banIP-1.8.0-1 X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=project%2Fluci.git luci-app-banip: sync with banIP-1.8.0-1 Signed-off-by: Dirk Brenken --- diff --git a/applications/luci-app-banip/Makefile b/applications/luci-app-banip/Makefile index ce20f7740e..bc6381faa5 100644 --- a/applications/luci-app-banip/Makefile +++ b/applications/luci-app-banip/Makefile @@ -1,4 +1,4 @@ -# Copyright 2018-2025 Dirk Brenken (dev@brenken.org) +# Copyright 2018-2026 Dirk Brenken (dev@brenken.org) # This is free software, licensed under the Apache License, Version 2.0 include $(TOPDIR)/rules.mk @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for banIP LUCI_DEPENDS:=+luci-base +banip -PKG_VERSION:=1.6.0 +PKG_VERSION:=1.8.0 PKG_RELEASE:=1 PKG_LICENSE:=Apache-2.0 PKG_MAINTAINER:=Dirk Brenken diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js index 43f62cd8db..678e3c2389 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js @@ -13,7 +13,7 @@ const resetScroll = () => { return view.extend({ load: function () { return L.resolveDefault(fs.stat(localFile), "") - .then(function (stat) { + .then(function (stat) { if (!stat) { return fs.write(localFile, ""); } @@ -24,7 +24,7 @@ return view.extend({ }); }, render: function (allowlist) { - if (allowlist[0].size >= 100000) { + if (allowlist[0] && allowlist[0].size >= 100000) { resetScroll(); ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error'); } diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js index a676bc8cc5..ad5c3fd39e 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js @@ -13,7 +13,7 @@ const resetScroll = () => { return view.extend({ load: function () { return L.resolveDefault(fs.stat(localFile), "") - .then(function (stat) { + .then(function (stat) { if (!stat) { return fs.write(localFile, ""); } @@ -24,19 +24,19 @@ return view.extend({ }); }, render: function (blocklist) { - if (blocklist[0].size >= 100000) { + if (blocklist[0] && blocklist[0].size >= 100000) { resetScroll(); ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error'); } return E('div', { 'class': 'cbi-section cbi-section-descr' }, [ E('p', _('This is the local banIP blocklist that will prevent certain MAC-, IP-addresses or domain names.
\ Please note: add only exactly one MAC/IPv4/IPv6 address or domain name per line. Ranges in CIDR notation and MAC/IP-bindings are allowed.')), - E('textarea', { - 'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em', - 'spellcheck': 'false', - 'wrap': 'off', - 'rows': 25 - }, [blocklist[1] != null ? blocklist[1] : '']) + E('textarea', { + 'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em', + 'spellcheck': 'false', + 'wrap': 'off', + 'rows': 25 + }, [blocklist[1] != null ? blocklist[1] : '']) ]); }, handleSave: function (ev) { diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js index 4ac74f4710..25ad62693c 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js @@ -119,59 +119,50 @@ function handleEdit(ev) { return ui.addNotification(null, E('p', _('Invalid input values, unable to save modifications.')), 'error'); } } - let sumSubElements = [], exportJson; + /* + gather all input data + */ + let sumSubElements = []; const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]'); - for (let i = 0; i < nodeKeys.length; i++) { - let subElements = {}; - const elements = document.querySelectorAll('[id^="widget.cbid.json.' + nodeKeys[i].id.split('.')[3] + '\."], \ - [id^="cbid.json.' + nodeKeys[i].id.split('.')[3] + '\.rule_4"], \ - [id^="cbid.json.' + nodeKeys[i].id.split('.')[3] + '\.rule_6"]'); - for (const element of elements) { - let key; - const value = element.value || ""; - const parts = element.id.split('.'); - if (parts.length === 5) { - key = element.id.split('.')[4]; - } else if (parts.length === 4) { - key = element.id.split('.')[3]; - } - if (!key || value === "") { - continue; - } - switch (key) { - case 'url_4': - subElements.url_4 = value; - break; - case 'rule_4': - subElements.rule_4 = value; - break; - case 'url_6': - subElements.url_6 = value; - break; - case 'rule_6': - subElements.rule_6 = value; - break; - case 'chain': - subElements.chain = value; - break; - case 'descr': - subElements.descr = value; - break; - case 'flag': - subElements.flag = value; - break; + for (const keyNode of nodeKeys) { + const keyValue = keyNode.value?.trim(); + if (!keyValue) continue; + const idParts = keyNode.id.split("."); + const ruleId = idParts[3]; + if (!ruleId) continue; + const selector = + `[id^="widget.cbid.json.${ruleId}."], ` + + `[id^="cbid.json.${ruleId}.rule"]`; + const elements = document.querySelectorAll(selector); + const sub = {}; + for (const el of elements) { + const parts = el.id.split("."); + const key = parts[parts.length - 1]; + const value = el.value?.trim(); + if (!value) continue; + if (["url_4", "url_6", "rule", "chain", "descr", "flag"].includes(key)) { + sub[key] = value; } } - if (nodeKeys[i].value !== "" && subElements.descr !== "") { - sumSubElements.push(nodeKeys[i].value, subElements); + if (sub.descr) { + sumSubElements.push(keyValue, sub); } } - if (sumSubElements.length > 0) { - exportJson = JSON.stringify(sumSubElements).replace(/^\[/, '{\n').replace(/\}]$/, '\n\t}\n}\n').replace(/,{"/g, ':{\n\t"').replace(/"},"/g, '"\n\t},\n"').replace(/","/g, '",\n\t"'); + /* + construct json object + */ + let exportObj = {}; + for (let i = 0; i < sumSubElements.length; i += 2) { + const key = sumSubElements[i]; + const value = sumSubElements[i + 1]; + exportObj[key] = value; } - return fs.write('/etc/banip/banip.custom.feeds', exportJson).then(function () { - location.reload(); - }); + const exportJson = JSON.stringify(exportObj, null, 4); + /* + save to file and reload + */ + return fs.write('/etc/banip/banip.custom.feeds', exportJson) + .then(() => location.reload()); } return view.extend({ @@ -186,7 +177,7 @@ return view.extend({ }, render: function (data) { - let m, s, o, feed, url_4, url_6, rule_4, rule_6, chain, descr, flag; + let m, s, o, feed, url_4, url_6, rule, chain, descr, flag; m = new form.JSONMap(data, null, _('With this editor you can upload your local custom feed file or fill up an initial one (a 1:1 copy of the version shipped with the package). \ The file is located at \'/etc/banip/banip.custom.feeds\'. \ @@ -194,9 +185,8 @@ return view.extend({ for (let i = 0; i < Object.keys(m.data.data).length; i++) { feed = Object.keys(m.data.data)[i]; url_4 = m.data.data[feed].url_4; - rule_4 = m.data.data[feed].rule_4; url_6 = m.data.data[feed].url_6; - rule_6 = m.data.data[feed].rule_6; + rule = m.data.data[feed].rule; chain = m.data.data[feed].chain; descr = m.data.data[feed].descr; flag = m.data.data[feed].flag; @@ -229,20 +219,6 @@ return view.extend({ return true; } - o = s.option(form.Value, 'rule_4', _('Rulev4')); - o.value('/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$1}', _('')); - o.value('/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{printf \"%s,\\n\",$1}', _('')); - o.value('/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s/%s,\\n\",$1,$3}', _(', concatinated')); - o.value('/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)$/{if(!seen[$1]++)printf \"%s,\\n\",$1}', _(', nodups')); - o.value('/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[-[:space:]]?/{printf \"%s,\\n\",$1}', _('[|]')); - o.value('/127\\./{next}/(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)[[:space:]]/{printf \"%s,\\n\",$2}', _('')); - o.value('BEGIN{FS=\",\"}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)/{printf \"%s,\\n\",$1}', _(', csv')); - o.value('BEGIN{IGNORECASE=1}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]NET)/{printf \"%s,\\n\",$1}', _('NET')); - o.value('BEGIN{IGNORECASE=1}/^127\\./{next}/^(([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\\/(1?[0-9]|2?[0-9]|3?[0-2]))?)([[:space:]]YOUR)/{printf \"%s,\\n\",$1}', _('YOUR')); - o.value('BEGIN{FS=\";\"}/content:\"127\\./{next}/(content:\"([1-9][0-9]{0,2}\\.){1}([0-9]{1,3}\\.){2}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\")/{printf \"%s,\\n\",substr($10,11,length($10)-11)}', _(', substring')); - o.optional = true; - o.rmempty = true; - o = s.option(form.Value, 'url_6', _('URLv6')); o.validate = function (section_id, value) { if (!value) { @@ -254,10 +230,11 @@ return view.extend({ return true; } - o = s.option(form.Value, 'rule_6', _('Rulev6')); - o.value('/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)[[:space:]]/{printf \"%s,\\n\",$1}', _('')); - o.value('/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)$/{printf \"%s,\\n\",$1}', _('')); - o.value('BEGIN{FS=\",\"}/^(([0-9A-f]{0,4}:){1,7}[0-9A-f]{0,4}:?(\\/(1?[0-2][0-8]|[0-9][0-9]))?)/{printf \"%s,\\n\",$1}', _(', csv')); + o = s.option(form.Value, 'rule', _('Rule')); + o.value('feed 1', _('')); + o.value('feed 1 ,', _('')); + o.value('feed 13', _(' ')); + o.value('suricata 1', _('')); o.optional = true; o.rmempty = true; diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/logtemplate.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/logtemplate.js index 10c552721f..c26aa23bbd 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/logtemplate.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/logtemplate.js @@ -18,25 +18,24 @@ function Logview(logtag, name) { const logEl = document.getElementById('logfile'); if (!logEl) return; - const entries = res?.log ?? []; - if (entries.length > 0) { - const filtered = entries - .filter(entry => !logtag || entry.msg.includes(logtag)) - .map(entry => { - const d = new Date(entry.time); - const date = d.toLocaleDateString([], { - year: 'numeric', - month: '2-digit', - day: '2-digit' - }); - const time = d.toLocaleTimeString([], { - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - hour12: false - }); - return `[${date}-${time}] ${entry.msg}`; - }); + const filtered = (res?.log ?? []) + .filter(entry => !logtag || entry.msg.includes(logtag)) + .map(entry => { + const d = new Date(entry.time); + const date = d.toLocaleDateString([], { + year: 'numeric', + month: '2-digit', + day: '2-digit' + }); + const time = d.toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false + }); + return `[${date}-${time}] ${entry.msg}`; + }); + if (filtered.length > 0) { logEl.value = filtered.join('\n'); } else { logEl.value = _('No %s related logs yet!').format(name); diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js index 642f82ee6d..fe529b4767 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js @@ -372,6 +372,10 @@ return view.extend({ o.optional = true; o.rmempty = true; + o = s.taboption('adv_chain', form.Flag, 'ban_bcp38', _('Enable BCP38'), _('Block packets with spoofed source IP addresses in all supported chains.')); + o.optional = true; + o.rmempty = true; + o = s.taboption('adv_chain', form.ListValue, 'ban_icmplimit', _('ICMP-Threshold'), _('ICMP-Threshold in packets per second to prevent WAN-DoS attacks. To disable this safeguard set it to \'0\'.')); o.value('0'); o.value('25'); @@ -435,8 +439,7 @@ return view.extend({ o.value('1'); o.value('3'); o.value('5'); - o.value('10'); - o.default = '5'; + o.default = '3'; o.placeholder = _('-- default --'); o.create = true; o.optional = true; diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js index 1148c73a30..8768cbab8e 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js @@ -272,6 +272,10 @@ return view.extend({ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked invalid tcp packets')), E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_tcpinvalid || '-') ]), + E('div', { 'class': 'cbi-value' }, [ + E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked bcp38 packets')), + E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_bcp38 || '-') + ]), E('hr'), E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('auto-added IPs to allowlist')), diff --git a/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json b/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json index b74902cdf0..e43ac0111f 100644 --- a/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json +++ b/applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json @@ -2,13 +2,13 @@ "luci-app-banip": { "description": "Grant access to LuCI app banIP", "write": { + "uci": [ "banip" ], "file": { "/etc/banip/*": [ "read", "write" ], "/etc/banip/banip.allowlist": [ "write" ], "/etc/banip/banip.blocklist": [ "write" ], "/etc/banip/banip.custom.feeds": [ "read", "write" ] - }, - "uci": [ "banip" ] + } }, "read": { "cgi-io": [ "exec" ],