Blackhole route for VPN configuration.

luci-app-ruantiblock: UI changes for settings.js.
ruantiblock-mod-lua, ruantiblock-mod-py: Added BLLIST_CIDR_EXCLUDED option.
This commit is contained in:
gSpot
2025-09-15 18:25:20 +03:00
parent 493cc103b8
commit 4f68d13026
15 changed files with 440 additions and 255 deletions
+3 -3
View File
@@ -10,9 +10,9 @@ LUCI_APP=1
HTTPS_DNS_PROXY=1
OWRT_VERSION="current"
RUAB_VERSION="2.1.7-r1"
RUAB_MOD_LUA_VERSION="2.1.7-r1"
RUAB_LUCI_APP_VERSION="2.1.7-r1"
RUAB_VERSION="2.1.8-r1"
RUAB_MOD_LUA_VERSION="2.1.8-r1"
RUAB_LUCI_APP_VERSION="2.1.8-r1"
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master"
PKG_DIR="/tmp"
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-ruantiblock
PKG_VERSION:=2.1.7
PKG_VERSION:=2.1.8
PKG_RELEASE:=1
LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock
@@ -192,138 +192,88 @@ return view.extend({
s.addremove = false;
/* Main settings tab */
/* General settings tab */
s.tab('main_tab', _('Main settings'));
s.tab('general_tab', _('General settings'));
// ENABLE_LOGGING
o = s.taboption('main_tab', form.Flag, 'enable_logging',
o = s.taboption('general_tab', form.Flag, 'enable_logging',
_('Logging events'));
o.rmempty = false;
// update_at_startup
o = s.taboption('main_tab', form.Flag, 'update_at_startup',
o = s.taboption('general_tab', form.Flag, 'update_at_startup',
_('Update at startup'));
o.description = _('Update blacklist after system startup');
o.rmempty = false;
// PROXY_LOCAL_CLIENTS
o = s.taboption('main_tab', form.Flag, 'proxy_local_clients',
o = s.taboption('general_tab', form.Flag, 'proxy_local_clients',
_('Apply proxy rules to router application traffic'));
o.rmempty = false;
// NFTSET_CLEAR_SETS
o = s.taboption('main_tab', form.Flag, 'nftset_clear_sets',
o = s.taboption('general_tab', form.Flag, 'nftset_clear_sets',
_('Clean up nftsets before updating blacklist'));
o.description = _('Reduces RAM consumption during update');
o.rmempty = false;
// ALLOWED_HOSTS_MODE
o = s.taboption('main_tab', form.ListValue, 'allowed_hosts_mode',
o = s.taboption('general_tab', form.ListValue, 'allowed_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');
o.description = _('Restriction the local network hosts that are allowed to bypass blocking');
// ALLOWED_HOSTS_LIST
o = s.taboption('main_tab', form.DynamicList, 'allowed_hosts_list',
o = s.taboption('general_tab', form.DynamicList, 'allowed_hosts_list',
_('IP addresses for host filter'));
o.datatype = 'ip4addr';
/* Tor tab */
s.tab('tor_tab', _('Tor mode'));
// TOR_TRANS_PORT
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
o = s.taboption('tor_tab', form.Button, '_torrc_btn',
_('Tor configuration file'));
o.onclick = () => torrc_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
/* VPN tab */
s.tab('vpn_tab', _('VPN mode'));
// IF_VPN
o = s.taboption('vpn_tab', widgets.DeviceSelect, 'if_vpn',
_('VPN interface'));
o.multiple = false;
o.noaliases = true;
o.rmempty = false;
o.default = tools.defaultConfig.if_vpn;
// VPN_GW_IP
o = s.taboption('vpn_tab', form.Value, 'vpn_gw_ip',
_('VPN gateway IP address'),
_('If not specified, the VPN interface address is used (or peer address for PPP protocols)'));
o.datatype = 'ip4addr(1)';
// VPN_ROUTE_CHECK
o = s.taboption('vpn_tab', form.ListValue, 'vpn_route_check',
_('Type of adding a VPN rule to the routing table'));
o.value('0', 'hotplug.d');
o.value('1', 'ruab_route_check');
o.description = _('hotplug.d - default option for many VPN applications that supported by OpenWrt.') +
'<br />' +
_('ruab_route_check - script that regularly checks an entry in the routing table.');
/* Tproxy tab */
s.tab('tproxy_tab', _('Transparent proxy mode'));
// T_PROXY_TYPE
o = s.taboption('tproxy_tab', form.ListValue, 't_proxy_type',
_('Proxy type'));
o.value('0', _('redirect'));
o.value('1', _('tproxy'));
o.description = _('Statement in nftables rules');
// T_PROXY_PORT_TCP
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'));
// ENABLE_TMP_DOWNLOADS
o = s.taboption('general_tab', form.Flag, 'enable_tmp_downloads',
_('Safe blacklist update'),
_('If update fails, the old blacklist configuration will be retained. Temporary files are used, when updating the blacklist (increases memory consumption).'));
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';
// BYPASS_MODE
o = s.taboption('general_tab', form.Flag, 'bypass_mode',
_('Enable exclusion list'), _('List of hosts that are excluded from block bypass (always available directly)'));
o.rmempty = false;
o.default = 0;
// BYPASS_ENTRIES edit dialog
o = s.taboption('general_tab', form.Button, '_bypass_entries_btn',
_('Exclusion list'));
o.onclick = () => bypass_entries_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BYPASS_ENTRIES_DNS
o = s.taboption('general_tab', form.Value, 'bypass_entries_dns',
_('DNS server that is used for the FQDN entries of exclusion list'), '<code>ipaddress[#port]</code>');
o.validate = this.validateIpPort;
/* Blacklist tab */
/* Main blacklist tab */
s.tab('blacklist_tab', _('Blacklist settings'));
s.tab('main_blacklist_tab', _('Main blacklist'));
o = s.taboption('main_blacklist_tab', form.SectionValue, 'config', form.NamedSection,
'config');
s.anonymous = true;
s.addremove = false;
ss = o.subsection;
/* Main settings tab */
ss.tab('b_settings_tab', _('Main settings'));
// PROXY_MODE
o = s.taboption('blacklist_tab', form.ListValue, 'proxy_mode',
o = ss.taboption('b_settings_tab', form.ListValue, 'proxy_mode',
_('Proxy mode'));
o.value('1', 'Tor');
o.value('2', 'VPN');
@@ -331,7 +281,7 @@ return view.extend({
o.default = tools.defaultConfig.proxy_mode;
// BLLIST_PRESET
let bllist_preset = s.taboption('blacklist_tab', form.ListValue,
let bllist_preset = ss.taboption('b_settings_tab', form.ListValue,
'bllist_preset', _('Blacklist update mode'));
bllist_preset.description = _('Blacklist sources') + ':';
bllist_preset.value('', _('user entries only'));
@@ -347,7 +297,7 @@ return view.extend({
});
// BLLIST_MODULE
let bllist_module = s.taboption('blacklist_tab', form.ListValue,
let bllist_module = ss.taboption('b_settings_tab', form.ListValue,
'bllist_module', _('Blacklist module') + '*');
bllist_module.value('', _('disabled'));
bllist_module.depends({ bllist_preset: new RegExp('^($|' + tools.appName + ')'), '!reverse': true });
@@ -355,49 +305,100 @@ return view.extend({
Object.entries(this.parsers).forEach(
e => bllist_module.value(e[1], e[0]));
// ENABLE_BLLIST_PROXY
o = s.taboption('blacklist_tab', form.Flag, 'enable_bllist_proxy',
_('Downloading a blacklist via proxy'), _('Turn on if blacklist source is blocked'));
o.rmempty = false;
o.default = 0;
// ENABLE_TMP_DOWNLOADS
o = s.taboption('blacklist_tab', form.Flag, 'enable_tmp_downloads',
_('Safe blacklist update'),
_('If update fails, the old blacklist configuration will be retained. Temporary files are used, when updating the blacklist (increases memory consumption).'));
o.rmempty = false;
o.default = 0;
// ENABLE_FPROXY
o = s.taboption('blacklist_tab', form.Flag, 'enable_fproxy',
o = ss.taboption('b_settings_tab', form.Flag, 'enable_fproxy',
_('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',
o = ss.taboption('b_settings_tab', form.DynamicList, 'fproxy_list',
_('IP addresses for full proxy mode'));
o.datatype = 'ip4addr';
// BYPASS_MODE
o = s.taboption('blacklist_tab', form.Flag, 'bypass_mode',
_('Enable exclusion list'), _('List of hosts that are excluded from block bypass (always available directly)'));
// ENABLE_BLLIST_PROXY
o = ss.taboption('b_settings_tab', form.Flag, 'enable_bllist_proxy',
_('Downloading a blacklist via proxy'), _('Turn on if blacklist source is blocked'));
o.rmempty = false;
o.default = 0;
// BYPASS_ENTRIES edit dialog
o = s.taboption('blacklist_tab', form.Button, '_bypass_entries_btn',
_('Exclusion list'));
o.onclick = () => bypass_entries_edit.show();
/* Tor tab */
ss.tab('b_tor_tab', _('Tor mode'));
// TOR_TRANS_PORT
o = ss.taboption('b_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 = ss.taboption('b_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
o = ss.taboption('b_tor_tab', form.Button, '_torrc_btn',
_('Tor configuration file'));
o.onclick = () => torrc_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BYPASS_ENTRIES_DNS
o = s.taboption('blacklist_tab', form.Value, 'bypass_entries_dns',
_('DNS server that is used for the FQDN entries of exclusion list'), '<code>ipaddress[#port]</code>');
o.validate = this.validateIpPort;
/* VPN tab */
ss.tab('b_vpn_tab', _('VPN mode'));
// IF_VPN
o = ss.taboption('b_vpn_tab', widgets.DeviceSelect, 'if_vpn',
_('VPN interface'));
o.multiple = false;
o.noaliases = true;
o.rmempty = false;
o.default = tools.defaultConfig.if_vpn;
// VPN_GW_IP
o = ss.taboption('b_vpn_tab', form.Value, 'vpn_gw_ip',
_('VPN gateway IP address'),
_('If not specified, the VPN interface address is used (or peer address for PPP protocols)'));
o.datatype = 'ip4addr(1)';
/* Tproxy tab */
ss.tab('b_tproxy_tab', _('Transparent proxy mode'));
// T_PROXY_TYPE
o = ss.taboption('b_tproxy_tab', form.ListValue, 't_proxy_type',
_('Proxy type'));
o.value('0', _('redirect'));
o.value('1', _('tproxy'));
o.description = _('Statement in nftables rules');
// T_PROXY_PORT_TCP
o = ss.taboption('b_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 = ss.taboption('b_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 = ss.taboption('b_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';
if(availableParsers) {
bllist_preset.description += '<br /> ( * - ' + _('requires installed blacklist module') + ' )';
@@ -405,103 +406,103 @@ return view.extend({
/* Parser settings tab */
s.tab('parser_settings_tab', _('Module settings'));
ss.tab('b_parser_settings_tab', _('Module settings'));
// BLLIST_MIN_ENTRIES
o = s.taboption('parser_settings_tab', form.Value, 'bllist_min_entries',
o = ss.taboption('b_parser_settings_tab', form.Value, 'bllist_min_entries',
_('Minimum allowed number of entries'));
o.description = _('If less than the specified number of entries are received from the source, then the lists are not updated');
o.rmempty = false;
o.datatype = 'uinteger';
// BLLIST_FQDN_FILTER
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_fqdn_filter',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_fqdn_filter',
_('Enable FQDN filter'));
o.description = _('Pick domains from blacklist by FQDN filter patterns');
o.rmempty = false;
// BLLIST_FQDN_FILTER_TYPE
o = s.taboption('parser_settings_tab', form.ListValue, 'bllist_fqdn_filter_type',
o = ss.taboption('b_parser_settings_tab', form.ListValue, 'bllist_fqdn_filter_type',
_('FQDN filter type'));
o.value('0', _('All entries except matching patterns'));
o.value('1', _('Only entries matching patterns'));
// BLLIST_FQDN_FILTER_FILE edit dialog
o = s.taboption('parser_settings_tab', form.Button, '_fqdn_filter_btn',
o = ss.taboption('b_parser_settings_tab', form.Button, '_fqdn_filter_btn',
_('FQDN filter'));
o.onclick = () => fqdn_filter_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BLLIST_SD_LIMIT
o = s.taboption('parser_settings_tab', form.Value, 'bllist_sd_limit',
o = ss.taboption('b_parser_settings_tab', 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';
// BLLIST_GR_EXCLUDED_SLD_FILE edit dialog
o = s.taboption('parser_settings_tab', form.Button, '_gr_excluded_sld_btn',
o = ss.taboption('b_parser_settings_tab', form.Button, '_gr_excluded_sld_btn',
_('2nd level domains that are excluded from optimization'));
o.onclick = () => gr_excluded_sld_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BLLIST_ENABLE_IDN
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_enable_idn',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_enable_idn',
_('Convert cyrillic domains to punycode'));
o.rmempty = false;
// BLLIST_ALT_NSLOOKUP
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_alt_nslookup',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_alt_nslookup',
_('Use optional DNS resolver'));
o.rmempty = false;
// BLLIST_ALT_DNS_ADDR
o = s.taboption('parser_settings_tab', form.Value, 'bllist_alt_dns_addr',
o = ss.taboption('b_parser_settings_tab', form.Value, 'bllist_alt_dns_addr',
_('Optional DNS resolver'), '<code>ipaddress[#port]</code>');
o.rmempty = false;
o.validate = this.validateIpPort;
// BLLIST_IP_FILTER
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_ip_filter',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_ip_filter',
_('Enable IP filter'));
o.description = _('Pick IP addresses from blacklist by IP filter patterns');
o.rmempty = false;
// BLLIST_IP_FILTER_TYPE
o = s.taboption('parser_settings_tab', form.ListValue, 'bllist_ip_filter_type',
o = ss.taboption('b_parser_settings_tab', form.ListValue, 'bllist_ip_filter_type',
_('IP filter type'));
o.value('0', _('All entries except matching patterns'));
o.value('1', _('Only entries matching patterns'));
// BLLIST_IP_FILTER_FILE edit dialog
o = s.taboption('parser_settings_tab', form.Button, '_ip_filter_btn',
o = ss.taboption('b_parser_settings_tab', form.Button, '_ip_filter_btn',
_('IP filter'));
o.onclick = () => ip_filter_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BLLIST_IP_LIMIT
o = s.taboption('parser_settings_tab', form.Value, 'bllist_ip_limit', _('IP limit'));
o = ss.taboption('b_parser_settings_tab', 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';
// BLLIST_GR_EXCLUDED_NETS_FILE edit dialog
o = s.taboption('parser_settings_tab', form.Button, '_gr_excluded_nets_btn',
o = ss.taboption('b_parser_settings_tab', form.Button, '_gr_excluded_nets_btn',
_('IP subnet patterns (/24) that are excluded from optimization'));
o.onclick = () => gr_excluded_nets_edit.show();
o.inputtitle = _('Edit');
o.inputstyle = 'edit btn';
// BLLIST_SUMMARIZE_IP
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_summarize_ip',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_summarize_ip',
_('Summarize IP ranges'));
o.rmempty = false;
// BLLIST_SUMMARIZE_CIDR
o = s.taboption('parser_settings_tab', form.Flag, 'bllist_summarize_cidr',
o = ss.taboption('b_parser_settings_tab', form.Flag, 'bllist_summarize_cidr',
_("Summarize '/24' networks"));
o.rmempty = false;
};
@@ -525,6 +526,12 @@ return view.extend({
ss.tab('u_main_tab', _('Main settings'));
// description
o = ss.taboption('u_main_tab', form.Value, 'u_description',
_("Description"));
o.datatype = 'maxlength(50)';
o.modalonly = null;
// U_ENABLED
o = ss.taboption('u_main_tab', form.Flag, 'u_enabled',
_('Enabled'),
@@ -534,12 +541,6 @@ return view.extend({
o.editable = true;
o.modalonly = false;
// description
o = ss.taboption('u_main_tab', form.Value, 'u_description',
_("Description"));
o.datatype = 'maxlength(100)';
o.modalonly = null;
// U_PROXY_MODE
o = ss.taboption('u_main_tab', form.ListValue, 'u_proxy_mode',
_('Proxy mode'));
@@ -601,7 +602,7 @@ return view.extend({
o = ss.taboption('u_vpn_tab', form.Value, 'u_vpn_gw_ip',
_('VPN gateway IP address'),
_('If not specified, the VPN interface address is used (or peer address for PPP protocols)'));
o.datatype = 'ip4addr(1)';
o.datatype = 'ip4addr(1)';
o.modalonly = true;
@@ -615,6 +616,7 @@ return view.extend({
o.value('0', _('redirect'));
o.value('1', _('tproxy'));
o.description = _('Statement in nftables rules');
o.modalonly = true;
// U_T_PROXY_PORT_TCP
o = ss.taboption('u_tproxy_tab', form.Value, 'u_t_proxy_port_tcp',
@@ -655,15 +657,12 @@ return view.extend({
'<br /><code>#comment<br />domain.net<br />sub.domain.com 8.8.8.8<br />sub.domain.com 8.8.8.8#53<br />74.125.131.19<br />74.125.0.0/16</code>'
);
// DEBUG
console.log(tools.userListsDir + '/' + s.section);
o.modalonly = true;
// U_ENTRIES_REMOTE
o = s.taboption('u_entries_tab', form.DynamicList, 'u_entries_remote',
_('URLs of remote user entries file'));
o.validate = this.validateUrl;
o.validate = this.validateUrl;
o.modalonly = true;
// U_ENABLE_ENTRIES_REMOTE_PROXY
@@ -681,6 +680,7 @@ return view.extend({
let map_promise = m.render();
map_promise.then(node => node.classList.add('fade-in'));
return map_promise;
},
+8 -5
View File
@@ -58,9 +58,6 @@ msgstr "Автообновление"
msgid "Blacklist module"
msgstr "Модуль блэклиста"
msgid "Blacklist settings"
msgstr "Настройки блэклиста"
msgid "Blacklist sources"
msgstr "Источники блэклиста"
@@ -194,6 +191,9 @@ msgstr "Не удалось получить статус инициализац
msgid "Filter settings"
msgstr "Настройки фильтра"
msgid "General settings"
msgstr "Общие настройки"
msgid "Get all entries"
msgstr "Все записи"
@@ -278,6 +278,9 @@ msgstr "Уровни логирования"
msgid "Logread not found"
msgstr "Logread не найден"
msgid "Main blacklist"
msgstr "Основной блэклист"
msgid "Main settings"
msgstr "Основные настройки"
@@ -403,8 +406,8 @@ msgstr "Обновить лог"
msgid "Reset"
msgstr "Сбросить"
msgid "Restriction of hosts that are allowed to bypass blocking"
msgstr "Ограничение хостов, которым разрешено обходить блокировки"
msgid "Restriction the local network hosts that are allowed to bypass blocking"
msgstr "Ограничение хостов локальной сети, которым разрешено обходить блокировки"
msgid "Ruantiblock"
msgstr "Ruantiblock"
@@ -43,9 +43,6 @@ msgstr ""
msgid "Blacklist module"
msgstr ""
msgid "Blacklist settings"
msgstr ""
msgid "Blacklist sources"
msgstr ""
@@ -179,6 +176,9 @@ msgstr ""
msgid "Filter settings"
msgstr ""
msgid "General settings"
msgstr ""
msgid "Get all entries"
msgstr ""
@@ -260,6 +260,9 @@ msgstr ""
msgid "Logread not found"
msgstr ""
msgid "Main blacklist"
msgstr ""
msgid "Main settings"
msgstr ""
@@ -373,7 +376,7 @@ msgstr ""
msgid "Reset"
msgstr ""
msgid "Restriction of hosts that are allowed to bypass blocking"
msgid "Restriction the local network hosts that are allowed to bypass blocking"
msgstr ""
msgid "Ruantiblock"
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock-mod-lua
PKG_VERSION:=2.1.7
PKG_VERSION:=2.1.8
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
@@ -1,5 +1,5 @@
--[[
(с) 2020 gSpot <https://github.com/gSpotx2f>
(с) 2020 gSpot <https://github.com/gSpotx2f/iptool-lua>
Some functions for manipulating IPv4 addresses.
@@ -98,6 +98,7 @@ local function summarize_address_range(first, last)
end
local nbits = math.min(count_righthand_zero_bits(first, ip_bits), bit_length(last - first + 1) - 1)
ret_val = {[1] = first, [2] = (ip_bits - nbits)}
first = first + lshift(1, nbits)
if first - 1 == ipv4_capacity then
return
@@ -154,6 +155,50 @@ local function get_supernet(network, new_prefix)
return band(network_address, lshift(netmask, diff_prefixlen))
end
local function overlap_ip(ip, network)
local network_address, prefixlen
if type(network) == "string" then
network_address, prefixlen = get_network_addr(network)
elseif type(network) == "table" then
network_address, prefixlen = network[1], network[2]
else
return
end
ip = ip_to_int(ip)
if ip == nil then
return
end
local offset = ipv4_length - prefixlen
return (rshift(ip, offset) == rshift(network_address, offset))
end
local function check_network(net)
local network_address, prefixlen
if type(net) == "string" then
network_address, prefixlen = get_network_addr(net)
elseif type(net) == "table" then
network_address, prefixlen = net[1], net[2]
else
return
end
return network_address, prefixlen
end
local function overlap_net(subnet, network)
local network_address_1, prefixlen_1 = check_network(subnet)
local network_address_2, prefixlen_2 = check_network(network)
if (network_address_1 == nil or prefixlen_1 == nil or
network_address_2 == nil or prefixlen_2 == nil) then
return
end
if network_address_1 == network_address_2 then
return true
end
local offset = ipv4_length - math.min(prefixlen_1, prefixlen_2)
return (rshift(network_address_1, offset) == rshift(network_address_2, offset))
end
return {
validate_ip = validate_ip,
ip_to_int = ip_to_int,
@@ -162,4 +207,6 @@ return {
get_network_addr = get_network_addr,
hosts_from_network = hosts_from_network,
get_supernet = get_supernet,
overlap_ip = overlap_ip,
overlap_net = overlap_net,
}
@@ -83,6 +83,8 @@ local Config = Class(nil, {
["BLLIST_FQDN_EXCLUDED_FILE"] = true,
["BLLIST_IP_EXCLUDED_ENABLE"] = true,
["BLLIST_IP_EXCLUDED_FILE"] = true,
["BLLIST_CIDR_EXCLUDED_ENABLE"] = true,
["BLLIST_CIDR_EXCLUDED_FILE"] = true,
},
BLLIST_FQDN_FILTER_PATTERNS = {},
BLLIST_IP_FILTER_PATTERNS = {},
@@ -91,6 +93,7 @@ local Config = Class(nil, {
BLLIST_GR_EXCLUDED_NETS_PATTERNS = {},
BLLIST_FQDN_EXCLUDED_ITEMS = {},
BLLIST_IP_EXCLUDED_ITEMS = {},
BLLIST_CIDR_EXCLUDED_ITEMS = {},
-- iconv type: standalone iconv or lua-iconv (standalone, lua)
ICONV_TYPE = "standalone",
-- standalone iconv
@@ -99,7 +102,7 @@ local Config = Class(nil, {
encoding = "UTF-8",
site_encoding = "",
http_send_headers = {
["User-Agent"] = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0",
["User-Agent"] = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/142.0",
},
connect_timeout = nil,
})
@@ -168,60 +171,7 @@ Config.BLLIST_SUMMARIZE_IP = remap_bool(Config.BLLIST_SUMMARIZE_IP)
Config.BLLIST_SUMMARIZE_CIDR = remap_bool(Config.BLLIST_SUMMARIZE_CIDR)
Config.BLLIST_FQDN_EXCLUDED_ENABLE = remap_bool(Config.BLLIST_FQDN_EXCLUDED_ENABLE)
Config.BLLIST_IP_EXCLUDED_ENABLE = remap_bool(Config.BLLIST_IP_EXCLUDED_ENABLE)
-- Loading filters
function Config:load_filter_files()
function load_file(file, t, is_array)
local file_handler = io.open(file, "r")
if file_handler then
for line in file_handler:lines() do
if #line > 0 and line:match("^[^#]") then
if is_array then
t[#t + 1] = line
else
t[line] = true
end
end
end
file_handler:close()
end
end
if self.BLLIST_FQDN_FILTER then
load_file(self.BLLIST_FQDN_FILTER_FILE, self.BLLIST_FQDN_FILTER_PATTERNS)
end
if self.BLLIST_IP_FILTER then
load_file(self.BLLIST_IP_FILTER_FILE, self.BLLIST_IP_FILTER_PATTERNS)
end
if self.BLLIST_GR_EXCLUDED_SLD_FILE then
load_file(self.BLLIST_GR_EXCLUDED_SLD_FILE, self.BLLIST_GR_EXCLUDED_SLD_PATTERNS)
end
if self.BLLIST_GR_EXCLUDED_SLD_MASKS_FILE then
load_file(self.BLLIST_GR_EXCLUDED_SLD_MASKS_FILE, self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS, true)
end
if self.BLLIST_GR_EXCLUDED_NETS_FILE then
load_file(self.BLLIST_GR_EXCLUDED_NETS_FILE, self.BLLIST_GR_EXCLUDED_NETS_PATTERNS)
end
if self.BLLIST_FQDN_EXCLUDED_ENABLE then
load_file(self.BLLIST_FQDN_EXCLUDED_FILE, self.BLLIST_FQDN_EXCLUDED_ITEMS)
end
if self.BLLIST_IP_EXCLUDED_ENABLE then
load_file(self.BLLIST_IP_EXCLUDED_FILE, self.BLLIST_IP_EXCLUDED_ITEMS)
end
end
function Config:check_sld_masks(sld)
if #self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS > 0 then
for _, pattern in ipairs(self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS) do
if sld:find(pattern) then
return true
end
end
end
return false
end
Config:load_filter_files()
Config.BLLIST_CIDR_EXCLUDED_ENABLE = remap_bool(Config.BLLIST_CIDR_EXCLUDED_ENABLE)
-- Importing packages
@@ -250,6 +200,7 @@ end
if not it then
Config.BLLIST_SUMMARIZE_CIDR = false
Config.BLLIST_SUMMARIZE_IP = false
Config.BLLIST_CIDR_EXCLUDED_ENABLE = false
end
--[[
local zlib = prequire("zlib")
@@ -272,6 +223,113 @@ else
error("Config.ICONV_TYPE should be either 'lua' or 'standalone'")
end
-- Loading filters
function Config:load_filter_files()
function load_file(file, t, is_array, func)
local file_handler = io.open(file, "r")
if file_handler then
for line in file_handler:lines() do
if #line > 0 and not line:match("^#") then
if func then
line = func(line)
end
if line ~= nil then
if is_array then
t[#t + 1] = line
else
t[line] = true
end
end
end
end
file_handler:close()
end
end
if self.BLLIST_FQDN_FILTER then
load_file(self.BLLIST_FQDN_FILTER_FILE, self.BLLIST_FQDN_FILTER_PATTERNS, true)
end
if self.BLLIST_IP_FILTER then
load_file(self.BLLIST_IP_FILTER_FILE, self.BLLIST_IP_FILTER_PATTERNS, true)
end
if self.BLLIST_GR_EXCLUDED_SLD_FILE then
load_file(self.BLLIST_GR_EXCLUDED_SLD_FILE, self.BLLIST_GR_EXCLUDED_SLD_PATTERNS)
end
if self.BLLIST_GR_EXCLUDED_SLD_MASKS_FILE then
load_file(self.BLLIST_GR_EXCLUDED_SLD_MASKS_FILE, self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS, true)
end
if self.BLLIST_GR_EXCLUDED_NETS_FILE then
load_file(self.BLLIST_GR_EXCLUDED_NETS_FILE, self.BLLIST_GR_EXCLUDED_NETS_PATTERNS)
end
if self.BLLIST_FQDN_EXCLUDED_ENABLE then
load_file(self.BLLIST_FQDN_EXCLUDED_FILE, self.BLLIST_FQDN_EXCLUDED_ITEMS)
end
if self.BLLIST_IP_EXCLUDED_ENABLE then
load_file(self.BLLIST_IP_EXCLUDED_FILE, self.BLLIST_IP_EXCLUDED_ITEMS)
end
if self.BLLIST_CIDR_EXCLUDED_ENABLE then
load_file(self.BLLIST_CIDR_EXCLUDED_FILE, self.BLLIST_CIDR_EXCLUDED_ITEMS, true,
function(l)
if l:match("^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?/%d%d?$") then
local a, p = it.get_network_addr(l)
if a ~= nil and p ~= nil then
return { [1] = a, [2] = p }
end
end
return
end
)
end
end
function Config:check_filter(str, filter_patterns, reverse)
if filter_patterns and str then
for _, pattern in ipairs(filter_patterns) do
if str:match(pattern) then
return not reverse
end
end
end
return reverse
end
function Config:check_sld_masks(sld)
if #self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS > 0 then
for _, pattern in ipairs(self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS) do
if sld:find(pattern) then
return true
end
end
end
return false
end
function Config:check_cidr_overlap_ip(ip)
if #self.BLLIST_CIDR_EXCLUDED_ITEMS > 0 then
for _, net in ipairs(self.BLLIST_CIDR_EXCLUDED_ITEMS) do
if it.overlap_ip(ip, net) then
return true
end
end
end
return false
end
function Config:check_cidr_overlap_net(ip)
if #self.BLLIST_CIDR_EXCLUDED_ITEMS > 0 then
for _, net in ipairs(self.BLLIST_CIDR_EXCLUDED_ITEMS) do
if it.overlap_net(ip, net) then
return true
end
end
end
return false
end
Config:load_filter_files()
------------------------------ Classes -------------------------------
local BlackListParser = Class(Config, {
@@ -323,17 +381,6 @@ function BlackListParser:convert_to_punycode(input)
return input and (idn.encode(input))
end
function BlackListParser:check_filter(str, filter_patterns, reverse)
if filter_patterns and str then
for pattern in pairs(filter_patterns) do
if str:match(pattern) then
return not reverse
end
end
end
return reverse
end
function BlackListParser:get_subnet(ip)
return ip:match("^(%d+%.%d+%.%d+%.)%d+$")
end
@@ -707,6 +754,23 @@ function OptimizeConfig:new(t)
return instance
end
function OptimizeConfig:_exclude_nets()
local ip_table = {}
for ip, subnet in pairs(self.ip_table) do
if not self:check_cidr_overlap_ip(ip) then
ip_table[ip] = subnet
end
end
self.ip_table = ip_table
local cidr_table = {}
for net in pairs(self.cidr_table) do
if not self:check_cidr_overlap_net(net) then
cidr_table[net] = true
end
end
self.cidr_table = cidr_table
end
function OptimizeConfig:_remove_subdomains()
local tld_table = {}
for fqdn, sld in pairs(self.fqdn_table) do
@@ -792,6 +856,9 @@ function OptimizeConfig:optimize()
self:_union(self.fqdn_table, i.fqdn_table)
self:_union(self.sld_table, i.sld_table)
end
if self.BLLIST_CIDR_EXCLUDED_ENABLE then
self:_exclude_nets()
end
self:_remove_subdomains()
self:_optimize_fqdn_table()
self:_optimize_ip_table()
@@ -1146,6 +1213,7 @@ if parser_classes then
for _, i in ipairs(parser_instances) do
ret_list[i:run()] = true
end
local return_sum = 0
for i, _ in pairs(ret_list) do
return_sum = return_sum + i
@@ -1161,4 +1229,5 @@ if parser_classes then
else
error("Wrong configuration! (Config.BLLIST_MODE, Config.BLLIST_SOURCE)")
end
os.exit(ret_list[1] and 1 or (ret_list[2] and 2 or 0))
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock-mod-py
PKG_VERSION:=2.1.7
PKG_VERSION:=2.1.8
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
@@ -8,7 +8,8 @@
"""
from contextlib import contextmanager
from ipaddress import IPv4Address, IPv4Network, summarize_address_range
from ipaddress import (IPv4Address, IPv4Network, summarize_address_range,
AddressValueError, NetmaskValueError)
import os
import re
import socket
@@ -68,14 +69,17 @@ class Config:
"BLLIST_FQDN_EXCLUDED_FILE",
"BLLIST_IP_EXCLUDED_ENABLE",
"BLLIST_IP_EXCLUDED_FILE",
"BLLIST_CIDR_EXCLUDED_ENABLE",
"BLLIST_CIDR_EXCLUDED_FILE",
]
BLLIST_FQDN_FILTER_PATTERNS = set()
BLLIST_IP_FILTER_PATTERNS = set()
BLLIST_FQDN_FILTER_PATTERNS = []
BLLIST_IP_FILTER_PATTERNS = []
BLLIST_GR_EXCLUDED_SLD_PATTERNS = set()
BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS = []
BLLIST_GR_EXCLUDED_NETS_PATTERNS = set()
BLLIST_FQDN_EXCLUDED_ITEMS = set()
BLLIST_IP_EXCLUDED_ITEMS = set()
BLLIST_CIDR_EXCLUDED_ITEMS = []
@classmethod
def _load_config(cls, cfg_dict):
@@ -119,15 +123,20 @@ class Config:
})
@classmethod
def _load_filter(cls, file_path, filter_patterns, is_array=False):
def _load_filter(cls, file_path, filter_patterns, is_array=False, func=None):
try:
with open(file_path, "rt") as file_handler:
for line in file_handler:
if line and re.match("[^#]", line):
if line and not re.match(r"(^#|^$)", line):
value = line.strip()
if func:
value = func(value)
if value is None:
continue
if is_array:
filter_patterns.append(line.strip())
filter_patterns.append(value)
else:
filter_patterns.add(line.strip())
filter_patterns.add(value)
except OSError:
pass
@@ -135,13 +144,13 @@ class Config:
def load_fqdn_filter(cls, file_path=None):
if cls.BLLIST_FQDN_FILTER:
cls._load_filter(file_path or cls.BLLIST_FQDN_FILTER_FILE,
cls.BLLIST_FQDN_FILTER_PATTERNS)
cls.BLLIST_FQDN_FILTER_PATTERNS, is_array=True)
@classmethod
def load_ip_filter(cls, file_path=None):
if cls.BLLIST_IP_FILTER:
cls._load_filter(file_path or cls.BLLIST_IP_FILTER_FILE,
cls.BLLIST_IP_FILTER_PATTERNS)
cls.BLLIST_IP_FILTER_PATTERNS, is_array=True)
@classmethod
def load_gr_excluded_sld(cls, file_path=None):
@@ -173,6 +182,30 @@ class Config:
cls._load_filter(file_path or cls.BLLIST_IP_EXCLUDED_FILE,
cls.BLLIST_IP_EXCLUDED_ITEMS)
@staticmethod
def makeIPv4Network(s):
net = None
try:
net = IPv4Network(s)
except (AddressValueError, NetmaskValueError):
pass
return net
@classmethod
def load_cidr_excluded(cls, file_path=None):
if cls.BLLIST_CIDR_EXCLUDED_ENABLE:
cls._load_filter(file_path or cls.BLLIST_CIDR_EXCLUDED_FILE,
cls.BLLIST_CIDR_EXCLUDED_ITEMS, is_array=True,
func=cls.makeIPv4Network)
@staticmethod
def _check_filter(string, filter_patterns, reverse=False):
if filter_patterns and string:
for pattern in filter_patterns:
if pattern and pattern.search(string):
return not reverse
return reverse
def check_sld_masks(self, sld):
if self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS:
for pattern in self.BLLIST_GR_EXCLUDED_SLD_MASKS_PATTERNS:
@@ -180,6 +213,18 @@ class Config:
return True
return False
def check_cidr_overlap(self, ip):
if self.BLLIST_CIDR_EXCLUDED_ITEMS:
try:
ip_obj = IPv4Network(ip)
except (AddressValueError, NetmaskValueError):
pass
else:
for net in self.BLLIST_CIDR_EXCLUDED_ITEMS:
if net.overlaps(ip_obj):
return True
return False
class ParserError(Exception):
def __init__(self, reason=None):
@@ -212,7 +257,7 @@ class BlackListParser(Config):
self.output_fqdn_count = 0
self.ssl_unverified = False
self.send_headers_dict = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0",
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/142.0",
}
### Proxies (ex.: self.proxies = {"http": "http://192.168.0.1:8080", "https": "http://192.168.0.1:8080"})
self.proxies = None
@@ -303,14 +348,6 @@ class BlackListParser(Config):
except UnicodeError:
pass
@staticmethod
def _check_filter(string, filter_patterns, reverse=False):
if filter_patterns and string:
for pattern in filter_patterns:
if pattern and pattern.search(string):
return not reverse
return reverse
def _get_subnet(self, ip_addr):
regexp_obj = self.ip_pattern.fullmatch(ip_addr)
return regexp_obj.group(1) if regexp_obj else None
@@ -511,6 +548,19 @@ class OptimizeConfig(Config):
self.ip_count = 0
self.output_fqdn_count = 0
def _exclude_nets(self):
if self.BLLIST_CIDR_EXCLUDED_ENABLE:
ip_dict = {}
for ip, subnet in self.ip_dict.items():
if not self.check_cidr_overlap(ip):
ip_dict[ip] = subnet
self.ip_dict = ip_dict
cidr_set = set()
for net in self.cidr_set:
if not self.check_cidr_overlap(net):
cidr_set.add(net)
self.cidr_set = cidr_set
def _remove_subdomains(self):
tld_dict = {}
for fqdn, sld in self.fqdn_dict.items():
@@ -571,6 +621,7 @@ class OptimizeConfig(Config):
self.ip_subnet_dict.update(i.ip_subnet_dict)
self.fqdn_dict.update(i.fqdn_dict)
self.sld_dict.update(i.sld_dict)
self._exclude_nets()
self._remove_subdomains()
self._optimize_fqdn_dict()
self._optimize_ip_dict()
@@ -831,6 +882,7 @@ if __name__ == "__main__":
Config.load_gr_excluded_nets()
Config.load_fqdn_excluded()
Config.load_ip_excluded()
Config.load_cidr_excluded()
parsers_dict = {
"ip": {"rublacklist": [RblIp], "zapret-info": [ZiIp], "antifilter": [AfIp], "fz": [FzIp], "ruantiblock": [Ra]},
"fqdn": {"rublacklist": [RblFQDN, RblDPI], "zapret-info": [ZiFQDN], "antifilter": [AfFQDN], "fz": [FzFQDN], "ruantiblock": [Ra]},
+1 -1
View File
@@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ruantiblock
PKG_VERSION:=2.1.7
PKG_VERSION:=2.1.8
PKG_RELEASE:=1
PKG_MAINTAINER:=gSpot <https://github.com/gSpotx2f/ruantiblock_openwrt>
@@ -121,6 +121,10 @@ BLLIST_IP_FILTER_FILE="/etc/ruantiblock/ip_filter"
BLLIST_IP_EXCLUDED_ENABLE=0
### Файл с записями IP/CIDR для опции BLLIST_IP_EXCLUDED_ENABLE
BLLIST_IP_EXCLUDED_FILE="/etc/ruantiblock/ip_excluded"
### Включение опции исключения IP входящих в подсети CIDR
BLLIST_CIDR_EXCLUDED_ENABLE=0
### Файл с записями IP/CIDR для опции BLLIST_CIDR_EXCLUDED_ENABLE
BLLIST_CIDR_EXCLUDED_FILE="/etc/ruantiblock/cidr_excluded"
### Лимит субдоменов для группировки. При достижении, в конфиг dnsmasq будет добавлен весь домен 2-го ур-ня вместо множества субдоменов (0 - выкл)
BLLIST_SD_LIMIT=16
### Файл с SLD не подлежащими группировке при оптимизации (одна запись на строку)
+4
View File
@@ -157,6 +157,10 @@ export BLLIST_IP_FILTER_FILE="${CONFIG_DIR}/ip_filter"
export BLLIST_IP_EXCLUDED_ENABLE=0
### Файл с записями IP/CIDR для опции BLLIST_IP_EXCLUDED_ENABLE
export BLLIST_IP_EXCLUDED_FILE="${CONFIG_DIR}/ip_excluded"
### Включение опции исключения IP входящих в подсети CIDR
export BLLIST_CIDR_EXCLUDED_ENABLE=0
### Файл с записями IP/CIDR для опции BLLIST_CIDR_EXCLUDED_ENABLE
export BLLIST_CIDR_EXCLUDED_FILE="${CONFIG_DIR}/cidr_excluded"
### Лимит субдоменов для группировки. При достижении, в конфиг dnsmasq будет добавлен весь домен 2-го ур-ня вместо множества субдоменов (0 - выкл)
export BLLIST_SD_LIMIT=0
### Файл с SLD не подлежащими группировке при оптимизации (одна запись на строку)
@@ -22,8 +22,8 @@ CheckIfaceStatus() {
}
VpnRouteInstanceStatus() {
local _vpn_route_table_id=$1
[ -n "$($IP_CMD route show table $_vpn_route_table_id 2> /dev/null)" ] && return 0
local _route_table_id=$1
$IP_CMD route show table $_route_table_id 2> /dev/null | $AWK_CMD 'BEGIN {code=1} /^(default|local)/ {code=0} END {exit code}' && return 0
return 1
}
@@ -62,11 +62,12 @@ NftRouteAdd() {
echo 0 > "/proc/sys/net/ipv4/conf/${_if_vpn}/rp_filter"
NftRouteDelete "$_route_table_id" 2> /dev/null
$IP_CMD rule add fwmark "$_pkts_mark" table "$_route_table_id" priority "$VPN_RULE_PRIO"
$IP_CMD route add default via "$_vpn_ip" table "$_route_table_id"
$IP_CMD route add default via "$_vpn_ip" table "$_route_table_id" metric 100
if [ $? -ne 0 ]; then
echo " Error! An error occurred while adding the route. Routing table id=${_route_table_id}, VPN gateway IP=${_vpn_ip}" >&2
MakeLogRecord "err" "Error! An error occurred while adding the route. Routing table id=${_route_table_id}, VPN gateway IP=${_vpn_ip}"
fi
$IP_CMD route add blackhole default table "$_route_table_id" metric 200
if [ $DEBUG -ge 1 ]; then
echo " nft_functions.NftRouteAdd: ${IP_CMD} rule add fwmark ${_pkts_mark} table ${_route_table_id} priority ${VPN_RULE_PRIO}" >&2
@@ -80,7 +81,7 @@ NftRouteAdd() {
NftRouteStatus() {
local _route_table_id=$1
[ -n "$($IP_CMD route show table "$_route_table_id" 2> /dev/null)" ] && return 0
$IP_CMD route show table $_route_table_id 2> /dev/null | $AWK_CMD 'BEGIN {code=1} /^(default|local)/ {code=0} END {exit code}' && return 0
return 1
}
@@ -90,7 +91,9 @@ NftAddBaseChains() {
$NFT_CMD add chain $NFT_TABLE "$NFT_BLLIST_CHAIN"
$NFT_CMD add chain $NFT_TABLE "$NFT_FPROXY_CHAIN" { type filter hook prerouting priority ${_chain_prio_fproxy}\; policy accept\; }
$NFT_CMD add chain $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" { type filter hook prerouting priority ${_chain_prio_first}\; policy accept\; }
NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_FPROXY_CHAIN" meta iif lo return
NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_FPROXY_CHAIN" ip daddr "@${NFTSET_FPROXY_PRIVATE}" return
NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" meta iif lo return
NftCmdWrapper $NFT_CMD add rule $NFT_TABLE "$NFT_ALLOWED_HOSTS_CHAIN" "$NFT_ALLOWED_HOSTS_PATTERN"
if [ "$BYPASS_MODE" = "1" ]; then
for _set in "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN"