# init script functions library for desktop linux systems [ -n "$ZAPRET_BASE" ] || ZAPRET_BASE=/opt/zapret # SHOULD EDIT config . "$ZAPRET_BASE/config" PIDDIR=/var/run IPSET_CR="$ZAPRET_BASE/ipset/create_ipset.sh" WS_USER=tpws QNUM=200 NFQWS="$ZAPRET_BASE/nfq/nfqws" NFQWS_OPT_BASE="--qnum=$QNUM --user=$WS_USER" TPPORT_HTTP=1188 TPPORT_HTTPS=1189 TPWS="$ZAPRET_BASE/tpws/tpws" HOSTLIST="$ZAPRET_BASE/ipset/zapret-hosts.txt.gz" [ -f "$HOSTLIST" ] || HOSTLIST="$ZAPRET_BASE/ipset/zapret-hosts-user.txt" TPWS_OPT_BASE="--user=$WS_USER --bind-addr=127.0.0.1" TPWS_OPT_BASE6="--user=$WS_USER --bind-addr=::1" # first wait for lan to ifup, then wait for bind-wait-ip-linklocal seconds for link local address and bind-wait-ip for any ipv6 as the worst case TPWS_OPT_BASE6_PRE="--user=$WS_USER --bind-linklocal=prefer --bind-wait-ifup=30 --bind-wait-ip=30 --bind-wait-ip-linklocal=3" TPWS_OPT_BASE_HTTP="--port=$TPPORT_HTTP" TPWS_OPT_BASE_HTTPS="--port=$TPPORT_HTTPS" [ -n "$IFACE_WAN" ] && IPT_OWAN="-o $IFACE_WAN" [ -n "$IFACE_WAN" ] && IPT_IWAN="-i $IFACE_WAN" [ -n "$IFACE_LAN" ] && IPT_ILAN="-i $IFACE_LAN" [ -n "$DESYNC_MARK" ] || DESYNC_MARK=0x40000000 # max wait time for the link local ipv6 on the LAN interface LINKLOCAL_WAIT_SEC=5 CUSTOM_SCRIPT="$ZAPRET_BASE/init.d/sysv/custom" [ -f "$CUSTOM_SCRIPT" ] && . "$CUSTOM_SCRIPT" IPSET_EXCLUDE="-m set ! --match-set nozapret" IPSET_EXCLUDE6="-m set ! --match-set nozapret6" exists() { which "$1" >/dev/null 2>/dev/null } existf() { type "$1" >/dev/null 2>/dev/null } 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" "$@" } ipt() { iptables -C "$@" 2>/dev/null || iptables -I "$@" } ipt_del() { iptables -C "$@" 2>/dev/null && iptables -D "$@" } ipt_add_del() { on_off_function ipt ipt_del "$@" } ipt6() { ip6tables -C "$@" 2>/dev/null || ip6tables -I "$@" } ipt6_del() { ip6tables -C "$@" 2>/dev/null && ip6tables -D "$@" } ipt6_add_del() { on_off_function ipt6 ipt6_del "$@" } # there's no route_localnet for ipv6 # the best we can is to route to link local of the incoming interface # OUTPUT - can DNAT to ::1 # PREROUTING - can't DNAT to ::1. can DNAT to link local of -i interface or to any global addr # not a good idea to expose tpws to the world (bind to ::) get_ipv6_linklocal() { # $1 - interface name. if empty - any interface local dev [ -n "$1" ] && dev="dev $1" ip addr show $dev | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope link.*$/\1/;t;d' | head -n 1 } get_ipv6_global() { # $1 - interface name. if empty - any interface local dev [ -n "$1" ] && dev="dev $1" ip addr show $dev | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope global.*$/\1/;t;d' | head -n 1 } iface_is_up() { # $1 - interface name [ -f /sys/class/net/$1/operstate ] || return local state read state /dev/null; then echo already running else "$2" $3 >/dev/null 2>/dev/null & PID=$! if [ -n "$PID" ]; then echo $PID >$PIDFILE else echo could not start daemon $1 : $2 $3 false fi fi fi } stop_daemon() { # $1 - daemon number : 1,2,3,... # $2 - daemon # use $PIDDIR/$DAEMONBASE$1.pid as pidfile local DAEMONBASE=$(basename $2) local PIDFILE=$PIDDIR/$DAEMONBASE$1.pid echo "Stopping daemon $1: $2" if exists start-stop-daemon ; then start-stop-daemon --stop --pidfile "$PIDFILE" --exec "$2" else if [ -f "$PIDFILE" ]; then read PID <"$PIDFILE" kill $PID rm -f "$PIDFILE" else echo no pidfile : $PIDFILE fi fi } do_daemon() { # $1 - 1 - run, 0 - stop on_off_function run_daemon stop_daemon "$@" } prepare_user() { # $WS_USER is required to prevent redirection of the traffic originating from TPWS itself # otherwise infinite loop will occur # also its good idea not to run tpws as root id -u $WS_USER >/dev/null 2>/dev/null || useradd --no-create-home --system --shell /bin/false $WS_USER } prepare_tpws() { prepare_user # otherwise linux kernel will treat 127.0.0.1 as "martian" ip and refuse routing to it # NOTE : kernels <3.6 do not have this feature. consider upgrading or change DNAT to REDIRECT and do not bind to 127.0.0.1 [ -n "$IFACE_LAN" ] && sysctl -qw net.ipv4.conf.$IFACE_LAN.route_localnet=1 } prepare_nfqws() { prepare_user } do_tpws() { # $1 : 1 - run, 0 - stop # $2 : daemon number # $3 : daemon args [ "$1" = "1" ] && prepare_tpws [ "$DISABLE_IPV4" = "1" ] || do_daemon $1 $2 $TPWS "$TPWS_OPT_BASE $3" [ "$DISABLE_IPV6" = "1" ] || { do_daemon $1 $((60+$2)) $TPWS "$TPWS_OPT_BASE6 $3" [ -n "$IFACE_LAN" ] && do_daemon $1 $((660+$2)) $TPWS "$TPWS_OPT_BASE6_PRE --bind-iface6=$IFACE_LAN $3" } } do_nfqws() { # $1 : 1 - run, 0 - stop # $2 : daemon number # $3 : daemon args [ "$1" = "1" ] && prepare_nfqws do_daemon $1 $2 $NFQWS "$NFQWS_OPT_BASE $3" } create_ipset() { echo "Creating ipset" "$IPSET_CR" "$@" } zapret_do_firewall() { # $1 - 1 - add, 0 - del local rule local synack="--tcp-flags SYN,ACK SYN,ACK" local ipset_zapret="-m set --match-set zapret" local ipset_zapret6="-m set --match-set zapret6" local desync="-m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK" # always create ipsets. ip_exclude ipset is required [ "$1" != "1" ] || create_ipset no-update case "${MODE}" in tpws_hostlist|tpws_all) fw_tpws $1 "--dport 80" "--dport 80" $TPPORT_HTTP ;; tpws_ipset) [ "$1" = "1" ] && prepare_tpws fw_tpws $1 "--dport 80 $ipset_zapret dst" "--dport 80 $ipset_zapret6 dst" $TPPORT_HTTP ;; tpws_ipset_https) [ "$1" = "1" ] && prepare_tpws fw_tpws $1 "--dport 80 $ipset_zapret dst" "--dport 80 $ipset_zapret6 dst" $TPPORT_HTTP fw_tpws $1 "--dport 443 $ipset_zapret dst" "--dport 443 $ipset_zapret6 dst" $TPPORT_HTTPS ;; tpws_all_https) [ "$1" = "1" ] && prepare_tpws fw_tpws $1 "--dport 80" "--dport 80" $TPPORT_HTTP fw_tpws $1 "--dport 443" "--dport 443" $TPPORT_HTTPS ;; nfqws_ipset) fw_nfqws_pre $1 "--sport 80 $synack $ipset_zapret src" "--sport 80 $synack $ipset_zapret6 src" $QNUM fw_nfqws_post $1 "--dport 80 $ipset_zapret dst" "--dport 80 $ipset_zapret6 dst" $QNUM ;; nfqws_ipset_https) rule="-m multiport --sports 80,443 $synack" fw_nfqws_pre $1 "$rule $ipset_zapret src" "$rule $ipset_zapret6 src" $QNUM fw_nfqws_post $1 "--dport 80 $ipset_zapret dst" "--dport 80 $ipset_zapret6 dst" $QNUM ;; nfqws_all) fw_nfqws_pre $1 "--sport 80 $synack" "--sport 80 $synack" $QNUM fw_nfqws_post $1 "--dport 80" "--dport 80" $QNUM ;; nfqws_all_https) rule="-m multiport --sports 80,443 $synack" fw_nfqws_pre $1 "$rule" "$rule" $QNUM fw_nfqws_post $1 "--dport 80" "--dport 80" $QNUM ;; nfqws_all_desync|nfqws_hostlist_desync) rule="-m multiport --sports 80,443 $synack" fw_nfqws_pre $1 "$rule" "$rule" $QNUM fw_nfqws_post $1 "$desync" "$desync" $QNUM ;; nfqws_ipset_desync) rule="-m multiport --sports 80,443 $synack" fw_nfqws_pre $1 "$rule $ipset_zapret src" "$rule $ipset_zapret6 src" $QNUM fw_nfqws_post $1 "$desync $ipset_zapret dst" "$desync $ipset_zapret6 dst" $QNUM ;; custom) existf zapret_custom_firewall && zapret_custom_firewall $1 ;; esac } zapret_apply_firewall() { zapret_do_firewall 1 "$@" } zapret_unapply_firewall() { zapret_do_firewall 0 "$@" } zapret_do_daemons() { # $1 - 1 - run, 0 - stop case "${MODE}" in tpws_hostlist) do_tpws $1 1 "$TPWS_OPT_BASE_HTTP $TPWS_OPT_HTTP --hostlist=$HOSTLIST" ;; tpws_ipset|tpws_all) do_tpws $1 1 "$TPWS_OPT_BASE_HTTP $TPWS_OPT_HTTP" ;; tpws_ipset_https|tpws_all_https) do_tpws $1 1 "$TPWS_OPT_BASE_HTTP $TPWS_OPT_HTTP" do_tpws $1 2 "$TPWS_OPT_BASE_HTTPS $TPWS_OPT_HTTPS" ;; nfqws_ipset|nfqws_ipset_https|nfqws_all|nfqws_all_https) do_nfqws $1 1 "$NFQWS_OPT" ;; nfqws_ipset_desync|nfqws_all_desync) do_nfqws $1 1 "$NFQWS_OPT_DESYNC" ;; nfqws_hostlist_desync) do_nfqws $1 1 "$NFQWS_OPT_DESYNC --hostlist=$HOSTLIST" ;; custom) existf zapret_custom_daemons && zapret_custom_daemons $1 ;; esac } zapret_run_daemons() { zapret_do_daemons 1 "$@" } zapret_stop_daemons() { zapret_do_daemons 0 "$@" }