Files
ruantiblock_openwrt/ruantiblock/files/usr/bin/ruantiblock
T
2026-03-04 16:22:22 +03:00

1365 lines
55 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
########################################################################
#
# Ruantiblock
# (с) 2025 gSpot (https://github.com/gSpotx2f/ruantiblock_openwrt)
#
########################################################################
export NAME="ruantiblock"
export APP_EXEC="$0"
export APP_NAME="$(basename $0)"
export LANG="en_US.UTF-8"
export LANGUAGE="en"
#################### Platform-specific settings ########################
CONFIG_DIR="/etc/${NAME}"
CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf"
SCRIPTS_DIR="/usr/share/${NAME}"
export DATA_DIR="/var/${NAME}"
export MODULES_DIR="/usr/libexec/${NAME}"
RUN_FILES_DIR="/var/run"
### Директория доп. конфигов dnsmasq
export DNSMASQ_CONFDIR="/var/dnsmasq.d"
### Команда для перезапуска dnsmasq
export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart"
### Директория для html-страницы статуса (не используется в OpenWrt)
export HTML_DIR="/www"
########################## Default Settings ############################
### Режим обработки пакетов в правилах nftables (1 - Tor, 2 - VPN, 3 - Прозрачный прокси)
export PROXY_MODE=1
### Применять правила проксификации для трафика локальных сервисов роутера (0 - выкл, 1 - вкл)
export PROXY_LOCAL_CLIENTS=0
### Удаление записей сетов перед началом обновления (для освобождения оперативной памяти перед обновлением сетов) (0 - выкл, 1 - вкл)
export NFTSET_CLEAR_SETS=0
### Исключить из обхода блокировок пакеты, у которых адрес назначения совпадает с любым IP адресом любого из интерфейсов роутера (0 - выкл, 1 - вкл)
export IGNORE_LOCAL_IP=1
### Режим фильтра хостов которым разрешено обходить блокировки (0 - выкл., 1 - только адреса из списка, 2 - любые адреса кроме присутствующих в списке)
export ALLOWED_HOSTS_MODE=0
### Список IP адресов хостов для фильтра, через пробел (прим.: 192.168.0.10 192.168.0.15)
export ALLOWED_HOSTS_LIST=""
### Порт прозрачного прокси Tor (параметр TransPort в torrc)
export TOR_TRANS_PORT=9040
### DNS-сервер для резолвинга в домене .onion (Tor)
export ONION_DNS_ADDR="127.0.0.1#9053"
### VPN интерфейс для правил маршрутизации
export IF_VPN="tun0"
### IP адрес шлюза для VPN конфигурации. Если не задан, используется адрес VPN интерфейса (или адрес пира для протоколов PPP)
export VPN_GW_IP=""
### Начальный номер таблицы маршрутизации для отправки пакетов в VPN туннель
export VPN_ROUTE_TABLE_ID_START=149
### Начальный номер таблицы маршрутизации для отправки локальных пакетов в tproxy
export TPROXY_ROUTE_TABLE_ID_START=201
### Приоритет правила отбора пакетов при маршрутизации в VPN-интерфейс
export VPN_RULE_PRIO=1000
### Приоритет правила отбора пакетов при маршрутизации в lo интерфейс
export LO_RULE_PRIO=1000
### Способ добавления в таблицу маршрутизации правила для отправки пакетов в VPN туннель (0 - hotplug.d, 1 - скрипт ruab_route_check)
export VPN_ROUTE_CHECK=0
### Тип прозрачного прокси (0 - redirect, 1 - tproxy)
export T_PROXY_TYPE=0
### TCP порт прокси в режиме прозрачного прокси
export T_PROXY_PORT_TCP=1100
### UDP порт прокси в режиме прозрачного прокси
export T_PROXY_PORT_UDP=1100
### Отправлять в прозрачный прокси UDP-трафик (0 - выкл, 1 - вкл)
export T_PROXY_ALLOW_UDP=0
### Начальное значение метки для отбора пакетов в фильтрах
export PKTS_MARK_START=8
### Запись событий в syslog (0 - выкл, 1 - вкл)
export ENABLE_LOGGING=1
### Вывод дополнительных сообщений в лог (0 - выкл, 1, 2)
export DEBUG=0
### Файл для вывода некоторых отладочных сообщений
export DEBUG_FILE="/tmp/${NAME}.debug"
### Html-страница с инфо о текущем статусе (0 - выкл, 1 - вкл) (не используется в OpenWrt)
export ENABLE_HTML_INFO=0
### Максимальное кол-во элементов списка nftables
export NFTSET_MAXELEM_CIDR=65535
export NFTSET_MAXELEM_IP=1000000
export NFTSET_MAXELEM_DNSMASQ=65535
export NFTSET_MAXELEM_BYPASS_IP=65535
export NFTSET_MAXELEM_BYPASS_FQDN=65535
### Политика отбора элементов в сетах nftables. "performance" - производительность и большее потребление RAM. "memory" - хуже производительность и меньше потребление RAM
export NFTSET_POLICY_CIDR="memory"
export NFTSET_POLICY_IP="memory"
export NFTSET_POLICY_DNSMASQ="performance"
### Таймаут для записей в сете $NFTSET_DNSMASQ
export NFTSET_DNSMASQ_TIMEOUT="150m"
### Динамическое обновление таймаута записей в сете $NFTSET_DNSMASQ (0 - выкл, 1 - вкл)
export NFTSET_DNSMASQ_TIMEOUT_UPDATE=1
### Приоритет правил отбора пакетов nftables
export NFT_PRIO=-140
### Приоритет правил отбора пакетов nftables для трафика локальных клиентов
export NFT_PRIO_LOCAL=-140
### Кол-во попыток скачивания удаленного файла записей пользователя (в случае неудачи)
export USER_ENTRIES_REMOTE_DOWNLOAD_ATTEMPTS=3
### Таймаут между попытками скачивания
export USER_ENTRIES_REMOTE_DOWNLOAD_TIMEOUT=60
### Директория конфигов экземпляров записей пользователя
export USER_INSTANCES_DIR="${CONFIG_DIR}/user_instances"
### Директория списков записей пользователя
export USER_LISTS_DIR="${CONFIG_DIR}/user_lists"
### Переменные экземпляров записей пользователя
export USER_INSTANCE_VARS="U_ENABLED U_NAME U_PROXY_MODE U_TOR_TRANS_PORT U_ONION_DNS_ADDR U_IF_VPN U_VPN_GW_IP U_T_PROXY_TYPE U_T_PROXY_PORT_TCP U_T_PROXY_PORT_UDP U_T_PROXY_ALLOW_UDP U_USER_ENTRIES_DNS U_USER_ENTRIES_REMOTE U_ENABLE_ENTRIES_REMOTE_PROXY U_ENABLE_FPROXY U_FPROXY_LIST"
### Кол-во экземпляров записей пользователя (не более 50!)
export USER_INSTANCES_MAX=5
### Режим списка IP адресов исключаемых из обхода блокировок (0 - выкл, 1 - вкл)
export BYPASS_MODE=0
### DNS-сервер для исключаемых записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет
export BYPASS_ENTRIES_DNS=""
### Файл исключаемых записей
export BYPASS_ENTRIES_FILE="${CONFIG_DIR}/bypass_entries"
### Включение режима полного прокси (0 - выкл, 1 - вкл)
export ENABLE_FPROXY=0
### Список IP адресов хостов для режима полного прокси, через пробел (прим.: 192.168.0.10 192.168.0.15)
export FPROXY_LIST=""
### Список приватных сетей для режима полного прокси, через пробел
export FPROXY_PRIVATE_NETS="192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 100.64.0.0/10 169.254.0.0/16"
### Режим безопасного обновления блэклиста. Скачивание во временный файл и затем замена основного. Увеличивает потребление памяти (0 - выкл, 1 - вкл)
export ENABLE_TMP_DOWNLOADS=0
### Скачивать блэклисты через прокси
export ENABLE_BLLIST_PROXY=0
### Список хостов источников блэклиста
export BLLIST_HOSTS="reestr.rublacklist.net raw.githubusercontent.com app.assembla.com antifilter.download blockedin.org"
### Кол-во попыток обновления блэклиста (в случае неудачи)
export MODULE_RUN_ATTEMPTS=3
### Таймаут между попытками обновления
export MODULE_RUN_TIMEOUT=60
### Модули для получения и обработки блэклиста
export BLLIST_MODULE=""
#export BLLIST_MODULE="${MODULES_DIR}/ruab_parser.lua"
#export BLLIST_MODULE="${MODULES_DIR}/ruab_parser.py"
##############################
### Режим обхода блокировок: ruantiblock-ip, ruantiblock-fqdn, zapret-info-ip, zapret-info-fqdn, zapret-info-fqdn-only, rublacklist-ip, rublacklist-fqdn, rublacklist-fqdn-only, antifilter-ip, antifilter-fqdn, antifilter-fqdn-only, fz-ip, fz-fqdn, fz-fqdn-only
export BLLIST_PRESET=""
### В случае если из источника получено менее указанного кол-ва записей, то обновления списков не происходит
export BLLIST_MIN_ENTRIES=3000
### Лимит IP адресов. При достижении, в конфиг nftables будет добавлена вся подсеть /24 вместо множества IP адресов пренадлежащих этой сети (0 - выкл)
export BLLIST_IP_LIMIT=0
### Файл с подсетями класса C (/24). IP адреса из этих подсетей не группируются при оптимизации (записи д.б. в виде: 68.183.221. 149.154.162. и пр. Одна запись на строку)
export BLLIST_GR_EXCLUDED_NETS_FILE="${CONFIG_DIR}/gr_excluded_nets"
### Группировать идущие подряд IP адреса в подсетях /24 в диапазоны CIDR
export BLLIST_SUMMARIZE_IP=0
### Группировать идущие подряд подсети /24 в диапазоны CIDR
export BLLIST_SUMMARIZE_CIDR=0
### Фильтрация записей блэклиста по шаблонам из файла BLLIST_IP_FILTER_FILE. Записи (IP, CIDR) попадающие под шаблоны исключаются из кофига nftables (0 - выкл, 1 - вкл)
export BLLIST_IP_FILTER=0
### Тип фильтра IP (0 - все записи, кроме совпадающих с шаблонами; 1 - только записи, совпадающие с шаблонами)
export BLLIST_IP_FILTER_TYPE=0
### Файл с шаблонами IP для опции BLLIST_IP_FILTER (каждый шаблон в отдельной строке. # в первом символе строки - комментирует строку)
export BLLIST_IP_FILTER_FILE="${CONFIG_DIR}/ip_filter"
### Включение опции исключения IP/CIDR из блэклиста
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 не подлежащими группировке при оптимизации (одна запись на строку)
export BLLIST_GR_EXCLUDED_SLD_FILE="${CONFIG_DIR}/gr_excluded_sld"
### Файл с масками SLD не подлежащими группировке при оптимизации (одна запись на строку)
export BLLIST_GR_EXCLUDED_SLD_MASKS_FILE="${CONFIG_DIR}/gr_excluded_sld_mask"
### Фильтрация записей блэклиста по шаблонам из файла ENTRIES_FILTER_FILE. Записи (FQDN) попадающие под шаблоны исключаются из кофига dnsmasq (0 - выкл, 1 - вкл)
export BLLIST_FQDN_FILTER=0
### Тип фильтра FQDN (0 - все записи, кроме совпадающих с шаблонами; 1 - только записи, совпадающие с шаблонами)
export BLLIST_FQDN_FILTER_TYPE=0
### Файл с шаблонами FQDN для опции BLLIST_FQDN_FILTER (каждый шаблон в отдельной строке. # в первом символе строки - комментирует строку)
export BLLIST_FQDN_FILTER_FILE="${CONFIG_DIR}/fqdn_filter"
### Включение опции исключения FQDN из блэклиста
export BLLIST_FQDN_EXCLUDED_ENABLE=0
### Файл с записями FQDN для опции BLLIST_FQDN_EXCLUDED_ENABLE
export BLLIST_FQDN_EXCLUDED_FILE="${CONFIG_DIR}/fqdn_excluded"
### Включение опции исключения записей определённых гос.органов из блэклиста
export BLLIST_ORG_EXCLUDED_ENABLE=0
### Файл с записями для опции BLLIST_ORG_EXCLUDED_ENABLE
export BLLIST_ORG_EXCLUDED_FILE="${CONFIG_DIR}/org_excluded"
### Обрезка www[0-9]. в FQDN (0 - выкл, 1 - вкл)
export BLLIST_STRIP_WWW=1
### Преобразование кириллических доменов в punycode (0 - выкл, 1 - вкл)
export BLLIST_ENABLE_IDN=0
### Перенаправлять DNS-запросы на альтернативный DNS-сервер для заблокированных FQDN (0 - выкл, 1 - вкл)
export BLLIST_ALT_NSLOOKUP=0
### Альтернативный DNS-сервер
export BLLIST_ALT_DNS_ADDR="8.8.8.8"
########################## Instances defaults ##########################
INSTANCES_DEF_PROXY_MODE=$PROXY_MODE
INSTANCES_DEF_TOR_TRANS_PORT=$TOR_TRANS_PORT
INSTANCES_DEF_IF_VPN=$IF_VPN
INSTANCES_DEF_T_PROXY_TYPE=$T_PROXY_TYPE
INSTANCES_DEF_T_PROXY_PORT_TCP=$T_PROXY_PORT_TCP
INSTANCES_DEF_T_PROXY_PORT_UDP=$T_PROXY_PORT_UDP
INSTANCES_DEF_T_PROXY_ALLOW_UDP=$T_PROXY_ALLOW_UDP
INSTANCES_DEF_ENABLE_BLLIST_PROXY=$ENABLE_BLLIST_PROXY
INSTANCES_DEF_ENABLE_FPROXY=$ENABLE_FPROXY
############################ Configuration #############################
### External config
[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"
CONFIG_SCRIPT="${SCRIPTS_DIR}/config_script"
export USER_INSTANCES_COMMON="${SCRIPTS_DIR}/user_instances_common"
export CONFIG_SCRIPT_USER_INSTANCES="${SCRIPTS_DIR}/config_script_user_instances"
BLLIST_SOURCES_SCRIPT="${SCRIPTS_DIR}/blacklist_sources"
### Event scripts
POST_START_SCRIPT="${MODULES_DIR}/post_start_script"
POST_STOP_SCRIPT="${MODULES_DIR}/post_stop_script"
PRE_UPDATE_SCRIPT="${MODULES_DIR}/pre_update_script"
POST_UPDATE_SCRIPT="${MODULES_DIR}/post_update_script"
### Config script
[ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT"
export DNSMASQ_DATA_FILE_BYPASS="${DNSMASQ_CONFDIR}/00-${NAME}_bypass.dnsmasq"
export DNSMASQ_DATA_FILE_USER_INSTANCES="${DNSMASQ_CONFDIR}/01-${NAME}_user_instances.dnsmasq"
export DNSMASQ_DATA_FILE="${DNSMASQ_CONFDIR}/02-${NAME}.dnsmasq"
### Utilities
export AWK_CMD="awk"
NFT_CMD="$(which nft)"
if [ $? -ne 0 ]; then
echo " Error! Nftables doesn't exists" >&2
exit 1
fi
LOGGER_CMD="$(which logger)"
if [ "$ENABLE_LOGGING" = "1" -a $? -ne 0 ]; then
echo " Logger doesn't exists" >&2
ENABLE_LOGGING=0
fi
export LOGGER_CMD
export LOGGER_PARAMS="-t ${APP_NAME}"
WGET_CMD="$(which wget)"
if [ $? -ne 0 ]; then
echo " Error! Wget doesn't exists" >&2
exit 1
fi
export WGET_CMD
export WGET_PARAMS="--no-check-certificate -q -O"
NSLOOKUP_CMD="$(which nslookup)"
if [ $? -ne 0 ]; then
echo " Error! Nslookup doesn't exists" >&2
exit 1
fi
IP_CMD="$(which ip)"
if [ $? -ne 0 ]; then
echo " Error! Iproute2 doesn't exists" >&2
exit 1
fi
export IP_CMD
USER_ENTRIES_PARSER="${MODULES_DIR}/ruab_parser_user_entries"
ROUTE_CHECK_EXEC="${MODULES_DIR}/ruab_route_check"
export IP_DATA_FILE="${DATA_DIR}/${NAME}.ip"
export IP_DATA_FILE_BYPASS="${DATA_DIR}/${NAME}_bypass.ip"
export IP_DATA_FILE_USER_INSTANCES="${DATA_DIR}/${NAME}_user_instances.ip"
export NFT_TABLE="ip r"
export NFT_TABLE_DNSMASQ="4#ip#r"
export NFTSET_LOCAL_IP="local_ip"
export NFTSET_ALLOWED_HOSTS="allowed_ip"
export NFTSET_BYPASS_IP="bi"
export NFTSET_BYPASS_FQDN="bd"
export NFTSET_FPROXY="fproxy"
export NFTSET_FPROXY_LOCAL="fproxy_local"
export NFTSET_BLLIST_PROXY="bllist_proxy"
export NFTSET_ONION="onion"
export NFTSET_CIDR="c"
export NFTSET_IP="i"
export NFTSET_DNSMASQ="d"
export NFTSET_LOCAL_IP_TYPE="ipv4_addr"
export NFTSET_ALLOWED_HOSTS_TYPE="ipv4_addr"
export NFTSET_BYPASS_IP_TYPE="ipv4_addr"
export NFTSET_BYPASS_FQDN_TYPE="ipv4_addr"
export NFTSET_FPROXY_TYPE="ipv4_addr"
export NFTSET_FPROXY_LOCAL_TYPE="ipv4_addr"
export NFTSET_BLLIST_PROXY_TYPE="ipv4_addr"
export NFTSET_CIDR_TYPE="ipv4_addr"
export NFTSET_IP_TYPE="ipv4_addr"
export NFTSET_DNSMASQ_TYPE="ipv4_addr"
export NFTSET_CIDR_PATTERN="set %s {type ${NFTSET_CIDR_TYPE};size ${NFTSET_MAXELEM_CIDR};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;"
export NFTSET_IP_PATTERN="set %s {type ${NFTSET_IP_TYPE};size ${NFTSET_MAXELEM_IP};policy ${NFTSET_POLICY_IP};flags dynamic;"
export NFTSET_CIDR_STRING_MAIN=$(printf "$NFTSET_CIDR_PATTERN" "${NFTSET_CIDR}")
export NFTSET_IP_STRING_MAIN=$(printf "$NFTSET_IP_PATTERN" "${NFTSET_IP}")
export NFTSET_BYPASS_IP_STRING="set ${NFTSET_BYPASS_IP} {type ${NFTSET_BYPASS_IP_TYPE};size ${NFTSET_MAXELEM_BYPASS_IP};policy ${NFTSET_POLICY_CIDR};flags interval;auto-merge;"
export UPDATE_STATUS_FILE="${DATA_DIR}/update_status"
export USER_ENTRIES_STATUS_FILE="${DATA_DIR}/user_entries_status"
U_PID_FILE="${RUN_FILES_DIR}/${NAME}_update.pid"
START_PID_FILE="${RUN_FILES_DIR}/${NAME}_start.pid"
TOKEN_FILE="${RUN_FILES_DIR}/${NAME}.token"
export HTML_OUTPUT="${HTML_DIR}/${NAME}.html"
NFT_FUNCTIONS="${SCRIPTS_DIR}/nft_functions"
INFO_OUTPUT_FUNCTION="${SCRIPTS_DIR}/info_output"
export IP_DATA_FILE_TMP="${IP_DATA_FILE}.tmp"
export IP_DATA_FILE_USER_INSTANCES_TMP="${IP_DATA_FILE_USER_INSTANCES}.tmp"
export DNSMASQ_DATA_FILE_USER_INSTANCES_TMP="${DNSMASQ_DATA_FILE_USER_INSTANCES}.tmp"
export DNSMASQ_DATA_FILE_TMP="${DNSMASQ_DATA_FILE}.tmp"
export UPDATE_STATUS_FILE_TMP="${UPDATE_STATUS_FILE}.tmp"
export USER_ENTRIES_STATUS_FILE_TMP="${USER_ENTRIES_STATUS_FILE}.tmp"
export USER_INSTANCES_ALL=""
export USER_INSTANCES_ALL_FNAMES=""
export USER_INSTANCES_VPN=""
export USER_INSTANCES_VPN_FNAMES=""
export USER_INSTANCES_CFG=""
export USER_INSTANCES_CFG_FNAMES=""
INSTANCES_CACHE="${RUN_FILES_DIR}/${NAME}.instances"
DL_IPSET_URL=""
DL_DMASK_URL=""
DL_STAT_URL=""
######################### External functions ###########################
. "$NFT_FUNCTIONS"
. "$USER_INSTANCES_COMMON"
if [ -f "$INFO_OUTPUT_FUNCTION" ]; then
. "$INFO_OUTPUT_FUNCTION"
else
ENABLE_HTML_INFO=0
fi
############################## Functions ###############################
Help() {
cat << EOF
Usage: ${APP_NAME} start|force-start|stop|destroy|restart|reload|update|force-update|blacklist-files|status|raw-status|html-info|help
start : Start
force-start : Removing the PID-file before running
stop : Stop
destroy : Stop, remove nft table and clear all data files
restart : Restart
reload : Renew nftables configuration
update : Update blacklist
force-update : Force update blacklist
blacklist-files : Create ${IP_DATA_FILE}, ${IP_DATA_FILE_USER_INSTANCES}, ${DNSMASQ_DATA_FILE}, ${DNSMASQ_DATA_FILE_USER_INSTANCES}, ${IP_DATA_FILE_BYPASS}, ${DNSMASQ_DATA_FILE_BYPASS} (without network functions)
status : Status & some info
raw-status : Return code: 0 - enabled, 1 - error, 2 - disabled, 3 - starting, 4 - updating
html-info : Return the html-info output
-h|--help|help : This message
Examples:
${APP_NAME} start
${APP_NAME} force-start
${APP_NAME} stop
${APP_NAME} destroy
${APP_NAME} restart
${APP_NAME} reload
${APP_NAME} update
${APP_NAME} force-update
${APP_NAME} blacklist-files
${APP_NAME} status
${APP_NAME} raw-status
${APP_NAME} html-info
EOF
}
MakeLogRecord() {
if [ "$ENABLE_LOGGING" = "1" ]; then
$LOGGER_CMD $LOGGER_PARAMS -p "user.${1}" "$2"
fi
}
Download() {
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.Download ${1} ${2}" >&2
MakeLogRecord "debug" "ruantiblock.Download ${1} ${2}"
fi
$WGET_CMD $WGET_PARAMS "$1" "$2"
if [ $? -ne 0 ]; then
echo " Downloading failed! Connection error (${2})" >&2
MakeLogRecord "err" "Downloading failed! Connection error (${2})"
return 1
fi
}
DownloadNativeBlacklist() {
local _ip_data_file _dnsmasq_data_file _update_status_file _return_code=0
if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then
_ip_data_file="$IP_DATA_FILE_TMP"
_dnsmasq_data_file="$DNSMASQ_DATA_FILE_TMP"
_update_status_file="$UPDATE_STATUS_FILE_TMP"
rm -f "$_ip_data_file" "$_dnsmasq_data_file" "$_update_status_file"
else
_ip_data_file="$IP_DATA_FILE"
_dnsmasq_data_file="$DNSMASQ_DATA_FILE"
_update_status_file="$UPDATE_STATUS_FILE"
fi
if [ -n "$DL_IPSET_URL" -a -n "$DL_DMASK_URL" -a -n "$DL_STAT_URL" ]; then
Download "$_ip_data_file" "$DL_IPSET_URL"
if [ $? -ne 0 ]; then
_return_code=1
else
Download "$_dnsmasq_data_file" "$DL_DMASK_URL"
if [ $? -ne 0 ]; then
_return_code=1
else
Download "$_update_status_file" "$DL_STAT_URL"
if [ $? -ne 0 ]; then
_return_code=1
fi
fi
fi
else
echo " Native blacklist configuration error (${1})" >&2
MakeLogRecord "err" "Native blacklist configuration error (${1})"
exit 1
fi
if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then
if [ $_return_code -eq 0 ]; then
mv -f "$_ip_data_file" "$IP_DATA_FILE"
mv -f "$_dnsmasq_data_file" "$DNSMASQ_DATA_FILE"
mv -f "$_update_status_file" "$UPDATE_STATUS_FILE"
else
rm -f "$_ip_data_file" "$_dnsmasq_data_file" "$_update_status_file"
fi
fi
return $_return_code
}
RestartDnsmasq() {
eval $(echo "$DNSMASQ_RESTART_CMD")
}
FlushNftSets() {
local _set
for _set in "$@"
do
$NFT_CMD flush set $NFT_TABLE "$_set" &> /dev/null
done
}
FlushInstancesNftSets() {
local _arg="$1" _name
for _name in $USER_INSTANCES_ALL " "
do
if [ "$_name" = " " ]; then
_name=""
else
_name=".${_name}"
fi
case "$_arg" in
bllist)
FlushNftSets "${NFTSET_CIDR}${_name}" "${NFTSET_IP}${_name}" "${NFTSET_DNSMASQ}${_name}" "${NFTSET_ONION}${_name}"
;;
*)
FlushNftSets "${NFTSET_FPROXY}${_name}" "${NFTSET_BLLIST_PROXY}${_name}" "${NFTSET_CIDR}${_name}" "${NFTSET_IP}${_name}" "${NFTSET_DNSMASQ}${_name}" "${NFTSET_ONION}${_name}"
;;
esac
done
}
FormatNftSetElemsList() {
printf "$1" | $AWK_CMD '{gsub(/[ ]+/, ",", $0); printf $0;}'
}
UpdateLocalIpSets() {
local _local_ips _fproxy_private
_local_ips=$($IP_CMD -4 addr list 2> /dev/null | $AWK_CMD '/inet/{if($2 !~ /^(127|0)/) printf $2 ","}')
FlushNftSets "$NFTSET_LOCAL_IP"
if [ -n "$_local_ips" ]; then
$NFT_CMD add element $NFT_TABLE "$NFTSET_LOCAL_IP" { "$_local_ips" }
fi
FlushNftSets "$NFTSET_FPROXY_LOCAL"
_fproxy_private=$(FormatNftSetElemsList "$FPROXY_PRIVATE_NETS")
if [ -n "$_fproxy_private" ]; then
$NFT_CMD add element $NFT_TABLE "$NFTSET_FPROXY_LOCAL" { "$_fproxy_private" }
fi
if [ -n "$_local_ips" ]; then
$NFT_CMD add element $NFT_TABLE "$NFTSET_FPROXY_LOCAL" { "$_local_ips" }
fi
}
AddBaseNftSets() {
local _allowed_hosts
$NFT_CMD add set $NFT_TABLE "$NFTSET_LOCAL_IP" { type "$NFTSET_LOCAL_IP_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
$NFT_CMD add set $NFT_TABLE "$NFTSET_ALLOWED_HOSTS" { type "$NFTSET_ALLOWED_HOSTS_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
_allowed_hosts=$(FormatNftSetElemsList "$ALLOWED_HOSTS_LIST")
if [ -n "$_allowed_hosts" ]; then
$NFT_CMD add element $NFT_TABLE "$NFTSET_ALLOWED_HOSTS" { "$_allowed_hosts" }
fi
$NFT_CMD add set $NFT_TABLE "$NFTSET_BYPASS_IP" { type "$NFTSET_BYPASS_IP_TYPE"\; size $NFTSET_MAXELEM_BYPASS_IP\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
$NFT_CMD add set $NFT_TABLE "$NFTSET_BYPASS_FQDN" { type "$NFTSET_BYPASS_FQDN_TYPE"\; size $NFTSET_MAXELEM_BYPASS_FQDN\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; }
$NFT_CMD add set $NFT_TABLE "$NFTSET_FPROXY_LOCAL" { type "$NFTSET_FPROXY_LOCAL_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
UpdateLocalIpSets
}
MakeInstanceNftSets() {
local _name="$1" _fproxy_list="$2" _fproxy_hosts
if [ "$_name" = " " ]; then
_name=""
else
_name=".${_name}"
fi
$NFT_CMD add set $NFT_TABLE "${NFTSET_CIDR}${_name}" { type "$NFTSET_CIDR_TYPE"\; size $NFTSET_MAXELEM_CIDR\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
$NFT_CMD add set $NFT_TABLE "${NFTSET_IP}${_name}" { type "$NFTSET_IP_TYPE"\; size $NFTSET_MAXELEM_IP\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; }
$NFT_CMD add set $NFT_TABLE "${NFTSET_DNSMASQ}${_name}" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; }
$NFT_CMD add set $NFT_TABLE "${NFTSET_ONION}${_name}" { type "$NFTSET_DNSMASQ_TYPE"\; size $NFTSET_MAXELEM_DNSMASQ\; policy "$NFTSET_POLICY_DNSMASQ"\; flags dynamic,timeout\; timeout "$NFTSET_DNSMASQ_TIMEOUT"\; }
$NFT_CMD add set $NFT_TABLE "${NFTSET_FPROXY}${_name}" { type "$NFTSET_FPROXY_TYPE"\; policy "$NFTSET_POLICY_CIDR"\; flags interval\; auto-merge\; }
_fproxy_hosts=$(FormatNftSetElemsList "$_fproxy_list")
if [ -n "$_fproxy_hosts" ]; then
$NFT_CMD add element $NFT_TABLE "${NFTSET_FPROXY}${_name}" { "$_fproxy_hosts" }
fi
$NFT_CMD add set $NFT_TABLE "${NFTSET_BLLIST_PROXY}${_name}" { type "$NFTSET_BLLIST_PROXY_TYPE"\; policy "$NFTSET_POLICY_IP"\; flags dynamic\; }
}
AddInstancesNftSets() {
local _inst
for _inst in $USER_INSTANCES_ALL_FNAMES
do
IncludeUserInstanceVars "$_inst"
MakeInstanceNftSets "$U_NAME" "$U_FPROXY_LIST"
ClearUserInstanceVars
done
MakeInstanceNftSets " " "$FPROXY_LIST"
}
UpdateBllistProxySet() {
local _name="$1" _urls="$2" _host _ip_string=""
if [ "$_name" = " " ]; then
_name=""
else
_name=".${_name}"
fi
for _host in $(echo "$_urls" | $AWK_CMD '
BEGIN {
RS = " ";
}
{
gsub("\n", "", $0);
sub(/^https?:\/\//, "", $0);
sub(/\/.*$/, "", $0);
sub(/:[0-9]{2,5}$/, "", $0);
if($0 ~ /^([a-z0-9._-]+[.])+([a-z]{2,}|xn--[a-z0-9]+)$/ || $0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}$/) {
hosts_arr[$0];
};
}
END {
for(i in hosts_arr) {
printf i " ";
};
}')
do
if printf "$_host" | $AWK_CMD '{exit ($0 ~ /^([0-9]{1,3}.){3}[0-9]{1,3}$/) ? 0 : 1}'; then
_ip_string="${_ip_string}${_host} "
else
_ip_string="${_ip_string}$($NSLOOKUP_CMD $_host 2> /dev/null | $AWK_CMD '/^Address: ([0-9]{1,3}.){3}[0-9]{1,3}$/ {printf $2" "}')"
fi
done
_ip_string=$(FormatNftSetElemsList "$_ip_string")
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.UpdateBllistProxySet()._ip_string=${_ip_string}; _name=${_name}" >&2
MakeLogRecord "debug" "ruantiblock.UpdateBllistProxySet()._ip_string=${_ip_string}; _name=${_name}"
fi
if [ -n "$_ip_string" ]; then
$NFT_CMD add element $NFT_TABLE "${NFTSET_BLLIST_PROXY}${_name}" { "$_ip_string" }
fi
}
UpdateBllistSets() {
local _return_code=0
if [ -f "$IP_DATA_FILE" -a -f "$IP_DATA_FILE_USER_INSTANCES" -a -f "$IP_DATA_FILE_BYPASS" ]; then
echo " Updating nft sets..."
$NFT_CMD -f "$IP_DATA_FILE_BYPASS"
_return_code=$?
if [ $_return_code -eq 0 ]; then
$NFT_CMD -f "$IP_DATA_FILE_USER_INSTANCES"
_return_code=$?
if [ $_return_code -eq 0 ]; then
$NFT_CMD -f "$IP_DATA_FILE"
_return_code=$?
fi
fi
if [ $_return_code -eq 0 ]; then
echo " Ok"
else
echo " Error! Nft set wasn't updated" >&2
MakeLogRecord "err" "Error! Nft set wasn't updated"
fi
fi
return $_return_code
}
AddUserInstancesNftRules() {
local _pkts_mark=$PKTS_MARK_START _inst _vpn_route_table_id=$VPN_ROUTE_TABLE_ID_START _tproxy_route_table_id=$TPROXY_ROUTE_TABLE_ID_START _route_table_id
for _inst in $USER_INSTANCES_ALL_FNAMES
do
IncludeUserInstanceVars "$_inst"
if [ "$U_PROXY_MODE" = "2" ]; then
_vpn_route_table_id=$(($_vpn_route_table_id + 1))
_route_table_id=$_vpn_route_table_id
elif [ "$U_PROXY_MODE" = "3" -a "$U_T_PROXY_TYPE" = "1" ]; then
_tproxy_route_table_id=$(($_tproxy_route_table_id + 1))
_route_table_id=$_tproxy_route_table_id
else
_route_table_id=0
fi
_pkts_mark=$(($_pkts_mark + 1))
NftInstanceAdd "\"$U_NAME\"" $_pkts_mark ${U_PROXY_MODE:=$INSTANCES_DEF_PROXY_MODE} ${U_TOR_TRANS_PORT:=$INSTANCES_DEF_TOR_TRANS_PORT} $_route_table_id "\"${U_IF_VPN:=$INSTANCES_DEF_IF_VPN}\"" ${U_T_PROXY_TYPE:=$INSTANCES_DEF_T_PROXY_TYPE} ${U_T_PROXY_PORT_TCP:=$INSTANCES_DEF_T_PROXY_PORT_TCP} ${U_T_PROXY_PORT_UDP:=$INSTANCES_DEF_T_PROXY_PORT_UDP} ${U_T_PROXY_ALLOW_UDP:=$INSTANCES_DEF_T_PROXY_ALLOW_UDP} ${U_ENABLE_ENTRIES_REMOTE_PROXY:=$INSTANCES_DEF_ENABLE_BLLIST_PROXY} ${U_ENABLE_FPROXY:=$INSTANCES_DEF_ENABLE_FPROXY} "\"$U_VPN_GW_IP\""
ClearUserInstanceVars
done
}
DeleteUserInstancesNftRules() {
local _inst _i=1 _j=1
for _inst in $USER_INSTANCES_CFG_FNAMES
do
IncludeUserInstanceVars "$_inst"
NftInstanceDelete "$U_NAME" 2> /dev/null
if [ "$U_PROXY_MODE" = "2" ]; then
NftRouteDelete $(($VPN_ROUTE_TABLE_ID_START + $_i)) 2> /dev/null
_i=$(($_i + 1))
elif [ "$U_PROXY_MODE" = "3" -a "$U_T_PROXY_TYPE" = "1" ]; then
NftRouteDelete $(($TPROXY_ROUTE_TABLE_ID_START + $_j)) 2> /dev/null
_j=$(($_j + 1))
fi
ClearUserInstanceVars
done
}
AddNftRules() {
local _chain_prio_first _chain_prio_local _chain_prio_fproxy _chain_prio_action _route_table_id
_chain_prio_first=$NFT_PRIO
_chain_prio_local=$NFT_PRIO_LOCAL
_chain_prio_fproxy=$(($NFT_PRIO + 1))
_chain_prio_action=$(($NFT_PRIO + 2))
if [ "$PROXY_MODE" = "2" ]; then
_route_table_id=$VPN_ROUTE_TABLE_ID_START
elif [ "$PROXY_MODE" = "3" -a "$T_PROXY_TYPE" = "1" ]; then
_route_table_id=$TPROXY_ROUTE_TABLE_ID_START
else
_route_table_id=0
fi
NftAddBaseChains $_chain_prio_first $_chain_prio_local $_chain_prio_fproxy
NftAddActionChains $_chain_prio_action
AddUserInstancesNftRules
NftInstanceAdd "\" \"" $PKTS_MARK_START ${PROXY_MODE:=$INSTANCES_DEF_PROXY_MODE} ${TOR_TRANS_PORT:=$INSTANCES_DEF_TOR_TRANS_PORT} $_route_table_id "\"${IF_VPN:=$INSTANCES_DEF_IF_VPN}\"" ${T_PROXY_TYPE:=$INSTANCES_DEF_T_PROXY_TYPE} ${T_PROXY_PORT_TCP:=$INSTANCES_DEF_T_PROXY_PORT_TCP} ${T_PROXY_PORT_UDP:=$INSTANCES_DEF_T_PROXY_PORT_UDP} ${T_PROXY_ALLOW_UDP:=$INSTANCES_DEF_T_PROXY_ALLOW_UDP} ${ENABLE_BLLIST_PROXY:=$INSTANCES_DEF_ENABLE_BLLIST_PROXY} ${ENABLE_FPROXY:=$INSTANCES_DEF_ENABLE_FPROXY} "\"$VPN_GW_IP\""
if [ "$PROXY_LOCAL_CLIENTS" = "1" ]; then
NftAddLocalClientsRule
fi
}
DeleteNftRules() {
NftDeleteActionChains
NftDeleteBaseChains
NftInstanceDelete " "
DeleteUserInstancesNftRules
if [ "$PROXY_MODE" = "2" ]; then
NftRouteDelete $VPN_ROUTE_TABLE_ID_START 2> /dev/null
elif [ "$PROXY_MODE" = "3" -a "$T_PROXY_TYPE" = "1" ]; then
NftRouteDelete $TPROXY_ROUTE_TABLE_ID_START 2> /dev/null
fi
}
SetNetConfig() {
$NFT_CMD add table $NFT_TABLE
AddBaseNftSets
AddInstancesNftSets
AddNftRules
}
DropNetConfig() {
DeleteNftRules
FlushInstancesNftSets
FlushNftSets "$NFTSET_LOCAL_IP" "$NFTSET_ALLOWED_HOSTS" "$NFTSET_FPROXY_LOCAL" "$NFTSET_BLLIST_PROXY" "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN"
}
DestroyNetConfig() {
$NFT_CMD flush table $NFT_TABLE &> /dev/null
$NFT_CMD delete table $NFT_TABLE &> /dev/null
}
CheckStatus() {
NftReturnStatus
return $?
}
GetVpnRouteStatus() {
local _inst _i=1 _ret_val=0
for _inst in $USER_INSTANCES_VPN_FNAMES
do
if ! NftRouteStatus $(($VPN_ROUTE_TABLE_ID_START + $_i)); then
_ret_val=1
break
fi
_i=$(($_i + 1))
done
if [ "$PROXY_MODE" = "2" ] && ! NftRouteStatus $VPN_ROUTE_TABLE_ID_START; then
_ret_val=1
fi
return $_ret_val
}
ClearDataFiles() {
local _arg="$1"
if [ -d "$DATA_DIR" ]; then
if [ -z "$_arg" -o "$_arg" = "main_instance" ]; then
printf "" > "$IP_DATA_FILE"
printf "0 0 0" > "$UPDATE_STATUS_FILE"
fi
if [ -z "$_arg" -o "$_arg" = "user_instances" ]; then
printf "" > "$IP_DATA_FILE_USER_INSTANCES"
printf "" > "$USER_ENTRIES_STATUS_FILE"
fi
if [ -z "$_arg" ]; then
printf "" > "$IP_DATA_FILE_BYPASS"
fi
fi
if [ -d "$DNSMASQ_CONFDIR" ]; then
if [ -z "$_arg" -o "$_arg" = "main_instance" ]; then
printf "" > "$DNSMASQ_DATA_FILE"
fi
if [ -z "$_arg" -o "$_arg" = "user_instances" ]; then
printf "" > "$DNSMASQ_DATA_FILE_USER_INSTANCES"
fi
if [ -z "$_arg" ]; then
printf "" > "$DNSMASQ_DATA_FILE_BYPASS"
fi
fi
}
PreStartCheck() {
[ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR"
[ "$ENABLE_HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR"
### Костыль для старта dnsmasq
if [ -d "$DNSMASQ_CONFDIR" ]; then
[ -e "$DNSMASQ_DATA_FILE" ] || printf "" > "$DNSMASQ_DATA_FILE"
[ -e "$DNSMASQ_DATA_FILE_BYPASS" ] || printf "" > "$DNSMASQ_DATA_FILE_BYPASS"
[ -e "$DNSMASQ_DATA_FILE_USER_INSTANCES" ] || printf "" > "$DNSMASQ_DATA_FILE_USER_INSTANCES"
fi
}
AddBypassEntries() {
if [ -d "$DATA_DIR" ]; then
printf "" > "$DNSMASQ_DATA_FILE_BYPASS"
printf "" > "$IP_DATA_FILE_BYPASS"
printf "flush set %s %s\nflush set %s %s\n" "$NFT_TABLE" "$NFTSET_BYPASS_IP" "$NFT_TABLE" "$NFTSET_BYPASS_FQDN" >> "$IP_DATA_FILE_BYPASS"
fi
FlushNftSets "$NFTSET_BYPASS_IP" "$NFTSET_BYPASS_FQDN"
if [ "$BYPASS_MODE" = "1" ]; then
if [ -f "$BYPASS_ENTRIES_FILE" ]; then
$AWK_CMD '
BEGIN {
delete ip_array;
delete fqdn_array;
}
function writeIpList(array, _str) {
for(i in array) {
_str = _str i ",";
};
return _str;
};
function writeDNSData(val, dns) {
if(length(dns) == 0 && length(ENVIRON["BYPASS_ENTRIES_DNS"]) > 0) {
dns = ENVIRON["BYPASS_ENTRIES_DNS"];
};
if(length(dns) > 0) {
printf "server=/%s/%s\n", val, dns >> ENVIRON["DNSMASQ_DATA_FILE_BYPASS"];
};
printf "nftset=/%s/%s#%s\n", val, ENVIRON["NFT_TABLE_DNSMASQ"], ENVIRON["NFTSET_BYPASS_FQDN"] >> ENVIRON["DNSMASQ_DATA_FILE_BYPASS"];
};
function writeFqdnEntries() {
for(i in fqdn_array) {
split(i, a, " ");
writeDNSData(a[1], a[2]);
};
};
($0 !~ /^([\040\011]*$|#)/) {
sub("\015", "", $0);
if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}([\057][0-9]{1,2})?$/) {
ip_array[$0];
}
else if($0 ~ /^([a-z0-9._-]+[.])*([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/) {
fqdn_array[$0];
};
}
END {
printf "table %s {\n%s", ENVIRON["NFT_TABLE"], ENVIRON["NFTSET_BYPASS_IP_STRING"] >> ENVIRON["IP_DATA_FILE_BYPASS"];
if(length(ip_array) > 0) {
printf "elements={%s};", writeIpList(ip_array) >> ENVIRON["IP_DATA_FILE_BYPASS"];
};
printf "}\n}\n" >> ENVIRON["IP_DATA_FILE_BYPASS"];
writeFqdnEntries();
}' "$BYPASS_ENTRIES_FILE"
fi
fi
}
AddUserEntries() {
local _inst _url _return_code=0 _instance_return_code=0 _attempt=1 _instance_entries_file _ip_data_file_user_instances _dnsmasq_data_file_user_instances _user_entries_status_file _str _update_string
if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then
_ip_data_file_user_instances="$IP_DATA_FILE_USER_INSTANCES_TMP"
_dnsmasq_data_file_user_instances="$DNSMASQ_DATA_FILE_USER_INSTANCES_TMP"
_user_entries_status_file="$USER_ENTRIES_STATUS_FILE_TMP"
rm -f "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file"
else
_ip_data_file_user_instances="$IP_DATA_FILE_USER_INSTANCES"
_dnsmasq_data_file_user_instances="$DNSMASQ_DATA_FILE_USER_INSTANCES"
_user_entries_status_file="$USER_ENTRIES_STATUS_FILE"
fi
if [ "$ENABLE_TMP_DOWNLOADS" != "1" ]; then
ClearDataFiles user_instances
fi
for _inst in $USER_INSTANCES_ALL_FNAMES
do
IncludeUserInstanceVars "$_inst"
_instance_entries_file="${USER_LISTS_DIR}/${_inst}"
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.AddUserEntries._instance_entries_file=${_instance_entries_file}" >&2
MakeLogRecord "debug" "ruantiblock.AddUserEntries._instance_entries_file=${_instance_entries_file}"
fi
printf "flush set %s %s\nflush set %s %s\n" "$NFT_TABLE" "${NFTSET_CIDR}.${U_NAME}" "$NFT_TABLE" "${NFTSET_IP}.${U_NAME}" >> "$_ip_data_file_user_instances"
if [ "$U_PROXY_MODE" != "2" -a "$U_PROXY_MODE" != "3" ]; then
### Запись для .onion
printf "server=/onion/%s\nnftset=/onion/%s#%s\n" "$U_ONION_DNS_ADDR" "$NFT_TABLE_DNSMASQ" "${NFTSET_ONION}.${U_NAME}" >> "$_dnsmasq_data_file_user_instances"
fi
if [ "$U_ENABLE_ENTRIES_REMOTE_PROXY" = "1" ]; then
for _url in $U_ENTRIES_REMOTE
do
UpdateBllistProxySet "$U_NAME" "$_url"
done
fi
export U_NAME
export U_ENTRIES_REMOTE
export U_ENTRIES_DNS
export I_NFTSET_CIDR_STRING="$(printf "$NFTSET_CIDR_PATTERN" "${NFTSET_CIDR}.${U_NAME}")"
export I_NFTSET_IP_STRING="$(printf "$NFTSET_IP_PATTERN" "${NFTSET_IP}.${U_NAME}")"
export I_NFTSET_DNSMASQ="${NFTSET_DNSMASQ}.${U_NAME}"
export I_IP_DATA_FILE="$_ip_data_file_user_instances"
export I_DNSMASQ_DATA_FILE="$_dnsmasq_data_file_user_instances"
export I_USER_ENTRIES_STATUS_FILE="$_user_entries_status_file"
export I_INSTANCE_ENTRIES_FILE="$_instance_entries_file"
$USER_ENTRIES_PARSER
_instance_return_code=$?
unset I_NFTSET_CIDR_STRING
unset I_NFTSET_IP_STRING
unset I_NFTSET_DNSMASQ
unset I_IP_DATA_FILE
unset I_DNSMASQ_DATA_FILE
unset I_USER_ENTRIES_STATUS_FILE
unset I_INSTANCE_ENTRIES_FILE
if [ "$U_ENABLE_ENTRIES_REMOTE_PROXY" = "1" ]; then
FlushNftSets "${NFTSET_BLLIST_PROXY}.${U_NAME}"
fi
if [ $_instance_return_code -ne 0 ]; then
_return_code=$_instance_return_code
if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then
break
fi
fi
ClearUserInstanceVars
done
if [ "$ENABLE_TMP_DOWNLOADS" = "1" ]; then
if [ $_return_code -eq 0 ]; then
ClearDataFiles user_instances
if [ -e "$_ip_data_file_user_instances" ]; then
cat "$_ip_data_file_user_instances" >> "$IP_DATA_FILE_USER_INSTANCES"
fi
if [ -e "$_dnsmasq_data_file_user_instances" ]; then
cat "$_dnsmasq_data_file_user_instances" >> "$DNSMASQ_DATA_FILE_USER_INSTANCES"
fi
if [ -e "$_user_entries_status_file" ]; then
mv -f "$_user_entries_status_file" "$USER_ENTRIES_STATUS_FILE"
fi
fi
rm -f "$_ip_data_file_user_instances" "$_dnsmasq_data_file_user_instances" "$_user_entries_status_file"
fi
if [ "$ENABLE_TMP_DOWNLOADS" != "1" ] || [ "$ENABLE_TMP_DOWNLOADS" = "1" -a $_return_code -eq 0 ]; then
while read _str
do
_update_string=$(printf "$_str" | $AWK_CMD '{
if(NF == 4) {
printf "User entries (%s): CIDR: %s, IP: %s, FQDN: %s", $4, $1, $2, $3;
};
}')
if [ -n "$_update_string" ]; then
### STDOUT
echo " ${_update_string}"
MakeLogRecord "notice" "${_update_string}"
fi
done < "$USER_ENTRIES_STATUS_FILE"
fi
return $_return_code
}
ToggleUPIDFile() {
if [ "$1" = "del" ]; then
rm -f "$U_PID_FILE"
else
echo "$$" > "$U_PID_FILE"
fi
}
GetMainInstanceEntries() {
local _return_code=1 _attempt=1 _update_string
PreStartCheck
if [ -n "$BLLIST_PRESET" -a -n "$BLLIST_MODULE" ]; then
while :
do
if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then
UpdateBllistProxySet " " "$BLLIST_HOSTS"
fi
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.GetMainInstanceEntries: BLLIST_MODULE=${BLLIST_MODULE} MODULE_RUN_TIMEOUT=${MODULE_RUN_TIMEOUT} _attempt=${_attempt}" >&2
MakeLogRecord "debug" "ruantiblock.GetMainInstanceEntries: BLLIST_MODULE=${BLLIST_MODULE} MODULE_RUN_TIMEOUT=${MODULE_RUN_TIMEOUT} _attempt=${_attempt}"
echo "BLLIST_MODULE=${BLLIST_MODULE}" > "$DEBUG_FILE"
$BLLIST_MODULE >> "$DEBUG_FILE" 2>&1
_return_code=$?
echo " ruantiblock.GetMainInstanceEntries._return_code=${_return_code}" >&2
MakeLogRecord "debug" "ruantiblock.GetMainInstanceEntries._return_code=${_return_code}"
else
$BLLIST_MODULE
_return_code=$?
fi
[ $_return_code -eq 0 ] && break
### STDOUT
echo " Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]" >&2
MakeLogRecord "err" "Module run attempt ${_attempt}: failed [${BLLIST_MODULE}]"
_attempt=$(($_attempt + 1))
[ $_attempt -gt $MODULE_RUN_ATTEMPTS ] && break
sleep $MODULE_RUN_TIMEOUT
done
if [ "$ENABLE_BLLIST_PROXY" = "1" ]; then
FlushNftSets "$NFTSET_BLLIST_PROXY"
fi
if [ $_return_code -eq 0 ]; then
_update_string=$($AWK_CMD '{
printf "Received entries: %s\n", (NF < 3) ? "No data" : "CIDR: "$1", IP: "$2", FQDN: "$3;
exit;
}' "$UPDATE_STATUS_FILE")
### STDOUT
echo " ${_update_string}"
MakeLogRecord "notice" "${_update_string}"
printf " $(date +%d.%m.%Y-%H:%M)\n" >> "$UPDATE_STATUS_FILE"
fi
elif [ -z "$BLLIST_PRESET" -a -z "$BLLIST_MODULE" ]; then
ClearDataFiles main_instance
_return_code=3
else
_return_code=2
return $_return_code
fi
if [ $_return_code -eq 0 ]; then
if [ "$PROXY_MODE" = "2" -o "$PROXY_MODE" = "3" ]; then
printf "" >> "$DNSMASQ_DATA_FILE"
else
### Запись для .onion в $DNSMASQ_DATA_FILE
printf "server=/onion/%s\nnftset=/onion/%s#%s\n" "$ONION_DNS_ADDR" "$NFT_TABLE_DNSMASQ" "$NFTSET_ONION" >> "$DNSMASQ_DATA_FILE"
fi
fi
return $_return_code
}
GetBlacklistFiles() {
local _return_code=0 _user_entries_ret_code=1
AddBypassEntries
GetMainInstanceEntries
case $? in
0)
echo " Blacklist updated"
MakeLogRecord "notice" "Blacklist updated"
;;
2)
echo " Error! Blacklist update error" >&2
MakeLogRecord "err" "Error! Blacklist update error"
_return_code=1
;;
3)
:
;;
*)
echo " Module error! [${BLLIST_MODULE}]" >&2
MakeLogRecord "err" "Module error! [${BLLIST_MODULE}]"
_return_code=1
;;
esac
AddUserEntries
_user_entries_ret_code=$?
if [ $_return_code -eq 0 ]; then
_return_code=$_user_entries_ret_code
fi
return $_return_code
}
MakeInstancesCache() {
printf "USER_INSTANCES_ALL=\"${USER_INSTANCES_ALL}\"\nUSER_INSTANCES_ALL_FNAMES=\"${USER_INSTANCES_ALL_FNAMES}\"\nUSER_INSTANCES_VPN=\"${USER_INSTANCES_VPN}\"\nUSER_INSTANCES_VPN_FNAMES=\"${USER_INSTANCES_VPN_FNAMES}\"\nUSER_INSTANCES_CFG=\"${USER_INSTANCES_CFG}\"\nUSER_INSTANCES_CFG_FNAMES=\"${USER_INSTANCES_CFG_FNAMES}\"\n" > "$INSTANCES_CACHE"
}
DeleteInstancesCache() {
rm -f "$INSTANCES_CACHE"
}
Init() {
local _arg="$1"
. "$BLLIST_SOURCES_SCRIPT"
if [ -e "$INSTANCES_CACHE" ]; then
. "$INSTANCES_CACHE"
if [ $DEBUG -ge 2 ]; then
echo " ruantiblock.Init(): read from INSTANCES_CACHE" >&2
MakeLogRecord "debug" "ruantiblock.Init(): read from INSTANCES_CACHE"
fi
else
SetUserInstancesItems
fi
}
MakeToken() {
date +%s > "$TOKEN_FILE"
}
CheckDnsmasqConfDir() {
if [ ! -d "$DNSMASQ_CONFDIR" ]; then
echo " Error! DNSMASQ_CONFDIR (${DNSMASQ_CONFDIR}) does not exists" >&2
MakeLogRecord "err" "Error! DNSMASQ_CONFDIR (${DNSMASQ_CONFDIR}) does not exists"
return 1
fi
return 0
}
Update() {
local _arg="$1" _return_code=0 _upd_sets_ret_code=0
MakeToken
if [ -e "$U_PID_FILE" ] && [ "$_arg" != "force-update" ]; then
echo " ${NAME} ${_arg} - Error! Another instance of update is already running" >&2
MakeLogRecord "err" "${_arg} - Error! Another instance of update is already running"
_return_code=2
else
ToggleUPIDFile add
### Pre-update script
[ -x "$PRE_UPDATE_SCRIPT" ] && $PRE_UPDATE_SCRIPT
echo " ${NAME} ${_arg}..."
MakeLogRecord "notice" "${_arg}..."
if [ "$NFTSET_CLEAR_SETS" = "1" ]; then
FlushInstancesNftSets bllist
fi
GetBlacklistFiles
_return_code=$?
FlushInstancesNftSets bllist
UpdateBllistSets
_upd_sets_ret_code=$?
if [ $_return_code -eq 0 ]; then
_return_code=$_upd_sets_ret_code
fi
RestartDnsmasq
ToggleUPIDFile del
### Post-update script
[ -x "$POST_UPDATE_SCRIPT" ] && $POST_UPDATE_SCRIPT &
fi
MakeToken
return $_return_code
}
Start() {
local _arg="$1" _return_code=1
if [ -e "$START_PID_FILE" ]; then
echo " ${NAME} is currently starting..." >&2
return 1
else
echo "$$" > "$START_PID_FILE"
fi
MakeToken
Init
if CheckStatus; then
echo " ${NAME} is already running" >&2
_return_code=1
else
echo " ${NAME} ${_arg}..."
MakeLogRecord "info" "${_arg}..."
DropNetConfig &> /dev/null
SetNetConfig
PreStartCheck
UpdateBllistSets
_return_code=$?
if [ "$VPN_ROUTE_CHECK" = "1" -a -x "$ROUTE_CHECK_EXEC" ] && [ "$PROXY_MODE" = "2" -o -n "$USER_INSTANCES_VPN" ]; then
$ROUTE_CHECK_EXEC start &> /dev/null &
fi
MakeInstancesCache
### Post-start script
[ -x "$POST_START_SCRIPT" ] && $POST_START_SCRIPT &
fi
rm -f "$START_PID_FILE"
MakeToken
return $_return_code
}
Stop() {
local _arg="$1" _return_code=1
if CheckStatus; then
MakeToken
echo " ${NAME} ${_arg}..."
MakeLogRecord "info" "${_arg}..."
DropNetConfig &> /dev/null
_return_code=$?
if [ -x "$ROUTE_CHECK_EXEC" ]; then
$ROUTE_CHECK_EXEC stop &> /dev/null
fi
### Post-stop script
[ -x "$POST_STOP_SCRIPT" ] && $POST_STOP_SCRIPT &
MakeToken
else
echo " ${NAME} does not running" >&2
fi
DeleteInstancesCache
return $_return_code
}
Reload() {
local _i=0 _attempts=60
if CheckStatus; then
MakeToken
while [ -e "$START_PID_FILE" ]
do
if [ $_i -ge $_attempts ]; then
return 1
fi
_i=$(($_i + 1))
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.Reload._i=${_i}" >&2
MakeLogRecord "debug" "ruantiblock.Reload._i ${_i}"
fi
sleep 1
done
if [ $DEBUG -ge 1 ]; then
echo " ruantiblock.Reload()" >&2
MakeLogRecord "debug" "ruantiblock.Reload()"
fi
echo " ${NAME} reload..."
DeleteNftRules &> /dev/null
AddNftRules &> /dev/null
UpdateLocalIpSets
MakeToken
else
echo " ${NAME} does not running" >&2
fi
}
Status() {
local _update_status _user_entries_status _vpn_error
if [ -f "$UPDATE_STATUS_FILE" ]; then
_update_status=$($AWK_CMD '{
update_string=(NF < 4) ? "No data" : $4" (CIDR: "$1" | IP: "$2" | FQDN: "$3")";
printf "Last blacklist update: %s", update_string;
}' "$UPDATE_STATUS_FILE")
else
_update_status="Last blacklist update: No data"
fi
if [ -f "$USER_ENTRIES_STATUS_FILE" ]; then
_user_entries_status=$($AWK_CMD '{
if(NF == 4) {
printf " User entries (%s): CIDR: %s | IP: %s | FQDN: %s\n", $4, $1, $2, $3;
};
}' "$USER_ENTRIES_STATUS_FILE")
fi
if ! GetVpnRouteStatus; then
_vpn_error="\033[1;31mVPN ROUTING ERROR! (NEED THE RESTART)\033[m"
fi
NftListBllistChain 2> /dev/null | $AWK_CMD -v UPDATE_STATUS="$_update_status" -v USER_ENTRIES_STATUS="$_user_entries_status" -v VPN_ERROR="$_vpn_error" '
BEGIN {
rules_str = "";
nftset = "";
bytes = "";
}
/@/ {
if(match($0, /@[^ ]+/) != 0) {
nftset = substr($0, RSTART+1, RLENGTH-1);
if(match($0, /bytes [^ ]+/) != 0) {
bytes = substr($0, RSTART+6, RLENGTH-6);
};
rules_str = rules_str " Match-set: " nftset "\n Bytes: " bytes "\n\n";
};
}
END {
if(NR == 0) {
printf "\n \033[1m" ENVIRON["NAME"] " status\033[m: \033[1mDisabled\033[m\n\n";
exit 2;
};
printf "\n \033[1m" ENVIRON["NAME"] " status\033[m: \033[1;32mEnabled\033[m\n\n PROXY_MODE: " ENVIRON["PROXY_MODE"] "\n PROXY_LOCAL_CLIENTS: " ENVIRON["PROXY_LOCAL_CLIENTS"] "\n BLLIST_PRESET: " ENVIRON["BLLIST_PRESET"] "\n BLLIST_MODULE: " ENVIRON["BLLIST_MODULE"] "\n";
printf "\n "UPDATE_STATUS"\n";
if(length(USER_ENTRIES_STATUS) > 0) {
printf "\n"USER_ENTRIES_STATUS"\n";
};
if(length(VPN_ERROR) > 0) {
printf "\n "VPN_ERROR"\n";
};
printf "\n \033[4mNftables rules\033[m:\n\n";
printf rules_str;
}'
}
StatusOutput() {
if [ "$ENABLE_HTML_INFO" = "1" -a -d "$HTML_DIR" ]; then
Info
fi
}
############################ Main section ##############################
return_code=1
case "$1" in
start|force-start)
[ "$1" = "force-start" ] && rm -f "$START_PID_FILE"
Start "$1"
return_code=$?
StatusOutput
;;
stop)
Init
Stop "$1"
return_code=$?
StatusOutput
;;
restart|delayed-restart)
if [ "$1" = "delayed-restart" -a -n "$2" ]; then
{
echo "$$" > "$START_PID_FILE"
sleep $2 &> /dev/null
rm -f "$START_PID_FILE"
Init
Stop "stop"
Start "start"
return_code=$?
StatusOutput
exit $return_code;
} &> /dev/null &
return_code=0
else
Init
Stop "stop"
Start "start"
return_code=$?
StatusOutput
fi
;;
reload)
Init
Reload
return_code=$?
StatusOutput
;;
destroy)
Init
Stop "$1" &> /dev/null
DestroyNetConfig
ClearDataFiles
return_code=$?
ToggleUPIDFile del
RestartDnsmasq
StatusOutput
;;
update|force-update)
Init
if CheckStatus; then
:
else
echo " ${NAME} ${_arg} - Error! ${NAME} does not running or another error has occurred" >&2
exit 1
fi
UpdateLocalIpSets
if CheckDnsmasqConfDir; then
Update "$1"
return_code=$?
StatusOutput
else
return_code=1
fi
;;
blacklist-files)
Init
if [ -e "$U_PID_FILE" ] && [ "$1" != "force-update" ]; then
echo " ${NAME} - Error! Another instance of update is already running" >&2
exit 2
else
if CheckDnsmasqConfDir; then
GetBlacklistFiles
return_code=$?
else
return_code=1
fi
fi
;;
status)
Init
Status
return_code=$?
;;
raw-status)
Init
CheckStatus
return_code=$?
case $return_code in
0)
if [ -e "$START_PID_FILE" ]; then
return_code=3
echo 3
elif [ -e "$U_PID_FILE" ]; then
return_code=4
echo 4
else
echo 0
fi
;;
*)
return_code=2
echo 2
;;
esac
;;
vpn-route-status)
Init
GetVpnRouteStatus
return_code=$?
echo $return_code
;;
html-info)
Init
Info
return_code=$?
;;
-h|--help|help)
Help
exit 0
;;
*)
Help
exit 1
;;
esac
exit $return_code;