mirror of
https://github.com/gSpotx2f/ruantiblock_openwrt.git
synced 2026-05-14 14:40:58 +00:00
753 lines
28 KiB
Bash
Executable File
753 lines
28 KiB
Bash
Executable File
#!/bin/sh
|
||
|
||
########################################################################
|
||
#
|
||
# Ruantiblock
|
||
# (с) 2020 gSpot (https://github.com/gSpotx2f/ruantiblock_openwrt)
|
||
#
|
||
########################################################################
|
||
|
||
export NAME="ruantiblock"
|
||
export LANG="en_US.UTF-8"
|
||
export LANGUAGE="en"
|
||
|
||
#################### Platform-specific settings ########################
|
||
|
||
CONFIG_DIR="/etc/${NAME}"
|
||
CONFIG_FILE="${CONFIG_DIR}/${NAME}.conf"
|
||
export DATA_DIR="/var/${NAME}"
|
||
export MODULES_DIR="/usr/libexec/${NAME}"
|
||
### Дополнительный конфиг dnsmasq с FQDN записями блэклиста
|
||
export DNSMASQ_DATA_FILE="/var/dnsmasq.d/${NAME}.dnsmasq"
|
||
### Команда для перезапуска dnsmasq
|
||
export DNSMASQ_RESTART_CMD="/etc/init.d/dnsmasq restart"
|
||
### Директория для html-страницы статуса (не используется в OpenWrt)
|
||
export HTML_DIR="/www"
|
||
|
||
########################## Default Settings ############################
|
||
|
||
### Режим обработки пакетов в правилах iptables (1 - Tor, 2 - VPN, 3 - Прозрачный прокси)
|
||
export PROXY_MODE=1
|
||
### Применять правила проксификации для трафика локальных сервисов роутера (0 - off, 1 - on)
|
||
export PROXY_LOCAL_CLIENTS=1
|
||
### Удаление записей из основных сетов перед началом заполнения временных сетов при обновлении (для освобождения оперативной памяти перед заполнением сетов) (0 - off, 1 - on)
|
||
export IPSET_CLEAR_SETS=0
|
||
### Режим фильтра хостов которым разрешено обходить блокировки (0 - выкл., 1 - только адреса из списка, 2 - любые адреса кроме присутствующих в списке)
|
||
export ALLOWED_HOSTS_MODE=0
|
||
### Список IP адресов хостов для фильтра, через пробел (прим.: 192.168.0.10 192.168.0.15)
|
||
export ALLOWED_HOSTS_LIST=""
|
||
### VPN интерфейс для правил маршрутизации
|
||
export IF_VPN="tun0"
|
||
### Порт прозрачного прокси Tor (параметр TransPort в torrc)
|
||
export TOR_TRANS_PORT=9040
|
||
### Отправлять в Tor UDP-трафик (0 - off, 1 - on)
|
||
export TOR_ALLOW_UDP=0
|
||
### DNS-сервер для резолвинга в домене .onion (Tor)
|
||
export ONION_DNS_ADDR="127.0.0.1#9053"
|
||
### --set-mark для отбора пакетов в VPN туннель
|
||
export VPN_PKTS_MARK=8
|
||
### TCP порт прокси в режиме прозрачного прокси
|
||
export T_PROXY_PORT_TCP=1100
|
||
### UDP порт прокси в режиме прозрачного прокси
|
||
export T_PROXY_PORT_UDP=1100
|
||
### Отправлять в прозрачный прокси UDP-трафик (0 - off, 1 - on)
|
||
export T_PROXY_ALLOW_UDP=0
|
||
### Добавление в список блокировок пользовательских записей из файла $USER_ENTRIES_FILE (0 - off, 1 - on)
|
||
### В $DATA_DIR можно создать текстовый файл user_entries с записями IP, CIDR или FQDN (одна на строку). Эти записи будут добавлены в список блокировок
|
||
### В записях FQDN можно задать DNS-сервер для разрешения данного домена, через пробел (прим.: domain.com 8.8.8.8)
|
||
### Можно комментировать строки (#)
|
||
export ADD_USER_ENTRIES=0
|
||
### DNS-сервер для пользовательских записей (пустая строка - без DNS-сервера). Можно с портом: 8.8.8.8#53. Если в записи указан свой DNS-сервер - он имеет приоритет
|
||
export USER_ENTRIES_DNS=""
|
||
### Файл пользовательских записей
|
||
export USER_ENTRIES_FILE="${CONFIG_DIR}/user_entries"
|
||
### Запись событий в syslog (0 - off, 1 - on)
|
||
export ENABLE_LOGGING=1
|
||
### Html-страница с инфо о текущем статусе (0 - off, 1 - on) (не используется в OpenWrt)
|
||
export ENABLE_HTML_INFO=0
|
||
### Максимальное кол-во элементов списка ipset
|
||
export IPSET_MAXELEM=2000000
|
||
### Таймаут для записей в сете $IPSET_DNSMASQ
|
||
export IPSET_DNSMASQ_TIMEOUT=3600
|
||
### Кол-во попыток обновления блэклиста (в случае неудачи)
|
||
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-fqdn, ruantiblock-ip, zapret-info-fqdn, zapret-info-ip, rublacklist-fqdn, rublacklist-ip, antifilter-ip
|
||
export BLLIST_PRESET=""
|
||
### В случае если из источника получено менее указанного кол-ва записей, то обновления списков не происходит
|
||
export BLLIST_MIN_ENTRIES=3000
|
||
### Лимит IP адресов. При достижении, в конфиг ipset будет добавлена вся подсеть /24 вместо множества IP адресов пренадлежащих этой сети (0 - off)
|
||
export BLLIST_IP_LIMIT=0
|
||
### Подсети класса C (/24). IP адреса из этих подсетей не группируются при оптимизации (записи д.б. в виде: 68.183.221. 149.154.162. и пр.). Прим.: "68.183.221. 149.154.162."
|
||
export BLLIST_GR_EXCLUDED_NETS=""
|
||
### Группировать идущие подряд IP адреса в подсетях /24 в диапазоны CIDR
|
||
export BLLIST_SUMMARIZE_IP=0
|
||
### Группировать идущие подряд подсети /24 в диапазоны CIDR
|
||
export BLLIST_SUMMARIZE_CIDR=0
|
||
### Фильтрация записей блэклиста по шаблонам из файла BLLIST_IP_FILTER_FILE. Записи (IP, CIDR) попадающие под шаблоны исключаются из кофига ipset (0 - off, 1 - on)
|
||
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"
|
||
### Лимит субдоменов для группировки. При достижении, в конфиг dnsmasq будет добавлен весь домен 2-го ур-ня вместо множества субдоменов (0 - off)
|
||
export BLLIST_SD_LIMIT=16
|
||
### SLD не подлежащие группировке при оптимизации (через пробел)
|
||
export BLLIST_GR_EXCLUDED_SLD="livejournal.com facebook.com vk.com blog.jp msk.ru net.ru org.ru net.ua com.ua org.ua co.uk amazonaws.com"
|
||
### Не группировать SLD попадающие под выражения (через пробел) ("[.][a-z]{2,3}[.][a-z]{2}$")
|
||
export BLLIST_GR_EXCLUDED_MASKS=""
|
||
### Фильтрация записей блэклиста по шаблонам из файла ENTRIES_FILTER_FILE. Записи (FQDN) попадающие под шаблоны исключаются из кофига dnsmasq (0 - off, 1 - on)
|
||
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"
|
||
### Обрезка www[0-9]. в FQDN (0 - off, 1 - on)
|
||
export BLLIST_STRIP_WWW=1
|
||
### Преобразование кириллических доменов в punycode (0 - off, 1 - on)
|
||
export BLLIST_ENABLE_IDN=0
|
||
### Перенаправлять DNS-запросы на альтернативный DNS-сервер для заблокированных FQDN (0 - off, 1 - on)
|
||
export BLLIST_ALT_NSLOOKUP=0
|
||
### Альтернативный DNS-сервер
|
||
export BLLIST_ALT_DNS_ADDR="8.8.8.8"
|
||
|
||
### Источники блэклиста
|
||
export RBL_ALL_URL="https://reestr.rublacklist.net/api/v3/snapshot/"
|
||
export RBL_IP_URL="https://reestr.rublacklist.net/api/v3/ips/"
|
||
export ZI_ALL_URL="https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv"
|
||
export AF_IP_URL="https://antifilter.download/list/allyouneed.lst"
|
||
export AF_FQDN_URL="https://antifilter.download/list/domains.lst"
|
||
export RA_IP_IPSET_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/ip/ruantiblock.ip"
|
||
export RA_IP_DMASK_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/ip/ruantiblock.dnsmasq"
|
||
export RA_IP_STAT_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/ip/update_status"
|
||
export RA_FQDN_IPSET_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/fqdn/ruantiblock.ip"
|
||
export RA_FQDN_DMASK_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/fqdn/ruantiblock.dnsmasq"
|
||
export RA_FQDN_STAT_URL="https://raw.githubusercontent.com/gSpotx2f/ruantiblock_blacklist/master/blacklist/fqdn/update_status"
|
||
export RBL_ENCODING=""
|
||
export ZI_ENCODING="CP1251"
|
||
export AF_ENCODING=""
|
||
export RA_ENCODING=""
|
||
|
||
############################ Configuration #############################
|
||
|
||
### External config
|
||
[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"
|
||
|
||
CONFIG_SCRIPT="${CONFIG_DIR}/scripts/config_script"
|
||
START_SCRIPT="${CONFIG_DIR}/scripts/start_script"
|
||
STOP_SCRIPT="${CONFIG_DIR}/scripts/stop_script"
|
||
|
||
### Config script
|
||
[ -f "$CONFIG_SCRIPT" ] && . "$CONFIG_SCRIPT"
|
||
|
||
### Utilities
|
||
AWK_CMD="awk"
|
||
IPSET_CMD=`which ipset`
|
||
if [ $? -ne 0 ]; then
|
||
echo " Error! Ipset 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
|
||
LOGGER_PARAMS="-t `basename $0`"
|
||
WGET_CMD=`which wget`
|
||
if [ $? -ne 0 ]; then
|
||
echo " Error! Wget doesn't exists" >&2
|
||
exit 1
|
||
fi
|
||
WGET_PARAMS="--no-check-certificate -q -O"
|
||
|
||
export IP_DATA_FILE="${DATA_DIR}/${NAME}.ip"
|
||
|
||
export IPSET_ALLOWED_HOSTS="r_allowed_ip"
|
||
export IPSET_ONION="r_onion"
|
||
export IPSET_CIDR="rc"
|
||
export IPSET_CIDR_TMP="${IPSET_CIDR}t"
|
||
export IPSET_IP="ri"
|
||
export IPSET_IP_TMP="${IPSET_IP}t"
|
||
export IPSET_DNSMASQ="rd"
|
||
|
||
export UPDATE_STATUS_FILE="${DATA_DIR}/update_status"
|
||
UPDATE_PID_FILE="/var/run/${NAME}_update.pid"
|
||
START_PID_FILE="/var/run/${NAME}_start.pid"
|
||
TOKEN_FILE="/var/run/${NAME}.token"
|
||
export HTML_OUTPUT="${HTML_DIR}/${NAME}.html"
|
||
IPT_FUNCTIONS="${CONFIG_DIR}/scripts/ipt_functions"
|
||
INFO_OUTPUT_FUNCTION="${CONFIG_DIR}/scripts/info_output"
|
||
|
||
######################### External functions ###########################
|
||
|
||
. "$IPT_FUNCTIONS"
|
||
if [ -f "$INFO_OUTPUT_FUNCTION" ]; then
|
||
. "$INFO_OUTPUT_FUNCTION"
|
||
else
|
||
ENABLE_HTML_INFO=0
|
||
fi
|
||
|
||
############################## Functions ###############################
|
||
|
||
Help() {
|
||
cat << EOF
|
||
Usage: `basename $0` start|force-start|stop|destroy|restart|update|force-update|data-files|status|raw-status|html-info|help
|
||
start : Start
|
||
force-start : Removing the pid-file before running
|
||
stop : Stop
|
||
destroy : Stop + destroy ipsets and clear all data files
|
||
restart : Restart
|
||
reload : Renew iptables configuration
|
||
update : Update blacklist
|
||
force-update : Force update blacklist
|
||
data-files : Create ${IP_DATA_FILE} & ${DNSMASQ_DATA_FILE} (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:
|
||
`basename $0` start
|
||
`basename $0` force-start
|
||
`basename $0` stop
|
||
`basename $0` destroy
|
||
`basename $0` restart
|
||
`basename $0` update
|
||
`basename $0` force-update
|
||
`basename $0` data-files
|
||
`basename $0` status
|
||
`basename $0` html-info
|
||
EOF
|
||
}
|
||
|
||
Download() {
|
||
$WGET_CMD $WGET_PARAMS "$1" "$2"
|
||
if [ $? -ne 0 ]; then
|
||
echo "Connection error (${2})" >&2
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
DownloadRuabBlacklist() {
|
||
case "$1" in
|
||
"ip")
|
||
Download "$IP_DATA_FILE" "$RA_IP_IPSET_URL" && Download "$DNSMASQ_DATA_FILE" "$RA_IP_DMASK_URL" && Download "$UPDATE_STATUS_FILE" "$RA_IP_STAT_URL"
|
||
;;
|
||
"fqdn")
|
||
Download "$DNSMASQ_DATA_FILE" "$RA_FQDN_DMASK_URL" && Download "$IP_DATA_FILE" "$RA_FQDN_IPSET_URL" && Download "$UPDATE_STATUS_FILE" "$RA_FQDN_STAT_URL"
|
||
;;
|
||
*)
|
||
echo "Blacklist configuration error (${1})" >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
MakeLogRecord() {
|
||
if [ $ENABLE_LOGGING = "1" ]; then
|
||
$LOGGER_CMD $LOGGER_PARAMS -p "user.${1}" "$2"
|
||
fi
|
||
}
|
||
|
||
DnsmasqRestart() {
|
||
eval `echo "$DNSMASQ_RESTART_CMD"`
|
||
}
|
||
|
||
IsIpsetExists() {
|
||
$IPSET_CMD list "$1" -terse &> /dev/null
|
||
return $?
|
||
}
|
||
|
||
FlushIpSets() {
|
||
local _set
|
||
for _set in "$@"
|
||
do
|
||
IsIpsetExists "$_set" && $IPSET_CMD flush "$_set"
|
||
done
|
||
}
|
||
|
||
DestroyIpsets() {
|
||
local _set
|
||
for _set in "$@"
|
||
do
|
||
IsIpsetExists "$_set" && $IPSET_CMD destroy "$_set"
|
||
done
|
||
}
|
||
|
||
FillAllowedHostsSet() {
|
||
local _entry
|
||
for _entry in $ALLOWED_HOSTS_LIST
|
||
do
|
||
$IPSET_CMD add "$IPSET_ALLOWED_HOSTS" "$_entry"
|
||
done
|
||
}
|
||
|
||
AddIptRules() {
|
||
IptMainAdd
|
||
if [ "$PROXY_LOCAL_CLIENTS" = "1" ]; then
|
||
IptLocalClientsAdd
|
||
fi
|
||
}
|
||
|
||
DelIptRules() {
|
||
IptLocalClientsDel
|
||
IptMainDel
|
||
}
|
||
|
||
SetNetConfig() {
|
||
local _set
|
||
### Создание списков ipset. Проверка на наличие списка с таким же именем, если нет, то создается новый
|
||
for _set in "$IPSET_CIDR_TMP" "$IPSET_CIDR"
|
||
do
|
||
IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:net maxelem $IPSET_MAXELEM
|
||
done
|
||
for _set in "$IPSET_ALLOWED_HOSTS" "$IPSET_IP_TMP" "$IPSET_IP"
|
||
do
|
||
IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:ip maxelem $IPSET_MAXELEM
|
||
done
|
||
for _set in "$IPSET_DNSMASQ" "$IPSET_ONION"
|
||
do
|
||
IsIpsetExists "$_set" || $IPSET_CMD create "$_set" hash:ip maxelem $IPSET_MAXELEM timeout $IPSET_DNSMASQ_TIMEOUT
|
||
done
|
||
AddIptRules
|
||
}
|
||
|
||
DropNetConfig() {
|
||
DelIptRules
|
||
FlushIpSets "$IPSET_ALLOWED_HOSTS" "$IPSET_CIDR_TMP" "$IPSET_CIDR" "$IPSET_IP_TMP" "$IPSET_IP" "$IPSET_DNSMASQ" "$IPSET_ONION"
|
||
}
|
||
|
||
FillIpsets() {
|
||
local _set
|
||
### Заполнение списков ipset $IPSET_IP и $IPSET_CIDR. Сначала restore загружает во временные списки, а затем swap из временных добавляет в основные
|
||
if [ -f "$IP_DATA_FILE" ]; then
|
||
echo " Filling ipsets..."
|
||
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
|
||
IsIpsetExists "$IPSET_IP_TMP" && IsIpsetExists "$IPSET_CIDR_TMP" && IsIpsetExists "$IPSET_IP" && IsIpsetExists "$IPSET_CIDR" &&\
|
||
cat "$IP_DATA_FILE" | $IPSET_CMD restore && { $IPSET_CMD swap "$IPSET_IP_TMP" "$IPSET_IP"; $IPSET_CMD swap "$IPSET_CIDR_TMP" "$IPSET_CIDR"; }
|
||
if [ $? -eq 0 ]; then
|
||
echo " Ok"
|
||
FlushIpSets "$IPSET_IP_TMP" "$IPSET_CIDR_TMP"
|
||
else
|
||
echo " Error! Ipset wasn't updated" >&2
|
||
MakeLogRecord "err" "Error! Ipset wasn't updated"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
ClearDataFiles() {
|
||
if [ -d "$DATA_DIR" ]; then
|
||
printf "" > "$DNSMASQ_DATA_FILE"
|
||
printf "" > "$IP_DATA_FILE"
|
||
printf "0 0 0" > "$UPDATE_STATUS_FILE"
|
||
fi
|
||
}
|
||
|
||
CheckStatus() {
|
||
local _set _ipset_return=0 _return_code=1
|
||
if [ "$1" = "ipsets" ]; then
|
||
for _set in "$IPSET_ALLOWED_HOSTS" "$IPSET_CIDR_TMP" "$IPSET_CIDR" "$IPSET_IP_TMP" "$IPSET_IP" "$IPSET_DNSMASQ" "$IPSET_ONION"
|
||
do
|
||
IsIpsetExists "$_set"
|
||
_ipset_return=$?
|
||
[ $_ipset_return -ne 0 ] && break
|
||
done
|
||
fi
|
||
if IptListBllistChain &> /dev/null && [ $_ipset_return -eq 0 ]; then
|
||
_return_code=0
|
||
fi
|
||
return $_return_code
|
||
}
|
||
|
||
PreStartCheck() {
|
||
[ -d "$DATA_DIR" ] || mkdir -p "$DATA_DIR"
|
||
[ "$ENABLE_HTML_INFO" = "1" -a ! -d "$HTML_DIR" ] && mkdir -p "$HTML_DIR"
|
||
### Костыль для старта dnsmasq
|
||
[ -e "$DNSMASQ_DATA_FILE" ] || printf "\n" > "$DNSMASQ_DATA_FILE"
|
||
}
|
||
|
||
AddUserEntries() {
|
||
if [ "$ADD_USER_ENTRIES" = "1" ]; then
|
||
if [ -f "$USER_ENTRIES_FILE" -a -s "$USER_ENTRIES_FILE" ]; then
|
||
$AWK_CMD 'BEGIN {
|
||
null="";
|
||
while((getline ip_string <ENVIRON["IP_DATA_FILE"]) > 0) {
|
||
split(ip_string, ip_string_arr, " ");
|
||
ip_data_array[ip_string_arr[3]]=null;
|
||
};
|
||
close(ENVIRON["IP_DATA_FILE"]);
|
||
while((getline fqdn_string <ENVIRON["DNSMASQ_DATA_FILE"]) > 0) {
|
||
split(fqdn_string, fqdn_string_arr, "/");
|
||
fqdn_data_array[fqdn_string_arr[2]]=null;
|
||
};
|
||
close(ENVIRON["DNSMASQ_DATA_FILE"]);
|
||
}
|
||
function writeIpsetEntries(val, set) {
|
||
printf "add %s %s\n", set, val >> ENVIRON["IP_DATA_FILE"];
|
||
};
|
||
function writeDNSData(val, dns) {
|
||
if(length(dns) == 0 && length(ENVIRON["USER_ENTRIES_DNS"]) > 0)
|
||
dns=ENVIRON["USER_ENTRIES_DNS"];
|
||
if(length(dns) > 0)
|
||
printf "server=/%s/%s\n", val, dns >> ENVIRON["DNSMASQ_DATA_FILE"];
|
||
printf "ipset=/%s/%s\n", val, ENVIRON["IPSET_DNSMASQ"] >> ENVIRON["DNSMASQ_DATA_FILE"];
|
||
};
|
||
($0 !~ /^([\040\011]*$|#)/) {
|
||
if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}$/ && !($0 in ip_data_array))
|
||
writeIpsetEntries($0, ENVIRON["IPSET_IP_TMP"]);
|
||
else if($0 ~ /^[0-9]{1,3}([.][0-9]{1,3}){3}[\057][0-9]{1,2}$/ && !($0 in ip_data_array))
|
||
writeIpsetEntries($0, ENVIRON["IPSET_CIDR_TMP"]);
|
||
else if($0 ~ /^[a-z0-9.\052-]+[.]([a-z]{2,}|xn--[a-z0-9]+)([ ][0-9]{1,3}([.][0-9]{1,3}){3}([#][0-9]{2,5})?)?$/ && !($1 in fqdn_data_array))
|
||
writeDNSData($1, $2);
|
||
}' "$USER_ENTRIES_FILE"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
GetDataFiles() {
|
||
local _return_code=1 _attempt=1 _update_string
|
||
PreStartCheck
|
||
echo "$$" > "$UPDATE_PID_FILE"
|
||
if [ -n "$BLLIST_PRESET" -a -n "$BLLIST_MODULE" ]; then
|
||
while :
|
||
do
|
||
$BLLIST_MODULE
|
||
_return_code=$?
|
||
[ $_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=`expr $_attempt + 1`
|
||
[ $_attempt -gt $MODULE_RUN_ATTEMPTS ] && break
|
||
sleep $MODULE_RUN_TIMEOUT
|
||
done
|
||
AddUserEntries
|
||
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
|
||
ADD_USER_ENTRIES=1
|
||
AddUserEntries
|
||
_return_code=0
|
||
else
|
||
_return_code=2
|
||
rm -f "$UPDATE_PID_FILE"
|
||
return $_return_code
|
||
fi
|
||
if [ "$PROXY_MODE" = "2" -o "$PROXY_MODE" = "3" ]; then
|
||
printf "\n" >> "$DNSMASQ_DATA_FILE"
|
||
else
|
||
### Запись для .onion в $DNSMASQ_DATA_FILE
|
||
printf "server=/onion/%s\nipset=/onion/%s\n" "${ONION_DNS_ADDR}" "${IPSET_ONION}" >> "$DNSMASQ_DATA_FILE"
|
||
fi
|
||
rm -f "$UPDATE_PID_FILE"
|
||
return $_return_code
|
||
}
|
||
|
||
MakeToken() {
|
||
date +%s > "$TOKEN_FILE"
|
||
}
|
||
|
||
Update() {
|
||
local _return_code=0
|
||
if CheckStatus ipsets; then
|
||
:
|
||
else
|
||
echo " ${NAME} ${1} - Error! ${NAME} does not running or another error has occurred" >&2
|
||
return 1
|
||
fi
|
||
MakeToken
|
||
if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then
|
||
echo " ${NAME} ${1} - Error! Another instance of update is already running" >&2
|
||
MakeLogRecord "err" "${1} - Error! Another instance of update is already running"
|
||
_return_code=2
|
||
else
|
||
echo " ${NAME} ${1}..."
|
||
MakeLogRecord "notice" "${1}..."
|
||
if [ "$IPSET_CLEAR_SETS" = "1" ]; then
|
||
FlushIpSets "$IPSET_IP" "$IPSET_CIDR" "$IPSET_DNSMASQ"
|
||
fi
|
||
GetDataFiles
|
||
case $? in
|
||
0)
|
||
echo " Blacklist updated"
|
||
MakeLogRecord "notice" "Blacklist updated"
|
||
;;
|
||
2)
|
||
echo " Blacklist update error!" >&2
|
||
MakeLogRecord "err" "Blacklist update error!"
|
||
_return_code=1
|
||
;;
|
||
*)
|
||
echo " Module error! [${BLLIST_MODULE}]" >&2
|
||
MakeLogRecord "err" "Module error! [${BLLIST_MODULE}]"
|
||
_return_code=1
|
||
;;
|
||
esac
|
||
FlushIpSets "$IPSET_DNSMASQ"
|
||
FillIpsets
|
||
_return_code=$?
|
||
DnsmasqRestart
|
||
fi
|
||
MakeToken
|
||
return $_return_code
|
||
}
|
||
|
||
Start() {
|
||
local _return_code=1
|
||
if [ -e "$START_PID_FILE" ]; then
|
||
echo " ${NAME} is currently starting..." >&2
|
||
return 1
|
||
else
|
||
echo "$$" > "$START_PID_FILE"
|
||
fi
|
||
MakeToken
|
||
if CheckStatus; then
|
||
echo " ${NAME} is already running" >&2
|
||
_return_code=1
|
||
else
|
||
echo " ${NAME} ${1}..."
|
||
MakeLogRecord "info" "${1}..."
|
||
DropNetConfig &> /dev/null
|
||
SetNetConfig
|
||
FillAllowedHostsSet
|
||
PreStartCheck
|
||
FillIpsets
|
||
_return_code=$?
|
||
### Start-script
|
||
[ -x "$START_SCRIPT" ] && $START_SCRIPT > /dev/null 2>&1 &
|
||
fi
|
||
rm -f "$START_PID_FILE"
|
||
MakeToken
|
||
return $_return_code
|
||
}
|
||
|
||
Stop() {
|
||
local _return_code=1
|
||
if CheckStatus; then
|
||
MakeToken
|
||
echo " ${NAME} ${1}..."
|
||
MakeLogRecord "info" "${1}..."
|
||
DropNetConfig &> /dev/null
|
||
_return_code=$?
|
||
### Stop-script
|
||
[ -x "$STOP_SCRIPT" ] && $STOP_SCRIPT > /dev/null 2>&1 &
|
||
MakeToken
|
||
else
|
||
echo " ${NAME} does not running" >&2
|
||
fi
|
||
return $_return_code
|
||
}
|
||
|
||
Reload() {
|
||
local _i=0 _attempts=60
|
||
MakeToken
|
||
while [ -e "$START_PID_FILE" ]
|
||
do
|
||
if [ $_i -ge $_attempts ]; then
|
||
return 1
|
||
fi
|
||
_i=`expr $_i + 1`
|
||
sleep 1
|
||
done
|
||
echo " ${NAME} reload..."
|
||
DelIptRules &> /dev/null
|
||
AddIptRules &> /dev/null
|
||
MakeToken
|
||
}
|
||
|
||
Status() {
|
||
local _set
|
||
if CheckStatus; then
|
||
printf "\n \033[1m${NAME} status\033[m: \033[1;32mEnabled\033[m\n\n PROXY_MODE: ${PROXY_MODE}\n PROXY_LOCAL_CLIENTS: ${PROXY_LOCAL_CLIENTS}\n BLLIST_PRESET: ${BLLIST_PRESET}\n BLLIST_MODULE: ${BLLIST_MODULE}\n"
|
||
if [ -f "$UPDATE_STATUS_FILE" ]; then
|
||
$AWK_CMD '{
|
||
update_string=(NF < 4) ? "No data" : $4" (CIDR: "$1" | IP: "$2" | FQDN: "$3")";
|
||
printf "\n Last blacklist update: %s\n", update_string;
|
||
}' "$UPDATE_STATUS_FILE"
|
||
else
|
||
printf "\n Last blacklist update: No data\n"
|
||
fi
|
||
if [ "$PROXY_MODE" = "2" ] && ! IptVpnRouteStatus; then
|
||
printf "\n \033[1;31mVPN ROUTING ERROR! (NEED THE RESTART)\033[m\n"
|
||
fi
|
||
printf "\n \033[4mIptables rules\033[m:\n\n"
|
||
IptListBllistChain | $AWK_CMD '
|
||
{
|
||
if(NR > 2) {
|
||
printf " Match-set: %s\n Bytes: %s\n\n", $11, $2;
|
||
};
|
||
}'
|
||
printf " \033[4mIp sets\033[m:\n\n"
|
||
for _set in "$IPSET_ALLOWED_HOSTS" "$IPSET_ONION" "$IPSET_CIDR_TMP" "$IPSET_CIDR" "$IPSET_IP_TMP" "$IPSET_IP" "$IPSET_DNSMASQ"
|
||
do
|
||
$IPSET_CMD list "$_set" -terse | $AWK_CMD -F ":" '
|
||
{
|
||
if($1 ~ /^(Name|Size in memory|Number of entries)/) {
|
||
printf " %s: %s\n", $1, $2;
|
||
if($1 ~ /^Number of entries/) printf "\n";
|
||
};
|
||
}'
|
||
done
|
||
else
|
||
printf "\n \033[1m${NAME} status\033[m: \033[1mDisabled\033[m\n\n"
|
||
exit 2
|
||
fi
|
||
}
|
||
|
||
StatusOutput() {
|
||
if [ "$ENABLE_HTML_INFO" = "1" -a -d "$HTML_DIR" ]; then
|
||
Info
|
||
fi
|
||
}
|
||
|
||
############################ Main section ##############################
|
||
|
||
### Blacklist source and mode
|
||
case "$BLLIST_PRESET" in
|
||
zapret-info-ip)
|
||
### Источник для обновления списка блокировок (zapret-info, rublacklist, antifilter, ruantiblock)
|
||
export BLLIST_SOURCE="zapret-info"
|
||
### Режим обхода блокировок: ip, fqdn
|
||
export BLLIST_MODE="ip"
|
||
;;
|
||
zapret-info-fqdn)
|
||
export BLLIST_SOURCE="zapret-info"
|
||
export BLLIST_MODE="fqdn"
|
||
;;
|
||
rublacklist-ip)
|
||
export BLLIST_SOURCE="rublacklist"
|
||
export BLLIST_MODE="ip"
|
||
;;
|
||
rublacklist-fqdn)
|
||
export BLLIST_SOURCE="rublacklist"
|
||
export BLLIST_MODE="fqdn"
|
||
;;
|
||
antifilter-ip)
|
||
export BLLIST_SOURCE="antifilter"
|
||
export BLLIST_MODE="ip"
|
||
;;
|
||
ruantiblock-ip)
|
||
export BLLIST_SOURCE="ruantiblock"
|
||
export BLLIST_MODE="ip"
|
||
BLLIST_MODULE="DownloadRuabBlacklist $BLLIST_MODE"
|
||
;;
|
||
ruantiblock-fqdn)
|
||
export BLLIST_SOURCE="ruantiblock"
|
||
export BLLIST_MODE="fqdn"
|
||
BLLIST_MODULE="DownloadRuabBlacklist $BLLIST_MODE"
|
||
;;
|
||
*)
|
||
export BLLIST_SOURCE=""
|
||
export BLLIST_MODE=""
|
||
;;
|
||
esac
|
||
|
||
return_code=1
|
||
case "$1" in
|
||
start|force-start)
|
||
[ "$1" == "force-start" ] && rm -f "$START_PID_FILE"
|
||
Start "$1"
|
||
return_code=$?
|
||
StatusOutput
|
||
;;
|
||
stop)
|
||
Stop "$1"
|
||
return_code=$?
|
||
StatusOutput
|
||
;;
|
||
restart)
|
||
Stop "stop"
|
||
Start "start"
|
||
return_code=$?
|
||
StatusOutput
|
||
;;
|
||
reload)
|
||
Reload
|
||
return_code=$?
|
||
StatusOutput
|
||
;;
|
||
destroy)
|
||
Stop "$1" &> /dev/null
|
||
DestroyIpsets "$IPSET_ALLOWED_HOSTS" "$IPSET_CIDR_TMP" "$IPSET_CIDR" "$IPSET_IP_TMP" "$IPSET_IP" "$IPSET_DNSMASQ" "$IPSET_ONION"
|
||
ClearDataFiles
|
||
return_code=$?
|
||
rm -f "$UPDATE_PID_FILE" "$START_PID_FILE"
|
||
DnsmasqRestart
|
||
StatusOutput
|
||
;;
|
||
update|force-update)
|
||
Update "$1"
|
||
return_code=$?
|
||
StatusOutput
|
||
;;
|
||
data-files)
|
||
if [ -e "$UPDATE_PID_FILE" ] && [ "$1" != "force-update" ]; then
|
||
echo " ${NAME} - Error! Another instance of update is already running" >&2
|
||
exit 2
|
||
else
|
||
GetDataFiles
|
||
return_code=$?
|
||
fi
|
||
;;
|
||
status)
|
||
Status
|
||
return_code=$?
|
||
;;
|
||
raw-status)
|
||
CheckStatus
|
||
return_code=$?
|
||
case $return_code in
|
||
0)
|
||
if [ -e "$START_PID_FILE" ]; then
|
||
return_code=3
|
||
echo 3
|
||
elif [ -e "$UPDATE_PID_FILE" ]; then
|
||
return_code=4
|
||
echo 4
|
||
else
|
||
echo 0
|
||
fi
|
||
;;
|
||
*)
|
||
return_code=2
|
||
echo 2
|
||
;;
|
||
esac
|
||
;;
|
||
vpn-route-status)
|
||
IptVpnRouteStatus
|
||
return_code=$?
|
||
echo $return_code
|
||
;;
|
||
html-info)
|
||
Info
|
||
return_code=$?
|
||
;;
|
||
-h|--help|help)
|
||
Help
|
||
exit 0
|
||
;;
|
||
*)
|
||
Help
|
||
exit 1
|
||
;;
|
||
esac
|
||
|
||
exit $return_code;
|