#!/bin/sh # automated script for easy installing zapret EXEDIR="$(dirname "$0")" EXEDIR="$(cd "$EXEDIR"; pwd)" IPSET_DIR="$EXEDIR/ipset" ZAPRET_CONFIG="$EXEDIR/config" ZAPRET_BASE="$EXEDIR" . "$ZAPRET_CONFIG" # install target ZAPRET_TARGET=/opt/zapret GET_LIST="$IPSET_DIR/get_config.sh" GET_LIST_PREFIX=/ipset/get_ INIT_SCRIPT=/etc/init.d/zapret [ -n "$TPPORT" ] || TPPORT=988 SYSTEMD_DIR=/lib/systemd [ -d "$SYSTEMD_DIR" ] || SYSTEMD_DIR=/usr/lib/systemd [ -d "$SYSTEMD_DIR" ] && SYSTEMD_SYSTEM_DIR="$SYSTEMD_DIR/system" ECHON="echo -n" exists() { which $1 >/dev/null 2>/dev/null } whichq() { which $1 2>/dev/null } MD5=md5sum exists $MD5 || MD5=md5 contains() { # check if substring $2 contains in $1 [ "${1#*$2}" != "$1" ] } exitp() { local A echo echo press enter to continue read A exit $1 } require_root() { local exe echo \* checking privileges [ $(id -u) -ne "0" ] && { echo root is required exe="$EXEDIR/$(basename "$0")" exists sudo && exec sudo "$exe" exists su && exec su root -c "$exe" echo su or sudo not found exitp 2 } } sedi() { # MacOS doesnt support -i without parameter. busybox doesnt support -i with parameter. # its not possible to put "sed -i ''" to a variable and then use it if [ "$SYSTEM" = "macos" ]; then sed -i '' "$@" else sed -i "$@" fi } read_yes_no() { # $1 - default (Y/N) local A read A [ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1 [ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ] } ask_yes_no() { # $1 - default (Y/N or 0/1) # $2 - text local DEFAULT=$1 [ "$1" = "1" ] && DEFAULT=Y [ "$1" = "0" ] && DEFAULT=N [ -z "$DEFAULT" ] && DEFAULT=N $ECHON "$2 (default : $DEFAULT) (Y/N) ? " read_yes_no $DEFAULT } ask_yes_no_var() { # $1 - variable name for answer : 0/1 # $2 - text local DEFAULT eval DEFAULT="\$$1" if ask_yes_no "$DEFAULT" "$2"; then eval $1=1 else eval $1=0 fi } on_off_function() { # $1 : function name on # $2 : function name off # $3 : 0 - off, 1 - on local F="$1" [ "$3" = "1" ] || F="$2" shift shift shift "$F" "$@" } get_dir_inode() { local dir="$1" [ -L "$dir" ] && dir=$(readlink "$dir") ls -id "$dir" | awk '{print $1}' } random() { # $1 - min, $2 - max local r rs if [ -c /dev/urandom ]; then read rs >"$tmp" n=$(($n+1)) done edit_file "$tmp" && parse_vars_checked "$tmp" "$@" rm -f "$tmp" } check_system() { echo \* checking system SYSTEM="" SYSTEMCTL=$(whichq systemctl) local 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 elif exists rc-update && [ "$INIT" = "openrc-init" ]; then SYSTEM=openrc elif [ -f "/etc/openwrt_release" ] && exists opkg && exists uci && [ "$INIT" = "procd" ] ; then SYSTEM=openwrt 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.txt for manual setup info. if ask_yes_no N "do you want to continue"; then SYSTEM=linux else exitp 5 fi fi elif [ "$UNAME" = "Darwin" ]; then SYSTEM=macos # MacOS echo from /bin/sh does not support -n ECHON=printf else echo easy installer only supports Linux and MacOS. check readme.txt for supported systems and manual setup info. exitp 5 fi echo system is based on $SYSTEM } 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_bins() { echo \* checking executables local arch=$(get_bin_arch) local make_target [ "$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 [ "$SYSTEM" = "macos" ] && make_target=mac 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() { "$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 } } find_str_in_list() { [ -n "$1" ] && { for v in $2; do [ "$v" = "$1" ] && return 0 done } return 1 } ask_list() { # $1 - mode var # $2 - space separated value list # $3 - (optional) default value local M_DEFAULT eval M_DEFAULT="\$$1" local M_ALL=$M_DEFAULT local M="" local m [ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;} n=1 for m in $2; do echo $n : $m n=$(($n+1)) done $ECHON "your choice (default : $M_DEFAULT) : " read m [ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null) [ -z "$M" ] && M="$M_DEFAULT" echo selected : $M eval $1="\"$M\"" [ "$M" != "$M_OLD" ] } write_config_var() { # $1 - mode var local M eval M="\$$1" if grep -q "^$1=\|^#$1=" "$ZAPRET_CONFIG"; then # replace / => \/ #M=${M//\//\\\/} M=$(echo $M | sed 's/\//\\\//g') if [ -n "$M" ]; then if contains "$M" " "; then sedi -Ee "s/^#?$1=.*$/$1=\"$M\"/" "$ZAPRET_CONFIG" else sedi -Ee "s/^#?$1=.*$/$1=$M/" "$ZAPRET_CONFIG" fi else # write with comment at the beginning sedi -Ee "s/^#?$1=.*$/#$1=/" "$ZAPRET_CONFIG" fi else # var does not exist in config. add it if [ -n "$M" ]; then echo "$1=$M" >>"$ZAPRET_CONFIG" else echo "#$1=$M" >>"$ZAPRET_CONFIG" fi fi } select_mode_mode() { local edited v vars MODES="tpws tpws-socks nfqws filter custom" [ "$SYSTEM" = "macos" ] && MODES="tpws tpws-socks filter custom" echo echo select MODE : ask_list MODE "$MODES" tpws && write_config_var MODE case $MODE in tpws) vars="TPWS_OPT" ;; nfqws) vars="NFQWS_OPT_DESYNC NFQWS_OPT_DESYNC_HTTP NFQWS_OPT_DESYNC_HTTPS NFQWS_OPT_DESYNC_HTTP6 NFQWS_OPT_DESYNC_HTTPS6" ;; esac [ -n "$vars" ] && { echo while [ 1=1 ]; do for var in $vars; do eval v="\$$var" echo $var=\"$v\" done ask_yes_no N "do you want to edit the options" || { [ -n "$edited" ] && { for var in $vars; do write_config_var $var done } break } edit_vars $vars edited=1 echo ..edited.. done } } select_mode_http() { [ "$MODE" != "filter" ] && [ "$MODE" != "tpws-socks" ] && { echo ask_yes_no_var MODE_HTTP "enable http support" write_config_var MODE_HTTP } } select_mode_keepalive() { [ "$MODE" = "nfqws" ] && [ "$MODE_HTTP" = "1" ] && { echo echo enable keep alive support only if DPI checks every outgoing packet for http signature echo dont enable otherwise because it consumes more cpu resources ask_yes_no_var MODE_HTTP_KEEPALIVE "enable http keep alive support" write_config_var MODE_HTTP_KEEPALIVE } } select_mode_https() { [ "$MODE" != "filter" ] && [ "$MODE" != "tpws-socks" ] && { echo ask_yes_no_var MODE_HTTPS "enable https support" write_config_var MODE_HTTPS } } select_mode_filter() { local filter="none ipset hostlist" [ "$MODE" = "tpws-socks" ] && filter="none hostlist" echo echo select filtering : ask_list MODE_FILTER "$filter" none && write_config_var MODE_FILTER } select_mode() { select_mode_mode select_mode_iface select_mode_http select_mode_keepalive select_mode_https select_mode_filter } select_getlist() { if [ "$MODE_FILTER" = "ipset" -o "$MODE_FILTER" = "hostlist" ]; 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" ] ; then local GL_OLD=$GETLIST GETLIST="get_reestr_hostlist.sh" [ "$GL_OLD" != "$GET_LIST" ] && write_config_var GETLIST else GETLISTS="get_user.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_reestr_ip.sh get_reestr_combined.sh get_reestr_resolve.sh" GETLIST_DEF="get_antifilter_ipsmart.sh" ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST fi return fi fi GETLIST="" write_config_var GETLIST } 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 } ask_config() { select_mode select_getlist } ask_config_offload() { is_flow_offload_avail && { echo echo flow offloading can greatly increase speed on slow devices and high speed links \(usually 150+ mbits\) 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 echo select flow offloading : ask_list FLOWOFFLOAD "donttouch none software hardware" donttouch && write_config_var FLOWOFFLOAD } } 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)) } 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 } } } 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 " case $SYSTEM in macos) ifs="$(ifconfig -l)" ;; *) ifs="$(ls /sys/class/net)" ;; esac [ -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 : ask_iface IFACE_LAN "NONE" } ask_iface_wan() { echo WAN interface : ask_iface IFACE_WAN "ANY" } select_mode_iface() { # openwrt has its own interface management scheme # filter just creates ip tables, no daemons involved # nfqws sits in POSTROUTING chain and unable to filter by incoming interface # tpws redirection works in PREROUTING chain # in tpws-socks mode IFACE_LAN specifies additional bind interface for the socks listener # it's not possible to instruct tpws to route outgoing connection to an interface (OS routing table decides) # custom mode can also benefit from interface names (depends on custom script code) if [ "$SYSTEM" = "openwrt" ] || [ "$MODE" = "filter" ]; then return; fi echo case "$MODE" in tpws-socks) echo "select LAN interface to allow socks access from your LAN. select NONE for localhost only." echo "expect socks on tcp port $TPPORT" ask_iface_lan ;; tpws) echo "select LAN interface to operate in router mode. select NONE for local outgoing traffic only." if [ "$SYSTEM" = "macos" ]; then echo "WARNING ! OS feature \"internet sharing\" is not supported." echo "Only manually configured PF router is supported." else echo "WARNING ! This installer will not configure routing, NAT, ... for you. Its your responsibility." fi ask_iface_lan ;; custom) echo "select LAN interface for your custom script (how it works depends on your code)" ask_iface_lan ;; esac case "$MODE" in tpws) echo "select WAN interface for $MODE operations. select ANY to operate on any interface." [ -n "$IFACE_LAN" ] && echo "WAN filtering works only for local outgoing traffic !" ask_iface_wan ;; nfqws) echo "select WAN interface for $MODE operations. select ANY to operate on any interface." ask_iface_wan ;; custom) echo "select WAN interface for your custom script (how it works depends on your code)" ask_iface_wan ;; esac } copy_all() { cp -R "$1" "$2" [ -d "$2/tmp" ] || mkdir "$2/tmp" } copy_openwrt() { local ARCH=$(get_bin_arch) local BINDIR="$1/binaries/$ARCH" [ -d "$2" ] || mkdir -p "$2" mkdir "$2/tpws" "$2/nfq" "$2/ip2net" "$2/mdig" "$2/binaries" "$2/binaries/$ARCH" "$2/init.d" "$2/tmp" cp -R "$1/ipset" "$2" cp -R "$1/init.d/openwrt" "$2/init.d" cp "$1/config" "$1/install_easy.sh" "$1/uninstall_easy.sh" "$1/install_bin.sh" "$1/blockcheck.sh" "$2" cp "$BINDIR/tpws" "$BINDIR/nfqws" "$BINDIR/ip2net" "$BINDIR/mdig" "$2/binaries/$ARCH" } _backup_settings() { local i=0 for f in "$@"; do [ -f "$ZAPRET_TARGET/$f" ] && cp -f "$ZAPRET_TARGET/$f" "/tmp/zapret-bkp-$i" i=$(($i+1)) done } _restore_settings() { local i=0 for f in "$@"; do [ -f "/tmp/zapret-bkp-$i" ] && mv -f "/tmp/zapret-bkp-$i" "$ZAPRET_TARGET/$f" || rm -f "/tmp/zapret-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" "init.d/openwrt/custom" "init.d/macos/custom" "ipset/zapret-hosts-user.txt" "ipset/zapret-hosts-user-exclude.txt" "ipset/zapret-hosts-user-ipban.txt" } check_location() { # $1 - copy function echo \* checking location # use inodes in case something is linked [ -d "$ZAPRET_TARGET" ] && [ $(get_dir_inode "$EXEDIR") = $(get_dir_inode "$ZAPRET_TARGET") ] || { 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 ask_yes_no Y "keep config, custom scripts and user lists" && keep=Y [ "$keep" = "Y" ] && backup_restore_settings 1 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" [ "$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 } echo running from $EXEDIR } check_prerequisites_linux() { echo \* checking prerequisites if exists iptables && exists ip6tables ; then echo iptables present else # looks like it's a limited system. will not guess how to install base tools echo '! iptables/ip6tables NOT present. you must install them manually.' exitp 5 fi if exists ipset && exists curl ; then echo ipset and curl are present else echo \* installing prerequisites APTGET=$(whichq apt-get) 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 ipset curl dnsutils || { echo could not install prerequisites exitp 6 } elif [ -x "$YUM" ] ; then "$YUM" -y install curl ipset || { echo could not install prerequisites exitp 6 } elif [ -x "$PACMAN" ] ; then "$PACMAN" -Syy "$PACMAN" --noconfirm -S ipset curl || { echo could not install prerequisites exitp 6 } elif [ -x "$ZYPPER" ] ; then "$ZYPPER" --non-interactive install ipset curl || { echo could not install prerequisites exitp 6 } elif [ -x "$EOPKG" ] ; then "$EOPKG" -y install ipset curl || { echo could not install prerequisites exitp 6 } elif [ -x "$APK" ] ; then "$APK" add ipset curl || { echo could not install prerequisites exitp 6 } else echo supported package manager not found echo you must manually install : ipset curl exitp 5 fi fi } service_install_systemd() { echo \* installing zapret service if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then rm -f "$INIT_SCRIPT" ln -fs "$EXEDIR/init.d/systemd/zapret.service" "$SYSTEMD_SYSTEM_DIR" "$SYSTEMCTL" daemon-reload "$SYSTEMCTL" enable zapret || { echo could not enable systemd service exitp 20 } else echo '!!! READONLY SYSTEM DETECTED !!! CANNOT INSTALL SYSTEMD UNITS !!!' fi } service_stop_systemd() { echo \* stopping zapret service "$SYSTEMCTL" daemon-reload "$SYSTEMCTL" disable zapret "$SYSTEMCTL" stop zapret } service_start_systemd() { echo \* starting zapret service "$SYSTEMCTL" start zapret || { echo could not start zapret service exitp 30 } } timer_install_systemd() { echo \* installing zapret-list-update timer if [ -w "$SYSTEMD_SYSTEM_DIR" ] ; then "$SYSTEMCTL" disable zapret-list-update.timer "$SYSTEMCTL" stop zapret-list-update.timer ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR" ln -fs "$EXEDIR/init.d/systemd/zapret-list-update.timer" "$SYSTEMD_SYSTEM_DIR" "$SYSTEMCTL" daemon-reload "$SYSTEMCTL" enable zapret-list-update.timer || { echo could not enable zapret-list-update.timer exitp 20 } "$SYSTEMCTL" start zapret-list-update.timer || { echo could not start zapret-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" || { echo could not download ip list exitp 25 } } } end_with_newline() { local c=$(tail -c 1) [ "$c" = "" ] } 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 } } 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" check_bins require_root check_readonly_system check_location copy_all check_prerequisites_linux service_stop_systemd install_binaries check_dns select_ipv6 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_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 zapret } ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT" [ "$1" != "0" ] && rc-update add zapret } service_start_sysv() { [ -x "$INIT_SCRIPT" ] && { echo \* starting zapret service "$INIT_SCRIPT" start || { echo could not start zapret service exitp 30 } } } service_stop_sysv() { [ -x "$INIT_SCRIPT" ] && { echo \* stopping zapret service "$INIT_SCRIPT" stop } } _install_sysv() { # $1 - install init script INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret" check_bins require_root check_readonly_system check_location copy_all check_prerequisites_linux service_stop_sysv install_binaries check_dns select_ipv6 ask_config $1 download_list crontab_del_quiet # desktop system. more likely up at daytime crontab_add 10 22 service_start_sysv } install_sysv() { _install_sysv install_sysv_init } install_openrc() { _install_sysv install_openrc_init } install_linux() { INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret" check_bins require_root check_location copy_all check_prerequisites_linux install_binaries check_dns select_ipv6 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" } check_kmod() { [ -f "/lib/modules/$(uname -r)/$1.ko" ] } check_package_exists_openwrt() { [ -n "$(opkg list $1)" ] } check_package_openwrt() { [ -n "$(opkg list-installed $1)" ] } check_packages_openwrt() { for pkg in $@; do check_package_openwrt $pkg || return done } is_linked_to_busybox() { local IFS F P IFS=: for path in $PATH; do F=$path/$1 P="$(readlink $F)" if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi [ "${P%busybox*}" != "$P" ] && return done } check_prerequisites_openwrt() { echo \* checking prerequisites local PKGS="iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ipset curl" [ "$DISABLE_IPV6" != "1" ] && PKGS="$PKGS ip6tables-mod-nat ip6tables-extra" local UPD=0 if check_packages_openwrt $PKGS ; then echo everything is present else echo \* installing prerequisites opkg update UPD=1 opkg 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" ] && { opkg update UPD=1 } opkg 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" ] && { opkg update UPD=1 } opkg install --force-overwrite coreutils-sort fi } is_linked_to_busybox grep && { echo echo your system uses default busybox grep. its damn infinite slow with -f option echo get_combined.sh will be severely impacted echo installer can install GNU grep but it requires about 0.5 Mb space if ask_yes_no N "do you want to install GNU grep"; then [ "$UPD" = "0" ] && { opkg update UPD=1 } opkg install --force-overwrite grep # someone reported device partially fail if /bin/grep is absent # grep package deletes /bin/grep [ -f /bin/grep ] || ln -s busybox /bin/grep fi } } 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 fw3 -q restart || { echo could not restart firewall exitp 30 } } remove_openwrt_firewall() { echo \* removing firewall script openwrt_fw_section_del # from old zapret versions. now we use single include openwrt_fw_section_del 6 # free some RAM "$IPSET_DIR/create_ipset.sh" clear } install_openwrt_iface_hook() { echo \* installing ifup hook ln -fs "$OPENWRT_IFACE_HOOK" /etc/hotplug.d/iface } is_flow_offload_avail() { # $1 = '' for ipv4, '6' for ipv6 grep -q FLOWOFFLOAD /proc/net/ip$1_tables_targets } deoffload_openwrt_firewall() { echo \* checking flow offloading is_flow_offload_avail || { echo unavailable return } local fo=$(uci -q get firewall.@defaults[0].flow_offloading) if [ "$fo" = "1" ] ; then local mod=0 $ECHON "system wide flow offloading detected. " case $FLOWOFFLOAD in donttouch) if [ "$MODE" = "nfqws" ]; then echo its incompatible with nfqws tcp data tampering. disabling uci set firewall.@defaults[0].flow_offloading=0 mod=1 else if [ "$MODE" = "custom" ] ; then echo custom mode selected !!! only you can decide whether flow offloading is compatible 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/zapret" FW_SCRIPT_SRC="$EXEDIR/init.d/openwrt/firewall.zapret" OPENWRT_FW_INCLUDE=/etc/firewall.zapret OPENWRT_IFACE_HOOK="$EXEDIR/init.d/openwrt/90-zapret" check_bins require_root check_location copy_openwrt install_binaries check_dns select_ipv6 check_prerequisites_openwrt ask_config ask_config_tmpdir ask_config_offload install_sysv_init # can be previous firewall preventing access remove_openwrt_firewall restart_openwrt_firewall download_list crontab_del_quiet # router system : works 24/7. night is the best time crontab_add 0 6 cron_ensure_running service_start_sysv install_openwrt_iface_hook install_openwrt_firewall deoffload_openwrt_firewall restart_openwrt_firewall } remove_pf_zapret_hooks() { echo \* removing zapret PF hooks pf_anchors_clear } service_install_macos() { echo \* installing zapret service ln -fs /opt/zapret/init.d/macos/zapret.plist /Library/LaunchDaemons } service_start_macos() { echo \* starting zapret service "$INIT_SCRIPT_SRC" start } service_stop_macos() { echo \* stopping zapret service "$INIT_SCRIPT_SRC" stop } macos_fw_reload_trigger_clear() { case "$MODE" in tpws|tpws-socks|custom) LISTS_RELOAD= write_config_var LISTS_RELOAD ;; esac } macos_fw_reload_trigger_set() { case "$MODE" in tpws|custom) LISTS_RELOAD="$INIT_SCRIPT_SRC reload-fw-tables" write_config_var LISTS_RELOAD ;; esac } install_macos() { INIT_SCRIPT_SRC="$EXEDIR/init.d/macos/zapret" # compile before root check_bins require_root check_location copy_all service_stop_macos remove_pf_zapret_hooks install_binaries check_dns select_ipv6 ask_config service_install_macos macos_fw_reload_trigger_clear # gzip lists are incompatible with PF GZIP_LISTS=0 write_config_var GZIP_LISTS download_list macos_fw_reload_trigger_set crontab_del_quiet # desktop system. more likely up at daytime crontab_add 10 22 service_start_macos } # build binaries, do not use precompiled [ "$1" = "make" ] && FORCE_BUILD=1 check_system [ "$SYSTEM" = "macos" ] && . "$EXEDIR/init.d/macos/functions" case $SYSTEM in systemd) install_systemd ;; openrc) install_openrc ;; linux) install_linux ;; openwrt) install_openwrt ;; macos) install_macos ;; esac exitp 0