mirror of
https://github.com/gSpotx2f/ruantiblock_openwrt.git
synced 2026-05-14 06:30:59 +00:00
v1.0. Support for nftables and dnsmasq 2.88.
This commit is contained in:
@@ -5,7 +5,18 @@
|
||||
'require view';
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
document.head.append(E('style', {'type': 'text/css'},
|
||||
`
|
||||
.log-entries-count {
|
||||
margin: 0 0 5px 5px;
|
||||
font-weight: bold;
|
||||
opacity: 0.7;
|
||||
}
|
||||
`));
|
||||
|
||||
return view.extend({
|
||||
pollInterval : L.env.pollinterval,
|
||||
|
||||
secToTimeString: function(value) {
|
||||
let string = '';
|
||||
if(/^\d+$/.test(value)) {
|
||||
@@ -31,11 +42,52 @@ return view.extend({
|
||||
return string;
|
||||
},
|
||||
|
||||
formatNftJson: function(data) {
|
||||
let output = { 'rules': [] };
|
||||
if(data.rules.nftables && data.rules.nftables.length > 1) {
|
||||
for(let i of data.rules.nftables) {
|
||||
if(!i.rule) continue;
|
||||
|
||||
let set, bytes;
|
||||
i.rule.expr.forEach(e => {
|
||||
if(e.match) {
|
||||
set = e.match.right.replace('@', '');
|
||||
}
|
||||
else if(e.counter) {
|
||||
bytes = e.counter.bytes;
|
||||
};
|
||||
});
|
||||
output.rules.push([ set, bytes ]);
|
||||
|
||||
};
|
||||
|
||||
function parseDnsmasqData(set) {
|
||||
let sArray = [];
|
||||
if(data[set].nftables && data[set].nftables.length > 1) {
|
||||
data[set].nftables.forEach(e => {
|
||||
if(e.set && e.set.elem) {
|
||||
e.set.elem.forEach(i => {
|
||||
if(i.elem) {
|
||||
sArray.push([ i.elem.val, i.elem.expires ]);
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
return sArray;
|
||||
};
|
||||
|
||||
output.dnsmasq = parseDnsmasqData('dnsmasq');
|
||||
output.dnsmasq_u = parseDnsmasqData('dnsmasq_u');
|
||||
};
|
||||
return output;
|
||||
},
|
||||
|
||||
makeDnsmasqTable: function(ipDataArray) {
|
||||
let lines = `<tr class="tr"><td class="td center">${_('No entries available...')}</td></tr>`;
|
||||
let ipTable = E('table', { 'id': 'ipTable', 'class': 'table' });
|
||||
|
||||
if(ipDataArray.length > 1) {
|
||||
if(ipDataArray.length > 0) {
|
||||
lines = [];
|
||||
ipDataArray.forEach((e, i) => {
|
||||
if(e) {
|
||||
@@ -57,18 +109,23 @@ return view.extend({
|
||||
|
||||
try {
|
||||
ipTable.insertAdjacentHTML('beforeend', lines);
|
||||
} catch(err) {
|
||||
if(err.name === 'SyntaxError') {
|
||||
} catch(e) {
|
||||
if(e.name === 'SyntaxError') {
|
||||
ui.addNotification(null,
|
||||
E('p', {}, _('HTML/XML error') + ': ' + err.message), 'error');
|
||||
E('p', {}, _('HTML/XML error') + ': ' + e.message), 'error');
|
||||
};
|
||||
throw err;
|
||||
throw e;
|
||||
};
|
||||
|
||||
return ipTable;
|
||||
return E([
|
||||
E('div', { 'class': 'log-entries-count' },
|
||||
`${_('Entries')}: ${ipDataArray.length}`
|
||||
),
|
||||
ipTable,
|
||||
]);
|
||||
},
|
||||
|
||||
infoPoll: function() {
|
||||
pollInfo: function() {
|
||||
return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
|
||||
ui.addNotification(null, E('p', _('Unable to execute or read contents')
|
||||
+ ': %s [ %s ]'.format(e.message, tools.execPath)
|
||||
@@ -81,7 +138,7 @@ return view.extend({
|
||||
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch(err) {};
|
||||
} catch(e) {};
|
||||
|
||||
if(data.status === 'enabled') {
|
||||
let date = document.getElementById('last_blacklist_update.date');
|
||||
@@ -111,34 +168,27 @@ return view.extend({
|
||||
};
|
||||
};
|
||||
|
||||
if(data.iptables) {
|
||||
for(let [k, v] of Object.entries(data.iptables)) {
|
||||
if(k === '_dummy') continue;
|
||||
let nft_data = this.formatNftJson(data);
|
||||
|
||||
let elem = document.getElementById('iptables.' + k);
|
||||
if(nft_data.rules.length > 0) {
|
||||
for(let [set, bytes] of nft_data.rules) {
|
||||
let elem = document.getElementById('rules.' + set);
|
||||
if(elem) {
|
||||
elem.textContent = v;
|
||||
elem.textContent = bytes;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if(data.ipset) {
|
||||
for(let [k, v] of Object.entries(data.ipset)) {
|
||||
if(k === '_dummy') continue;
|
||||
|
||||
let elem0 = document.getElementById('ipset.' + k + '.' + '0');
|
||||
let elem1 = document.getElementById('ipset.' + k + '.' + '1');
|
||||
if(elem0 && elem1) {
|
||||
elem0.textContent = v[0];
|
||||
elem1.textContent = v[1];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if(data.dnsmasq) {
|
||||
if(nft_data.dnsmasq.length > 0) {
|
||||
let rdTableWrapper = document.getElementById('rdTableWrapper');
|
||||
rdTableWrapper.innerHTML = '';
|
||||
rdTableWrapper.append(this.makeDnsmasqTable(data.dnsmasq));
|
||||
rdTableWrapper.append(this.makeDnsmasqTable(nft_data.dnsmasq));
|
||||
};
|
||||
|
||||
if(nft_data.dnsmasq_u.length > 0) {
|
||||
let rduTableWrapper = document.getElementById('rduTableWrapper');
|
||||
rduTableWrapper.innerHTML = '';
|
||||
rduTableWrapper.append(this.makeDnsmasqTable(nft_data.dnsmasq_u));
|
||||
};
|
||||
} else {
|
||||
if(poll.active()) {
|
||||
@@ -163,12 +213,12 @@ return view.extend({
|
||||
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch(err) {};
|
||||
} catch(e) {};
|
||||
|
||||
let update_status = null,
|
||||
iptables = null,
|
||||
ipset = null,
|
||||
dnsmasq = null;
|
||||
rules = null,
|
||||
dnsmasq = null,
|
||||
dnsmasq_u = null;
|
||||
if(data) {
|
||||
if(data.status === 'enabled') {
|
||||
update_status = E('table', { 'class': 'table' });
|
||||
@@ -211,8 +261,10 @@ return view.extend({
|
||||
);
|
||||
};
|
||||
|
||||
if(data.iptables) {
|
||||
let table_iptables = E('table', { 'class': 'table' }, [
|
||||
let nft_data = this.formatNftJson(data);
|
||||
|
||||
if(nft_data.rules) {
|
||||
let table_rules = E('table', { 'class': 'table' }, [
|
||||
E('tr', { 'class': 'tr table-titles' }, [
|
||||
E('th', { 'class': 'th left', 'style': 'min-width:33%' },
|
||||
_('Match-set')),
|
||||
@@ -220,76 +272,33 @@ return view.extend({
|
||||
]),
|
||||
]);
|
||||
|
||||
for(let [k, v] of Object.entries(data.iptables)) {
|
||||
if(k === '_dummy') continue;
|
||||
|
||||
table_iptables.append(
|
||||
for(let [set, bytes] of nft_data.rules) {
|
||||
table_rules.append(
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', {
|
||||
E('td',{
|
||||
'class' : 'td left',
|
||||
'data-title': _('Match-set'),
|
||||
}, k),
|
||||
}, set + ' (' + set.replace(/^c/, 'CIDR').replace(/^i/, 'IP').replace(/^d/, 'dnsmasq').replace(/u$/, '-user') + ')'),
|
||||
E('td', {
|
||||
'class' : 'td left',
|
||||
'id' : 'iptables.' + k,
|
||||
'id' : 'rules.' + set,
|
||||
'data-title': _('Bytes'),
|
||||
}, v),
|
||||
}, bytes),
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
iptables = E([
|
||||
E('h3', {}, _('Iptables rules')),
|
||||
table_iptables,
|
||||
rules = E([
|
||||
E('h3', {}, _('Nftables rules')),
|
||||
table_rules,
|
||||
]);
|
||||
};
|
||||
|
||||
if(data.ipset) {
|
||||
let table_ipset = E('table', { 'class': 'table' },
|
||||
E('tr', { 'class': 'tr table-titles' }, [
|
||||
E('th', { 'class': 'th left', 'style': 'min-width:33%' },
|
||||
_('Name')),
|
||||
E('th', { 'class': 'th left' },
|
||||
_('Size in memory')),
|
||||
E('th', { 'class': 'th left' },
|
||||
_('Number of entries')),
|
||||
])
|
||||
);
|
||||
|
||||
for(let [k, v] of Object.entries(data.ipset)) {
|
||||
if(k === '_dummy') continue;
|
||||
|
||||
table_ipset.append(
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', {
|
||||
'class': 'td left',
|
||||
'data-title': _('Name'),
|
||||
}, k),
|
||||
E('td', {
|
||||
'class' : 'td left',
|
||||
'id' : 'ipset.' + k + '.' + '0',
|
||||
'data-title': _('Size in memory'),
|
||||
}, v[0]),
|
||||
E('td', {
|
||||
'class' : 'td left',
|
||||
'id' : 'ipset.' + k + '.' + '1',
|
||||
'data-title': _('Number of entries'),
|
||||
}, v[1]),
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
ipset = E([
|
||||
E('h3', {}, _('Ipset')),
|
||||
table_ipset,
|
||||
]);
|
||||
};
|
||||
|
||||
if(data.dnsmasq) {
|
||||
if(nft_data.dnsmasq) {
|
||||
let rdTableWrapper = E('div', {
|
||||
'id' : 'rdTableWrapper',
|
||||
'style': 'width:100%'
|
||||
}, this.makeDnsmasqTable(data.dnsmasq));
|
||||
}, this.makeDnsmasqTable(nft_data.dnsmasq));
|
||||
|
||||
dnsmasq = E([
|
||||
E('h3', {}, _('Dnsmasq')),
|
||||
@@ -297,7 +306,19 @@ return view.extend({
|
||||
]);
|
||||
};
|
||||
|
||||
poll.add(L.bind(this.infoPoll, this));
|
||||
if(nft_data.dnsmasq_u) {
|
||||
let rduTableWrapper = E('div', {
|
||||
'id' : 'rduTableWrapper',
|
||||
'style': 'width:100%'
|
||||
}, this.makeDnsmasqTable(nft_data.dnsmasq_u));
|
||||
|
||||
dnsmasq_u = E([
|
||||
E('h3', {}, _('Dnsmasq') + ' - ' + _('User entries')),
|
||||
rduTableWrapper,
|
||||
]);
|
||||
};
|
||||
|
||||
poll.add(L.bind(this.pollInfo, this), this.pollInterval);
|
||||
} else {
|
||||
update_status = E('em', {}, _('Status') + ' : ' + _('disabled'));
|
||||
};
|
||||
@@ -311,15 +332,14 @@ return view.extend({
|
||||
E('div', { 'class': 'cbi-section-node' }, update_status)
|
||||
),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, iptables)
|
||||
),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, ipset)
|
||||
E('div', { 'class': 'cbi-section-node' }, rules)
|
||||
),
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, dnsmasq)
|
||||
),
|
||||
|
||||
E('div', { 'class': 'cbi-section fade-in' },
|
||||
E('div', { 'class': 'cbi-section-node' }, dnsmasq_u)
|
||||
),
|
||||
]);
|
||||
},
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ return view.extend({
|
||||
btn_destroy.onclick = L.bind(this.dialogDestroy, this);
|
||||
|
||||
layout_append(btn_destroy, _('Shutdown'),
|
||||
_('Complete service shutdown, as well as deleting ipsets and blacklist data'));
|
||||
_('Complete service shutdown, as well as deleting nftsets and blacklist data'));
|
||||
|
||||
this.setAppStatus(status_array, [
|
||||
status_string,
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
'require view.ruantiblock.tools as tools';
|
||||
|
||||
return view.extend({
|
||||
parsers: {},
|
||||
parsers : {},
|
||||
|
||||
appStatusCode : null,
|
||||
appStatusCode: null,
|
||||
|
||||
depends: function(elem, key, array, empty=true) {
|
||||
depends : function(elem, key, array, empty=true) {
|
||||
if(empty && array.length === 0) {
|
||||
elem.depends(key, '_dummy');
|
||||
} else {
|
||||
@@ -111,18 +111,17 @@ return view.extend({
|
||||
s.anonymous = true;
|
||||
s.addremove = false;
|
||||
|
||||
|
||||
/* Main settings tab */
|
||||
|
||||
s.tab('main_settings', _('Main settings'));
|
||||
|
||||
// PROXY_MODE
|
||||
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||
o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
|
||||
_('Proxy mode'));
|
||||
o.value('1', 'Tor');
|
||||
o.value('2', 'VPN');
|
||||
o.value('3', _('Transparent proxy'));
|
||||
};
|
||||
o = s.taboption('main_settings', form.ListValue, 'proxy_mode',
|
||||
_('Proxy mode'));
|
||||
o.value('1', 'Tor');
|
||||
o.value('2', 'VPN');
|
||||
o.value('3', _('Transparent proxy'));
|
||||
|
||||
// PROXY_LOCAL_CLIENTS
|
||||
let proxy_local_clients = s.taboption('main_settings', form.Flag, 'proxy_local_clients',
|
||||
@@ -140,9 +139,9 @@ return view.extend({
|
||||
o.description = _('Update blacklist after system startup');
|
||||
o.rmempty = false;
|
||||
|
||||
// IPSET_CLEAR_SETS
|
||||
o = s.taboption('main_settings', form.Flag, 'ipset_clear_sets',
|
||||
_('Clean up ipsets before updating blacklist'));
|
||||
// NFTSET_CLEAR_SETS
|
||||
o = s.taboption('main_settings', form.Flag, 'nftset_clear_sets',
|
||||
_('Clean up nftsets before updating blacklist'));
|
||||
o.description = _('Reduces RAM consumption during update');
|
||||
o.rmempty = false;
|
||||
|
||||
@@ -160,70 +159,68 @@ return view.extend({
|
||||
o.datatype = "ip4addr";
|
||||
|
||||
|
||||
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
|
||||
/* Tor tab */
|
||||
/* Tor tab */
|
||||
|
||||
s.tab('tor_settings', _('Tor mode'));
|
||||
s.tab('tor_settings', _('Tor mode'));
|
||||
|
||||
// TOR_TRANS_PORT
|
||||
o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
|
||||
_('Transparent proxy port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
// TOR_TRANS_PORT
|
||||
o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
|
||||
_('Transparent proxy port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
|
||||
//TOR_ALLOW_UDP
|
||||
o = s.taboption('tor_settings', form.Flag, 'tor_allow_udp',
|
||||
_("Send UDP traffic to Tor"));
|
||||
o.rmempty = false;
|
||||
//TOR_ALLOW_UDP
|
||||
o = s.taboption('tor_settings', form.Flag, 'tor_allow_udp',
|
||||
_("Send UDP traffic to Tor"));
|
||||
o.rmempty = false;
|
||||
|
||||
// ONION_DNS_ADDR
|
||||
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
|
||||
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
|
||||
o.rmempty = false;
|
||||
o.validate = this.validateIpPort;
|
||||
// ONION_DNS_ADDR
|
||||
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
|
||||
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
|
||||
o.rmempty = false;
|
||||
o.validate = this.validateIpPort;
|
||||
|
||||
// Torrc edit dialog
|
||||
o = s.taboption('tor_settings', form.Button, '_torrc_btn',
|
||||
_('Tor configuration file'));
|
||||
o.onclick = () => torrc_edit.show();
|
||||
o.inputtitle = _('Edit');
|
||||
o.inputstyle = 'edit btn';
|
||||
// Torrc edit dialog
|
||||
o = s.taboption('tor_settings', form.Button, '_torrc_btn',
|
||||
_('Tor configuration file'));
|
||||
o.onclick = () => torrc_edit.show();
|
||||
o.inputtitle = _('Edit');
|
||||
o.inputstyle = 'edit btn';
|
||||
|
||||
|
||||
/* VPN tab */
|
||||
/* VPN tab */
|
||||
|
||||
s.tab('vpn_settings', _('VPN mode'));
|
||||
s.tab('vpn_settings', _('VPN mode'));
|
||||
|
||||
// IF_VPN
|
||||
o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
|
||||
_('VPN interface'));
|
||||
o.multiple = false;
|
||||
o.noaliases = true;
|
||||
o.rmempty = false;
|
||||
o.default = 'tun0';
|
||||
// IF_VPN
|
||||
o = s.taboption('vpn_settings', widgets.DeviceSelect, 'if_vpn',
|
||||
_('VPN interface'));
|
||||
o.multiple = false;
|
||||
o.noaliases = true;
|
||||
o.rmempty = false;
|
||||
o.default = 'tun0';
|
||||
|
||||
|
||||
/* Proxy tab */
|
||||
/* Proxy tab */
|
||||
|
||||
s.tab('proxy_settings', _('Transparent proxy mode'));
|
||||
s.tab('proxy_settings', _('Transparent proxy mode'));
|
||||
|
||||
// T_PROXY_PORT_TCP
|
||||
o = s.taboption('proxy_settings', form.Value, 't_proxy_port_tcp',
|
||||
_('Transparent proxy TCP port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
// T_PROXY_PORT_TCP
|
||||
o = s.taboption('proxy_settings', form.Value, 't_proxy_port_tcp',
|
||||
_('Transparent proxy TCP port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
|
||||
//T_PROXY_ALLOW_UDP
|
||||
o = s.taboption('proxy_settings', form.Flag, 't_proxy_allow_udp',
|
||||
_("Send UDP traffic to transparent proxy"));
|
||||
o.rmempty = false;
|
||||
//T_PROXY_ALLOW_UDP
|
||||
o = s.taboption('proxy_settings', form.Flag, 't_proxy_allow_udp',
|
||||
_("Send UDP traffic to transparent proxy"));
|
||||
o.rmempty = false;
|
||||
|
||||
// T_PROXY_PORT_UDP
|
||||
o = s.taboption('proxy_settings', form.Value, 't_proxy_port_udp',
|
||||
_('Transparent proxy UDP port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
};
|
||||
// T_PROXY_PORT_UDP
|
||||
o = s.taboption('proxy_settings', form.Value, 't_proxy_port_udp',
|
||||
_('Transparent proxy UDP port'));
|
||||
o.rmempty = false;
|
||||
o.datatype = "port";
|
||||
|
||||
|
||||
/* Blacklist module tab */
|
||||
|
||||
Reference in New Issue
Block a user