v0.9.2. New blacklist source: ruabtiblock. Allowed hosts option. Configuration variable changes. Removed total-proxy.

This commit is contained in:
gSpot
2022-05-05 18:28:32 +03:00
parent 6f3a4efcfb
commit 1b2db6e708
25 changed files with 560 additions and 564 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=0.9.1-2
PKG_VERSION:=0.9.2-0
LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock
LUCI_PKGARCH:=all
@@ -17,10 +17,9 @@ return view.extend({
disableButtons: function(bool, btn, elems=[]) {
let btn_start = elems[1] || document.getElementById("btn_start");
let btn_destroy = elems[5] || document.getElementById("btn_destroy");
let btn_destroy = elems[4] || document.getElementById("btn_destroy");
let btn_enable = elems[2] || document.getElementById("btn_enable");
let btn_update = elems[4] || document.getElementById("btn_update");
let btn_tp = elems[3] || document.getElementById("btn_tp");
let btn_update = elems[3] || document.getElementById("btn_update");
btn_start.disabled = bool;
btn_update.disabled = bool;
@@ -30,15 +29,11 @@ return view.extend({
} else {
btn_enable.disabled = bool;
};
if(btn_tp) {
btn_tp.disabled = bool;
};
},
getAppStatus: function() {
return Promise.all([
fs.exec(tools.execPath, [ 'raw-status' ]),
fs.exec(tools.execPath, [ 'total-proxy-status' ]),
fs.exec(tools.execPath, [ 'vpn-route-status' ]),
tools.getInitStatus(tools.appName),
L.resolveDefault(fs.read(tools.tokenFile), 0),
@@ -62,14 +57,12 @@ return view.extend({
};
let app_status_code = (force_app_code) ? force_app_code : status_array[0].code;
let tp_status_code = status_array[1].code;
let vpn_route_status_code = status_array[2].code;
let enabled_flag = status_array[3];
let vpn_route_status_code = status_array[1].code;
let enabled_flag = status_array[2];
let proxy_local_clients = section.proxy_local_clients;
let proxy_mode = section.proxy_mode;
let bllist_mode = section.bllist_mode;
let bllist_preset = section.bllist_preset;
let bllist_module = section.bllist_module;
let bllist_source = section.bllist_source;
let btn_enable = elems[2] || document.getElementById('btn_enable');
if(enabled_flag == true) {
@@ -84,24 +77,9 @@ return view.extend({
btn_enable.className = btn_style_negative;
};
let btn_tp = elems[3] || document.getElementById('btn_tp');
if(btn_tp) {
if(tp_status_code == 0) {
btn_tp.onclick = ui.createHandlerFn(
this, this.appAction, 'total-proxy-off', 'btn_tp');
btn_tp.textContent = _('Enabled');
btn_tp.className = btn_style_positive;
} else {
btn_tp.onclick = ui.createHandlerFn(
this, this.appAction, 'total-proxy-on', 'btn_tp');
btn_tp.textContent = _('Disabled');
btn_tp.className = btn_style_negative;
};
};
let btn_start = elems[1] || document.getElementById('btn_start');
let btn_update = elems[4] || document.getElementById('btn_update');
let btn_destroy = elems[5] || document.getElementById('btn_destroy');
let btn_update = elems[3] || document.getElementById('btn_update');
let btn_destroy = elems[4] || document.getElementById('btn_destroy');
let btnStartStateOn = () => {
btn_start.onclick = ui.createHandlerFn(
@@ -122,17 +100,11 @@ return view.extend({
btnStartStateOn();
btn_destroy.disabled = false;
btn_update.disabled = false;
if(btn_tp) {
btn_tp.disabled = false;
};
}
else if(app_status_code == 2) {
this.disableButtons(false, null, elems);
btnStartStateOff();
btn_update.disabled = true;
if(btn_tp) {
btn_tp.disabled = true;
};
}
else if(app_status_code == 3) {
btnStartStateOff();
@@ -151,10 +123,8 @@ return view.extend({
(elems[0] || document.getElementById("status")).innerHTML = tools.makeStatusString(
app_status_code,
proxy_mode,
bllist_mode,
bllist_preset,
bllist_module,
bllist_source,
tp_status_code,
vpn_route_status_code);
if(!poll.active()) {
@@ -291,16 +261,6 @@ return view.extend({
}, _('Enable'));
layout_append(btn_enable, _('Run at startup'));
let btn_tp = E('button', {
'id' : 'btn_tp',
'name' : 'btn_tp',
'class': btn_style_positive,
}, _('Enable'));
if(proxy_local_clients == '0') {
layout_append(btn_tp, _('Total-proxy'),
_('All traffic goes through the proxy without applying rules'));
};
let btn_update = E('button', {
'id' : 'btn_update',
'name' : 'btn_update',
@@ -323,7 +283,6 @@ return view.extend({
status_string,
btn_start,
btn_enable,
btn_tp,
btn_update,
btn_destroy,
]);
@@ -1,9 +1,9 @@
'use strict';
'require fs';
'require uci';
'require form';
'require ui';
'require tools.widgets as widgets';
'require uci';
'require ui';
'require view';
'require view.ruantiblock.tools as tools';
@@ -29,20 +29,6 @@ return view.extend({
+ ` ${_('One of the following:')}\n - ${_('valid IP address')}\n - ${_('valid address#port')}\n`;
},
CBIBlockTitle: form.DummyValue.extend({
string: null,
renderWidget: function(section_id, option_index, cfgvalue) {
this.title = this.description = null;
return E([
E('label', { 'class': 'cbi-value-title' }),
E('div', { 'class': 'cbi-value-field' },
E('b', {}, this.string)
),
]);
},
}),
load: function() {
return Promise.all([
L.resolveDefault(fs.exec(tools.execPath, [ 'raw-status' ]), 1),
@@ -132,43 +118,47 @@ return view.extend({
_("Apply proxy rules to router application traffic"));
proxy_local_clients.rmempty = false;
// USE_LOGGER
o = s.taboption('main_settings', form.Flag, 'use_logger',
// ENABLE_LOGGING
o = s.taboption('main_settings', form.Flag, 'enable_logging',
_('Logging events'));
o.rmempty = false;
// DEF_TOTAL_PROXY
o = s.taboption('main_settings', form.Flag, 'def_total_proxy',
_("Enable the 'total-proxy' option at startup"));
o.rmempty = false;
o.default = 0;
o.depends('proxy_local_clients', '0');
// IPSET_CLEAR_SETS
o = s.taboption('main_settings', form.Flag, 'ipset_clear_sets',
_('Clean up ipsets before updating blacklist'));
o.description = _('Reduces RAM consumption during update');
o.rmempty = false;
// ALOWED_HOSTS_MODE
o = s.taboption('main_settings', form.ListValue, 'alowed_hosts_mode',
_('Host filter'));
o.value('0', _('Disabled'));
o.value('1', _('Only listed hosts'));
o.value('2', _('All hosts except listed'));
o.description = _('Restriction of hosts that are allowed to bypass blocking');
// ALOWED_HOSTS_LIST
o = s.taboption('main_settings', form.DynamicList, 'alowed_hosts_list',
_('IP addresses of hosts'));
o.datatype = "ip4addr";
if(this.appStatusCode == 1 || this.appStatusCode == 2) {
/* Tor tab */
s.tab('tor_settings', _('Tor mode'));
// IF_LAN
o = s.taboption('tor_settings', widgets.DeviceSelect, 'if_lan',
_('LAN interface'));
o.multiple = false;
o.noaliases = true;
o.optional = true;
// TOR_TRANS_PORT
o = s.taboption('tor_settings', form.Value, 'tor_trans_port',
_('Transparent proxy port for iptables rules'));
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;
// ONION_DNS_ADDR
o = s.taboption('tor_settings', form.Value, 'onion_dns_addr',
_("Optional DNS resolver for '.onion' zone"), '<code>ipaddress#port</code>');
@@ -208,32 +198,27 @@ return view.extend({
Object.entries(this.availableParsers).forEach(
e => bllist_module.value(e[1], e[0]));
// BLLIST_MODE
let bllist_mode = s.taboption('parser_settings', form.ListValue,
'bllist_mode', _('Module operation mode'));
bllist_mode.value('ip');
bllist_mode.value('fqdn');
// BLLIST_PRESET
let bllist_preset = s.taboption('parser_settings', form.ListValue,
'bllist_preset', _('Blacklist update mode'));
bllist_preset.description = _("Blacklist sources") + ':';
Object.entries(tools.blacklistPresets).forEach(e => {
bllist_preset.value(e[0], `${e[1][0]} - ${e[1][1]}`);
});
let bllist_sources = {};
Object.values(tools.blacklistPresets).forEach(v => {bllist_sources[v[0]] = v[2]});
Object.entries(bllist_sources).forEach(e => {
bllist_preset.description += `<br />${e[0]} - <a href="${e[1]}" target="_blank">${e[1]}</a>`;
});
// BLLIST_SOURCE
let bllist_source = s.taboption('parser_settings', form.ListValue,
'bllist_source', _('Blacklist source'));
bllist_source.description = _("Options") + ':';
for(let [k, v] of Object.entries(tools.blacklistSources)) {
bllist_source.value(k);
bllist_source.description += `<br />${k} - <a href="${v}" target="_blank">${v}</a>`;
};
o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_ip');
o.string = _('IP configuration') + ':';
// IP_LIMIT
o = s.taboption('parser_settings', form.Value, 'ip_limit', _("IP limit"));
// BLLIST_IP_LIMIT
o = s.taboption('parser_settings', form.Value, 'bllist_ip_limit', _("IP limit"));
o.description = _("The number of IP addresses in the subnet, upon reaching which the entire '/24' subnet is added to the list");
o.rmempty = false;
o.datatype = 'uinteger';
// OPT_EXCLUDE_NETS
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_nets');
// BLLIST_GR_EXCLUDED_NETS
o = s.taboption('parser_settings', form.DynamicList, 'bllist_gr_excluded_nets');
o.title = _('IP subnet patterns (/24) that are excluded from optimization');
o.description = _('e.g:') + ' <code>192.168.1.</code>';
o.placeholder = _('e.g:') + ' 192.168.1.';
@@ -242,45 +227,42 @@ return view.extend({
+ ' ' + _('net pattern') + ' (' + _('e.g:') + ' 192.168.3.)\n';
};
// SUMMARIZE_IP
o = s.taboption('parser_settings', form.Flag, 'summarize_ip',
// BLLIST_SUMMARIZE_IP
o = s.taboption('parser_settings', form.Flag, 'bllist_summarize_ip',
_("Summarize IP ranges"));
o.rmempty = false;
// SUMMARIZE_CIDR
o = s.taboption('parser_settings', form.Flag, 'summarize_cidr',
// BLLIST_SUMMARIZE_CIDR
o = s.taboption('parser_settings', form.Flag, 'bllist_summarize_cidr',
_("Summarize '/24' networks"));
o.rmempty = false;
o = s.taboption('parser_settings', this.CBIBlockTitle, '_dummy_fqdn');
o.string = _('FQDN configuration') + ':';
// SD_LIMIT
o = s.taboption('parser_settings', form.Value, 'sd_limit',
// BLLIST_SD_LIMIT
o = s.taboption('parser_settings', form.Value, 'bllist_sd_limit',
_("Subdomains limit"));
o.description = _('The number of subdomains in the domain, upon reaching which the entire 2nd level domain is added to the list');
o.rmempty = false;
o.datatype = 'uinteger';
// OPT_EXCLUDE_SLD
o = s.taboption('parser_settings', form.DynamicList, 'opt_exclude_sld',
// BLLIST_GR_EXCLUDED_SLD
o = s.taboption('parser_settings', form.DynamicList, 'bllist_gr_excluded_sld',
_('2nd level domains that are excluded from optimization'));
o.description = _('e.g:') + ' <code>livejournal.com</code>';
o.placeholder = _('e.g:') + ' livejournal.com';
o.datatype = "hostname";
// USE_IDN
o = s.taboption('parser_settings', form.Flag, 'use_idn',
// BLLIST_ENABLE_IDN
o = s.taboption('parser_settings', form.Flag, 'bllist_enable_idn',
_("Convert cyrillic domains to punycode"));
o.rmempty = false;
// ALT_NSLOOKUP
o = s.taboption('parser_settings', form.Flag, 'alt_nslookup',
// BLLIST_ALT_NSLOOKUP
o = s.taboption('parser_settings', form.Flag, 'bllist_alt_nslookup',
_('Use optional DNS resolver'));
o.rmempty = false;
// ALT_DNS_ADDR
o = s.taboption('parser_settings', form.Value, 'alt_dns_addr',
// BLLIST_ALT_DNS_ADDR
o = s.taboption('parser_settings', form.Value, 'bllist_alt_dns_addr',
_("Optional DNS resolver"), '<code>ipaddress[#port]</code>');
o.rmempty = false;
o.validate = this.validateIpPort;
@@ -290,26 +272,26 @@ return view.extend({
s.tab('entries_filter_tab', _('Blacklist entry filters'));
// IP_FILTER
o = s.taboption('entries_filter_tab', form.Flag, 'ip_filter',
// BLLIST_IP_FILTER
o = s.taboption('entries_filter_tab', form.Flag, 'bllist_ip_filter',
_("Enable IP filter"));
o.description = _('Exclude IP addresses from blacklist by IP filter patterns');
o.rmempty = false;
// IP_FILTER edit dialog
// BLLIST_IP_FILTER_FILE edit dialog
o = s.taboption('entries_filter_tab', form.Button, '_ip_filter_btn',
_("IP filter"));
o.onclick = () => ip_filter_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// FQDN_FILTER
o = s.taboption('entries_filter_tab', form.Flag, 'fqdn_filter',
// BLLIST_FQDN_FILTER
o = s.taboption('entries_filter_tab', form.Flag, 'bllist_fqdn_filter',
_("Enable FQDN filter"));
o.description = _('Exclude domains from blacklist by FQDN filter patterns');
o.rmempty = false;
// FQDN_FILTER edit dialog
// BLLIST_FQDN_FILTER_FILE edit dialog
o = s.taboption('entries_filter_tab', form.Button, '_fqdn_filter_btn',
_("FQDN filter"));
o.onclick = () => fqdn_filter_edit.show();
@@ -31,9 +31,6 @@ document.head.append(E('style', {'type': 'text/css'},
.error {
background-color: #ff4e54 !important;
}
.total-proxy {
background-color: #ffb937 !important;
}
`));
return baseclass.extend({
@@ -52,10 +49,14 @@ return baseclass.extend({
infoLabelStopped : '<span class="label-status stopped">' + _('Disabled') + '</span>',
infoLabelError : '<span class="label-status error">' + _('Error') + '</span>',
blacklistSources: {
'rublacklist': 'https://rublacklist.net',
'zapret-info': 'https://github.com/zapret-info/z-i',
'antifilter' : 'https://antifilter.download',
blacklistPresets: {
'zapret-info-fqdn': [ 'zapret-info', 'fqdn', 'https://github.com/zapret-info/z-i' ],
'zapret-info-ip' : [ 'zapret-info', 'ip', 'https://github.com/zapret-info/z-i' ],
'rublacklist-fqdn': [ 'rublacklist', 'fqdn', 'https://rublacklist.net' ],
'rublacklist-ip' : [ 'rublacklist', 'ip', 'https://rublacklist.net' ],
'antifilter-ip' : [ 'antifilter', 'ip', 'https://antifilter.download' ],
'ruantiblock-fqdn': [ 'ruantiblock', 'fqdn', 'https://github.com/gSpotx2f/ruantiblock_blacklist' ],
'ruantiblock-ip' : [ 'ruantiblock', 'ip', 'https://github.com/gSpotx2f/ruantiblock_blacklist' ],
},
callInitStatus: rpc.declare({
@@ -104,10 +105,8 @@ return baseclass.extend({
makeStatusString: function(
app_status_code,
proxy_mode,
bllist_mode,
bllist_preset,
bllist_module,
bllist_source,
tp_status_code,
vpn_route_status_code) {
let app_status_label;
let spinning = '';
@@ -147,7 +146,7 @@ return baseclass.extend({
${_('Status')}:
</td>
<td class="td left%s">
%s %s %s
%s %s
</td>
</tr>
<tr class="tr">
@@ -166,29 +165,19 @@ return baseclass.extend({
%s
</td>
</tr>
%s
</table>
`.format(
spinning,
app_status_label,
(tp_status_code == 0) ? '<span class="label-status total-proxy">'
+ _('Total-proxy is on') + '</span>' : '',
(app_status_code != 2 && proxy_mode == 2 && vpn_route_status_code != 0)
? '<span class="label-status error">'
+ _('VPN routing error! Need restart') + '</span>' : '',
(proxy_mode == 1) ? 'Tor' : 'VPN',
(!bllist_module || bllist_module === '') ? _('user entries only') : bllist_mode,
(!bllist_module || bllist_module === '') ? '' :
`<tr class="tr">
<td class="td left">
${_('Blacklist source')}:
</td>
<td class="td left">
<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklistSources[bllist_source]}">
${bllist_source}
</span>
</td>
</tr>`
(!bllist_module || bllist_module === '') ? _('user entries only') :
(this.blacklistPresets[bllist_preset]) ?
`<span style="cursor:help; border-bottom:1px dotted" data-tooltip="${this.blacklistPresets[bllist_preset][2]}">
${this.blacklistPresets[bllist_preset][0]}</span> - ${this.blacklistPresets[bllist_preset][1]}`
: _('Error') + '!'
);
},
+23 -26
View File
@@ -25,8 +25,11 @@ msgstr "Тревога"
msgid "All"
msgstr "Все"
msgid "All traffic goes through the proxy without applying rules"
msgstr "Весь трафик отправляется в прокси, без применения правил"
msgid "All hosts except listed"
msgstr "Все хосты, кроме перечисленных"
msgid "Allows you to limit the hosts that are allowed to bypass blocking"
msgstr "Позволяет ограничить хосты, которым разрешено обходить блокировки"
msgid "Apply"
msgstr "Применить"
@@ -43,8 +46,8 @@ msgstr "Модуль блэклиста"
msgid "Blacklist settings"
msgstr "Настройки блэклиста"
msgid "Blacklist source"
msgstr "Источник блэклиста"
msgid "Blacklist sources"
msgstr "Источники блэклиста"
msgid "Blacklist update mode"
msgstr "Режим обновления блэклиста"
@@ -119,9 +122,6 @@ msgstr "Включить фильтр FQDN"
msgid "Enable IP filter"
msgstr "Включить фильтр IP"
msgid "Enable the 'total-proxy' option at startup"
msgstr "Включать 'total-proxy' при старте"
msgid "Enabled"
msgstr "Включено"
@@ -140,9 +140,6 @@ msgstr "Исключение доменов из блэклиста по шаб
msgid "Expecting:"
msgstr "Ожидается:"
msgid "FQDN configuration"
msgstr "Конфигурация FQDN"
msgid "FQDN filter"
msgstr "Фильтр FQDN"
@@ -158,14 +155,14 @@ msgstr "Ошибка HTML/XML"
msgid "Host"
msgstr "Хост"
msgid "Hosts"
msgstr "Хосты"
msgid "Host filter"
msgstr "Фильтр хостов"
msgid "Hour"
msgstr "Час"
msgid "IP configuration"
msgstr "Конфигурация IP"
msgid "IP addresses of hosts"
msgstr "IP адреса хостов"
msgid "IP filter"
msgstr "Фильтр IP"
@@ -173,6 +170,9 @@ msgstr "Фильтр IP"
msgid "IP limit"
msgstr "Лимит IP адресов"
msgid "IP restriction mode"
msgstr "Режим ограничения IP адресов"
msgid "IP subnet patterns (/24) that are excluded from optimization"
msgstr "Шаблоны IP подсетей (/24) не подлежащих оптимизации"
@@ -191,9 +191,6 @@ msgstr "Ipset"
msgid "Iptables rules"
msgstr "Правила iptables"
msgid "LAN interface"
msgstr "LAN интерфейс"
msgid "Last blacklist update"
msgstr "Последнее обновление блэклиста"
@@ -267,15 +264,15 @@ msgstr ""
msgid "One of the following:"
msgstr "Одно из следующих значений:"
msgid "Only listed hosts"
msgstr "Только перечисленные хосты"
msgid "Optional DNS resolver"
msgstr "Альтернативный DNS резолвер"
msgid "Optional DNS resolver for '.onion' zone"
msgstr "Дополнительный DNS резолвер для '.onion' зоны"
msgid "Options"
msgstr "Опции"
msgid ""
"Patterns can be strings or regular expressions. Each pattern in a separate "
"line, the symbol <code>#</code> in the first position of the line - comments "
@@ -306,6 +303,9 @@ msgstr "Обновить лог"
msgid "Reset"
msgstr "Сбросить"
msgid "Restriction of hosts that are allowed to bypass blocking"
msgstr "Ограничение хостов, которым разрешено обходить блокировки"
msgid "Ruantiblock"
msgstr "Ruantiblock"
@@ -315,6 +315,9 @@ msgstr "Запуск при старте системы"
msgid "Save"
msgstr "Сохранить"
msgid "Send UDP traffic to Tor"
msgstr "Отправлять в Tor UDP-трафик"
msgid "Service"
msgstr "Служба"
@@ -386,12 +389,6 @@ msgstr "Конфигурационный файл Tor"
msgid "Tor mode"
msgstr "Режим Tor"
msgid "Total-proxy"
msgstr "Total-proxy"
msgid "Total-proxy is on"
msgstr "Total-proxy включен"
msgid "Transparent proxy port for iptables rules"
msgstr "Порт прозрачного прокси для правил iptables"
@@ -13,7 +13,7 @@ msgstr ""
msgid "All"
msgstr ""
msgid "All traffic goes through the proxy without applying rules"
msgid "All hosts except listed"
msgstr ""
msgid "Apply"
@@ -31,7 +31,7 @@ msgstr ""
msgid "Blacklist settings"
msgstr ""
msgid "Blacklist source"
msgid "Blacklist sources"
msgstr ""
msgid "Blacklist update mode"
@@ -79,6 +79,7 @@ msgstr ""
msgid "Debug"
msgstr ""
msgid "Disabled"
msgstr ""
@@ -104,13 +105,12 @@ msgstr ""
msgid "Enable IP filter"
msgstr ""
msgid "Enable the 'total-proxy' option at startup"
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Entries"
msgstr ""
msgid "Error"
msgstr ""
@@ -123,9 +123,6 @@ msgstr ""
msgid "Expecting:"
msgstr ""
msgid "FQDN configuration"
msgstr ""
msgid "FQDN filter"
msgstr ""
@@ -141,13 +138,13 @@ msgstr ""
msgid "Host"
msgstr ""
msgid "Hosts"
msgid "Host filter"
msgstr ""
msgid "Hour"
msgstr ""
msgid "IP configuration"
msgid "IP addresses of hosts"
msgstr ""
msgid "IP filter"
@@ -174,9 +171,6 @@ msgstr ""
msgid "Iptables rules"
msgstr ""
msgid "LAN interface"
msgstr ""
msgid "Last blacklist update"
msgstr ""
@@ -247,15 +241,15 @@ msgstr ""
msgid "One of the following:"
msgstr ""
msgid "Only listed hosts"
msgstr ""
msgid "Optional DNS resolver"
msgstr ""
msgid "Optional DNS resolver for '.onion' zone"
msgstr ""
msgid "Options"
msgstr ""
msgid ""
"Patterns can be strings or regular expressions. Each pattern in a separate "
"line, the symbol <code>#</code> in the first position of the line - comments "
@@ -280,6 +274,9 @@ msgstr ""
msgid "Reset"
msgstr ""
msgid "Restriction of hosts that are allowed to bypass blocking"
msgstr ""
msgid "Ruantiblock"
msgstr ""
@@ -289,6 +286,9 @@ msgstr ""
msgid "Save"
msgstr ""
msgid "Send UDP traffic to Tor"
msgstr ""
msgid "Service"
msgstr ""
@@ -353,12 +353,6 @@ msgstr ""
msgid "Tor mode"
msgstr ""
msgid "Total-proxy"
msgstr ""
msgid "Total-proxy is on"
msgstr ""
msgid "Transparent proxy port for iptables rules"
msgstr ""