v2.1. Refactoring, fixes & improvements.

This commit is contained in:
gSpot
2024-11-06 15:30:03 +03:00
parent 06219e9328
commit 0cc02a7ddd
18 changed files with 282 additions and 477 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ruantiblock
PKG_VERSION:=2.0.0
PKG_VERSION:=2.1.0
PKG_RELEASE:=1
LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock
@@ -43,97 +43,61 @@ return view.extend({
},
formatNftJson(data) {
let output = { 'sink': [] };
if(data.sink.nftables && data.sink.nftables.length > 1) {
let rules = [];
for(let i of data.sink.nftables) {
if(i.rule) {
let instance = (i.rule.comment === ' ') ? '-main-' : i.rule.comment;
let proto, bytes;
i.rule.expr.forEach(e => {
if(e.match && e.match.left && e.match.left.meta && e.match.left.meta.key && e.match.left.meta.key == "l4proto") {
proto = e.match.right;
}
else if(e.counter) {
bytes = e.counter.bytes;
};
});
rules.push([ instance, proto, bytes ]);
} else {
continue;
};
};
if(rules.length > 0) {
output.sink = rules;
};
};
if(data.sink_local && data.sink_local.nftables && data.sink_local.nftables.length > 1) {
output.sink_local = [];
let rules = [];
for(let i of data.sink_local.nftables) {
if(i.rule) {
let instance = (i.rule.comment === ' ') ? '-main-' : i.rule.comment;
let proto, bytes;
i.rule.expr.forEach(e => {
if(e.match && e.match.left && e.match.left.meta && e.match.left.meta.key && e.match.left.meta.key == "l4proto") {
proto = e.match.right;
}
else if(e.counter) {
bytes = e.counter.bytes;
};
});
rules.push([ instance, proto, bytes ]);
} else {
continue;
};
};
if(rules.length > 0) {
output.sink_local = rules;
};
};
function parseDnsmasqData(set) {
let sArray = [];
if(set.nftables && set.nftables.length > 1) {
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 ]);
};
});
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 && e.match.left && e.match.left.payload) {
set = e.match.right.replace('@', '');
}
else if(e.counter) {
bytes = e.counter.bytes;
};
});
output.rules.push([ set, bytes ]);
};
return sArray;
};
if(data.dnsmasq) {
output.dnsmasq = parseDnsmasqData(data.dnsmasq);
};
if(data.dnsmasq_bypass) {
output.dnsmasq_bypass = parseDnsmasqData(data.dnsmasq_bypass);
};
if(data.dnsmasq_user_instances) {
output.dnsmasq_user_instances = [];
if(data.dnsmasq_user_instances && data.dnsmasq_user_instances.length > 1) {
for(let i of data.dnsmasq_user_instances) {
if(i.nftables) {
let name;
i.nftables.forEach(e => {
if(e.set) {
name = e.set.name;
};
});
output.dnsmasq_user_instances.push([ name, parseDnsmasqData(i) ]);
function parseDnsmasqData(set) {
let sArray = [];
if(set.nftables && set.nftables.length > 1) {
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;
};
if(data.dnsmasq) {
output.dnsmasq = parseDnsmasqData(data.dnsmasq);
};
if(data.dnsmasq_bypass) {
output.dnsmasq_bypass = parseDnsmasqData(data.dnsmasq_bypass);
};
if(data.dnsmasq_user_instances) {
output.dnsmasq_user_instances = [];
if(data.dnsmasq_user_instances && data.dnsmasq_user_instances.length > 1) {
for(let i of data.dnsmasq_user_instances) {
if(i.nftables) {
let name;
i.nftables.forEach(e => {
if(e.set) {
name = e.set.name;
};
});
output.dnsmasq_user_instances.push([ name, parseDnsmasqData(i) ]);
};
};
};
};
};
return output;
},
@@ -228,20 +192,11 @@ return view.extend({
let nft_data = this.formatNftJson(data);
if(nft_data.sink.length > 0) {
for(let i of nft_data.sink) {
let elem = document.getElementById('sink.' + i[0] + '.' + (i[1] || 'all'));
if(nft_data.rules.length > 0) {
for(let [set, bytes] of nft_data.rules) {
let elem = document.getElementById('rules.' + set);
if(elem) {
elem.textContent = i[2];
};
};
};
if(nft_data.sink_local && nft_data.sink_local.length > 0) {
for(let i of nft_data.sink_local) {
let elem = document.getElementById('sink_local.' + i[0] + '.' + (i[1] || 'all'));
if(elem) {
elem.textContent = i[2];
elem.textContent = bytes;
};
};
};
@@ -267,6 +222,14 @@ return view.extend({
});
},
formatRuleDescription(s) {
return (s.length >= 1) ? (
s.replace(/^c\.?(.*)/, '$1 CIDR').replace(/^i\.?(.*)/, '$1 IP')
.replace(/^d\.?(.*)/, '$1 dnsmasq').replace(/^onion\.?(.*)/, '$1 onion')
.replace(/^bi/, 'bypass IP').replace(/^bd/, 'bypass dnsmasq')
) : '';
},
load() {
return fs.exec_direct(tools.execPath, [ 'html-info' ], 'json').catch(e => {
ui.addNotification(null, E('p', _('Unable to execute or read contents')
@@ -286,10 +249,10 @@ return view.extend({
let update_status = null,
user_entries = null,
sink = null,
sink_local = null,
rules = null,
dnsmasq = null,
dnsmasqUserInstances = null;
dnsmasqUserInstances = null,
dnsmasqBypass = null;
if(data) {
if(data.status === 'enabled') {
@@ -350,87 +313,42 @@ return view.extend({
let nft_data = this.formatNftJson(data);
if(nft_data.sink) {
let table = E('table', { 'class': 'table' }, [
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%' },
_('Instance')),
E('th', { 'class': 'th left' }, _('Protocol')),
_('Match-set')),
E('th', { 'class': 'th left' }, _('Description')),
E('th', { 'class': 'th left' }, _('Bytes')),
]),
]);
for(let i of nft_data.sink) {
let instance = i[0];
let proto = (i[1] === undefined) ? _('all') : i[1];
let bytes = i[2];
if(!instance) {
for(let [set, bytes] of nft_data.rules) {
if(!set) {
continue;
};
table.append(
table_rules.append(
E('tr', { 'class': 'tr' }, [
E('td',{
'class' : 'td left',
'data-title': _('Match-set'),
}, set),
E('td', {
'class' : 'td left',
'data-title': _('Instance'),
}, instance),
'data-title': _('Description'),
}, this.formatRuleDescription(set)),
E('td', {
'class' : 'td left',
'data-title': _('Protocol'),
}, proto),
E('td', {
'class' : 'td left',
'id' : 'sink.' + instance + '.' + (i[1] || 'all'),
'id' : 'rules.' + set,
'data-title': _('Bytes'),
}, bytes),
])
);
};
sink = E([
E('h3', {}, _('Transit traffic')),
table,
]);
};
if(nft_data.sink_local) {
let table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th left', 'style': 'min-width:33%' },
_('Instance')),
E('th', { 'class': 'th left' }, _('Protocol')),
E('th', { 'class': 'th left' }, _('Bytes')),
]),
]);
for(let i of nft_data.sink_local) {
let instance = i[0];
let proto = (i[1] === undefined) ? _('all') : i[1];
let bytes = i[2];
if(!instance) {
continue;
};
table.append(
E('tr', { 'class': 'tr' }, [
E('td', {
'class' : 'td left',
'data-title': _('Instance'),
}, instance),
E('td', {
'class' : 'td left',
'data-title': _('Protocol'),
}, proto),
E('td', {
'class' : 'td left',
'id' : 'sink_local.' + instance + '.' + (i[1] || 'all'),
'data-title': _('Bytes'),
}, bytes),
])
);
};
sink_local = E([
E('h3', {}, _('Local traffic')),
table,
rules = E([
E('h3', {}, _('Nftables rules')),
table_rules,
]);
};
@@ -462,6 +380,17 @@ return view.extend({
};
};
if(nft_data.dnsmasq_bypass) {
let rdbTableWrapper = E('div', {
'id' : 'rdbTableWrapper',
'style': 'width:100%'
}, this.makeDnsmasqTable(nft_data.dnsmasq_bypass, _('Dnsmasq bypass')));
dnsmasqBypass = E([
rdbTableWrapper,
]);
};
poll.add(L.bind(this.pollInfo, this), this.pollInterval);
} else {
update_status = E('em', {}, _('Status') + ' : ' + _('disabled'));
@@ -477,7 +406,7 @@ return view.extend({
E('div', { 'class': 'cbi-section-node' }, update_status)
),
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' }, sink)
E('div', { 'class': 'cbi-section-node' }, rules)
),
];
@@ -490,10 +419,10 @@ return view.extend({
);
}
if(sink_local) {
if(dnsmasqBypass) {
layout.splice(5, 0,
E('div', { 'class': 'cbi-section fade-in' },
E('div', { 'class': 'cbi-section-node' }, sink_local)
E('div', { 'class': 'cbi-section-node' }, dnsmasqBypass)
)
);
};
@@ -248,12 +248,14 @@ return view.extend({
o = s.taboption('tor_tab', form.Value, 'tor_trans_port',
_('Transparent proxy port'));
o.rmempty = false;
o.default = tools.defaultConfig.tor_trans_port;
o.datatype = 'port';
// ONION_DNS_ADDR
o = s.taboption('tor_tab', form.Value, 'onion_dns_addr',
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
o.rmempty = false;
o.default = tools.defaultConfig.onion_dns_addr;
o.validate = this.validateIpPort;
// Torrc edit dialog
@@ -274,7 +276,7 @@ return view.extend({
o.multiple = false;
o.noaliases = true;
o.rmempty = false;
o.default = 'tun0';
o.default = tools.defaultConfig.if_vpn;
// VPN_GW_IP
o = s.taboption('vpn_tab', form.Value, 'vpn_gw_ip',
@@ -307,17 +309,20 @@ return view.extend({
o = s.taboption('tproxy_tab', form.Value, 't_proxy_port_tcp',
_('Transparent proxy TCP port'));
o.rmempty = false;
o.default = tools.defaultConfig.t_proxy_port_tcp;
o.datatype = 'port';
// T_PROXY_ALLOW_UDP
o = s.taboption('tproxy_tab', form.Flag, 't_proxy_allow_udp',
_('Send UDP traffic to transparent proxy'));
o.rmempty = false;
o.default = 0;
// T_PROXY_PORT_UDP
o = s.taboption('tproxy_tab', form.Value, 't_proxy_port_udp',
_('Transparent proxy UDP port'));
o.rmempty = false;
o.default = tools.defaultConfig.t_proxy_port_udp;
o.datatype = 'port';
@@ -331,6 +336,7 @@ return view.extend({
o.value('1', 'Tor');
o.value('2', 'VPN');
o.value('3', _('Transparent proxy'));
o.default = tools.defaultConfig.proxy_mode;
// BLLIST_PRESET
let bllist_preset = s.taboption('blacklist_tab', form.ListValue,
@@ -375,6 +381,7 @@ return view.extend({
_('Enable full proxy mode'));
o.description = _('All traffic of the specified hosts passes through the proxy, without a blacklist');
o.rmempty = false;
o.default = 0;
// FPROXY_LIST
o = s.taboption('blacklist_tab', form.DynamicList, 'fproxy_list',
@@ -531,7 +538,7 @@ return view.extend({
_('Enabled'),
);
o.rmempty = false;
o.default = '1';
o.default = 1;
o.editable = true;
o.modalonly = false;
@@ -547,14 +554,7 @@ return view.extend({
o.value('1', 'Tor');
o.value('2', 'VPN');
o.value('3', _('Transparent proxy'));
o.default = '2';
o.modalonly = true;
// U_SKIP_MARKED_PACKETS
o = ss.taboption('u_main_tab', form.Flag, 'u_skip_marked_packets',
_('Lowest priority'));
o.description = _('This proxy will receive traffic last, even after the main blacklist');
o.rmempty = false;
o.default = tools.defaultConfig.proxy_mode;
o.modalonly = true;
// U_ENABLE_FPROXY
@@ -562,6 +562,7 @@ return view.extend({
_('Enable full proxy mode'));
o.description = _('All traffic of the specified hosts passes through the proxy, without a blacklist');
o.rmempty = false;
o.default = 0;
o.modalonly = true;
// U_FPROXY_LIST
@@ -579,6 +580,7 @@ return view.extend({
o = ss.taboption('u_tor_tab', form.Value, 'u_tor_trans_port',
_('Transparent proxy port'));
o.rmempty = false;
o.default = tools.defaultConfig.tor_trans_port;
o.datatype = 'port';
o.modalonly = true;
@@ -586,6 +588,7 @@ return view.extend({
o = ss.taboption('u_tor_tab', form.Value, 'u_onion_dns_addr',
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
o.rmempty = false;
o.default = tools.defaultConfig.onion_dns_addr;
o.validate = this.validateIpPort;
o.modalonly = true;
@@ -599,7 +602,7 @@ return view.extend({
o.multiple = false;
o.noaliases = true;
o.rmempty = false;
o.default = 'tun0';
o.default = tools.defaultConfig.if_vpn;
o.modalonly = true;
// U_VPN_GW_IP
@@ -625,19 +628,22 @@ return view.extend({
o = ss.taboption('u_tproxy_tab', form.Value, 'u_t_proxy_port_tcp',
_('Transparent proxy TCP port'));
o.rmempty = false;
o.default = tools.defaultConfig.t_proxy_port_tcp;
o.datatype = 'port';
o.modalonly = true;
// U_T_PROXY_ALLOW_UDP
o = ss.taboption('u_tproxy_tab', form.Flag, 'u_t_proxy_allow_udp',
_('Send UDP traffic to transparent proxy'));
o.rmempty = false;
o.rmempty = false;
o.default = 0;
o.modalonly = true;
// U_T_PROXY_PORT_UDP
o = ss.taboption('u_tproxy_tab', form.Value, 'u_t_proxy_port_udp',
_('Transparent proxy UDP port'));
o.rmempty = false;
o.default = tools.defaultConfig.t_proxy_port_udp;
o.datatype = 'port';
o.modalonly = true;
@@ -34,25 +34,25 @@ document.head.append(E('style', {'type': 'text/css'},
`));
return baseclass.extend({
appName : 'ruantiblock',
execPath : '/usr/bin/ruantiblock',
tokenFile : '/var/run/ruantiblock.token',
parsersDir : '/usr/libexec/ruantiblock',
dnsmasqCfgDirsRoot: '/tmp',
torrcFile : '/etc/tor/torrc',
userEntriesFile : '/etc/ruantiblock/user_entries',
userListsDir : '/etc/ruantiblock/user_lists',
bypassEntriesFile : '/etc/ruantiblock/bypass_entries',
fqdnFilterFile : '/etc/ruantiblock/fqdn_filter',
ipFilterFile : '/etc/ruantiblock/ip_filter',
grExcludedNetsFile: '/etc/ruantiblock/gr_excluded_nets',
grExcludedSldFile : '/etc/ruantiblock/gr_excluded_sld',
crontabFile : '/etc/crontabs/root',
infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>',
infoLabelRunning : '<span class="label-status running">' + _('Enabled') + '</span>',
infoLabelUpdating : '<span class="label-status updating">' + _('Updating') + '</span>',
infoLabelStopped : '<span class="label-status stopped">' + _('Disabled') + '</span>',
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
appName : 'ruantiblock',
execPath : '/usr/bin/ruantiblock',
tokenFile : '/var/run/ruantiblock.token',
parsersDir : '/usr/libexec/ruantiblock',
dnsmasqCfgDirsRoot : '/tmp',
torrcFile : '/etc/tor/torrc',
userEntriesFile : '/etc/ruantiblock/user_entries',
userListsDir : '/etc/ruantiblock/user_lists',
bypassEntriesFile : '/etc/ruantiblock/bypass_entries',
fqdnFilterFile : '/etc/ruantiblock/fqdn_filter',
ipFilterFile : '/etc/ruantiblock/ip_filter',
grExcludedNetsFile : '/etc/ruantiblock/gr_excluded_nets',
grExcludedSldFile : '/etc/ruantiblock/gr_excluded_sld',
crontabFile : '/etc/crontabs/root',
infoLabelStarting : '<span class="label-status starting">' + _('Starting') + '</span>',
infoLabelRunning : '<span class="label-status running">' + _('Enabled') + '</span>',
infoLabelUpdating : '<span class="label-status updating">' + _('Updating') + '</span>',
infoLabelStopped : '<span class="label-status stopped">' + _('Disabled') + '</span>',
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
blacklistPresets: {
'ruantiblock-fqdn': [ 'ruantiblock', 'fqdn', 'https://github.com/gSpotx2f/ruantiblock_blacklist' ],
@@ -64,6 +64,15 @@ return baseclass.extend({
'antifilter-ip' : [ '*antifilter', 'ip', 'https://antifilter.download' ],
},
defaultConfig: {
'proxy_mode' : '2',
'tor_trans_port' : '9040',
'onion_dns_addr' : '127.0.0.1#9053',
'if_vpn' : 'tun0',
't_proxy_port_tcp': '1100',
't_proxy_port_udp': '1100',
},
callInitStatus: rpc.declare({
object: 'luci',
method: 'getInitList',
@@ -107,11 +116,11 @@ return baseclass.extend({
return (v && typeof(v) === 'string') ? v.trim().replace(/\r?\n/g, '') : v;
},
makeStatusString: function(
app_status_code,
bllist_preset,
bllist_module,
vpn_route_status_code) {
makeStatusString(
app_status_code,
bllist_preset,
bllist_module,
vpn_route_status_code) {
let app_status_label;
let spinning = '';
@@ -226,7 +235,7 @@ return baseclass.extend({
let textarea = document.getElementById('widget.modal_content');
let value = textarea.value.trim().replace(/\r\n/g, '\n') + '\n';
return fs.write(this.file, value).then(async rc => {
return fs.write(this.file, value).then(rc => {
textarea.value = value;
ui.addNotification(null, E('p', _('Contents have been saved.')),
'info');
+4 -13
View File
@@ -272,9 +272,6 @@ msgstr "Список хостов, которые исключаются из о
msgid "Loading"
msgstr "Загрузка"
msgid "Local traffic"
msgstr "Локальный трафик"
msgid "Log"
msgstr "Лог"
@@ -287,14 +284,11 @@ msgstr "Уровни логирования"
msgid "Logread not found"
msgstr "Logread не найден"
msgid "Lowest priority"
msgstr "Самый низкий приоритет"
msgid "Main settings"
msgstr "Основные настройки"
msgid "Match-set"
msgstr "Правило"
msgstr "Сет"
msgid "Message"
msgstr "Сообщение"
@@ -314,6 +308,9 @@ msgstr "Настройки модуля"
msgid "Name"
msgstr "Имя"
msgid "Nftables rules"
msgstr "Правила Nftables"
msgid "No Sсhedule"
msgstr "Нет расписания"
@@ -502,9 +499,6 @@ msgid ""
msgstr ""
"Служба будет выключена и все данные блэклиста будут удалены. Продолжить?"
msgid "This proxy will receive traffic last, even after the main blacklist"
msgstr "В этот прокси трафик будет попадать в последнюю очередь, даже после основного блэклиста"
msgid "Time"
msgstr "Время"
@@ -523,9 +517,6 @@ msgstr "Конфигурационный файл Tor"
msgid "Tor mode"
msgstr "Режим Tor"
msgid "Transit traffic"
msgstr "Транзитный трафик"
msgid "Transparent proxy"
msgstr "Прозрачный прокси"
@@ -253,9 +253,6 @@ msgstr ""
msgid "Loading"
msgstr ""
msgid "Local traffic"
msgstr ""
msgid "Log"
msgstr ""
@@ -268,9 +265,6 @@ msgstr ""
msgid "Logread not found"
msgstr ""
msgid "Lowest priority"
msgstr ""
msgid "Main settings"
msgstr ""
@@ -295,6 +289,9 @@ msgstr ""
msgid "Name"
msgstr ""
msgid "Nftables rules"
msgstr ""
msgid "No Sсhedule"
msgstr ""
@@ -457,9 +454,6 @@ msgid ""
"Continue?"
msgstr ""
msgid "This proxy will receive traffic last, even after the main blacklist"
msgstr ""
msgid "Time"
msgstr ""
@@ -478,9 +472,6 @@ msgstr ""
msgid "Tor mode"
msgstr ""
msgid "Transit traffic"
msgstr ""
msgid "Transparent proxy"
msgstr ""