diff --git a/docs/changes.txt b/docs/changes.txt index 7a84887..01efa34 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -448,3 +448,6 @@ blockcheck: override all dialog questions and enable batch mode blockcheck: parallel attempts nfqws: weaken wireguard initiation recognition. use len=148 and data[0]=1 signature nfqws: apply split+seqovl only to the first reasm fragment +install_easy: dnf packager support +nfqws,tpws: hostlist/ipset track not only file mod time but also file size +nfqws,tpws,ipset: return lists reload on HUP diff --git a/docs/readme.en.md b/docs/readme.en.md index fada456..82f5209 100644 --- a/docs/readme.en.md +++ b/docs/readme.en.md @@ -965,7 +965,8 @@ If you need "all except" mode you dont have to delete zapret-hosts-users.txt. Ju Subdomains auto apply. For example, "ru" in the list affects "*.ru" . -**tpws** and **nfqws** automatically reload lists if their modification date is changed. +**tpws** and **nfqws** automatically reload lists if their modification time or file size is changed. +HUP signal forcibly reloads all lists. When filtering by domain name, daemons should run without filtering by ipset. When using large regulator lists estimate the amount of RAM on the router ! diff --git a/docs/readme.md b/docs/readme.md index 0927481..0c6bbfa 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -74,7 +74,7 @@ zapret является свободным и open source. обойти блокировки или замедление сайтов HTTP(S), сигнатурный анализ TCP и UDP протоколов, например, с целью блокировки VPN. -Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWRT. Поддерживаются +Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWrt. Поддерживаются традиционные Linux-системы, FreeBSD, OpenBSD, частично macOS. В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам. @@ -263,7 +263,7 @@ dvtws, собираемый из тех же исходников (см. [док `net.netfilter.nf_conntrack_checksum=1` заставляет conntrack проверять tcp и udp чексуммы входящих пакетов и выставлять state INVALID для пакетов с инвалидной суммой. Обычно в правилах iptables вставляется правило для дропа пакетов с состоянием INVALID в цепочке FORWARD. Совместное сочетание этих факторов приводит к непрохождению badsum - через такой роутер. В openwrt из коробки `net.netfilter.nf_conntrack_checksum=0`, в других роутерах часто нет, и не + через такой роутер. В OpenWrt из коробки `net.netfilter.nf_conntrack_checksum=0`, в других роутерах часто нет, и не всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное значение sysctl в 0. nfqws на самом роутере будет работать и без этой настройки, потому что чексумма локально созданных пакетов не проверяется никогда. Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets вы ничего @@ -566,7 +566,7 @@ ipv6 : Нет способа для приложения гарантирова Чтобы не загромождать описание, смотрите пример решения этой проблемы в `blockcheck.sh`. Иногда требуется подгружать модуль `ip6table_raw` с параметром `raw_before_defrag=1`. -В openwrt параметры модулей указываются через пробел после их названий в файлах `/etc/modules.d`. +В OpenWrt параметры модулей указываются через пробел после их названий в файлах `/etc/modules.d`. В традиционных системах посмотрите используется ли `iptables-legacy` или `iptables-nft`. Если legacy, то нужно создать файл `/etc/modprobe.d/ip6table_raw.conf` с содержимым : ``` @@ -740,10 +740,10 @@ iptables могут не работать. При включенном offloadin DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. Однако, остальные соединения идут через SFO, потому NFQUEUE будет срабатывать только до помещения соединения в flowtable. Практически это означает, что почти весь функционал nfqws работать не будет. Offload включается через специальный target в iptables `FLOWOFFLOAD`. Не обязательно пропускать весь трафик через offload. Можно исключить из -offload соединения, которые должны попасть на tpws или nfqws. openwrt не предусматривает выборочного управления offload. -Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt. +offload соединения, которые должны попасть на tpws или nfqws. OpenWrt не предусматривает выборочного управления offload. +Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в OpenWrt. -iptables target `FLOWOFFLOAD` - это проприетарное изобретение openwrt. +iptables target `FLOWOFFLOAD` - это проприетарное изобретение OpenWrt. Управление offload в nftables реализовано в базовом ядре linux без патчей. @@ -1303,7 +1303,8 @@ ipset/get_refilter_domains.sh ``` Он кладется в `ipset/zapret-hosts.txt.gz`. -При изменении времени модификации файлов списки перечитываются автоматически. +При изменении времени модификации или размера файлов списки перечитываются автоматически. +После неатомарных операций изменения можно послать tpws/nfqws сигнал HUP для принудительной перечитки всех листов. При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset. tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic). @@ -1457,7 +1458,7 @@ UNBLOCKED_DOM - незаблокированный домен, который и `SECURE_DNS=1 SKIP_TPWS=1 CURL_MAX_TIME=1 CURL=/tmp/curl ./blockcheck.sh` **СКАН ПОРТОВ**\ -Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в openwrt по умолчанию нет), +Если в системе присутствует совместимый `netcat` (ncat от nmap или openbsd ncat. в OpenWrt по умолчанию нет), то выполняется сканирование портов http или https всех IP адресов домена. Если ни один IP не отвечает, то результат очевиден. Можно останавливать сканирование. Автоматически оно не остановится, потому что netcat-ы недостаточно подробно информируют о причинах ошибки. @@ -1564,7 +1565,7 @@ curl: (28) Connection timed out after 2002 milliseconds На linux системах можно выбрать использовать `iptables` или `nftables`. По умолчанию на традиционных linux выбирается `nftables`, если установлен nft. -На openwrt по умолчанию выбирается `nftables` на новых версиях с firewall4. +На OpenWrt по умолчанию выбирается `nftables` на новых версиях с firewall4. `FWTYPE=iptables` @@ -1775,11 +1776,11 @@ LISTS_RELOAD="pfctl -f /etc/pf.conf" LISTS_RELOAD=- ``` -В openwrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws. +В OpenWrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws. Но возможно задать другие сети или список сетей:\ `OPENWRT_LAN="lan lan2 lan3"` -В openwrt в качестве wan берутся интерфейсы, имеющие default route. Отдельно для ipv4 и ipv6. +В OpenWrt в качестве wan берутся интерфейсы, имеющие default route. Отдельно для ipv4 и ipv6. Это можно переопределить: ``` OPENWRT_WAN4="wan4 vpn" @@ -1789,7 +1790,7 @@ OPENWRT_WAN6="wan6 vpn6" Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables.\ При иных значениях или если параметр закомментирован, правила применены не будут.\ Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила.\ -На openwrt неприменимо при использовании firewall3+iptables. +На OpenWrt неприменимо при использовании firewall3+iptables. ***Следующие настройки не актуальны для openwrt:*** @@ -1843,7 +1844,7 @@ _Для `nftables` предусмотрено несколько дополни Обновить set-ы интерфейсов, относящихся к lan, wan и wan6. Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN. -Для openwrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN. +Для OpenWrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN. Все интерфейсы lan и wan так же добавляются в ingress hook от flow table.\ `/opt/zapret/init.d/sysv/zapret reload_ifsets` @@ -1895,7 +1896,7 @@ zapret_custom_firewall_v6 zapret_custom_daemons поднимает демоны **nfqws**/**tpws** в нужном вам количестве и с нужными вам параметрами. В первом параметре передается код операции: 1 = запуск, 0 = останов. -Схема запуска демонов в openwrt отличается - используется procd. +Схема запуска демонов в OpenWrt отличается - используется procd. Поэтому логика останова отсутствует за ненадобностью, останов никогда не вызывается. zapret_custom_firewall поднимает и убирает правила `iptables`. @@ -1937,7 +1938,7 @@ zapret_custom_firewall_nft поднимает правила nftables. ## Простая установка `install_easy.sh` автоматизирует ручные варианты процедур установки. -Он поддерживает OpenWRT, linux системы на базе systemd или openrc и MacOS. +Он поддерживает OpenWrt, linux системы на базе systemd или openrc и MacOS. Для более гибкой настройки перед запуском инсталлятора следует выполнить раздел "Выбор параметров". @@ -1954,7 +1955,7 @@ zapret_custom_firewall_nft поднимает правила nftables. `install_easy.sh make` -Под openwrt все уже сразу готово для использования системы в качестве роутера. +Под OpenWrt все уже сразу готово для использования системы в качестве роутера. Имена интерфейсов WAN и LAN известны из настроек системы. Под другими системами роутер вы настраиваете самостоятельно. Инсталлятор в это не вмешивается. инсталлятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы. @@ -2087,7 +2088,7 @@ chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws Работа blockcheck в android shell не поддерживается, но имея рута можно развернуть rootfs какого-нибудь дистрибутива linux. Это лучше всего делать с компа через adb shell. Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный. -Подойдет что-то легковесное, например, alpine или даже openwrt. +Подойдет что-то легковесное, например, alpine или даже OpenWrt. Если это не эмулятор android, то универсальная архитектура - arm (любой вариант). Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64. Выяснить архитектуру можно командой `uname -a`. @@ -2231,10 +2232,10 @@ entware содержит репозиторий user-mode компонент, к _Подробное описание настроек для других прошивок выходит за рамки данного проекта._ -Openwrt является одной из немногих относительно полноценных linux систем для embedded devices. +OpenWrt является одной из немногих относительно полноценных linux систем для embedded devices. Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивк: * полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть -* корень r/w. это практически уникальная особенность openwrt. заводские и большинство альтернативных прошивок +* корень r/w. это практически уникальная особенность OpenWrt. заводские и большинство альтернативных прошивок построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном @@ -2255,7 +2256,7 @@ Openwrt является одной из немногих относительн Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост. Предлагается использовать прозрачный редирект через socks5 посредством `iptables+redsocks`, либо `iptables+iproute+vpn`. -Настройка варианта с redsocks на openwrt описана в [redsocks.txt](./redsocks.txt). +Настройка варианта с redsocks на OpenWrt описана в [redsocks.txt](./redsocks.txt). Настройка варианта с `iproute+wireguard` - в [wireguard_iproute_openwrt.txt](./wireguard_iproute_openwrt.txt). diff --git a/ipset/def.sh b/ipset/def.sh index 078c097..aa55ca3 100644 --- a/ipset/def.sh +++ b/ipset/def.sh @@ -267,3 +267,15 @@ getipban() _get_ipban return 0 } + +hup_zapret_daemons() +{ + echo forcing zapret daemons to reload their hostlist + if exists killall; then + killall -HUP tpws nfqws dvtws 2>/dev/null + elif exists pkill; then + pkill -HUP ^tpws$ ^nfqws$ ^dvtws$ + else + echo no mass killer available ! cant HUP zapret daemons + fi +} diff --git a/ipset/get_antizapret_domains.sh b/ipset/get_antizapret_domains.sh index 1bbbdc4..12583a8 100755 --- a/ipset/get_antizapret_domains.sh +++ b/ipset/get_antizapret_domains.sh @@ -31,4 +31,6 @@ sort -u "$ZDOM" | zz "$ZHOSTLIST" rm -f "$ZDOM" +hup_zapret_daemons + exit 0 diff --git a/ipset/get_reestr_hostlist.sh b/ipset/get_reestr_hostlist.sh index 9c3ee95..0054cbc 100755 --- a/ipset/get_reestr_hostlist.sh +++ b/ipset/get_reestr_hostlist.sh @@ -58,6 +58,8 @@ rm -f "$ZREESTR" [ "$DISABLE_IPV6" != "1" ] && $AWK '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}($|(\/[0-9]{2,3}$))/' "$IPB" | cut_local6 | ip2net6 | zz "$ZIPLIST_IPBAN6" rm -f "$IPB" +hup_zapret_daemons + ipban_fin exit 0 diff --git a/ipset/get_reestr_resolvable_domains.sh b/ipset/get_reestr_resolvable_domains.sh index 6785916..fa00869 100755 --- a/ipset/get_reestr_resolvable_domains.sh +++ b/ipset/get_reestr_resolvable_domains.sh @@ -34,6 +34,8 @@ dl() dl "$URL" "$ZHOSTLIST" 65536 67108864 +hup_zapret_daemons + [ "$DISABLE_IPV4" != "1" ] && dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576 [ "$DISABLE_IPV6" != "1" ] && dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576 diff --git a/ipset/get_refilter_domains.sh b/ipset/get_refilter_domains.sh index f329ad6..b11d26d 100755 --- a/ipset/get_refilter_domains.sh +++ b/ipset/get_refilter_domains.sh @@ -37,4 +37,6 @@ getipban || FAIL=1 dl "$URL" "$ZHOSTLIST" 32768 4194304 +hup_zapret_daemons + exit 0 diff --git a/nfq/desync.c b/nfq/desync.c index 06196b7..f61d982 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -367,7 +367,8 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname DLOG_PERROR("write to auto hostlist:"); return; } - dp->hostlist_auto->mod_time = file_mod_time(dp->hostlist_auto->filename); + if (!file_mod_signature(dp->hostlist_auto->filename, &dp->hostlist_auto->mod_sig)) + DLOG_PERROR("file_mod_signature"); } else { diff --git a/nfq/helpers.c b/nfq/helpers.c index aba018c..2e4727d 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -300,6 +300,18 @@ time_t file_mod_time(const char *filename) struct stat st; return stat(filename,&st)==-1 ? 0 : st.st_mtime; } +bool file_mod_signature(const char *filename, file_mod_sig *ms) +{ + struct stat st; + if (stat(filename,&st)==-1) + { + FILE_MOD_RESET(ms); + return false; + } + ms->mod_time=st.st_mtime; + ms->size=st.st_size; + return true; +} bool pf_in_range(uint16_t port, const port_filter *pf) { diff --git a/nfq/helpers.h b/nfq/helpers.h index 756bab6..5e8e80c 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -60,6 +60,14 @@ void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize int fprint_localtime(FILE *F); +typedef struct +{ + time_t mod_time; + off_t size; +} file_mod_sig; +#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size)) +#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig)) +bool file_mod_signature(const char *filename, file_mod_sig *ms); time_t file_mod_time(const char *filename); typedef struct diff --git a/nfq/hostlist.c b/nfq/hostlist.c index 9b75758..34e25cf 100644 --- a/nfq/hostlist.c +++ b/nfq/hostlist.c @@ -105,21 +105,21 @@ static bool LoadHostList(struct hostlist_file *hfile) { if (hfile->filename) { - time_t t = file_mod_time(hfile->filename); - if (!t) + file_mod_sig fsig; + if (!file_mod_signature(hfile->filename, &fsig)) { // stat() error DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename); return true; } - if (t==hfile->mod_time) return true; // up to date + if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date StrPoolDestroy(&hfile->hostlist); if (!AppendHostList(&hfile->hostlist, hfile->filename)) { StrPoolDestroy(&hfile->hostlist); return false; } - hfile->mod_time=t; + hfile->mod_sig=fsig; } return true; } diff --git a/nfq/hostlist.h b/nfq/hostlist.h index deedc5c..9676613 100644 --- a/nfq/hostlist.h +++ b/nfq/hostlist.h @@ -13,3 +13,5 @@ bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *exclu struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename); bool HostlistsReloadCheckForProfile(const struct desync_profile *dp); void HostlistsDebug(); + +#define ResetAllHostlistsModTime() hostlist_files_reset_modtime(¶ms.hostlists) diff --git a/nfq/ipset.c b/nfq/ipset.c index 86970b0..a4d1ebe 100644 --- a/nfq/ipset.c +++ b/nfq/ipset.c @@ -126,21 +126,21 @@ static bool LoadIpset(struct ipset_file *hfile) { if (hfile->filename) { - time_t t = file_mod_time(hfile->filename); - if (!t) + file_mod_sig fsig; + if (!file_mod_signature(hfile->filename, &fsig)) { // stat() error DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename); return true; } - if (t==hfile->mod_time) return true; // up to date + if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date ipsetDestroy(&hfile->ipset); if (!AppendIpset(&hfile->ipset, hfile->filename)) { ipsetDestroy(&hfile->ipset); return false; } - hfile->mod_time=t; + hfile->mod_sig=fsig; } return true; } diff --git a/nfq/ipset.h b/nfq/ipset.h index f283c2f..b711ac5 100644 --- a/nfq/ipset.h +++ b/nfq/ipset.h @@ -10,3 +10,5 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename); void IpsetsDebug(); bool AppendIpsetItem(ipset *ips, char *ip); + +#define ResetAllIpsetModTime() ipset_files_reset_modtime(¶ms.ipsets) diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 965893f..fdd4712 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -49,14 +49,34 @@ #define MAX_CONFIG_FILE_SIZE 16384 struct params_s params; +static bool bReload=false; #ifdef __CYGWIN__ bool bQuit=false; #endif static void onhup(int sig) { - printf("HUP received !\n"); - // do not do anything. lists auto reload themselves based on file time. + printf("HUP received ! Lists will be reloaded.\n"); + bReload=true; +} +static void ReloadCheck() +{ + if (bReload) + { + ResetAllHostlistsModTime(); + if (!LoadAllHostLists()) + { + DLOG_ERR("hostlists load failed. this is fatal.\n"); + exit(1); + } + ResetAllIpsetModTime(); + if (!LoadAllIpsets()) + { + DLOG_ERR("ipset load failed. this is fatal.\n"); + exit(1); + } + bReload=false; + } } static void onusr1(int sig) @@ -251,6 +271,7 @@ static int nfq_main(void) { while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0) { + ReloadCheck(); if (rd) { int r = nfq_handle_packet(h, (char *)buf, (int)rd); @@ -371,6 +392,8 @@ static int dvt_main(void) uint8_t verdict; size_t len = rd; + ReloadCheck(); + DLOG("packet: id=%u len=%zu\n", id, len); verdict = processPacketData(&mark, NULL, buf, &len); switch (verdict & VERDICT_MASK) @@ -489,6 +512,8 @@ static int win_main(const char *windivert_filter) return w_win32_error; } + ReloadCheck(); + *ifout=0; if (wa.Outbound) snprintf(ifout,sizeof(ifout),"%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx); diff --git a/nfq/pools.c b/nfq/pools.c index abb82d8..4cce2f6 100644 --- a/nfq/pools.c +++ b/nfq/pools.c @@ -154,7 +154,6 @@ void strlist_destroy(struct str_list_head *head) - struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename) { struct hostlist_file *entry = malloc(sizeof(struct hostlist_file)); @@ -170,7 +169,7 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const } else entry->filename = NULL; - entry->mod_time = 0; + FILE_MOD_RESET(&entry->mod_sig); entry->hostlist = NULL; LIST_INSERT_HEAD(head, entry, next); } @@ -202,6 +201,13 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co } return NULL; } +void hostlist_files_reset_modtime(struct hostlist_files_head *list) +{ + struct hostlist_file *hfile; + + LIST_FOREACH(hfile, list, next) + FILE_MOD_RESET(&hfile->mod_sig); +} struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile) { @@ -384,7 +390,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi } else entry->filename = NULL; - entry->mod_time = 0; + FILE_MOD_RESET(&entry->mod_sig); memset(&entry->ipset,0,sizeof(entry->ipset)); LIST_INSERT_HEAD(head, entry, next); } @@ -416,6 +422,13 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char } return NULL; } +void ipset_files_reset_modtime(struct ipset_files_head *list) +{ + struct ipset_file *hfile; + + LIST_FOREACH(hfile, list, next) + FILE_MOD_RESET(&hfile->mod_sig); +} struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile) { diff --git a/nfq/pools.h b/nfq/pools.h index cd37bdd..aeda63f 100644 --- a/nfq/pools.h +++ b/nfq/pools.h @@ -50,7 +50,7 @@ void strlist_destroy(struct str_list_head *head); struct hostlist_file { char *filename; - time_t mod_time; + file_mod_sig mod_sig; strpool *hostlist; LIST_ENTRY(hostlist_file) next; }; @@ -59,6 +59,7 @@ LIST_HEAD(hostlist_files_head, hostlist_file); struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename); void hostlist_files_destroy(struct hostlist_files_head *head); struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename); +void hostlist_files_reset_modtime(struct hostlist_files_head *list); struct hostlist_item { struct hostlist_file *hfile; @@ -111,7 +112,7 @@ void ipsetPrint(ipset *ipset); struct ipset_file { char *filename; - time_t mod_time; + file_mod_sig mod_sig; ipset ipset; LIST_ENTRY(ipset_file) next; }; @@ -120,6 +121,7 @@ LIST_HEAD(ipset_files_head, ipset_file); struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename); void ipset_files_destroy(struct ipset_files_head *head); struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename); +void ipset_files_reset_modtime(struct ipset_files_head *list); struct ipset_item { struct ipset_file *hfile; diff --git a/tpws/helpers.c b/tpws/helpers.c index 8d71403..7db6aac 100644 --- a/tpws/helpers.c +++ b/tpws/helpers.c @@ -314,6 +314,18 @@ time_t file_mod_time(const char *filename) struct stat st; return stat(filename, &st) == -1 ? 0 : st.st_mtime; } +bool file_mod_signature(const char *filename, file_mod_sig *ms) +{ + struct stat st; + if (stat(filename,&st)==-1) + { + FILE_MOD_RESET(ms); + return false; + } + ms->mod_time=st.st_mtime; + ms->size=st.st_size; + return true; +} bool pf_in_range(uint16_t port, const port_filter *pf) { diff --git a/tpws/helpers.h b/tpws/helpers.h index 3c8a372..1b74430 100644 --- a/tpws/helpers.h +++ b/tpws/helpers.h @@ -62,6 +62,14 @@ static inline void phton16(uint8_t *p, uint16_t v) { int fprint_localtime(FILE *F); +typedef struct +{ + time_t mod_time; + off_t size; +} file_mod_sig; +#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size)) +#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig)) +bool file_mod_signature(const char *filename, file_mod_sig *ms); time_t file_mod_time(const char *filename); typedef struct diff --git a/tpws/hostlist.c b/tpws/hostlist.c index 6fbbd7d..c10aca6 100644 --- a/tpws/hostlist.c +++ b/tpws/hostlist.c @@ -105,21 +105,21 @@ static bool LoadHostList(struct hostlist_file *hfile) { if (hfile->filename) { - time_t t = file_mod_time(hfile->filename); - if (!t) + file_mod_sig fsig; + if (!file_mod_signature(hfile->filename, &fsig)) { // stat() error DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename); return true; } - if (t==hfile->mod_time) return true; // up to date + if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date StrPoolDestroy(&hfile->hostlist); if (!AppendHostList(&hfile->hostlist, hfile->filename)) { StrPoolDestroy(&hfile->hostlist); return false; } - hfile->mod_time=t; + hfile->mod_sig=fsig; } return true; } diff --git a/tpws/hostlist.h b/tpws/hostlist.h index deedc5c..9676613 100644 --- a/tpws/hostlist.h +++ b/tpws/hostlist.h @@ -13,3 +13,5 @@ bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *exclu struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename); bool HostlistsReloadCheckForProfile(const struct desync_profile *dp); void HostlistsDebug(); + +#define ResetAllHostlistsModTime() hostlist_files_reset_modtime(¶ms.hostlists) diff --git a/tpws/ipset.c b/tpws/ipset.c index b803205..b486eb4 100644 --- a/tpws/ipset.c +++ b/tpws/ipset.c @@ -126,21 +126,21 @@ static bool LoadIpset(struct ipset_file *hfile) { if (hfile->filename) { - time_t t = file_mod_time(hfile->filename); - if (!t) + file_mod_sig fsig; + if (!file_mod_signature(hfile->filename, &fsig)) { // stat() error DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename); return true; } - if (t==hfile->mod_time) return true; // up to date + if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date ipsetDestroy(&hfile->ipset); if (!AppendIpset(&hfile->ipset, hfile->filename)) { ipsetDestroy(&hfile->ipset); return false; } - hfile->mod_time=t; + hfile->mod_sig=fsig; } return true; } diff --git a/tpws/ipset.h b/tpws/ipset.h index f283c2f..b711ac5 100644 --- a/tpws/ipset.h +++ b/tpws/ipset.h @@ -10,3 +10,5 @@ bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, con struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename); void IpsetsDebug(); bool AppendIpsetItem(ipset *ips, char *ip); + +#define ResetAllIpsetModTime() ipset_files_reset_modtime(¶ms.ipsets) diff --git a/tpws/pools.c b/tpws/pools.c index 631a251..4cce2f6 100644 --- a/tpws/pools.c +++ b/tpws/pools.c @@ -169,7 +169,7 @@ struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const } else entry->filename = NULL; - entry->mod_time = 0; + FILE_MOD_RESET(&entry->mod_sig); entry->hostlist = NULL; LIST_INSERT_HEAD(head, entry, next); } @@ -201,6 +201,13 @@ struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, co } return NULL; } +void hostlist_files_reset_modtime(struct hostlist_files_head *list) +{ + struct hostlist_file *hfile; + + LIST_FOREACH(hfile, list, next) + FILE_MOD_RESET(&hfile->mod_sig); +} struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile) { @@ -383,7 +390,7 @@ struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *fi } else entry->filename = NULL; - entry->mod_time = 0; + FILE_MOD_RESET(&entry->mod_sig); memset(&entry->ipset,0,sizeof(entry->ipset)); LIST_INSERT_HEAD(head, entry, next); } @@ -415,6 +422,13 @@ struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char } return NULL; } +void ipset_files_reset_modtime(struct ipset_files_head *list) +{ + struct ipset_file *hfile; + + LIST_FOREACH(hfile, list, next) + FILE_MOD_RESET(&hfile->mod_sig); +} struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile) { diff --git a/tpws/pools.h b/tpws/pools.h index cd37bdd..aeda63f 100644 --- a/tpws/pools.h +++ b/tpws/pools.h @@ -50,7 +50,7 @@ void strlist_destroy(struct str_list_head *head); struct hostlist_file { char *filename; - time_t mod_time; + file_mod_sig mod_sig; strpool *hostlist; LIST_ENTRY(hostlist_file) next; }; @@ -59,6 +59,7 @@ LIST_HEAD(hostlist_files_head, hostlist_file); struct hostlist_file *hostlist_files_add(struct hostlist_files_head *head, const char *filename); void hostlist_files_destroy(struct hostlist_files_head *head); struct hostlist_file *hostlist_files_search(struct hostlist_files_head *head, const char *filename); +void hostlist_files_reset_modtime(struct hostlist_files_head *list); struct hostlist_item { struct hostlist_file *hfile; @@ -111,7 +112,7 @@ void ipsetPrint(ipset *ipset); struct ipset_file { char *filename; - time_t mod_time; + file_mod_sig mod_sig; ipset ipset; LIST_ENTRY(ipset_file) next; }; @@ -120,6 +121,7 @@ LIST_HEAD(ipset_files_head, ipset_file); struct ipset_file *ipset_files_add(struct ipset_files_head *head, const char *filename); void ipset_files_destroy(struct ipset_files_head *head); struct ipset_file *ipset_files_search(struct ipset_files_head *head, const char *filename); +void ipset_files_reset_modtime(struct ipset_files_head *list); struct ipset_item { struct ipset_file *hfile; diff --git a/tpws/tamper.c b/tpws/tamper.c index 7492728..c06613e 100644 --- a/tpws/tamper.c +++ b/tpws/tamper.c @@ -443,7 +443,8 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname DLOG_PERROR("write to auto hostlist:"); return; } - dp->hostlist_auto->mod_time = file_mod_time(dp->hostlist_auto->filename); + if (!file_mod_signature(dp->hostlist_auto->filename, &dp->hostlist_auto->mod_sig)) + DLOG_PERROR("file_mod_signature"); } else { diff --git a/tpws/tpws.c b/tpws/tpws.c index d261ebf..c52a275 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -50,10 +50,31 @@ #define MAX_CONFIG_FILE_SIZE 16384 struct params_s params; +static bool bReload=false; static void onhup(int sig) { - printf("HUP received !\n"); + printf("HUP received ! Lists will be reloaded.\n"); + bReload=true; +} +void ReloadCheck() +{ + if (bReload) + { + ResetAllHostlistsModTime(); + if (!LoadAllHostLists()) + { + DLOG_ERR("hostlists load failed. this is fatal.\n"); + exit(1); + } + ResetAllIpsetModTime(); + if (!LoadAllIpsets()) + { + DLOG_ERR("ipset load failed. this is fatal.\n"); + exit(1); + } + bReload=false; + } } static void onusr2(int sig) diff --git a/tpws/tpws.h b/tpws/tpws.h index fa4eb30..baa7d60 100644 --- a/tpws/tpws.h +++ b/tpws/tpws.h @@ -6,4 +6,4 @@ #include -void dohup(void); +void ReloadCheck(); diff --git a/tpws/tpws_conn.c b/tpws/tpws_conn.c index e30bd1a..1294e74 100644 --- a/tpws/tpws_conn.c +++ b/tpws/tpws_conn.c @@ -1544,6 +1544,8 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) for(;;) { + ReloadCheck(); + DBGPRINT("epoll_wait\n"); if ((num_events = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1)) == -1)