luci-app-banip: sync with banIP 0.7.0

* sync with current banIP release
* move app to client side JS
* tested with all standard themes

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken 2021-02-04 16:05:54 +01:00
parent 6ae138c2fe
commit f89450fd3e
No known key found for this signature in database
GPG key ID: 9D71CD547BFAE684
53 changed files with 24376 additions and 11367 deletions

View file

@ -1,12 +1,14 @@
# Copyright 2018 Dirk Brenken (dev@brenken.org)
# Copyright 2018-2021 Dirk Brenken (dev@brenken.org)
# This is free software, licensed under the Apache License, Version 2.0
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for banIP
LUCI_DEPENDS:=+luci-compat +banip +luci-lib-jsonc
LUCI_DEPENDS:=+banip +luci-lib-jsonc
LUCI_PKGARCH:=all
PKG_LICENSE:=Apache-2.0
include ../../luci.mk
# call BuildPackage - OpenWrt buildroot signature

View file

@ -0,0 +1,37 @@
'use strict';
'require view';
'require fs';
'require ui';
return view.extend({
load: function() {
return L.resolveDefault(fs.read_direct('/etc/banip/banip.blacklist'), '');
},
handleSave: function(ev) {
var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n';
return fs.write('/etc/banip/banip.blacklist', value)
.then(function(rc) {
document.querySelector('textarea').value = value;
ui.addNotification(null, E('p', _('Blacklist changes have been saved. Refresh your banIP lists that changes take effect.')), 'info');
}).catch(function(e) {
ui.addNotification(null, E('p', _('Unable to save changes: %s').format(e.message)));
});
},
render: function(blacklist) {
return E([
E('p', {},
_('This is the local banIP blacklist to always-deny certain IP/CIDR addresses.<br /> \
<em><b>Please note:</b></em> add only one IPv4 or IPv6 address per line. Comments introduced with \'#\' are allowed - domains, wildcards and regex are not.')),
E('p', {},
E('textarea', {
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [ blacklist != null ? blacklist : '' ])
)
]);
},
handleSaveApply: null,
handleReset: null
});

View file

@ -0,0 +1,245 @@
'use strict';
'require view';
'require fs';
'require ui';
/*
button handling
*/
function handleAction(ev) {
if (ev.target && ev.target.getAttribute('name') === 'whitelist') {
L.ui.showModal(_('Whitelist IP/CIDR'), [
E('p', _('Add this IP/CIDR to your local whitelist.')),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'style': 'width:300px', 'spellcheck': 'false', 'id': 'whitelist', 'value': ev.target.getAttribute('value') }, [])
])
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': L.hideModal
}, _('Cancel')),
' ',
E('button', {
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function(ev) {
L.resolveDefault(fs.read_direct('/etc/banip/banip.whitelist'), '')
.then(function(res) {
var ip = document.getElementById('whitelist').value.trim().toLowerCase();
if (ip) {
var whitelist = res + ip + '\n';
fs.write('/etc/banip/banip.whitelist', whitelist);
ui.addNotification(null, E('p', _('Whitelist changes have been saved. Refresh your banIP lists that changes take effect.')), 'info');
}
L.hideModal();
});
})
}, _('Save'))
])
]);
document.getElementById('whitelist').focus();
}
if (ev === 'query') {
L.ui.showModal(_('IPSet Query'), [
E('p', _('Search the active banIP-related IPSets for a specific IP, CIDR or MAC address.')),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('label', { 'style': 'padding-top:.5em', 'id': 'run' }, [
E('input', {
'class': 'cbi-input-text',
'placeholder': '192.168.0.1',
'style': 'width:300px',
'spellcheck': 'false',
'id': 'search'
})
])
]),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
'\xa0',
E('h5', _('Result')),
E('textarea', {
'id': 'result',
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'readonly': 'readonly',
'wrap': 'off',
'rows': 20
})
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': L.hideModal
}, _('Cancel')),
' ',
E('button', {
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function(ev) {
var ip = document.getElementById('search').value.trim().toLowerCase();
if (ip) {
document.getElementById('run').classList.add("spinning");
document.getElementById('search').value = ip;
document.getElementById('result').textContent = 'The query is running, please wait...';
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['query', ip])).then(function(res) {
var result = document.getElementById('result');
if (res) {
result.textContent = res.trim();
} else {
result.textContent = _('No Query results!');
}
document.getElementById('run').classList.remove("spinning");
document.getElementById('search').value = '';
})
}
document.getElementById('search').focus();
})
}, _('Query'))
])
]);
document.getElementById('search').focus();
}
}
return view.extend({
load: function() {
return L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'json']),'');
},
render: function(ipsetreport) {
if (!ipsetreport) {
ipsetreport = '{}';
};
var content;
content = JSON.parse(ipsetreport);
var rows_ipsets = [];
var tbl_ipsets = E('table', { 'class': 'table', 'id': 'ipsets' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Name')),
E('th', { 'class': 'th' }, _('Type')),
E('th', { 'class': 'th' }, _('Count SUM')),
E('th', { 'class': 'th' }, _('Count IP')),
E('th', { 'class': 'th' }, _('Count CIDR')),
E('th', { 'class': 'th' }, _('Count MAC')),
E('th', { 'class': 'th' }, _('Count ACC')),
E('th', { 'class': 'th' }, _('Entry Details')),
E('th', { 'class': 'th' }, _('')),
E('th', { 'class': 'th' }, _('Action'))
])
]);
if (content.ipsets) {
var button, member, urlprefix;
Object.keys(content.ipsets).forEach(function(key) {
rows_ipsets.push([
E('em', key),
E('em', content.ipsets[key].type),
E('em', content.ipsets[key].count),
E('em', content.ipsets[key].count_ip),
E('em', content.ipsets[key].count_cidr),
E('em', content.ipsets[key].count_mac),
E('em', content.ipsets[key].count_acc)
]);
for (var i = 0; i < content.ipsets[key].member_acc.length; i++) {
if (key != 'maclist' && key.substr(0,9) != 'whitelist') {
urlprefix = content.ipsets[key].member_acc[i].member.includes('/') ? 'prefix/' : 'ip/';
member = '<a href="https://api.bgpview.io/' + urlprefix + encodeURIComponent(content.ipsets[key].member_acc[i].member) + '" target="_blank" rel="noreferrer noopener" title="IP/CIDR Lookup" >' + content.ipsets[key].member_acc[i].member + '</a>';
button = E('button', {
'class': 'cbi-button cbi-button-apply',
'style': 'word-break: inherit',
'name': 'whitelist',
'value': content.ipsets[key].member_acc[i].member,
'click': handleAction
}, [ _('Whitelist...')]);
} else {
member = content.ipsets[key].member_acc[i].member;
button = '';
}
rows_ipsets.push([
'',
'',
'',
'',
'',
'',
'',
member,
content.ipsets[key].member_acc[i].packets,
button
]);
}
});
}
cbi_update_table(tbl_ipsets, rows_ipsets);
return E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('div', { 'class': 'cbi-section' }, [
E('p', _('This tab shows the last generated IPSet Report, press the \'Refresh\' button to get a current one.')),
E('p', '\xa0'),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Timestamp')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.timestamp || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of all IPSets')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_set_sum || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of all entries')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_sum || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of IP entries')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_ip_sum || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of CIDR entries')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_cidr_sum || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of MAC entries')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_mac_sum || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'float:left;width:230px' }, _('Number of accessed entries')),
E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'float:left;color:#37c' }, content.cnt_acc_sum || '-')
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-apply',
'click': ui.createHandlerFn(this, function() {
return handleAction('query');
})
}, [ _('IPSet Query...') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-positive',
'click': ui.createHandlerFn(this, async function() {
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'gen']),'');
var running = 1;
while (running === 1) {
await new Promise(r => setTimeout(r, 1000));
L.resolveDefault(fs.read_direct('/var/run/banip.pid')).then(function(res) {
if (!res) {
running = 0;
}
})
}
location.reload();
})
}, [ _('Refresh') ])
]),
]),
E('br'),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'left' }, [
E('h3', _('IPSet details')),
tbl_ipsets
])
])
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View file

@ -0,0 +1,41 @@
'use strict';
'require view';
'require poll';
'require fs';
return view.extend({
load: function() {
return Promise.all([
L.resolveDefault(fs.stat('/sbin/logread'), null),
L.resolveDefault(fs.stat('/usr/sbin/logread'), null)
]);
},
render: function(stat) {
var logger = stat[0] ? stat[0].path : stat[1] ? stat[1].path : null;
poll.add(function() {
return L.resolveDefault(fs.exec_direct(logger, ['-e', 'banIP-'])).then(function(res) {
var log = document.getElementById("logfile");
if (res) {
log.value = res.trim();
} else {
log.value = _('No banIP related logs yet!');
}
log.scrollTop = log.scrollHeight;
});
});
return E('div', { class: 'cbi-map' },
E('div', { class: 'cbi-section' }, [
E('div', { class: 'cbi-section-descr' }, _('The syslog output, pre-filtered for banIP related messages only.')),
E('textarea', {
'id': 'logfile',
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'readonly': 'readonly',
'wrap': 'off',
'rows': 25
})
]));
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});

View file

@ -0,0 +1,37 @@
'use strict';
'require view';
'require fs';
'require ui';
return view.extend({
load: function() {
return L.resolveDefault(fs.read_direct('/etc/banip/banip.maclist'), '');
},
handleSave: function(ev) {
var value = ((document.querySelector('textarea').value || '').trim().toUpperCase().replace(/\r\n/g, '\n')) + '\n';
return fs.write('/etc/banip/banip.maclist', value)
.then(function(rc) {
document.querySelector('textarea').value = value;
ui.addNotification(null, E('p', _('Maclist changes have been saved. Refresh your banIP lists that changes take effect.')), 'info');
}).catch(function(e) {
ui.addNotification(null, E('p', _('Unable to save changes: %s').format(e.message)));
});
},
render: function(blacklist) {
return E([
E('p', {},
_('This is the local banIP maclist to always-allow certain MAC addresses.<br /> \
<em><b>Please note:</b></em> add only one MAC address per line. Comments introduced with \'#\' are allowed - domains, wildcards and regex are not.')),
E('p', {},
E('textarea', {
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [ blacklist != null ? blacklist : '' ])
)
]);
},
handleSaveApply: null,
handleReset: null
});

View file

@ -0,0 +1,766 @@
'use strict';
'require view';
'require poll';
'require fs';
'require ui';
'require uci';
'require form';
'require tools.widgets as widgets';
/*
button handling
*/
async function handleAction(ev) {
if (ev === 'timer') {
L.ui.showModal(_('Refresh Timer'), [
E('p', _('To keep your banIP lists up-to-date, you should setup an automatic update job for these lists.')),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('h5', _('Existing job(s)')),
E('textarea', {
'id': 'cronView',
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'readonly': 'readonly',
'wrap': 'off',
'rows': 5
})
]),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em' }, [
E('h5', _('Set a new banIP job')),
E('select', { 'class': 'cbi-input-select', 'id': 'timerA' }, [
E('option', { 'value': 'start' }, 'Start'),
E('option', { 'value': 'reload' }, 'Reload'),
E('option', { 'value': 'restart' }, 'Restart'),
E('option', { 'value': 'refresh' }, 'Refresh'),
E('option', { 'value': 'suspend' }, 'Suspend'),
E('option', { 'value': 'resume' }, 'Resume'),
E('option', { 'value': 'report gen' }, 'Report'),
E('option', { 'value': 'report mail' }, 'Report &amp; Mail')
]),
'\xa0\xa0\xa0',
_('banIP action')
]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'timerH', 'maxlength': '2' }, [
]),
'\xa0\xa0\xa0',
_('The hours portition (req., range: 0-23)')
]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'timerM', 'maxlength': '2' }),
'\xa0\xa0\xa0',
_('The minutes portion (opt., range: 0-59)')
]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'id': 'timerD', 'maxlength': '13' }),
'\xa0\xa0\xa0',
_('The day of the week (opt., values: 1-7 possibly sep. by , or -)')
])
]),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em' }, [
E('h5', _('Remove an existing job')),
E('input', { 'class': 'cbi-input-text', 'id': 'lineno', 'maxlength': '2' }, [
]),
'\xa0\xa0\xa0',
_('Line number to remove')
])
]),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'btn',
'click': L.hideModal
}, _('Cancel')),
' ',
E('button', {
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function(ev) {
var lineno = document.getElementById('lineno').value;
var action = document.getElementById('timerA').value;
var hours = document.getElementById('timerH').value;
var minutes = document.getElementById('timerM').value || '0';
var days = document.getElementById('timerD').value || '*';
if (hours) {
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['timer', 'add', action, hours, minutes, days]))
.then(function(res) {
if (res) {
ui.addNotification(null, E('p', _('The Refresh Timer could not been updated.')), 'error');
} else {
ui.addNotification(null, E('p', _('The Refresh Timer has been updated.')), 'info');
}
});
} else if (lineno) {
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['timer', 'remove', lineno]))
.then(function(res) {
if (res) {
ui.addNotification(null, E('p', _('The Refresh Timer could not been updated.')), 'error');
} else {
ui.addNotification(null, E('p', _('The Refresh Timer has been updated.')), 'info');
}
});
} else {
document.getElementById('timerH').focus();
return
}
L.hideModal();
})
}, _('Save'))
])
]);
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['timer', 'list']))
.then(function(res) {
document.getElementById('cronView').value = res.trim();
});
document.getElementById('timerH').focus();
return
}
if (document.getElementById('status') && document.getElementById('btn_suspend')) {
if (document.getElementById('status').textContent.substr(0,6) === 'paused') {
ev = 'resume';
}
}
poll.start();
fs.exec_direct('/etc/init.d/banip', [ev])
var running = 1;
while (running === 1) {
await new Promise(r => setTimeout(r, 1000));
L.resolveDefault(fs.read_direct('/var/run/banip.pid')).then(function(res) {
if (!res) {
running = 0;
if (document.getElementById('status') && document.getElementById('btn_suspend')) {
if (document.getElementById('status').textContent.substr(0,7) === 'enabled') {
document.querySelector('#btn_suspend').textContent = 'Suspend';
}
}
}
})
}
poll.stop();
}
return view.extend({
load: function() {
return Promise.all([
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['list']), {}),
L.resolveDefault(fs.exec_direct('/usr/sbin/iptables', ['-L']), null),
L.resolveDefault(fs.exec_direct('/usr/sbin/ip6tables', ['-L']), null),
L.resolveDefault(fs.read_direct('/etc/banip/banip.countries'), ''),
uci.load('banip')
]);
},
render: function(result) {
var m, s, o;
m = new form.Map('banip', 'banIP', _('Configuration of the banIP package to block ip adresses/subnets via IPSet. \
For further information <a href="https://github.com/openwrt/packages/blob/master/net/banip/files/README.md" target="_blank" rel="noreferrer noopener" >check the online documentation</a>'));
/*
poll runtime information
*/
var rt_res, inf_stat, inf_ipsets, inf_sources, inf_srcarr, inf_devices, inf_devarr, inf_ifaces, inf_ifarr, inf_logterms, inf_logtarr
var inf_subnets, inf_subnarr, inf_misc, inf_flags, inf_run
pollData: poll.add(function() {
return L.resolveDefault(fs.read_direct('/tmp/ban_runtime.json'), 'null').then(function(res) {
rt_res = JSON.parse(res);
inf_stat = document.getElementById('status');
if (inf_stat && rt_res) {
inf_stat.textContent = (rt_res.status || '-') + ' / ' + (rt_res.version || '-');
if (rt_res.status === "running") {
if (!inf_stat.classList.contains("spinning")) {
inf_stat.classList.add("spinning");
}
} else {
if (inf_stat.classList.contains("spinning")) {
inf_stat.classList.remove("spinning");
poll.stop();
}
}
if (inf_stat.textContent.substr(0,6) === 'paused' && document.getElementById('btn_suspend')) {
document.querySelector('#btn_suspend').textContent = 'Resume';
}
} else if (inf_stat) {
inf_stat.textContent = '-';
if (inf_stat.classList.contains("spinning")) {
inf_stat.classList.remove("spinning");
}
}
inf_ipsets = document.getElementById('ipsets');
if (inf_ipsets && rt_res) {
inf_ipsets.textContent = rt_res.ipset_info || '-';
}
inf_sources = document.getElementById('sources');
inf_srcarr = [];
if (inf_sources && rt_res) {
for (var i = 0; i < rt_res.active_sources.length; i++) {
if (i < rt_res.active_sources.length-1) {
inf_srcarr += rt_res.active_sources[i].source + ', ';
} else {
inf_srcarr += rt_res.active_sources[i].source
}
}
inf_sources.textContent = inf_srcarr || '-';
}
inf_devices = document.getElementById('devices');
inf_devarr = [];
if (inf_devices && rt_res) {
for (var i = 0; i < rt_res.active_devs.length; i++) {
if (i < rt_res.active_devs.length-1) {
inf_devarr += rt_res.active_devs[i].dev + ', ';
} else {
inf_devarr += rt_res.active_devs[i].dev
}
}
inf_devices.textContent = inf_devarr || '-';
}
inf_ifaces = document.getElementById('ifaces');
inf_ifarr = [];
if (inf_ifaces && rt_res) {
for (var i = 0; i < rt_res.active_ifaces.length; i++) {
if (i < rt_res.active_ifaces.length-1) {
inf_ifarr += rt_res.active_ifaces[i].iface + ', ';
} else {
inf_ifarr += rt_res.active_ifaces[i].iface
}
}
inf_ifaces.textContent = inf_ifarr || '-';
}
inf_logterms = document.getElementById('logterms');
inf_logtarr = [];
if (inf_logterms && rt_res) {
for (var i = 0; i < rt_res.active_logterms.length; i++) {
if (i < rt_res.active_logterms.length-1) {
inf_logtarr += rt_res.active_logterms[i].term + ', ';
} else {
inf_logtarr += rt_res.active_logterms[i].term
}
}
inf_logterms.textContent = inf_logtarr || '-';
}
inf_subnets = document.getElementById('subnets');
inf_subnarr = [];
if (inf_subnets && rt_res) {
for (var i = 0; i < rt_res.active_subnets.length; i++) {
if (i < rt_res.active_subnets.length-1) {
inf_subnarr += rt_res.active_subnets[i].subnet + ', ';
} else {
inf_subnarr += rt_res.active_subnets[i].subnet
}
}
inf_subnets.textContent = inf_subnarr || '-';
}
inf_misc = document.getElementById('infos');
if (inf_misc && rt_res) {
inf_misc.textContent = rt_res.run_infos || '-';
}
inf_flags = document.getElementById('flags');
if (inf_flags && rt_res) {
inf_flags.textContent = rt_res.run_flags || '-';
}
inf_run = document.getElementById('run');
if (inf_run && rt_res) {
inf_run.textContent = rt_res.last_run || '-';
}
});
}, 1);
/*
runtime information and buttons
*/
s = m.section(form.NamedSection, 'global');
s.render = L.bind(function(view, section_id) {
return E('div', { 'class': 'cbi-section' }, [
E('h3', _('Information')),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')),
E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'color:#37c' },'\xa0')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('IPSet Information')),
E('div', { 'class': 'cbi-value-field', 'id': 'ipsets', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Sources')),
E('div', { 'class': 'cbi-value-field', 'id': 'sources', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Devices')),
E('div', { 'class': 'cbi-value-field', 'id': 'devices', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Interfaces')),
E('div', { 'class': 'cbi-value-field', 'id': 'ifaces', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Logterms')),
E('div', { 'class': 'cbi-value-field', 'id': 'logterms', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Subnets')),
E('div', { 'class': 'cbi-value-field', 'id': 'subnets', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Information')),
E('div', { 'class': 'cbi-value-field', 'id': 'infos', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')),
E('div', { 'class': 'cbi-value-field', 'id': 'flags', 'style': 'color:#37c' },'-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')),
E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'color:#37c' },'-')
]),
E('div', { class: 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-apply',
'click': ui.createHandlerFn(this, function() {
return handleAction('timer');
})
}, [ _('Refresh Timer...') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-apply',
'id': 'btn_suspend',
'click': ui.createHandlerFn(this, function() {
return handleAction('suspend');
})
}, [ _('Suspend') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-positive',
'click': ui.createHandlerFn(this, function() {
return handleAction('refresh');
})
}, [ _('Refresh') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-negative',
'click': ui.createHandlerFn(this, function() {
return handleAction('restart');
})
}, [ _('Restart') ])
])
]);
}, o, this);
this.pollData;
/*
tabbed config section
*/
s = m.section(form.NamedSection, 'global', 'banip', _('Settings'));
s.addremove = false;
s.tab('general', _('General Settings'));
s.tab('additional', _('Additional Settings'));
s.tab('adv_chain', _('Advanced Chain Settings'));
s.tab('adv_log', _('Advanced Log Settings'));
s.tab('adv_email', _('Advanced E-Mail Settings'));
s.tab('sources', _('Blocklist Sources'));
/*
general settings tab
*/
o = s.taboption('general', form.Flag, 'ban_enabled', _('Enabled'), _('Enable the banIP service.'));
o.rmempty = false;
o = s.taboption('general', widgets.NetworkSelect, 'ban_trigger', _('Startup Trigger Interface'), _('List of available network interfaces to trigger the banIP start.'));
o.unspecified = true;
o.nocreate = true;
o.rmempty = true;
o = s.taboption('general', form.Flag, 'ban_autodetect', _('Auto Detection'), _('Detect relevant network interfaces, devices, subnets and protocols automatically.'));
o.rmempty = false;
o = s.taboption('general', widgets.NetworkSelect, 'ban_ifaces', _('Network Interfaces'), _('Select the relevant network interfaces manually.'));
o.depends('ban_autodetect', '0');
o.unspecified = true;
o.multiple = true;
o.nocreate = true;
o.optional = true;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_proto4_enabled', _('IPv4 Support'), _('Enables IPv4 support in banIP.'));
o.depends('ban_autodetect', '0');
o.optional = true;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_proto6_enabled', _('IPv6 Support'), _('Enables IPv6 support in banIP.'));
o.depends('ban_autodetect', '0');
o.optional = true;
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_monitor_enabled', _('Log Monitor'), _('Starts a small log monitor in the background to block suspicious SSH/LuCI login attempts.'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_logsrc_enabled', _('Enable SRC logging'), _('Log suspicious incoming packets - usually dropped.'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_logdst_enabled', _('Enable DST logging'), _('Log suspicious outgoing packets - usually rejected. \
Logging such packets may cause an increase in latency due to it requiring additional system resources.'));
o.rmempty = false;
o = s.taboption('general', form.Flag, 'ban_mail_enabled', _('E-Mail Notification'), _('Send banIP related notification e-mails. \
This needs the installation and setup of the additional \'msmtp\' package.'));
o.rmempty = false;
o = s.taboption('general', form.Value, 'ban_mailreceiver', _('E-Mail Receiver Address'), _('Receiver address for banIP notification e-mails.'));
o.depends('ban_mail_enabled', '1');
o.placeholder = 'name@example.com';
o.rmempty = true;
/*
additional settings tab
*/
o = s.taboption('additional', form.Flag, 'ban_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.'));
o.rmempty = false;
o = s.taboption('additional', form.ListValue, 'ban_nice', _('Service Priority'), _('The selected priority will be used for banIP background processing. \
This change requires a full banIP service restart to take effect.'));
o.value('-20', _('Highest Priority'));
o.value('-10', _('High Priority'));
o.value('0', _('Normal Priority (default)'));
o.value('10', _('Less Priority'));
o.value('19', _('Least Priority'));
o.optional = true;
o.rmempty = true;
o = s.taboption('additional', form.Value, 'ban_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds before banIP processing begins.'));
o.placeholder = '5';
o.datatype = 'range(1,120)';
o.rmempty = true;
o = s.taboption('additional', form.ListValue, 'ban_maxqueue', _('Download Queue'), _('Size of the download queue for download processing in parallel.'));
o.value('1');
o.value('2');
o.value('4');
o.value('8');
o.value('16');
o.value('32');
o.optional = true;
o.rmempty = false;
o = s.taboption('additional', form.Value, 'ban_tmpbase', _('Base Temp Directory'), _('Base Temp Directory used for all banIP related runtime operations.'));
o.placeholder = '/tmp';
o.rmempty = true;
o = s.taboption('additional', form.Value, 'ban_backupdir', _('Backup Directory'), _('Target directory for compressed source list backups.'));
o.placeholder = '/tmp/banIP-Backup';
o.rmempty = true;
o = s.taboption('additional', form.Value, 'ban_reportdir', _('Report Directory'), _('Target directory for IPSet related report files.'));
o.placeholder = '/tmp/banIP-Report';
o.rmempty = true;
o = s.taboption('additional', form.ListValue, 'ban_fetchutil', _('Download Utility'), _('List of supported and fully pre-configured download utilities.'));
o.value('uclient-fetch');
o.value('wget');
o.value('curl');
o.value('aria2c');
o.optional = true;
o.rmempty = true;
o = s.taboption('additional', form.Value, 'ban_fetchparm', _('Download Parameters'), _('Special config options for the selected download utility.'))
o.rmempty = true;
/*
advanced chain settings tab
*/
o = s.taboption('adv_chain', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>Changes on this tab needs a full banIP service restart to take effect.</b></em>';
o = s.taboption('adv_chain', form.ListValue, 'ban_global_settype', _('Global IPSet Type'), _('Set the global IPset type default, to block incoming (SRC) and/or outgoing (DST) packets.'));
o.value('src+dst');
o.value('src');
o.value('dst');
o.rmempty = false;
o = s.taboption('adv_chain', form.ListValue, 'ban_target_src', _('SRC Target'), _('Set the firewall target for all SRC related rules.'));
o.value('DROP');
o.value('REJECT');
o.rmempty = false;
o = s.taboption('adv_chain', form.ListValue, 'ban_target_dst', _('DST Target'), _('Set the firewall target for all DST related rules.'));
o.value('REJECT');
o.value('DROP');
o.rmempty = false;
o = s.taboption('adv_chain', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>Individual IPSet Types</b></em>';
/*
prepare source data
*/
var info, source, sources = [];
if (result[0]) {
sources = result[0].trim().split('\n');
}
o = s.taboption('adv_chain', form.MultiValue, 'ban_settype_src', _('SRC IPSet Type'), _('Set individual SRC type per IPset to block only incoming packets.'));
for (var i = 0; i < sources.length; i++) {
if (sources[i].match(/^\s+\+/)) {
source = sources[i].match(/^\s+\+\s(\w+)\s/)[1].trim();
o.value(source);
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.MultiValue, 'ban_settype_dst', _('DST IPSet Type'), _('Set individual DST type per IPset to block only outgoing packets.'));
for (var i = 0; i < sources.length; i++) {
if (sources[i].match(/^\s+\+/)) {
source = sources[i].match(/^\s+\+\s(\w+)\s/)[1].trim();
o.value(source);
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.MultiValue, 'ban_settype_all', _('SRC+DST IPSet Type'), _('Set individual SRC+DST type per IPset to block incoming and outgoing packets.'));
for (var i = 0; i < sources.length; i++) {
if (sources[i].match(/^\s+\+/)) {
source = sources[i].match(/^\s+\+\s(\w+)\s/)[1].trim();
o.value(source);
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>IPv4 Chains</b></em>';
/*
prepare iptables data
*/
var chain, result_v4=[], result_v6=[];
if (result[1]) {
result_v4 = result[1].trim().split('\n');
} else if (result[2]) {
result_v4 = result[2].trim().split('\n');
}
if (result[2]) {
result_v6 = result[2].trim().split('\n');
} else if (result[1]) {
result_v6 = result[1].trim().split('\n');
}
o = s.taboption('adv_chain', form.DynamicList, 'ban_lan_inputchains_4', _('LAN Input'), _('Default chain used by banIP is \'input_lan_rule\''));
for (var i = 0; i < result_v4.length; i++) {
if (result_v4[i].match(/^Chain input[\w_]+\s+/)) {
chain = result_v4[i].match(/\s+(input[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_lan_forwardchains_4', _('LAN Forward'), _('Default chain used by banIP is \'forwarding_lan_rule\''));
for (var i = 0; i < result_v4.length; i++) {
if (result_v4[i].match(/^Chain forwarding[\w_]+\s+/)) {
chain = result_v4[i].match(/\s+(forwarding[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_wan_inputchains_4', _('WAN Input'), _('Default chain used by banIP is \'input_wan_rule\''));
for (var i = 0; i < result_v4.length; i++) {
if (result_v4[i].match(/^Chain input[\w_]+\s+/)) {
chain = result_v4[i].match(/\s+(input[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_wan_forwardchains_4', _('WAN Forward'), _('Default chain used by banIP is \'forwarding_wan_rule\''));
for (var i = 0; i < result_v4.length; i++) {
if (result_v4[i].match(/^Chain forwarding[\w_]+\s+/)) {
chain = result_v4[i].match(/\s+(forwarding[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>IPv6 Chains</b></em>';
o = s.taboption('adv_chain', form.DynamicList, 'ban_lan_inputchains_6', _('LAN Input'), _('Default chain used by banIP is \'input_lan_rule\''));
for (var i = 0; i < result_v6.length; i++) {
if (result_v6[i].match(/^Chain input[\w_]+\s+/)) {
chain = result_v6[i].match(/\s+(input[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_lan_forwardchains_6', _('LAN Forward'), _('Default chain used by banIP is \'forwarding_lan_rule\''));
for (var i = 0; i < result_v6.length; i++) {
if (result_v6[i].match(/^Chain forwarding[\w_]+\s+/)) {
chain = result_v6[i].match(/\s+(forwarding[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_wan_inputchains_6', _('WAN Input'), _('Default chain used by banIP is \'input_wan_rule\''));
for (var i = 0; i < result_v6.length; i++) {
if (result_v6[i].match(/^Chain input[\w_]+\s+/)) {
chain = result_v6[i].match(/\s+(input[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_chain', form.DynamicList, 'ban_wan_forwardchains_6', _('WAN Forward'), _('Default chain used by banIP is \'forwarding_wan_rule\''));
for (var i = 0; i < result_v6.length; i++) {
if (result_v6[i].match(/^Chain forwarding[\w_]+\s+/)) {
chain = result_v6[i].match(/\s+(forwarding[\w_]+)\s+/)[1].trim();
o.value(chain);
}
}
o.datatype = 'uciname';
o.optional = true;
o.rmempty = true;
/*
advanced log settings tab
*/
o = s.taboption('adv_log', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>Changes on this tab needs a full banIP service restart to take effect.</b></em>';
o = s.taboption('adv_log', form.ListValue, 'ban_loglimit', _('Log Limit'), _('Parse only the last stated number of log entries for suspicious events.'));
o.value('50');
o.value('100');
o.value('250');
o.value('500');
o.rmempty = false;
o = s.taboption('adv_log', form.MultiValue, 'ban_logterms', _('Log Terms'), _('Limit the log monitor to certain log terms.'));
o.value('dropbear');
o.value('sshd');
o.value('luci');
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_log', form.Value, 'ban_logopts_src', _('SRC Log Options'), _('Set special SRC log options, e.g. to set a limit rate.'));
o.nocreate = false;
o.unspecified = true;
o.value('-m limit --limit 2/sec', _('-m limit --limit 2/sec (default)'));
o.value('-m limit --limit 10/sec');
o.optional = true;
o.rmempty = true;
o = s.taboption('adv_log', form.Value, 'ban_logopts_dst', _('DST Log Options'), _('Set special DST log options, e.g. to set a limit rate.'));
o.nocreate = false;
o.unspecified = true;
o.value('-m limit --limit 2/sec', _('-m limit --limit 2/sec (default)'));
o.value('-m limit --limit 10/sec');
o.optional = true;
o.rmempty = true;
/*
advanced email settings tab
*/
o = s.taboption('adv_email', form.Value, 'ban_mailsender', _('E-Mail Sender Address'), _('Sender address for banIP notification E-Mails.'));
o.placeholder = 'no-reply@banIP';
o.rmempty = true;
o = s.taboption('adv_email', form.Value, 'ban_mailtopic', _('E-Mail Topic'), _('Topic for banIP notification E-Mails.'));
o.placeholder = 'banIP notification';
o.rmempty = true;
o = s.taboption('adv_email', form.Value, 'ban_mailprofile', _('E-Mail Profile'), _('Profile used by \'msmtp\' for banIP notification E-Mails.'));
o.placeholder = 'ban_notify';
o.datatype = 'uciname';
o.rmempty = true;
o = s.taboption('adv_email', form.MultiValue, 'ban_mailactions', _('E-Mail Actions'), _('Limit E-Mail trigger to certain banIP actions.'));
o.value('start');
o.value('reload');
o.value('restart');
o.value('refresh');
o.rmempty = true;
/*
blocklist sources tab
*/
o = s.taboption('sources', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>List of supported and fully pre-configured banIP sources.</b></em>';
o = s.taboption('sources', form.MultiValue, 'ban_sources', _('Sources (Info)'));
for (var i = 0; i < sources.length; i++) {
if (sources[i].match(/^\s+\+/)) {
source = sources[i].match(/^\s+\+\s(\w+)\s/)[1].trim();
info = sources[i].slice(35,70).trim();
o.value(source, source + ' (' + info + ')');
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('sources', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>Country selection</b></em>';
/*
prepare country data
*/
var code, country, countries = [];
if (result[3]) {
countries = result[3].trim().split('\n');
}
o = s.taboption('sources', form.DynamicList, 'ban_countries', _('Countries'));
for (var i = 0; i < countries.length; i++) {
code = countries[i].match(/^(\w+);/)[1].trim();
country = countries[i].match(/^\w+;(.*$)/)[1].trim();
o.value(code, country);
}
o.optional = true;
o.rmempty = true;
o = s.taboption('sources', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>ASN selection</b></em>';
o = s.taboption('sources', form.DynamicList, 'ban_asns', _('ASNs'));
o.datatype = 'uinteger';
o.optional = true;
o.rmempty = true;
o = s.taboption('sources', form.DummyValue, '_sub');
o.rawhtml = true;
o.default = '<em><b>Local Sources</b></em>';
o = s.taboption('sources', form.Flag, 'ban_autoblacklist', _('Auto Blacklist'), _('Automatically transfers suspicious IPs from the log to the banIP blacklist during runtime.'));
o.rmempty = false;
o = s.taboption('sources', form.Flag, 'ban_autowhitelist', _('Auto Whitelist'), _('Automatically transfers uplink IPs to the banIP whitelist during runtime.'));
o.rmempty = false;
return m.render();
},
handleReset: null
});

View file

@ -0,0 +1,37 @@
'use strict';
'require view';
'require fs';
'require ui';
return view.extend({
load: function() {
return L.resolveDefault(fs.read_direct('/etc/banip/banip.whitelist'), '');
},
handleSave: function(ev) {
var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n';
return fs.write('/etc/banip/banip.whitelist', value)
.then(function(rc) {
document.querySelector('textarea').value = value;
ui.addNotification(null, E('p', _('Whitelist changes have been saved. Refresh your banIP lists that changes take effect.')), 'info');
}).catch(function(e) {
ui.addNotification(null, E('p', _('Unable to save changes: %s').format(e.message)));
});
},
render: function(whitelist) {
return E([
E('p', {},
_('This is the local banIP whitelist to always allow certain IP/CIDR addresses.<br /> \
<em><b>Please note:</b></em> add only one IPv4 or IPv6 address or per line. Comments introduced with \'#\' are allowed - domains, wildcards and regex are not.')),
E('p', {},
E('textarea', {
'style': 'width: 100% !important; padding: 5px; font-family: monospace',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [ whitelist != null ? whitelist : '' ])
)
]);
},
handleSaveApply: null,
handleReset: null
});

View file

@ -1,100 +1,13 @@
-- Copyright 2018-2019 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
-- stub lua controller for 19.07 backward compatibility
module("luci.controller.banip", package.seeall)
local util = require("luci.util")
local http = require("luci.http")
local i18n = require("luci.i18n")
local json = require("luci.jsonc")
local uci = require("luci.model.uci").cursor()
function index()
if not nixio.fs.access("/etc/config/banip") then
return
end
local e = entry({"admin", "services", "banip"}, firstchild(), _("banIP"), 40)
e.dependent = false
e.acl_depends = { "luci-app-banip" }
entry({"admin", "services", "banip", "tab_from_cbi"}, cbi("banip/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true
entry({"admin", "services", "banip", "ipset"}, template("banip/ipsetview"), _("IPSet-Lookup"), 20).leaf = true
entry({"admin", "services", "banip", "ripe"}, template("banip/ripeview"), _("RIPE-Lookup"), 30).leaf = true
entry({"admin", "services", "banip", "log"}, template("banip/logview"), _("View Logfile"), 40).leaf = true
entry({"admin", "services", "banip", "advanced"}, firstchild(), _("Advanced"), 100)
entry({"admin", "services", "banip", "advanced", "blacklist"}, form("banip/blacklist_tab"), _("Edit Blacklist"), 110).leaf = true
entry({"admin", "services", "banip", "advanced", "whitelist"}, form("banip/whitelist_tab"), _("Edit Whitelist"), 120).leaf = true
entry({"admin", "services", "banip", "advanced", "configuration"}, form("banip/configuration_tab"), _("Edit Configuration"), 130).leaf = true
entry({"admin", "services", "banip", "ipsetview"}, call("ipset_view"), nil).leaf = true
entry({"admin", "services", "banip", "ripeview"}, call("ripe_view"), nil).leaf = true
entry({"admin", "services", "banip", "logview"}, call("log_view"), nil).leaf = true
entry({"admin", "services", "banip", "status"}, call("status_update"), nil).leaf = true
entry({"admin", "services", "banip", "action"}, call("ban_action"), nil).leaf = true
end
function ban_action(name)
if name == "do_refresh" then
luci.sys.call("/etc/init.d/banip refresh >/dev/null 2>&1")
elseif name == "do_reload" then
luci.sys.call("/etc/init.d/banip reload >/dev/null 2>&1")
end
luci.http.prepare_content("text/plain")
luci.http.write("0")
end
function status_update()
local rt_file
local content
rt_file = uci:get("banip", "global", "ban_rtfile") or "/tmp/ban_runtime.json"
if nixio.fs.access(rt_file) then
content = json.parse(nixio.fs.readfile(rt_file) or "")
http.prepare_content("application/json")
http.write_json(content)
end
end
function log_view()
local content = util.trim(util.exec("logread -e 'banIP-' 2>/dev/null")) or ""
if content == "" then
content = "No banIP related logs yet!"
end
http.write(content)
end
function ipset_view(ipset, filter)
local content
if not (ipset or filter) then
return
end
if filter == "false" then
content = util.trim(util.exec("ipset -L " .. ipset .. " 2>/dev/null"))
else
content = util.trim(util.exec("ipset -L " .. ipset .. " 2>/dev/null | grep -e 'packets [1-9]\\|^[A-Z]'"))
end
if content == "" then
content = "IPSet is empty!"
end
http.write(content)
end
function ripe_view(query, input)
local content
if not (query or input) then
return
end
content = util.trim(util.exec("uclient-fetch --no-check-certificate -O- https://stat.ripe.net/data/" ..query.. "/data.json?resource=" ..input.. " 2>/dev/null"))
if content == "" then
content = "No response!"
end
http.write(content)
entry({"admin", "services", "banip"}, firstchild(), _("banIP"), 60).acl_depends = { "luci-app-banip" }
entry({"admin", "services", "banip", "overview"}, view("banip/overview"), _("Overview"), 10)
entry({"admin", "services", "banip", "ipsetreport"}, view("banip/ipsetreport"), _("IPSet Report"), 20)
entry({"admin", "services", "banip", "blacklist"}, view("banip/blacklist"), _("Edit Blacklist"), 30)
entry({"admin", "services", "banip", "whitelist"}, view("banip/whitelist"), _("Edit Whitelist"), 40)
entry({"admin", "services", "banip", "maclist"}, view("banip/maclist"), _("Edit Maclist"), 50)
entry({"admin", "services", "banip", "logread"}, view("banip/logread"), _("Log View"), 60)
end

View file

@ -1,55 +0,0 @@
-- Copyright 2018 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local util = require("luci.util")
local uci = require("luci.model.uci").cursor()
local input = uci:get("banip", "blacklist", "ban_src") or uci:get("banip", "blacklist", "ban_src_6") or "/etc/banip/adblock.blacklist"
if not fs.access(input) then
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
m.reset = false
m.submit = false
return m
end
if fs.stat(input).size >= 102400 then
m = SimpleForm("error", nil,
translate("The file size is too large for online editing in LuCI (&ge; 100 KB). ")
.. translate("Please edit this file directly in a terminal session."))
m.reset = false
m.submit = false
return m
end
m = SimpleForm("edit", nil)
m:append(Template("banip/banip_css"))
m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
translatef("This form allows you to modify the content of the banIP blacklist (%s).<br />", input)
.. translate("Please add only one IPv4 or IPv6 address per line. IP ranges in CIDR notation and comments introduced with '#' are allowed."))
f = s:option(TextValue, "data")
f.datatype = "string"
f.rows = 20
f.rmempty = true
function f.cfgvalue()
return fs.readfile(input) or ""
end
function f.write(self, section, data)
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
end
function f.remove(self, section, value)
return fs.writefile(input, "")
end
function s.handle(self, state, data)
return true
end
return m

View file

@ -1,52 +0,0 @@
-- Copyright 2018 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local util = require("luci.util")
local input = "/etc/config/banip"
if not fs.access(input) then
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
m.reset = false
m.submit = false
return m
end
if fs.stat(input).size >= 102400 then
m = SimpleForm("error", nil,
translate("The file size is too large for online editing in LuCI (&ge; 100 KB). ")
.. translate("Please edit this file directly in a terminal session."))
m.reset = false
m.submit = false
return m
end
m = SimpleForm("edit", nil)
m:append(Template("banip/banip_css"))
m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
translate("This form allows you to modify the content of the main banIP configuration file (/etc/config/banip)."))
f = s:option(TextValue, "data")
f.rows = 20
f.rmempty = true
function f.cfgvalue()
return fs.readfile(input) or ""
end
function f.write(self, section, data)
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
end
function f.remove(self, section, value)
return fs.writefile(input, "")
end
function s.handle(self, state, data)
return true
end
return m

View file

@ -1,215 +0,0 @@
-- Copyright 2018-2019 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local uci = require("luci.model.uci").cursor()
local net = require "luci.model.network".init()
local util = require("luci.util")
local dump = util.ubus("network.interface", "dump", {})
m = Map("banip", translate("banIP"),
translate("Configuration of the banIP package to block ip adresses/subnets via IPSet. ")
..translatef("For further information "
.. "<a href=\"%s\" target=\"_blank\">"
.. "check the online documentation</a>", "https://github.com/openwrt/packages/blob/master/net/banip/files/README.md"))
-- Main banIP Options
s = m:section(NamedSection, "global", "banip")
o1 = s:option(Flag, "ban_enabled", translate("Enable banIP"))
o1.default = o1.disabled
o1.rmempty = false
o2 = s:option(Flag, "ban_automatic", translate("Automatic WAN Interface Detection"))
o2.default = o2.enabled
o2.rmempty = false
o3 = s:option(MultiValue, "ban_iface", translate("Manual WAN Interface Selection"),
translate("Select your preferred interface(s) manually."))
if dump then
local i, v
for i, v in ipairs(dump.interface) do
if v.interface ~= "loopback" then
local device = v.l3_device or v.device or "-"
o3:value(v.interface, " " .. v.interface .. " (" .. device .. ") ")
end
end
end
o3:depends("ban_automatic", 0)
o3.widget = "checkbox"
o3.rmempty = true
o4 = s:option(Flag, "ban_realtime", translate("SSH/LuCI RT Monitor"),
translate("Starts a small log/banIP monitor in the background to block SSH/LuCI brute force attacks in realtime."))
o4.enabled = "true"
o4.default = o4.disabled
o4.rmempty = false
-- Runtime Information
ds = s:option(DummyValue, "_dummy")
ds.template = "banip/runtime"
-- Source Table
bl = m:section(TypedSection, "source", translate("IPSet Sources"))
bl.template = "banip/sourcelist"
name_4 = bl:option(Flag, "ban_src_on", translate("enable IPv4"))
name_4.rmempty = false
name_6 = bl:option(Flag, "ban_src_on_6", translate("enable IPv6"))
name_6.rmempty = false
type = bl:option(ListValue, "ban_src_ruletype", translate("SRC/DST"))
type:value("src")
type:value("dst")
type:value("src+dst")
type.default = "src"
type.rmempty = false
des = bl:option(DummyValue, "ban_src_desc", translate("Description"))
cat = bl:option(DynamicList, "ban_src_cat", translate("ASN/Country"))
cat.datatype = "uciname"
cat.optional = true
-- Extra options
e = m:section(NamedSection, "extra", "banip", translate("Extra Options"),
translate("Options for further tweaking in case the defaults are not suitable for you."))
e1 = e:option(Flag, "ban_debug", translate("Verbose Debug Logging"),
translate("Enable verbose debug logging in case of any processing error."))
e1.rmempty = false
e2 = e:option(Flag, "ban_nice", translate("Low Priority Service"),
translate("Set the nice level to 'low priority' and banIP background processing will take less resources from the system. ")
..translate("This change requires a manual service stop/re-start to take effect."))
e2.disabled = "0"
e2.enabled = "10"
e2.rmempty = false
e3 = e:option(Value, "ban_backupdir", translate("Backup Directory"),
translate("Target directory for banIP backups. Default is '/tmp', please use preferably a non-volatile disk if available."))
e3.datatype = "directory"
e3.default = "/tmp"
e3.rmempty = true
e4 = e:option(Value, "ban_maxqueue", translate("Max. Download Queue"),
translate("Size of the download queue to handle downloads &amp; IPset processing in parallel (default '4'). ")
.. translate("For further performance improvements you can raise this value, e.g. '8' or '16' should be safe."))
e4.default = 4
e4.datatype = "range(1,32)"
e4.rmempty = false
e5 = e:option(ListValue, "ban_sshdaemon", translate("SSH Daemon"),
translate("Select the SSH daemon for logfile parsing, to detect break-in events."))
e5:value("dropbear")
e5:value("sshd")
e5.default = "dropbear"
e5.rmempty = true
e6 = e:option(Flag, "ban_autoblacklist", translate("Local Save Blacklist Addons"),
translate("Blacklist auto addons are stored temporary in the IPSet and saved permanently in the local blacklist. Disable this option to prevent the local save."))
e6.default = e6.enabled
e6.rmempty = true
e7 = e:option(Flag, "ban_autowhitelist", translate("Local Save Whitelist Addons"),
translate("Whitelist auto addons are stored temporary in the IPSet and saved permanently in the local whitelist. Disable this option to prevent the local save."))
e7.default = e7.enabled
e7.rmempty = true
-- Optional Extra Options
e20 = e:option(ListValue, "ban_fetchutil", translate("Download Utility"),
translate("Select your preferred download utility."))
e20:value("uclient-fetch")
e20:value("wget")
e20:value("curl")
e20:value("aria2c")
e20.optional = true
e21 = e:option(Value, "ban_fetchparm", translate("Download Options"),
translate("Special options for the selected download utility, e.g. '--timeout=20 -O'."))
e21.optional = true
e22 = e:option(Value, "ban_triggerdelay", translate("Trigger Delay"),
translate("Additional trigger delay in seconds before banIP processing begins."))
e22.default = 2
e22.datatype = "range(1,60)"
e22.optional = true
e23 = e:option(ListValue, "ban_starttype", translate("Start Type"),
translate("Select the used start type during boot."))
e23:value("start")
e23:value("reload")
e23.default = "start"
e23.optional = true
e30 = e:option(Value, "ban_wan_input_chain", translate("WAN Input Chain IPv4"))
e30.default = "input_wan_rule"
e30.datatype = "uciname"
e30.optional = true
e31 = e:option(Value, "ban_wan_forward_chain", translate("WAN Forward Chain IPv4"))
e31.default = "forwarding_wan_rule"
e31.datatype = "uciname"
e31.optional = true
e32 = e:option(Value, "ban_lan_input_chain", translate("LAN Input Chain IPv4"))
e32.default = "input_lan_rule"
e32.datatype = "uciname"
e32.optional = true
e33 = e:option(Value, "ban_lan_forward_chain", translate("LAN Forward Chain IPv4"))
e33.default = "forwarding_lan_rule"
e33.datatype = "uciname"
e33.optional = true
e34 = e:option(ListValue, "ban_target_src", translate("SRC Target IPv4"))
e34:value("REJECT")
e34:value("DROP")
e34.default = "DROP"
e34.optional = true
e35 = e:option(ListValue, "ban_target_dst", translate("DST Target IPv4"))
e35:value("REJECT")
e35:value("DROP")
e35.default = "REJECT"
e35.optional = true
e36 = e:option(Value, "ban_wan_input_chain_6", translate("WAN Input Chain IPv6"))
e36.default = "input_wan_rule"
e36.datatype = "uciname"
e36.optional = true
e37 = e:option(Value, "ban_wan_forward_chain_6", translate("WAN Forward Chain IPv6"))
e37.default = "forwarding_wan_rule"
e37.datatype = "uciname"
e37.optional = true
e38 = e:option(Value, "ban_lan_input_chain_6", translate("LAN Input Chain IPv6"))
e38.default = "input_lan_rule"
e38.datatype = "uciname"
e38.optional = true
e39 = e:option(Value, "ban_lan_forward_chain_6", translate("LAN Forward Chain IPv6"))
e39.default = "forwarding_lan_rule"
e39.datatype = "uciname"
e39.optional = true
e40 = e:option(ListValue, "ban_target_src_6", translate("SRC Target IPv6"))
e40:value("REJECT")
e40:value("DROP")
e40.default = "DROP"
e40.optional = true
e41 = e:option(ListValue, "ban_target_dst_6", translate("DST Target IPv6"))
e41:value("REJECT")
e41:value("DROP")
e41.default = "REJECT"
e41.optional = true
return m

View file

@ -1,55 +0,0 @@
-- Copyright 2018 Dirk Brenken (dev@brenken.org)
-- This is free software, licensed under the Apache License, Version 2.0
local fs = require("nixio.fs")
local util = require("luci.util")
local uci = require("luci.model.uci").cursor()
local input = uci:get("banip", "whitelist", "ban_src") or uci:get("banip", "whitelist", "ban_src_6") or "/etc/banip/adblock.whitelist"
if not fs.access(input) then
m = SimpleForm("error", nil, translate("Input file not found, please check your configuration."))
m.reset = false
m.submit = false
return m
end
if fs.stat(input).size >= 102400 then
m = SimpleForm("error", nil,
translate("The file size is too large for online editing in LuCI (&ge; 100 KB). ")
.. translate("Please edit this file directly in a terminal session."))
m.reset = false
m.submit = false
return m
end
m = SimpleForm("edit", nil)
m:append(Template("banip/banip_css"))
m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
translatef("This form allows you to modify the content of the banIP whitelist (%s).<br />", input)
.. translate("Please add only one IPv4 or IPv6 address per line. IP ranges in CIDR notation and comments introduced with '#' are allowed."))
f = s:option(TextValue, "data")
f.datatype = "string"
f.rows = 20
f.rmempty = true
function f.cfgvalue()
return fs.readfile(input) or ""
end
function f.write(self, section, data)
return fs.writefile(input, "\n" .. util.trim(data:gsub("\r\n", "\n")) .. "\n")
end
function f.remove(self, section, value)
return fs.writefile(input, "")
end
function s.handle(self, state, data)
return true
end
return m

View file

@ -1,95 +0,0 @@
<style type="text/css">
textarea
{
width: 100% !important;
height: 450px !important;
border: 1px solid #cccccc;
padding: 5px;
font-size: 12px;
font-family: monospace;
resize: none;
white-space: pre;
overflow-wrap: normal;
overflow-x: scroll;
}
select[readonly],
textarea[readonly]
{
width: 100% !important;
height: 450px !important;
border: 1px solid #cccccc;
padding: 5px;
font-size: 12px;
font-family: monospace;
resize: none;
pointer-events: auto;
cursor: auto;
}
.table.cbi-section-table .th,
.table.cbi-section-table .td,
.cbi-section-table-cell,
.cbi-section-table-row,
.tr[data-title]::before
{
text-align: left !important;
vertical-align: top;
margin-left: 0px;
padding-left: 2px;
}
.table.cbi-section-table .th
{
white-space: nowrap;
}
.cbi-section-table-row > .cbi-value-field .cbi-input-select,
.table.cbi-section-table select
{
width: 70px;
}
.item,
.add-item
{
white-space: nowrap;
width: 8.2em;
}
.cbi-input-checkbox
{
height: 1em;
}
.cbi-button
{
-webkit-appearance: menulist;
}
.runtime
{
color: #37c;
font-weight: bold;
display: inline-block;
width: 100%;
padding-top: 0.5rem;
}
.ripe_desc
{
font-style: italic;
display: inline-block;
width: 100%;
height: 20px;
margin: 2px 2px;
}
.button_running
{
display: inline-block;
width: 16px;
height: 16px;
margin: 0 5px;
}
</style>

View file

@ -1,67 +0,0 @@
<%#
Copyright 2018 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%-
local util = require("luci.util")
local ipsets = util.split(util.trim(util.exec("ipset -n -L 2>/dev/null | sort")), "\n", nil, true) or {}
-%>
<%+header%>
<%+banip/banip_css%>
<script type="text/javascript">
//<![CDATA[
function ipset_view()
{
var div_ipsets = document.getElementById("div_ipsets");
var ipset = div_ipsets.querySelector("#s_ipsets").value;
var filter = document.getElementById("checkbox_filter").checked;
var view = document.getElementById("view_id");
if (!ipset)
{
return;
}
view.value = "<%:Loading ...%>";
new XHR().get('<%=luci.dispatcher.build_url("admin", "services", "banip")%>/ipsetview/' + ipset + "/" + filter, null,
function(x)
{
if (!x)
{
view.value = "<%:No response!%>";
return;
}
view.value = x.responseText;
});
}
//]]>
</script>
<div class="cbi-map">
<div class="cbi-section">
<div class="cbi-section-descr"><%:Check the current available IPSets.%></div>
<div class="cbi-section-node">
<div class="table cbi-section-table">
<div class="tr cbi-section-table-row">
<div class="td left">
<input class="cbi-input-checkbox" data-update="click change" type="checkbox" id="checkbox_filter" name="checkbox_filter" value="1" checked="checked" />
<label for="checkbox_filter"><%_Show only set member with packet counter &gt; 0%></label>
</div>
</div>
<div class="tr cbi-section-table-row" id="div_ipsets">
<div class="td left">
<select id="s_ipsets" class="cbi-input-select cbi-button" style="width:15em">
<%- for _, z in ipairs(ipsets) do -%><option value="<%=z%>"><%=z%></option><%- end -%>
</select>
<input type="button" id="bt_load" value="<%:Load%>" onclick="ipset_view()" class="cbi-button cbi-button-add" />
</div>
</div>
</div>
</div>
<textarea id="view_id" readonly="readonly" wrap="off" value=""></textarea>
</div>
</div>
<%+footer%>

View file

@ -1,36 +0,0 @@
<%#
Copyright 2018 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%+header%>
<%+banip/banip_css%>
<script type="text/javascript">
//<![CDATA[
function log_update()
{
XHR.poll(-1, '<%=luci.dispatcher.build_url("admin", "services", "banip", "logview")%>', null,
function(x)
{
if (!x)
{
return;
}
var view = document.getElementById("view_id");
view.value = x.responseText;
view.scrollTop = view.scrollHeight;
});
}
window.onload = log_update();
//]]>
</script>
<div class="cbi-map">
<div class="cbi-section">
<div class="cbi-section-descr"><%:The syslog output, pre-filtered for banIP related messages only.%></div>
<textarea id="view_id" readonly="readonly" wrap="off" value=""></textarea>
</div>
</div>
<%+footer%>

View file

@ -1,107 +0,0 @@
<%#
Copyright 2018 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%+header%>
<%+banip/banip_css%>
<script type="text/javascript">
//<![CDATA[
function ripe_desc()
{
var div_ripe = document.getElementById("div_ripe");
var query = div_ripe.querySelector("#s_ripe").value;
var output = document.getElementById("ripe_desc");
switch (query) {
case "geoloc":
output.innerHTML = "<%:This data call returns geolocation information for the given IP space, or for announced IP prefixes in the case of ASNs.%>";
break;
case "as-overview":
output.innerHTML = "<%:This data call shows general informations about an ASN like its announcement status and the name of its holder according to the WHOIS service.%>";
break;
case "announced-prefixes":
output.innerHTML = "<%:This data call returns all announced prefixes for a given ASN.%>";
break;
case "network-info":
output.innerHTML = "<%:This data call returns the containing prefix and announcing ASN of a given IP address.%>";
break;
case "country-resource-list":
output.innerHTML = "<%:This data call lists the Internet resources associated with a country, including ASNs, IPv4 ranges and IPv4/6 CIDR prefixes.%>";
break;
case "whois":
output.innerHTML = "<%:This data call returns whois information from the relevant Regional Internet Registry and Routing Registry.%>";
break;
case "dns-chain":
output.innerHTML = "<%:This data call returns the recursive chain of DNS forward (A/AAAA/CNAME) and reverse (PTR) records starting form either a hostname or an IP address.%>";
break;
case "iana-registry-info":
output.innerHTML = "<%:This data call gives access to various data sources maintained by IANA.%>";
break;
default:
output.innerHTML = "";
}
}
function ripe_view()
{
var div_ripe = document.getElementById("div_ripe");
var query = div_ripe.querySelector("#s_ripe").value;
var input = document.getElementById("ripe_input");
var view = document.getElementById("view_id");
if (!input.value)
{
return;
}
view.value = "<%:Loading ...%>";
new XHR().get('<%=luci.dispatcher.build_url("admin", "services", "banip")%>/ripeview/' + query + "/" + input.value, null,
function(x)
{
if (!x)
{
view.value = "<%:No response!%>";
return;
}
view.value = x.responseText;
});
}
window.onload = ripe_desc;
//]]>
</script>
<div class="cbi-map">
<div class="cbi-section">
<div class="cbi-section-descr"><%_The RIPEstat Data API is the public data interface provided by RIPE NCC, for details look <a href="https://stat.ripe.net/docs/data_api" target="_blank" rel="noopener noreferrer">here</a>.%></div>
<div class="cbi-section-node">
<div class="table cbi-section-table">
<div class="tr cbi-section-table-row">
<div class="td left">
<input class="cbi-input-text" style="width:20em" type="text" id="ripe_input" placeholder="<%:Enter IP/CIDR/ASN/ISO%>" value="" />
</div>
</div>
<div class="tr cbi-section-table-row" id="div_ripe">
<div class="td left">
<select id="s_ripe" class="cbi-input-select cbi-button" style="width:15em" onchange="ripe_desc()">
<option value="geoloc" selected="selected"><%:Geo Location%></option>
<option value="as-overview"><%:ASN Overview%></option>
<option value="announced-prefixes"><%:ASN Prefixes%></option>
<option value="network-info"><%:IP/ASN Mapping%></option>
<option value="country-resource-list"><%:Country Resources%></option>
<option value="whois"><%:Whois Information%></option>
<option value="dns-chain"><%:DNS Chain%></option>
<option value="iana-registry-info"><%:IANA Information%></option>
</select>
<input type="button" id="bt_load" value="<%:Load%>" onclick="ripe_view()" class="cbi-button cbi-button-add" /><br /><br />
<span class="ripe_desc" id="ripe_desc"></span>
</div>
</div>
</div>
</div>
<textarea id="view_id" readonly="readonly" wrap="off" value=""></textarea>
</div>
</div>
<%+footer%>

View file

@ -1,164 +0,0 @@
<%#
Copyright 2018-2019 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%+banip/banip_css%>
<script type="text/javascript">
//<![CDATA[
function status_update(json)
{
var btn1 = document.getElementById("btn1");
var btn1_running = document.getElementById("btn1_running");
var btn2 = document.getElementById("btn2");
var btn2_running = document.getElementById("btn2_running");
var view = document.getElementById("value_1");
var input = json.data.status;
btn1.value = "<%:Refresh%>";
btn1.name = "do_refresh";
btn2.value = "<%:Reload%>";
btn2.name = "do_reload";
view.innerHTML = input || "-";
if (input != "running")
{
btn1.disabled = false;
running(btn1_running, 0);
btn2.disabled = false;
running(btn2_running, 0);
}
view = document.getElementById("value_2");
input = json.data.version;
view.innerHTML = input || "-";
view = document.getElementById("value_3");
input = json.data.util_info;
view.innerHTML = input || "-";
view = document.getElementById("value_4");
input = json.data.ipset_info;
view.innerHTML = input || "-";
view = document.getElementById("value_5");
input = json.data.backup_dir;
view.innerHTML = input || "-";
view = document.getElementById("value_6");
input = json.data.last_run;
view.innerHTML = input || "-";
}
function btn_action(action)
{
var btn1 = document.getElementById("btn1");
var btn1_running = document.getElementById("btn1_running");
var btn2 = document.getElementById("btn2");
var btn2_running = document.getElementById("btn2_running");
if (action.name === "do_refresh")
{
btn1.disabled = true;
btn2.disabled = true;
running(btn1_running, 1);
}
else if (action.name === "do_reload")
{
btn1.disabled = true;
btn2.disabled = true;
running(btn2_running, 1);
}
new XHR.get('<%=luci.dispatcher.build_url("admin", "services", "banip")%>/action/' + action.name, null,
function(x)
{
if (!x)
{
return;
}
});
}
function running(element, state)
{
if (state === 1)
{
var running_html = '<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" width="16" height="16" style="vertical-align:middle" />';
element.innerHTML = running_html;
}
else
{
element.innerHTML = '';
}
}
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "banip", "status")%>', null,
function(x, json_info)
{
if (!x || !json_info)
{
return;
}
status_update(json_info)
});
XHR.poll(-1, '<%=luci.dispatcher.build_url("admin", "services", "banip", "status")%>', null,
function(x, json_info)
{
if (!x || !json_info)
{
return;
}
status_update(json_info)
});
//]]>
</script>
<h3><%:Runtime Information%></h3>
<div class="cbi-value" id="status_1">
<label class="cbi-value-title" for="status_1"><%:banIP Status%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_1">-</span>
</div>
</div>
<div class="cbi-value" id="status_2">
<label class="cbi-value-title" for="status_2"><%:banIP Version%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_2">-</span>
</div>
</div>
<div class="cbi-value" id="status_3">
<label class="cbi-value-title" for="status_3"><%:Download Utility, RT Monitor%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_3">-</span>
</div>
</div>
<div class="cbi-value" id="status_4">
<label class="cbi-value-title" for="status_4"><%:IPSet Information%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_4">-</span>
</div>
</div>
<div class="cbi-value" id="status_5">
<label class="cbi-value-title" for="status_5"><%:Backup Directory%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_5">-</span>
</div>
</div>
<div class="cbi-value" id="status_6">
<label class="cbi-value-title" for="status_6"><%:Last Run%></label>
<div class="cbi-value-field">
<span class="runtime" id="value_6">-</span>
</div>
</div>
<hr />
<div class="cbi-value" id="button_1">
<label class="cbi-value-title" for="button_1"><%:Refresh IPSets%></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-apply" id="btn1" type="button" name="do_refresh" value="<%:Refresh%>" onclick="btn_action(this)" />
<span id="btn1_running" class="btn_running"></span>
</div>
</div>
<div class="cbi-value" id="button_2">
<label class="cbi-value-title" for="button_2"><%:Reload IPSet Sources%></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-reset" id="btn2" type="button" name="do_reload" value="<%:Reload%>" onclick="btn_action(this)" />
<span id="btn2_running" class="btn_running"></span>
</div>
</div>

View file

@ -1,47 +0,0 @@
<%#
Copyright 2018 Dirk Brenken (dev@brenken.org)
This is free software, licensed under the Apache License, Version 2.0
-%>
<%-
local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
-%>
<%+banip/banip_css%>
<div class="cbi-section" id="cbi-<%=self.config%>-<%=self.sectiontype%>">
<% if self.title then -%>
<h3><%=self.title%></h3>
<%- end %>
<div class="cbi-section-descr"><%=self.description%></div>
<div class="cbi-section-node">
<div class="table cbi-section-table">
<div class="tr cbi-section-table-titles <%=anonclass%>">
<%- for i, k in pairs(self.children) do -%>
<div class="th cbi-section-table-cell">
<%-=k.title-%>
</div>
<%- end -%>
</div>
<%- local section, scope, isempty = true
for i, k in ipairs(self:cfgsections()) do
section = k
local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
isempty = false
scope = { valueheader = "cbi/cell_valueheader", valuefooter = "cbi/cell_valuefooter" }
-%>
<div class="tr cbi-section-table-row" id="cbi-<%=self.config%>-<%=section%>"<%=sectiontitle%>>
<%-
for k, node in ipairs(self.children) do
node:render(section, scope or {})
end
if not scope.cbid:match("ban_src_cat") then
-%>
<div class="td cbi-value-field">&#160;</div>
<%- end -%>
</div>
<%- end -%>
</div>
</div>
</div>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,66 @@
{
"admin/services/banip": {
"title": "banIP",
"order": "60",
"action": {
"type": "alias",
"path": "admin/services/banip/overview"
},
"depends": {
"acl": [ "luci-app-banip" ],
"fs": {
"/usr/bin/banip.sh": "executable",
"/etc/init.d/banip": "executable"
},
"uci": { "banip": true }
}
},
"admin/services/banip/overview": {
"title": "Overview",
"order": 10,
"action": {
"type": "view",
"path": "banip/overview"
}
},
"admin/services/banip/ipsetreport": {
"title": "IPSet Report",
"order": 20,
"action": {
"type": "view",
"path": "banip/ipsetreport"
}
},
"admin/services/banip/blacklist": {
"title": "Edit Blacklist",
"order": 30,
"action": {
"type": "view",
"path": "banip/blacklist"
}
},
"admin/services/banip/whitelist": {
"title": "Edit Whitelist",
"order": 40,
"action": {
"type": "view",
"path": "banip/whitelist"
}
},
"admin/services/banip/maclist": {
"title": "Edit Maclist",
"order": 50,
"action": {
"type": "view",
"path": "banip/maclist"
}
},
"admin/services/banip/logread": {
"title": "Log View",
"order": 60,
"action": {
"type": "view",
"path": "banip/logread"
}
}
}

View file

@ -1,10 +1,37 @@
{
"luci-app-banip": {
"description": "Grant UCI access for luci-app-banip",
"read": {
"uci": [ "banip" ]
},
"description": "Grant access to LuCI app banIP",
"write": {
"uci": [ "banip" ],
"file": {
"/etc/banip/*": [ "read" ],
"/etc/banip/banip.blacklist": [ "write" ],
"/etc/banip/banip.whitelist": [ "write" ],
"/etc/banip/banip.maclist": [ "write" ]
}
},
"read": {
"cgi-io": [ "exec" ],
"file": {
"/var/run/banip.pid": [ "read" ],
"/tmp/ban_runtime.json": [ "read" ],
"/sbin/logread -e banIP-": [ "exec" ],
"/usr/sbin/logread -e banIP-": [ "exec" ],
"/usr/sbin/iptables -L": [ "exec" ],
"/usr/sbin/ip6tables -L": [ "exec" ],
"/etc/init.d/banip list" : [ "exec" ],
"/etc/init.d/banip refresh" : [ "exec" ],
"/etc/init.d/banip reload" : [ "exec" ],
"/etc/init.d/banip restart" : [ "exec" ],
"/etc/init.d/banip suspend" : [ "exec" ],
"/etc/init.d/banip resume" : [ "exec" ],
"/etc/init.d/banip report gen" : [ "exec" ],
"/etc/init.d/banip report json" : [ "exec" ],
"/etc/init.d/banip timer list" : [ "exec" ],
"/etc/init.d/banip timer remove [0-9]*" : [ "exec" ],
"/etc/init.d/banip timer add * [0-9]* [0-9*]* [1-7,-*]*" : [ "exec" ],
"/etc/init.d/banip query *" : [ "exec" ]
},
"uci": [ "banip" ]
}
}