From 69b08f0a362146e7e736d1e35946cfac050a285e Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 2 Dec 2025 15:40:39 +0300 Subject: [PATCH] install_easy --- common/installer.sh | 803 +++++++++++++++++ config.default | 7 +- docs/changes.txt | 1 + init.d/openrc/{zapret => zapret2} | 2 +- init.d/pfsense/zapret2.sh | 27 + init.d/runit/zapret2/finish | 2 + init.d/runit/zapret2/run | 3 + init.d/s6/zapret2/down | 2 + init.d/s6/zapret2/type | 1 + init.d/s6/zapret2/up | 2 + init.d/windivert.filter.examples/README.txt | 14 + .../windivert_part.discord_media.txt | 20 + .../windivert_part.quic_initial_ietf.txt | 4 + .../windivert_part.stun.txt | 3 + .../windivert_part.wireguard.txt | 3 + install_easy.sh | 833 ++++++++++++++++++ install_prereq.sh | 51 ++ uninstall_easy.sh | 99 +++ 18 files changed, 1872 insertions(+), 5 deletions(-) create mode 100644 common/installer.sh rename init.d/openrc/{zapret => zapret2} (96%) mode change 100644 => 100755 create mode 100755 init.d/pfsense/zapret2.sh create mode 100755 init.d/runit/zapret2/finish create mode 100755 init.d/runit/zapret2/run create mode 100755 init.d/s6/zapret2/down create mode 100644 init.d/s6/zapret2/type create mode 100755 init.d/s6/zapret2/up create mode 100644 init.d/windivert.filter.examples/README.txt create mode 100644 init.d/windivert.filter.examples/windivert_part.discord_media.txt create mode 100644 init.d/windivert.filter.examples/windivert_part.quic_initial_ietf.txt create mode 100644 init.d/windivert.filter.examples/windivert_part.stun.txt create mode 100644 init.d/windivert.filter.examples/windivert_part.wireguard.txt create mode 100755 install_easy.sh create mode 100755 install_prereq.sh create mode 100755 uninstall_easy.sh diff --git a/common/installer.sh b/common/installer.sh new file mode 100644 index 0000000..d1f1b28 --- /dev/null +++ b/common/installer.sh @@ -0,0 +1,803 @@ +GET_LIST_PREFIX=/ipset/get_ + +SYSTEMD_DIR=/lib/systemd +[ -d "$SYSTEMD_DIR" ] || SYSTEMD_DIR=/usr/lib/systemd +[ -d "$SYSTEMD_DIR" ] && SYSTEMD_SYSTEM_DIR="$SYSTEMD_DIR/system" + +INIT_SCRIPT=/etc/init.d/zapret2 + + +exitp() +{ + echo + echo press enter to continue + read A + exit $1 +} + +extract_var_def() +{ + # $1 - var name + # this sed script parses single or multi line shell var assignments with optional ' or " enclosure + sed -n \ +"/^$1=\"/ { +:s1 +/\".*\"/ { + p + b +} +N +t c1 +b s1 +:c1 +} +/^$1='/ { +:s2 +/'.*'/ { + p + b +} +N +t c2 +b s2 +:c2 +} +/^$1=/p +" +} +replace_var_def() +{ + # $1 - var name + # $2 - new val + # $3 - conf file + # this sed script replaces single or multi line shell var assignments with optional ' or " enclosure + local repl + if [ -z "$2" ]; then + repl="#$1=" + elif contains "$2" " "; then + repl="$1=\"$2\"" + else + repl="$1=$2" + fi + local script=\ +"/^#*[[:space:]]*$1=\"/ { +:s1 +/\".*\"/ { + c\\ +$repl + b +} +N +t c1 +b s1 +:c1 +} +/^#*[[:space:]]*$1='/ { +:s2 +/'.*'/ { + c\\ +$repl + b +} +N +t c2 +b s2 +:c2 +} +/^#*[[:space:]]*$1=/c\\ +$repl" + # there's incompatibility with -i option on BSD and busybox/GNU + if [ "$UNAME" = "Linux" ]; then + sed -i -e "$script" "$3" + else + sed -i '' -e "$script" "$3" + fi +} + +parse_var_checked() +{ + # $1 - file name + # $2 - var name + + local tmp="/tmp/zvar-pid-$$.sh" + local v + cat "$1" | extract_var_def "$2" >"$tmp" + . "$tmp" + rm -f "$tmp" + eval v="\$$2" + # trim + v="$(echo "$v" | trim)" + eval $2=\""$v"\" +} +parse_vars_checked() +{ + # $1 - file name + # $2,$3,... - var names + local f="$1" + shift + while [ -n "$1" ]; do + parse_var_checked "$f" $1 + shift + done +} +edit_file() +{ + # $1 - file name + local ed="$EDITOR" + [ -n "$ed" ] || { + for e in mcedit nano vim vi; do + exists "$e" && { + ed="$e" + break + } + done + } + [ -n "$ed" ] && "$ed" "$1" +} +echo_var() +{ + local v delimeter delims= + eval v="\$$1" + if find_str_in_list $1 "$EDITVAR_NEWLINE_VARS"; then + echo "$1=\"" + for delimeter in $EDITVAR_NEWLINE_DELIMETERS; do + delims="${delims:+$delims }-e "'"'"s/$delimeter/"'\\n'"$delimeter/g"'"' + done + echo "$v\"" | tr '\n' ' ' | tr -d '\r' | eval sed -e 's/^\ *//' -e 's/\ *$//' $delims + else + if contains "$v" " "; then + echo $1=\"$v\" + else + echo $1=$v + fi + fi +} +edit_vars() +{ + # $1,$2,... - var names + local n=1 var tmp="/tmp/zvars-pid-$$.txt" + rm -f "$tmp" + while : ; do + eval var="\${$n}" + [ -n "$var" ] || break + echo_var $var >> "$tmp" + n=$(($n+1)) + done + edit_file "$tmp" && parse_vars_checked "$tmp" "$@" + rm -f "$tmp" +} + +list_vars() +{ + while [ -n "$1" ] ; do + echo_var $1 + shift + done + echo +} + +openrc_test() +{ + exists rc-update || return 1 + # some systems do not usse openrc-init but launch openrc from inittab + [ "$INIT" = "openrc-init" ] || grep -qE "sysinit.*openrc" /etc/inittab 2>/dev/null +} +check_system() +{ + # $1 - nonempty = do not fail on unknown rc system + + echo \* checking system + + SYSTEM= + SUBSYS= + SYSTEMCTL="$(whichq systemctl)" + + get_fwtype + OPENWRT_FW3= + OPENWRT_FW4= + + local info + UNAME=$(uname) + if [ "$UNAME" = "Linux" ]; then + # do not use 'exe' because it requires root + local INIT="$(sed 's/\x0/\n/g' /proc/1/cmdline | head -n 1)" + [ -L "$INIT" ] && INIT=$(readlink "$INIT") + INIT="$(basename "$INIT")" + # some distros include systemctl without systemd + if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then + SYSTEM=systemd + [ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions" + elif [ -f "/etc/openwrt_release" ] && exists opkg || exists apk && exists uci && [ "$INIT" = "procd" ] ; then + SYSTEM=openwrt + OPENWRT_PACKAGER=opkg + OPENWRT_PACKAGER_INSTALL="opkg install" + OPENWRT_PACKAGER_UPDATE="opkg update" + exists apk && { + OPENWRT_PACKAGER=apk + OPENWRT_PACKAGER_INSTALL="apk add" + OPENWRT_PACKAGER_UPDATE= + } + info="package manager $OPENWRT_PACKAGER\n" + if openwrt_fw3 ; then + OPENWRT_FW3=1 + info="${info}firewall fw3" + if is_ipt_flow_offload_avail; then + info="$info. hardware flow offloading requires iptables." + else + info="$info. flow offloading unavailable." + fi + elif openwrt_fw4; then + OPENWRT_FW4=1 + info="${info}firewall fw4. flow offloading requires nftables." + fi + [ -f "$EXEDIR/init.d/openwrt/functions" ] && . "$EXEDIR/init.d/openwrt/functions" + elif openrc_test; then + SYSTEM=openrc + [ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions" + else + echo system is not either systemd, openrc or openwrt based + echo easy installer can set up config settings but can\'t configure auto start + echo you have to do it manually. check readme.md for manual setup info. + if [ -n "$1" ] || ask_yes_no N "do you want to continue"; then + SYSTEM=linux + else + exitp 5 + fi + [ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions" + fi + linux_get_subsys + else + echo easy installer only supports Linux. check readme.md for supported systems and manual setup info. + exitp 5 + fi + echo system is based on $SYSTEM + [ -n "$info" ] && printf "${info}\n" +} + +get_free_space_mb() +{ + df -m $PWD | awk '/[0-9]%/{print $(NF-2)}' +} +get_ram_kb() +{ + grep MemTotal /proc/meminfo | awk '{print $2}' +} +get_ram_mb() +{ + local R=$(get_ram_kb) + echo $(($R/1024)) +} + +crontab_del() +{ + exists crontab || return + + echo \* removing crontab entry + + CRONTMP=/tmp/cron.tmp + crontab -l >$CRONTMP 2>/dev/null + if grep -q "$GET_LIST_PREFIX" $CRONTMP; then + echo removing following entries from crontab : + grep "$GET_LIST_PREFIX" $CRONTMP + grep -v "$GET_LIST_PREFIX" $CRONTMP >$CRONTMP.2 + crontab $CRONTMP.2 + rm -f $CRONTMP.2 + fi + rm -f $CRONTMP +} +crontab_del_quiet() +{ + exists crontab || return + + CRONTMP=/tmp/cron.tmp + crontab -l >$CRONTMP 2>/dev/null + if grep -q "$GET_LIST_PREFIX" $CRONTMP; then + grep -v "$GET_LIST_PREFIX" $CRONTMP >$CRONTMP.2 + crontab $CRONTMP.2 + rm -f $CRONTMP.2 + fi + rm -f $CRONTMP +} +crontab_add() +{ + # $1 - hour min + # $2 - hour max + [ -x "$GET_LIST" ] && { + echo \* adding crontab entry + + if exists crontab; then + CRONTMP=/tmp/cron.tmp + crontab -l >$CRONTMP 2>/dev/null + if grep -q "$GET_LIST_PREFIX" $CRONTMP; then + echo some entries already exist in crontab. check if this is corrent : + grep "$GET_LIST_PREFIX" $CRONTMP + else + end_with_newline <"$CRONTMP" || echo >>"$CRONTMP" + echo "$(random 0 59) $(random $1 $2) */2 * * $GET_LIST" >>$CRONTMP + crontab $CRONTMP + fi + rm -f $CRONTMP + else + echo '!!! CRON IS ABSENT !!! LISTS AUTO UPDATE WILL NOT WORK !!!' + fi + } +} +cron_ensure_running() +{ + # if no crontabs present in /etc/cron openwrt init script does not launch crond. this is default + [ "$SYSTEM" = "openwrt" ] && { + /etc/init.d/cron enable + /etc/init.d/cron start + } +} + + +service_start_systemd() +{ + echo \* starting zapret2 service + + "$SYSTEMCTL" start zapret2 || { + echo could not start zapret2 service + exitp 30 + } +} +service_stop_systemd() +{ + echo \* stopping zapret2 service + + "$SYSTEMCTL" daemon-reload + "$SYSTEMCTL" disable zapret2 + "$SYSTEMCTL" stop zapret2 +} +service_remove_systemd() +{ + echo \* removing zapret2 service + + rm -f "$SYSTEMD_SYSTEM_DIR/zapret2.service" + "$SYSTEMCTL" daemon-reload +} +timer_remove_systemd() +{ + echo \* removing zapret2-list-update timer + + "$SYSTEMCTL" daemon-reload + "$SYSTEMCTL" disable zapret2-list-update.timer + "$SYSTEMCTL" stop zapret2-list-update.timer + rm -f "$SYSTEMD_SYSTEM_DIR/zapret2-list-update.service" "$SYSTEMD_SYSTEM_DIR/zapret2-list-update.timer" + "$SYSTEMCTL" daemon-reload +} + +install_sysv_init() +{ + # $1 - "0"=disable + echo \* installing init script + + [ -x "$INIT_SCRIPT" ] && { + "$INIT_SCRIPT" stop + "$INIT_SCRIPT" disable + } + ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT" + [ "$1" != "0" ] && "$INIT_SCRIPT" enable +} +install_openrc_init() +{ + # $1 - "0"=disable + echo \* installing init script + + [ -x "$INIT_SCRIPT" ] && { + "$INIT_SCRIPT" stop + rc-update del zapret2 + } + ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT" + [ "$1" != "0" ] && rc-update add zapret2 +} +service_remove_openrc() +{ + echo \* removing zapret2 service + + [ -x "$INIT_SCRIPT" ] && { + rc-update del zapret2 + "$INIT_SCRIPT" stop + } + rm -f "$INIT_SCRIPT" +} +service_start_sysv() +{ + [ -x "$INIT_SCRIPT" ] && { + echo \* starting zapret2 service + "$INIT_SCRIPT" start || { + echo could not start zapret2 service + exitp 30 + } + } +} +service_stop_sysv() +{ + [ -x "$INIT_SCRIPT" ] && { + echo \* stopping zapret2 service + "$INIT_SCRIPT" stop + } +} +service_remove_sysv() +{ + echo \* removing zapret2 service + + [ -x "$INIT_SCRIPT" ] && { + "$INIT_SCRIPT" disable + "$INIT_SCRIPT" stop + } + rm -f "$INIT_SCRIPT" +} + +check_kmod() +{ + [ -f "/lib/modules/$(uname -r)/$1.ko" ] +} +check_package_exists_openwrt() +{ + [ -n "$($OPENWRT_PACKAGER list $1)" ] +} +check_package_openwrt() +{ + case $OPENWRT_PACKAGER in + opkg) + [ -n "$(opkg list-installed $1)" ] && return 0 + local what="$(opkg whatprovides $1 | tail -n +2 | head -n 1)" + [ -n "$what" ] || return 1 + [ -n "$(opkg list-installed $what)" ] + ;; + apk) + apk info -e $1 + ;; + esac +} +check_packages_openwrt() +{ + for pkg in $@; do + check_package_openwrt $pkg || return + done +} + +install_openwrt_iface_hook() +{ + echo \* installing ifup hook + + ln -fs "$OPENWRT_IFACE_HOOK" /etc/hotplug.d/iface +} +remove_openwrt_iface_hook() +{ + echo \* removing ifup hook + + rm -f /etc/hotplug.d/iface/??-zapret2 +} +openwrt_fw_section_find() +{ + # $1 - fw include postfix + # echoes section number + + i=0 + while true + do + path=$(uci -q get firewall.@include[$i].path) + [ -n "$path" ] || break + [ "$path" = "$OPENWRT_FW_INCLUDE$1" ] && { + echo $i + return 0 + } + i=$(($i+1)) + done + return 1 +} +openwrt_fw_section_del() +{ + # $1 - fw include postfix + + local id="$(openwrt_fw_section_find $1)" + [ -n "$id" ] && { + uci delete firewall.@include[$id] && uci commit firewall + rm -f "$OPENWRT_FW_INCLUDE$1" + } +} +openwrt_fw_section_add() +{ + openwrt_fw_section_find || + { + uci add firewall include >/dev/null || return + echo -1 + } +} +openwrt_fw_section_configure() +{ + local id="$(openwrt_fw_section_add $1)" + [ -z "$id" ] || + ! uci set firewall.@include[$id].path="$OPENWRT_FW_INCLUDE" || + ! uci set firewall.@include[$id].reload="1" || + ! uci commit firewall && + { + echo could not add firewall include + exitp 50 + } +} +install_openwrt_firewall() +{ + echo \* installing firewall script $1 + + [ -n "MODE" ] || { + echo should specify MODE in $ZAPRET_CONFIG + exitp 7 + } + + echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE" + ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE" + + openwrt_fw_section_configure $1 +} +restart_openwrt_firewall() +{ + echo \* restarting firewall + + local FW=fw4 + [ -n "$OPENWRT_FW3" ] && FW=fw3 + exists $FW && $FW -q restart || { + echo could not restart firewall $FW + } +} +remove_openwrt_firewall() +{ + echo \* removing firewall script + + openwrt_fw_section_del +} + +clear_ipset() +{ + echo "* clearing ipset(s)" + + # free some RAM + "$IPSET_DIR/create_ipset.sh" clear +} + + + +write_config_var() +{ + # $1 - mode var + local M + eval M="\$$1" + # replace / => \/ + #M=${M//\//\\\/} + M=$(echo $M | sed 's/\//\\\//g' | trim) + grep -q "^[[:space:]]*$1=\|^#*[[:space:]]*$1=" "$ZAPRET_CONFIG" || { + # var does not exist in config. add it + echo $1= >>"$ZAPRET_CONFIG" + } + replace_var_def $1 "$M" "$ZAPRET_CONFIG" +} + +no_prereq_exit() +{ + echo could not install prerequisites + exitp 6 +} +check_prerequisites_linux() +{ + echo \* checking prerequisites + + local s cmd PKGS UTILS req="curl curl" + local APTGET DNF YUM PACMAN ZYPPER EOPKG APK + case "$FWTYPE" in + iptables) + req="$req iptables iptables ip6tables iptables ipset ipset" + ;; + nftables) + req="$req nft nftables" + ;; + esac + + PKGS=$(for s in $req; do echo $s; done | + while read cmd; do + read pkg + exists $cmd || echo $pkg + done | sort -u | xargs) + UTILS=$(for s in $req; do echo $s; done | + while read cmd; do + read pkg + echo $cmd + done | sort -u | xargs) + + if [ -z "$PKGS" ] ; then + echo required utilities exist : $UTILS + else + echo \* installing prerequisites + + echo packages required : $PKGS + + APTGET=$(whichq apt-get) + DNF=$(whichq dnf) + YUM=$(whichq yum) + PACMAN=$(whichq pacman) + ZYPPER=$(whichq zypper) + EOPKG=$(whichq eopkg) + APK=$(whichq apk) + if [ -x "$APTGET" ] ; then + "$APTGET" update + "$APTGET" install -y --no-install-recommends $PKGS dnsutils || no_prereq_exit + elif [ -x "$DNF" ] ; then + "$DNF" -y install $PKGS || no_prereq_exit + elif [ -x "$YUM" ] ; then + "$YUM" -y install $PKGS || no_prereq_exit + elif [ -x "$PACMAN" ] ; then + "$PACMAN" -Syy + "$PACMAN" --noconfirm -S $PKGS || no_prereq_exit + elif [ -x "$ZYPPER" ] ; then + "$ZYPPER" --non-interactive install $PKGS || no_prereq_exit + elif [ -x "$EOPKG" ] ; then + "$EOPKG" -y install $PKGS || no_prereq_exit + elif [ -x "$APK" ] ; then + "$APK" update + # for alpine + [ "$FWTYPE" = iptables ] && [ -n "$($APK list ip6tables)" ] && PKGS="$PKGS ip6tables" + "$APK" add $PKGS || no_prereq_exit + else + echo supported package manager not found + echo you must manually install : $UTILS + exitp 5 + fi + fi +} + +removable_pkgs_openwrt() +{ + local pkg PKGS2 + [ -n "$OPENWRT_FW4" ] && PKGS2="$PKGS2 iptables-zz-legacy iptables ip6tables-zz-legacy ip6tables" + [ -n "$OPENWRT_FW3" ] && PKGS2="$PKGS2 nftables-json nftables-nojson nftables" + PKGS= + for pkg in $PKGS2; do + check_package_exists_openwrt $pkg && PKGS="${PKGS:+$PKGS }$pkg" + done + PKGS="ipset iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32 ip6tables-mod-nat ip6tables-extra kmod-nft-queue gzip coreutils-sort coreutils-sleep curl $PKGS" +} + +openwrt_fix_broken_apk_uninstall_scripts() +{ + # at least in early snapshots with apk removing gnu gzip, sort, ... does not restore links to busybox + # system may become unusable + exists sort || { echo fixing missing sort; ln -fs /bin/busybox /usr/bin/sort; } + exists gzip || { echo fixing missing gzip; ln -fs /bin/busybox /bin/gzip; } + exists sleep || { echo fixing missing sleep; ln -fs /bin/busybox /bin/sleep; } +} + +remove_extra_pkgs_openwrt() +{ + local PKGS + echo \* remove dependencies + removable_pkgs_openwrt + echo these packages may have been installed by install_easy.sh : $PKGS + ask_yes_no N "do you want to remove them" && { + case $OPENWRT_PACKAGER in + opkg) + opkg remove --autoremove $PKGS + ;; + apk) + apk del $PKGS + openwrt_fix_broken_apk_uninstall_scripts + ;; + esac + } +} + +check_prerequisites_openwrt() +{ + echo \* checking prerequisites + + local PKGS="curl" UPD=0 local pkg_iptables + + case "$FWTYPE" in + iptables) + pkg_iptables=iptables + check_package_exists_openwrt iptables-zz-legacy && pkg_iptables=iptables-zz-legacy + PKGS="$PKGS ipset $pkg_iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32" + check_package_exists_openwrt ip6tables-zz-legacy && pkg_iptables=ip6tables-zz-legacy + [ "$DISABLE_IPV6" = 1 ] || PKGS="$PKGS $pkg_iptables ip6tables-mod-nat ip6tables-extra" + ;; + nftables) + PKGS="$PKGS nftables kmod-nft-nat kmod-nft-offload kmod-nft-queue" + ;; + esac + + if check_packages_openwrt $PKGS ; then + echo everything is present + else + echo \* installing prerequisites + + $OPENWRT_PACKAGER_UPDATE + UPD=1 + $OPENWRT_PACKAGER_INSTALL $PKGS || { + echo could not install prerequisites + exitp 6 + } + fi + + is_linked_to_busybox gzip && { + echo + echo your system uses default busybox gzip. its several times slower than GNU gzip. + echo ip/host list scripts will run much faster with GNU gzip + echo installer can install GNU gzip but it requires about 100 Kb space + if ask_yes_no N "do you want to install GNU gzip"; then + [ "$UPD" = "0" ] && { + $OPENWRT_PACKAGER_UPDATE + UPD=1 + } + $OPENWRT_PACKAGER_INSTALL --force-overwrite gzip + fi + } + is_linked_to_busybox sort && { + echo + echo your system uses default busybox sort. its much slower and consumes much more RAM than GNU sort + echo ip/host list scripts will run much faster with GNU sort + echo installer can install GNU sort but it requires about 100 Kb space + if ask_yes_no N "do you want to install GNU sort"; then + [ "$UPD" = "0" ] && { + $OPENWRT_PACKAGER_UPDATE + UPD=1 + } + $OPENWRT_PACKAGER_INSTALL --force-overwrite coreutils-sort + fi + } + [ "$FSLEEP" = 0 ] && is_linked_to_busybox sleep && { + echo + echo no methods of sub-second sleep were found. + echo if you want to speed up blockcheck install coreutils-sleep. it requires about 40 Kb space + if ask_yes_no N "do you want to install COREUTILS sleep"; then + [ "$UPD" = "0" ] && { + $OPENWRT_PACKAGER_UPDATE + UPD=1 + } + $OPENWRT_PACKAGER_INSTALL --force-overwrite coreutils-sleep + fsleep_setup + fi + } +} + + + +select_ipv6() +{ + local T=N + + [ "$DISABLE_IPV6" != '1' ] && T=Y + local old6=$DISABLE_IPV6 + echo + if ask_yes_no $T "enable ipv6 support"; then + DISABLE_IPV6=0 + else + DISABLE_IPV6=1 + fi + [ "$old6" != "$DISABLE_IPV6" ] && write_config_var DISABLE_IPV6 +} +select_fwtype() +{ + echo + [ $(get_ram_mb) -le 400 ] && { + echo WARNING ! you are running a low RAM system + echo WARNING ! nft requires lots of RAM to load huge ip sets, much more than ipsets require + echo WARNING ! if you need large lists it may be necessary to fall back to iptables+ipset firewall + } + echo select firewall type : + ask_list FWTYPE "iptables nftables" "$FWTYPE" && write_config_var FWTYPE +} + +dry_run_nfqws_() +{ + local NFQWS="$ZAPRET_BASE/nfq2/nfqws2" + echo verifying nfqws options + "$NFQWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@" +} +dry_run_nfqws() +{ + [ "$NFQWS2_ENABLE" = 1 ] || return 0 + local opt="$NFQWS2_OPT" qn=${QNUM:-300} + filter_apply_hostlist_target opt + dry_run_nfqws_ --qnum=$qn $opt + echo NOTE ! LUA code validity cannot be verified at this stage ! +} diff --git a/config.default b/config.default index d29d887..ce89795 100644 --- a/config.default +++ b/config.default @@ -75,9 +75,9 @@ NFQWS2_UDP_PKT_IN=0 # hostlist markers are replaced to empty string if MODE_FILTER does not satisfy # appends ipset/zapret-hosts-auto.txt as normal list NFQWS2_OPT=" ---filter-tcp=80 --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 --lua-desync=multisplit:pos=method+2 --new ---filter-tcp=443 --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000 --lua-desync=multidisorder:pos=1,midsld --new ---filter-udp=443 --payload=quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=6 +--filter-tcp=80 --filter-l7=http --payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 --lua-desync=multisplit:pos=method+2 --new +--filter-tcp=443 --filter-l7=tls --payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000 --lua-desync=multidisorder:pos=1,midsld --new +--filter-udp=443 --filter-l7=quic --payload=quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=6 " # none,ipset,hostlist,autohostlist @@ -97,7 +97,6 @@ FLOWOFFLOAD=donttouch # or leave them commented if its not router # it's possible to specify multiple interfaces like this : IFACE_WAN="eth0 eth1 eth2" # if IFACE_WAN6 is not defined it take the value of IFACE_WAN -#IFACE_LAN=eth0 #IFACE_WAN=eth1 #IFACE_WAN6="ipsec0 wireguard0 he_net" diff --git a/docs/changes.txt b/docs/changes.txt index 5e94629..53c6aed 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -38,3 +38,4 @@ v0.2 v0.3 * init.d launch scripts * init.d: 40-webserver custom script +* install_easy diff --git a/init.d/openrc/zapret b/init.d/openrc/zapret2 old mode 100644 new mode 100755 similarity index 96% rename from init.d/openrc/zapret rename to init.d/openrc/zapret2 index 3a1ca58..0bcd7dd --- a/init.d/openrc/zapret +++ b/init.d/openrc/zapret2 @@ -6,7 +6,7 @@ EXEDIR=$(dirname "$RC_SERVICE") EXEDIR="$(cd "$EXEDIR"; pwd)" ZAPRET_BASE="$EXEDIR/../.." -ZAPRET_INIT="$ZAPRET_BASE/init.d/sysv/zapret" +ZAPRET_INIT="$ZAPRET_BASE/init.d/sysv/zapret2" extra_commands="start_fw stop_fw restart_fw start_daemons stop_daemons restart_daemons reload_ifsets list_ifsets list_table" description="extra commands :" diff --git a/init.d/pfsense/zapret2.sh b/init.d/pfsense/zapret2.sh new file mode 100755 index 0000000..7e92e1a --- /dev/null +++ b/init.d/pfsense/zapret2.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# this file should be placed to /usr/local/etc/rc.d and chmod 755 + +# copy 'lua' dir there +ZDIR=/usr/local/etc/zapret2 + +# prepare system + +kldload ipfw +kldload ipdivert + +# for older pfsense versions. newer do not have these sysctls +sysctl net.inet.ip.pfil.outbound=ipfw,pf +sysctl net.inet.ip.pfil.inbound=ipfw,pf +sysctl net.inet6.ip6.pfil.outbound=ipfw,pf +sysctl net.inet6.ip6.pfil.inbound=ipfw,pf + +# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state +pfctl -d ; pfctl -e + +# add ipfw rules and start daemon + +ipfw delete 100 +ipfw add 100 divert 990 tcp from any to any 80,443 out not diverted not sockarg +pkill ^dvtws2$ +dvtws2 --daemon --port 990 --lua-init=@$ZDIR/zapret-lib.lua --lua-init=@$ZDIR/zapret-antidpi.lua --lua-desync=multisplit diff --git a/init.d/runit/zapret2/finish b/init.d/runit/zapret2/finish new file mode 100755 index 0000000..1448fd1 --- /dev/null +++ b/init.d/runit/zapret2/finish @@ -0,0 +1,2 @@ +#!/bin/sh +/opt/zapret2/init.d/sysv/zapret2 stop diff --git a/init.d/runit/zapret2/run b/init.d/runit/zapret2/run new file mode 100755 index 0000000..4c5854a --- /dev/null +++ b/init.d/runit/zapret2/run @@ -0,0 +1,3 @@ +#!/bin/sh +/opt/zapret2/init.d/sysv/zapret2 start +exec chpst -b zapret2 sleep infinity diff --git a/init.d/s6/zapret2/down b/init.d/s6/zapret2/down new file mode 100755 index 0000000..98445df --- /dev/null +++ b/init.d/s6/zapret2/down @@ -0,0 +1,2 @@ +#!/bin/execlineb -P +exec /opt/zapret2/init.d/sysv/zapret2 stop diff --git a/init.d/s6/zapret2/type b/init.d/s6/zapret2/type new file mode 100644 index 0000000..bdd22a1 --- /dev/null +++ b/init.d/s6/zapret2/type @@ -0,0 +1 @@ +oneshot diff --git a/init.d/s6/zapret2/up b/init.d/s6/zapret2/up new file mode 100755 index 0000000..99371aa --- /dev/null +++ b/init.d/s6/zapret2/up @@ -0,0 +1,2 @@ +#!/bin/execlineb -P +exec /opt/zapret2/init.d/sysv/zapret2 start diff --git a/init.d/windivert.filter.examples/README.txt b/init.d/windivert.filter.examples/README.txt new file mode 100644 index 0000000..decde50 --- /dev/null +++ b/init.d/windivert.filter.examples/README.txt @@ -0,0 +1,14 @@ +Цель этих фильтров - отсекать полезную нагрузку в режиме ядра, не насилуя процессор перенаправлением целого потока на winws. +Задействуются через `winws --wf-raw-part=@filename`. Может быть несколько частичных фильтров. Они могут сочетаться с --wf-tcp и --wf-udp. +Однако, язык фильтров windivert не содержит операций с битовыми полями, сдвигов и побитовой логики. +Поэтому фильтры получились более слабыми, способными передавать неправильную нагрузку. +Дофильтрация производится силами winws. + +Описание языка фильтров : https://reqrypt.org/windivert-doc.html#filter_language +Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw-part=@windivert_part.discord_media.txt --wf-raw-part=@windivert_part.stun.txt --filter-l7=stun,discord --dpi-desync=fake` + + +These filters are invoked using `winws --wf-raw-part=@filename`. Multiple filter parts are supported. They can be combined with --wf-tcp and --wf-udp. +Filters are kernel mode and save great amount of CPU. +However windivert cannot filter by bit fields, lacks shift and bitwise logic operations. +Filters are relaxed and can pass wrong payloads. Finer filtering is done by winws. diff --git a/init.d/windivert.filter.examples/windivert_part.discord_media.txt b/init.d/windivert.filter.examples/windivert_part.discord_media.txt new file mode 100644 index 0000000..26c2014 --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.discord_media.txt @@ -0,0 +1,20 @@ + outbound and ip and + udp.DstPort>=50000 and udp.DstPort<=50099 and + udp.PayloadLength=74 and + udp.Payload32[0]=0x00010046 and + udp.Payload32[2]=0 and + udp.Payload32[3]=0 and + udp.Payload32[4]=0 and + udp.Payload32[5]=0 and + udp.Payload32[6]=0 and + udp.Payload32[7]=0 and + udp.Payload32[8]=0 and + udp.Payload32[9]=0 and + udp.Payload32[10]=0 and + udp.Payload32[11]=0 and + udp.Payload32[12]=0 and + udp.Payload32[13]=0 and + udp.Payload32[14]=0 and + udp.Payload32[15]=0 and + udp.Payload32[16]=0 and + udp.Payload32[17]=0 \ No newline at end of file diff --git a/init.d/windivert.filter.examples/windivert_part.quic_initial_ietf.txt b/init.d/windivert.filter.examples/windivert_part.quic_initial_ietf.txt new file mode 100644 index 0000000..6e01bef --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.quic_initial_ietf.txt @@ -0,0 +1,4 @@ + outbound and + udp.PayloadLength>=256 and + udp.Payload[0]>=0xC0 and udp.Payload[0]<0xD0 and + udp.Payload[1]=0 and udp.Payload16[1]=0 and udp.Payload[4]=1 diff --git a/init.d/windivert.filter.examples/windivert_part.stun.txt b/init.d/windivert.filter.examples/windivert_part.stun.txt new file mode 100644 index 0000000..a761690 --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.stun.txt @@ -0,0 +1,3 @@ + outbound and + udp.PayloadLength>=20 and + udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40 \ No newline at end of file diff --git a/init.d/windivert.filter.examples/windivert_part.wireguard.txt b/init.d/windivert.filter.examples/windivert_part.wireguard.txt new file mode 100644 index 0000000..9b07c08 --- /dev/null +++ b/init.d/windivert.filter.examples/windivert_part.wireguard.txt @@ -0,0 +1,3 @@ + outbound and + udp.PayloadLength=148 and + udp.Payload[0]=0x01 \ No newline at end of file diff --git a/install_easy.sh b/install_easy.sh new file mode 100755 index 0000000..2fda492 --- /dev/null +++ b/install_easy.sh @@ -0,0 +1,833 @@ +#!/bin/sh + +# automated script for easy installing zapret + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" +ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"} +ZAPRET_TARGET=${ZAPRET_TARGET:-/opt/zapret2} +ZAPRET_TARGET_RW=${ZAPRET_RW:-"$ZAPRET_TARGET"} +ZAPRET_TARGET_CONFIG="$ZAPRET_TARGET_RW/config" +ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"} +ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"} +ZAPRET_CONFIG_DEFAULT="$ZAPRET_BASE/config.default" +IPSET_DIR="$ZAPRET_BASE/ipset" + +[ -f "$ZAPRET_CONFIG" ] || { + ZAPRET_CONFIG_DIR="$(dirname "$ZAPRET_CONFIG")" + [ -d "$ZAPRET_CONFIG_DIR" ] || mkdir -p "$ZAPRET_CONFIG_DIR" + cp "$ZAPRET_CONFIG_DEFAULT" "$ZAPRET_CONFIG" +} +. "$ZAPRET_CONFIG" +. "$ZAPRET_BASE/common/base.sh" +. "$ZAPRET_BASE/common/elevate.sh" +. "$ZAPRET_BASE/common/fwtype.sh" +. "$ZAPRET_BASE/common/dialog.sh" +. "$ZAPRET_BASE/common/ipt.sh" +. "$ZAPRET_BASE/common/installer.sh" +. "$ZAPRET_BASE/common/virt.sh" +. "$ZAPRET_BASE/common/list.sh" + +GET_LIST="$IPSET_DIR/get_config.sh" + +check_readonly_system() +{ + local RO + echo \* checking readonly system + case $SYSTEM in + systemd) + [ -w "$SYSTEMD_SYSTEM_DIR" ] || RO=1 + ;; + openrc) + [ -w "$(dirname "$INIT_SCRIPT")" ] || RO=1 + ;; + esac + [ -z "$RO" ] || { + echo '!!! READONLY SYSTEM DETECTED !!!' + echo '!!! WILL NOT BE ABLE TO CONFIGURE STARTUP !!!' + echo '!!! MANUAL STARTUP CONFIGURATION IS REQUIRED !!!' + ask_yes_no N "do you want to continue" || exitp 5 + } +} + +check_source() +{ + local bad=0 + + echo \* checking source files + case $SYSTEM in + systemd) + [ -f "$EXEDIR/init.d/systemd/zapret2.service" ] || bad=1 + ;; + openrc) + [ -f "$EXEDIR/init.d/openrc/zapret2" ] || bad=1 + ;; + esac + [ "$bad" = 1 ] && { + echo 'some critical files are missing' + echo 'are you sure you are not using embedded release ? you need full version for traditional systems' + exitp 5 + } +} + +check_bins() +{ + echo \* checking executables + + fix_perms_bin_test "$EXEDIR" + local arch="$(get_bin_arch)" + local make_target + local cf="-march=native" + [ "$FORCE_BUILD" = "1" ] && { + echo forced build mode + if [ "$arch" = "my" ]; then + echo already compiled + else + arch="" + fi + } + if [ -n "$arch" ] ; then + echo found architecture "\"$arch\"" + elif [ -f "$EXEDIR/Makefile" ] && exists make; then + echo trying to compile + case $SYSTEM in + systemd) + make_target=systemd + ;; + esac + CFLAGS="${cf:+$cf }${CFLAGS}" OPTIMIZE=-O2 make -C "$EXEDIR" $make_target || { + echo could not compile + make -C "$EXEDIR" clean + exitp 8 + } + echo compiled + else + echo build tools not found + exitp 8 + fi +} + +call_install_bin() +{ + sh "$EXEDIR/install_bin.sh" $1 +} +get_bin_arch() +{ + call_install_bin getarch +} + +install_binaries() +{ + echo \* installing binaries + + call_install_bin || { + echo compatible binaries not found + exitp 8 + } +} + +ws_opt_validate() +{ + # ПРИМЕЧАНИЕ ДЛЯ РАСПРОСТРАНИТЕЛЕЙ КОПИПАСТЫ + # ЭТОТ КОД СДЕЛАН СПЕЦИАЛЬНО ДЛЯ ВАС, ЧТОБЫ ВЫ НЕ ПОСТИЛИ В СЕТЬ ПЛОХИЕ РЕЦЕПТЫ + # ЕСЛИ ВАМ ХОЧЕТСЯ ЕГО УДАЛИТЬ И НАПИСАТЬ ИНСТРУКЦИЮ КАК ЕГО УДАЛЯТЬ, ВЫ ДЕЛАЕТЕ ХРЕНОВУЮ УСЛУГУ. НАПИШИТЕ ЛУЧШЕ custom script. + # custom script - ЭТО ФАЙЛИК, КОТОРЫЙ ДОСТАТОЧНО СКОПИРОВАТЬ В НУЖНУЮ ДИРЕКТОРИЮ, ЧТОБЫ ОН СДЕЛАЛ ТОЖЕ САМОЕ, НО ЭФФЕКТИВНО. + # ФИЛЬТРАЦИЯ ПО IPSET В ЯДРЕ НЕСРАВНИМО ЭФФЕКТИВНЕЕ, ЧЕМ ПЕРЕКИДЫВАТЬ ВСЕ ПАКЕТЫ В nfqws И ТАМ ФИЛЬТРОВАТЬ + # --ipset СУЩЕСТВУЕТ ТОЛЬКО ДЛЯ ВИНДЫ И LINUX СИСТЕМ БЕЗ ipset (НАПРИМЕР, Android). + # И ТОЛЬКО ПО ЭТОЙ ПРИЧИНЕ ОНО НЕ ВЫКИНУТО ПОЛНОСТЬЮ ИЗ LINUX ВЕРСИИ + has_bad_ws_options "$1" && { + help_bad_ws_options + return 1 + } + return 0 +} +nfqws_opt_validate() +{ + ws_opt_validate "$1" || return 1 + dry_run_nfqws || { + echo invalid nfqws2 options + return 1 + } +} + +select_mode_group() +{ + # $1 - ENABLE var name + # $2 - ask text + # $3 - vars + # $4 - validator func + # $5 - validator func param var + + local enabled var v edited bad Y param + + echo + ask_yes_no_var $1 "$2" + write_config_var $1 + eval enabled=\$$1 + [ "$enabled" = 1 ] && { + echo + while : ; do + list_vars $3 + bad=0; Y=N + [ -n "$4" ] && { + eval param="\$$5" + $4 "$param"; bad=$? + [ "$bad" = 1 ] && Y=Y + } + ask_yes_no $Y "do you want to edit the options" || { + [ "$bad" = 1 ] && { + echo installer will not allow to use bad options. exiting. + exitp 3 + } + [ -n "$edited" ] && { + for var in $3; do + write_config_var $var + done + } + break + } + edit_vars $3 + edited=1 + echo ..edited.. + done + } +} + +select_mode_nfqws() +{ + local EDITVAR_NEWLINE_DELIMETERS="--new --out-range --in-range --payload" EDITVAR_NEWLINE_VARS="NFQWS2_OPT" + select_mode_group NFQWS2_ENABLE "enable nfqws2 ?" "NFQWS2_PORTS_TCP NFQWS2_PORTS_UDP NFQWS2_TCP_PKT_OUT NFQWS2_TCP_PKT_IN NFQWS2_UDP_PKT_OUT NFQWS2_UDP_PKT_IN NFQWS2_PORTS_TCP_KEEPALIVE NFQWS2_PORTS_UDP_KEEPALIVE NFQWS2_OPT" nfqws_opt_validate NFQWS2_OPT +} + +select_mode_mode() +{ + select_mode_nfqws + + echo + echo "current custom scripts in $CUSTOM_DIR/custom.d:" + [ -d "$CUSTOM_DIR/custom.d" ] && ls "$CUSTOM_DIR/custom.d" + echo "Make sure this is ok" + echo +} + +select_mode_filter() +{ + local filter="none ipset hostlist autohostlist" + echo + echo select filtering : + ask_list MODE_FILTER "$filter" none && write_config_var MODE_FILTER +} + +select_mode() +{ + select_mode_filter + select_mode_mode + select_mode_iface +} + +select_getlist() +{ + if [ "$MODE_FILTER" = "ipset" -o "$MODE_FILTER" = "hostlist" -o "$MODE_FILTER" = "autohostlist" ]; then + local D=N + [ -n "$GETLIST" ] && D=Y + echo + if ask_yes_no $D "do you want to auto download ip/host list"; then + if [ "$MODE_FILTER" = "hostlist" -o "$MODE_FILTER" = "autohostlist" ] ; then + GETLISTS="get_refilter_domains.sh get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh" + GETLIST_DEF="get_antizapret_domains.sh" + else + GETLISTS="get_user.sh get_refilter_ipsum.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh" + GETLIST_DEF="get_antifilter_allyouneed.sh" + fi + ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST + return + fi + fi + GETLIST="" + write_config_var GETLIST +} + +ask_config() +{ + select_mode + select_getlist +} + +ask_config_offload() +{ + [ "$FWTYPE" = nftables ] || is_ipt_flow_offload_avail && { + echo + echo flow offloading can greatly increase speed on slow devices and high speed links \(usually 150+ mbits\) + if [ "$SYSTEM" = openwrt ]; then + echo unfortuantely its not compatible with most nfqws options. nfqws traffic must be exempted from flow offloading. + echo donttouch = disable system flow offloading setting if nfqws mode was selected, dont touch it otherwise and dont configure selective flow offloading + echo none = always disable system flow offloading setting and dont configure selective flow offloading + echo software = always disable system flow offloading setting and configure selective software flow offloading + echo hardware = always disable system flow offloading setting and configure selective hardware flow offloading + else + echo offloading is applicable only to forwarded traffic. it has no effect on outgoing traffic + echo hardware flow offloading is available only on specific supporting hardware. most likely will not work on a generic system + fi + echo offloading likely breaks traffic shaper + echo select flow offloading : + local options="none software hardware" + local default="none" + [ "$SYSTEM" = openwrt ] && { + options="donttouch none software hardware" + default="donttouch" + } + ask_list FLOWOFFLOAD "$options" $default && write_config_var FLOWOFFLOAD + } +} + +ask_config_tmpdir() +{ + # ask tmpdir change for low ram systems with enough free disk space + [ -n "$GETLIST" ] && [ $(get_free_space_mb "$EXEDIR/tmp") -ge 128 ] && [ $(get_ram_mb) -le 400 ] && { + echo + echo /tmp in openwrt is tmpfs. on low RAM systems there may be not enough RAM to store downloaded files + echo default tmpfs has size of 50% RAM + echo "RAM : $(get_ram_mb) Mb" + echo "DISK : $(get_free_space_mb) Mb" + echo select temp file location + [ -z "$TMPDIR" ] && TMPDIR=/tmp + ask_list TMPDIR "/tmp $EXEDIR/tmp" && { + [ "$TMPDIR" = "/tmp" ] && TMPDIR= + write_config_var TMPDIR + } + } +} + +nft_flow_offload() +{ + [ "$UNAME" = Linux -a "$FWTYPE" = nftables ] && [ "$FLOWOFFLOAD" = software -o "$FLOWOFFLOAD" = hardware ] +} + +ask_iface() +{ + # $1 - var to ask + # $2 - additional name for empty string synonim + + local ifs i0 def new + eval def="\$$1" + + [ -n "$2" ] && i0="$2 " + ifs="$(ls /sys/class/net)" + [ -z "$def" ] && eval $1="$2" + ask_list $1 "$i0$ifs" && { + eval new="\$$1" + [ "$new" = "$2" ] && eval $1="" + write_config_var $1 + } +} +ask_iface_lan() +{ + echo LAN interface : + local opt + nft_flow_offload || opt=NONE + ask_iface IFACE_LAN $opt +} +ask_iface_wan() +{ + echo WAN interface : + local opt + nft_flow_offload || opt=ANY + ask_iface IFACE_WAN $opt +} + +select_mode_iface() +{ + # openwrt has its own interface management scheme + # LAN interface names are used only to setup flow offloading rules + + [ "$SYSTEM" = "openwrt" ] && return + + ask_iface_lan + ask_iface_wan +} + +default_files() +{ + # $1 - ro location + # $2 - rw location (can be equal to $1) + [ -d "$2/ipset" ] || mkdir -p "$2/ipset" + [ -f "$2/ipset/zapret-hosts-user-exclude.txt" ] || cp "$1/ipset/zapret-hosts-user-exclude.txt.default" "$2/ipset/zapret-hosts-user-exclude.txt" + [ -f "$2/ipset/zapret-hosts-user.txt" ] || echo nonexistent.domain >> "$2/ipset/zapret-hosts-user.txt" + [ -f "$2/ipset/zapret-hosts-user-ipban.txt" ] || touch "$2/ipset/zapret-hosts-user-ipban.txt" + for dir in openwrt sysv macos; do + [ -d "$1/init.d/$dir" ] && { + [ -d "$2/init.d/$dir" ] || mkdir -p "$2/init.d/$dir" + [ -d "$2/init.d/$dir/custom.d" ] || mkdir -p "$2/init.d/$dir/custom.d" + } + done +} +copy_all() +{ + local dir + + cp -R "$1" "$2" + [ -d "$2/tmp" ] || mkdir "$2/tmp" +} +copy_openwrt() +{ + local ARCH="$(get_bin_arch)" + local BINDIR="$1/binaries/$ARCH" + local file + + [ -d "$2" ] || mkdir -p "$2" + + mkdir "$2/nfq2" "$2/ip2net" "$2/mdig" "$2/binaries" "$2/binaries/$ARCH" "$2/init.d" "$2/tmp" "$2/files" + cp -R "$1/files/fake" "$2/files" + cp -R "$1/common" "$1/ipset" "$1/blockcheck2.d" "$1/lua" "$2" + cp -R "$1/init.d/openwrt" "$1/init.d/custom.d.examples.linux" "$2/init.d" + cp "$1/config" "$1/config.default" "$1/install_easy.sh" "$1/uninstall_easy.sh" "$1/install_bin.sh" "$1/install_prereq.sh" "$1/blockcheck2.sh" "$2" + cp "$BINDIR/nfqws2" "$BINDIR/ip2net" "$BINDIR/mdig" "$2/binaries/$ARCH" +} + +fix_perms_bin_test() +{ + [ -d "$1" ] || return + find "$1/binaries" -name ip2net ! -perm -111 -exec chmod +x {} \; +} +fix_perms() +{ + [ -d "$1" ] || return + find "$1" -type d -exec chmod 755 {} \; + find "$1" -type f -exec chmod 644 {} \; + local chow + case "$UNAME" in + Linux) + chow=root:root + ;; + *) + chow=root:wheel + esac + chown -R $chow "$1" + find "$1/binaries" '(' -name dvtws2 -o -name nfqws2 -o -name ip2net -o -name mdig ')' -exec chmod 755 {} \; + for f in \ +install_bin.sh \ +blockcheck2.sh \ +install_easy.sh \ +install_prereq.sh \ +files/huawei/E8372/zapret-ip \ +files/huawei/E8372/unzapret-ip \ +files/huawei/E8372/run-zapret-hostlist \ +files/huawei/E8372/unzapret \ +files/huawei/E8372/zapret \ +files/huawei/E8372/run-zapret-ip \ +ipset/get_exclude.sh \ +ipset/clear_lists.sh \ +ipset/create_ipset.sh \ +ipset/get_config.sh \ +ipset/get_user.sh \ +ipset/get_ipban.sh \ +ipset/get_refilter_domains.sh \ +ipset/get_refilter_ipsum.sh \ +ipset/get_reestr_resolvable_domains.sh \ +ipset/get_reestr_preresolved.sh \ +ipset/get_reestr_preresolved_smart.sh \ +ipset/get_reestr_resolve.sh \ +ipset/get_reestr_hostlist.sh \ +ipset/get_antifilter_allyouneed.sh \ +ipset/get_antifilter_ipsum.sh \ +ipset/get_antifilter_ipsmart.sh \ +ipset/get_antifilter_ip.sh \ +ipset/get_antifilter_ipresolve.sh \ +ipset/get_antizapret_domains.sh \ +init.d/pfsense/zapret2.sh \ +init.d/runit/zapret2/run \ +init.d/runit/zapret2/finish \ +init.d/openrc/zapret2 \ +init.d/sysv/zapret2 \ +init.d/openwrt/zapret2 \ +uninstall_easy.sh \ + ; do chmod 755 "$1/$f" 2>/dev/null ; done +} + + +_backup_settings() +{ + local i=0 + for f in "$@"; do + # safety check + [ -z "$f" -o "$f" = "/" ] && continue + + [ -f "$ZAPRET_TARGET/$f" ] && cp -f "$ZAPRET_TARGET/$f" "/tmp/zapret2-bkp-$i" + [ -d "$ZAPRET_TARGET/$f" ] && cp -rf "$ZAPRET_TARGET/$f" "/tmp/zapret2-bkp-$i" + i=$(($i+1)) + done +} +_restore_settings() +{ + local i=0 + for f in "$@"; do + # safety check + [ -z "$f" -o "$f" = "/" ] && continue + + [ -f "/tmp/zapret2-bkp-$i" ] && { + mv -f "/tmp/zapret2-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret2-bkp-$i" + } + [ -d "/tmp/zapret2-bkp-$i" ] && { + [ -d "$ZAPRET_TARGET/$f" ] && rm -r "$ZAPRET_TARGET/$f" + mv -f "/tmp/zapret2-bkp-$i" "$ZAPRET_TARGET/$f" || rm -r "/tmp/zapret2-bkp-$i" + } + i=$(($i+1)) + done +} +backup_restore_settings() +{ + # $1 - 1 - backup, 0 - restore + local mode=$1 + on_off_function _backup_settings _restore_settings $mode "config" "init.d/sysv/custom.d" "init.d/openwrt/custom.d" "ipset/zapret-hosts-user.txt" "ipset/zapret-hosts-user-exclude.txt" "ipset/zapret-hosts-user-ipban.txt" "ipset/zapret-hosts-auto.txt" +} + +check_location() +{ + # $1 - copy function + + echo \* checking location + # use inodes in case something is linked + if [ -d "$ZAPRET_TARGET" ] && [ $(get_dir_inode "$EXEDIR") = $(get_dir_inode "$ZAPRET_TARGET") ]; then + default_files "$ZAPRET_TARGET" "$ZAPRET_RW" + else + local rwdir=0 + [ $(get_dir_inode "$ZAPRET_BASE") = $(get_dir_inode "$ZAPRET_RW") ] || rwdir=1 + echo + echo easy install is supported only from default location : $ZAPRET_TARGET + echo currently its run from $EXEDIR + if ask_yes_no N "do you want the installer to copy it for you"; then + local keep=N + if [ -d "$ZAPRET_TARGET" ]; then + echo + echo installer found existing $ZAPRET_TARGET + echo directory needs to be replaced. config and custom scripts can be kept or replaced with clean version + if ask_yes_no N "do you want to delete all files there and copy this version"; then + echo + if [ $rwdir != 1 ]; then + ask_yes_no Y "keep config, custom scripts and user lists" && keep=Y + [ "$keep" = "Y" ] && backup_restore_settings 1 + fi + rm -r "$ZAPRET_TARGET" + else + echo refused to overwrite $ZAPRET_TARGET. exiting + exitp 3 + fi + fi + local B="$(dirname "$ZAPRET_TARGET")" + [ -d "$B" ] || mkdir -p "$B" + $1 "$EXEDIR" "$ZAPRET_TARGET" + fix_perms "$ZAPRET_TARGET" + [ "$keep" = "Y" ] && backup_restore_settings 0 + echo relaunching itself from $ZAPRET_TARGET + exec "$ZAPRET_TARGET/$(basename "$0")" + else + echo copying aborted. exiting + exitp 3 + fi + fi + echo running from $EXEDIR +} + + +service_install_systemd() +{ + echo \* installing zapret service + + if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then + rm -f "$INIT_SCRIPT" + cp -f "$EXEDIR/init.d/systemd/zapret2.service" "$SYSTEMD_SYSTEM_DIR" + "$SYSTEMCTL" daemon-reload + "$SYSTEMCTL" enable zapret2 || { + echo could not enable systemd service + exitp 20 + } + else + echo '!!! READONLY SYSTEM DETECTED !!! CANNOT INSTALL SYSTEMD UNITS !!!' + fi +} + +timer_install_systemd() +{ + echo \* installing zapret2-list-update timer + + if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then + "$SYSTEMCTL" disable zapret2-list-update.timer + "$SYSTEMCTL" stop zapret2-list-update.timer + cp -f "$EXEDIR/init.d/systemd/zapret2-list-update.service" "$SYSTEMD_SYSTEM_DIR" + cp -f "$EXEDIR/init.d/systemd/zapret2-list-update.timer" "$SYSTEMD_SYSTEM_DIR" + "$SYSTEMCTL" daemon-reload + "$SYSTEMCTL" enable zapret2-list-update.timer || { + echo could not enable zapret2-list-update.timer + exitp 20 + } + "$SYSTEMCTL" start zapret2-list-update.timer || { + echo could not start zapret2-list-update.timer + exitp 30 + } + else + echo '!!! READONLY SYSTEM DETECTED !!! CANNOT INSTALL SYSTEMD UNITS !!!' + fi +} + +download_list() +{ + [ -x "$GET_LIST" ] && { + echo \* downloading blocked ip/host list + + # can be txt or txt.gz + "$IPSET_DIR/clear_lists.sh" + "$GET_LIST" + } +} + + +dnstest() +{ + # $1 - dns server. empty for system resolver + nslookup w3.org $1 >/dev/null 2>/dev/null +} +check_dns() +{ + echo \* checking DNS + + dnstest || { + echo -- DNS is not working. It's either misconfigured or blocked or you don't have inet access. + return 1 + } + echo system DNS is working + return 0 +} + + +install_systemd() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret" + CUSTOM_DIR="$ZAPRET_RW/init.d/sysv" + + check_bins + require_root + check_readonly_system + check_location copy_all + check_dns + check_virt + service_stop_systemd + select_fwtype + check_prerequisites_linux + install_binaries + select_ipv6 + ask_config_offload + ask_config + service_install_systemd + download_list + # in case its left from old version of zapret + crontab_del_quiet + # now we use systemd timers + timer_install_systemd + service_start_systemd +} + +_install_sysv() +{ + # $1 - install init script + + CUSTOM_DIR="$ZAPRET_RW/init.d/sysv" + + check_bins + require_root + check_readonly_system + check_location copy_all + check_dns + check_virt + service_stop_sysv + select_fwtype + check_prerequisites_linux + install_binaries + select_ipv6 + ask_config_offload + ask_config + $1 + download_list + crontab_del_quiet + # desktop system. more likely up at daytime + crontab_add 10 22 + service_start_sysv +} + +install_sysv() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret2" + _install_sysv install_sysv_init +} + +install_openrc() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/openrc/zapret2" + _install_sysv install_openrc_init +} + + +install_linux() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret2" + CUSTOM_DIR="$ZAPRET_RW/init.d/sysv" + + check_bins + require_root + check_location copy_all + check_dns + check_virt + select_fwtype + check_prerequisites_linux + install_binaries + select_ipv6 + ask_config_offload + ask_config + download_list + crontab_del_quiet + # desktop system. more likely up at daytime + crontab_add 10 22 + + echo + echo '!!! WARNING. YOUR SETUP IS INCOMPLETE !!!' + echo you must manually add to auto start : $INIT_SCRIPT_SRC start + echo make sure it\'s executed after your custom/firewall iptables configuration + echo "if your system uses sysv init : ln -fs $INIT_SCRIPT_SRC /etc/init.d/zapret ; chkconfig zapret on" +} + + +deoffload_openwrt_firewall() +{ + echo \* checking flow offloading + + [ "$FWTYPE" = "nftables" ] || is_ipt_flow_offload_avail || { + echo unavailable + return + } + + local fo=$(uci -q get firewall.@defaults[0].flow_offloading) + + if [ "$fo" = "1" ] ; then + local mod=0 + printf "system wide flow offloading detected. " + case $FLOWOFFLOAD in + donttouch) + if [ "$NFQWS2_ENABLE" = "1" ]; then + echo its incompatible with nfqws tcp data tampering. disabling + uci set firewall.@defaults[0].flow_offloading=0 + mod=1 + else + if dir_is_not_empty "$CUSTOM_DIR/custom.d" ; then + echo + echo !!! CUSTOM SCRIPTS ARE PRESENT !!! only you can decide whether flow offloading is compatible. + echo !!! CUSTOM SCRIPTS ARE PRESENT !!! if they use nfqws they will not work. you have to disable system-wide offloading. + else + echo its compatible with selected options. not disabling + fi + fi + ;; + *) + echo zapret will disable system wide offloading setting and add selective rules if required + uci set firewall.@defaults[0].flow_offloading=0 + mod=1 + esac + [ "$mod" = "1" ] && uci commit firewall + else + echo system wide software flow offloading disabled. ok + fi +} + + + +install_openwrt() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/openwrt/zapret2" + CUSTOM_DIR="$ZAPRET_RW/init.d/openwrt" + FW_SCRIPT_SRC="$EXEDIR/init.d/openwrt/firewall.zapret2" + OPENWRT_FW_INCLUDE=/etc/firewall.zapret2 + OPENWRT_IFACE_HOOK="$EXEDIR/init.d/openwrt/90-zapret2" + + check_bins + require_root + check_location copy_openwrt + install_binaries + check_dns + check_virt + + local FWTYPE_OLD=$FWTYPE + + echo \* stopping current firewall rules/daemons + "$INIT_SCRIPT_SRC" stop_fw + "$INIT_SCRIPT_SRC" stop_daemons + + select_fwtype + select_ipv6 + check_prerequisites_openwrt + ask_config + ask_config_tmpdir + ask_config_offload + # stop and reinstall sysv init + install_sysv_init + [ "$FWTYPE_OLD" != "$FWTYPE" -a "$FWTYPE_OLD" = iptables -a -n "$OPENWRT_FW3" ] && remove_openwrt_firewall + # free some RAM + clear_ipset + download_list + crontab_del_quiet + # router system : works 24/7. night is the best time + crontab_add 0 6 + cron_ensure_running + install_openwrt_iface_hook + # in case of nftables or iptables without fw3 sysv init script also controls firewall + [ -n "$OPENWRT_FW3" -a "$FWTYPE" = iptables ] && install_openwrt_firewall + service_start_sysv + deoffload_openwrt_firewall + restart_openwrt_firewall +} + + + +remove_pf_zapret_hooks() +{ + echo \* removing zapret PF hooks + + pf_anchors_clear +} + +macos_fw_reload_trigger_clear() +{ + LISTS_RELOAD= + write_config_var LISTS_RELOAD +} +macos_fw_reload_trigger_set() +{ + LISTS_RELOAD="$INIT_SCRIPT_SRC reload-fw-tables" + write_config_var LISTS_RELOAD +} + + + +# build binaries, do not use precompiled +[ "$1" = "make" ] && FORCE_BUILD=1 + +umask 0022 +fix_sbin_path +fsleep_setup +check_system +check_source + +case $SYSTEM in + systemd) + install_systemd + ;; + openrc) + install_openrc + ;; + linux) + install_linux + ;; + openwrt) + install_openwrt + ;; +esac + + +exitp 0 diff --git a/install_prereq.sh b/install_prereq.sh new file mode 100755 index 0000000..be938cc --- /dev/null +++ b/install_prereq.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# install prerequisites + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" +ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"} +ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"} +ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"} +ZAPRET_CONFIG_DEFAULT="$ZAPRET_BASE/config.default" + +[ -f "$ZAPRET_CONFIG" ] || { + ZAPRET_CONFIG_DIR="$(dirname "$ZAPRET_CONFIG")" + [ -d "$ZAPRET_CONFIG_DIR" ] || mkdir -p "$ZAPRET_CONFIG_DIR" + cp "$ZAPRET_CONFIG_DEFAULT" "$ZAPRET_CONFIG" +} + +. "$ZAPRET_CONFIG" +. "$ZAPRET_BASE/common/base.sh" +. "$ZAPRET_BASE/common/elevate.sh" +. "$ZAPRET_BASE/common/fwtype.sh" +. "$ZAPRET_BASE/common/dialog.sh" +. "$ZAPRET_BASE/common/installer.sh" +. "$ZAPRET_BASE/common/ipt.sh" + +umask 0022 +fix_sbin_path +fsleep_setup +check_system accept_unknown_rc +[ $UNAME = "Linux" ] || { + echo no prerequisites required for $UNAME + exitp 0 +} +require_root + +case $UNAME in + Linux) + select_fwtype + case $SYSTEM in + openwrt) + select_ipv6 + check_prerequisites_openwrt + ;; + *) + check_prerequisites_linux + ;; + esac + ;; +esac + +exitp 0 diff --git a/uninstall_easy.sh b/uninstall_easy.sh new file mode 100755 index 0000000..365d44a --- /dev/null +++ b/uninstall_easy.sh @@ -0,0 +1,99 @@ +#!/bin/sh + +# automated script for easy uninstalling zapret + +EXEDIR="$(dirname "$0")" +EXEDIR="$(cd "$EXEDIR"; pwd)" +ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"} +ZAPRET_RW=${ZAPRET_RW:-"$ZAPRET_BASE"} +ZAPRET_CONFIG=${ZAPRET_CONFIG:-"$ZAPRET_RW/config"} +ZAPRET_CONFIG_DEFAULT="$ZAPRET_BASE/config.default" +IPSET_DIR="$ZAPRET_BASE/ipset" + +[ -f "$ZAPRET_CONFIG" ] || { + ZAPRET_CONFIG_DIR="$(dirname "$ZAPRET_CONFIG")" + [ -d "$ZAPRET_CONFIG_DIR" ] || mkdir -p "$ZAPRET_CONFIG_DIR" + cp "$ZAPRET_CONFIG_DEFAULT" "$ZAPRET_CONFIG" +} + +. "$ZAPRET_CONFIG" +. "$ZAPRET_BASE/common/base.sh" +. "$ZAPRET_BASE/common/elevate.sh" +. "$ZAPRET_BASE/common/fwtype.sh" +. "$ZAPRET_BASE/common/dialog.sh" +. "$ZAPRET_BASE/common/ipt.sh" +. "$ZAPRET_BASE/common/nft.sh" +. "$ZAPRET_BASE/common/installer.sh" + +remove_systemd() +{ + clear_ipset + service_stop_systemd + service_remove_systemd + timer_remove_systemd + nft_del_table + crontab_del +} + +remove_openrc() +{ + clear_ipset + service_remove_openrc + nft_del_table + crontab_del +} + +remove_linux() +{ + INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret2" + + clear_ipset + + echo \* executing sysv init stop + "$INIT_SCRIPT_SRC" stop + + nft_del_table + crontab_del + + echo + echo '!!! WARNING. YOUR UNINSTALL IS INCOMPLETE !!!' + echo 'you must manually remove zapret auto start from your system' +} + +remove_openwrt() +{ + OPENWRT_FW_INCLUDE=/etc/firewall.zapret2 + + clear_ipset + service_remove_sysv + remove_openwrt_firewall + remove_openwrt_iface_hook + nft_del_table + restart_openwrt_firewall + crontab_del + remove_extra_pkgs_openwrt + echo + echo to fully remove zapret : rm -r \"$ZAPRET_BASE\" +} + +fix_sbin_path +check_system +require_root + +case $SYSTEM in + systemd) + remove_systemd + ;; + openrc) + remove_openrc + ;; + linux) + remove_linux + ;; + openwrt) + remove_openwrt + ;; +esac + + +exitp 0