. /lib/functions/network.sh [ -n "$ZAPRET_BASE" ] || ZAPRET_BASE=/opt/zapret . "$ZAPRET_BASE/config" QNUM=200 TPPORT_HTTP=1188 TPPORT_HTTPS=1189 TPWS_USER=daemon # max wait time for the link local ipv6 on the LAN interface LINKLOCAL_WAIT_SEC=5 IPSET_CR=$ZAPRET_BASE/ipset/create_ipset.sh exists() { which $1 >/dev/null 2>/dev/null } # can be multiple ipv6 outgoing interfaces # uplink from isp, tunnelbroker, vpn, ... # want them all. who knows what's the real one that blocks sites # dont want any manual configuration - want to do it automatically # standard network_find_wan[6] return only the first # we use low level function from network.sh to avoid this limitation # it can change theoretically and stop working network_find_wan_all() { __network_ifstatus "$1" "" "[@.route[@.target='0.0.0.0' && !@.table]].interface" "" 10 2>/dev/null && return network_find_wan $1 } network_find_wan6_all() { __network_ifstatus "$1" "" "[@.route[@.target='::' && !@.table]].interface" "" 10 2>/dev/null && return network_find_wan6 $1 } ipt() { iptables -C "$@" 2>/dev/null || iptables -I "$@" } ipt6() { ip6tables -C "$@" 2>/dev/null || ip6tables -I "$@" } # 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 if exists ip ; then 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 else ifconfig $1 | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Link.*$/\1/;t;d' | head -n 1 fi } get_ipv6_global() { # $1 - interface name. if empty - any interface if exists ip ; then 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 else ifconfig $1 | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Global.*$/\1/;t;d' | head -n 1 fi } dnat6_target() { # get target ip address for DNAT. prefer link locals # tpws should be as inaccessible from outside as possible # link local address can appear not immediately after ifup # DNAT6_TARGET=- means attempt was made but address was not found (to avoid multiple re-attempts) [ -n "$DNAT6_TARGET" ] || { # no reason to query if its down network_is_up lan || return local DEVICE network_get_device DEVICE lan local ct=0 while DNAT6_TARGET=$(get_ipv6_linklocal $DEVICE) [ -n "$DNAT6_TARGET" ] && break [ "$ct" -ge "$LINKLOCAL_WAIT_SEC" ] && break echo waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ... ct=$(($ct+1)) sleep 1 do :; done [ -n "$DNAT6_TARGET" ] || { echo no link local. getting global DNAT6_TARGET=$(get_ipv6_global $DEVICE) [ -n "$DNAT6_TARGET" ] || { echo could not get any address DNAT6_TARGET=- } } } } fw_nfqws_pre() { # $1 - filter ipv4 # $2 - filter ipv6 # $3 - queue number local DEVICE wan_iface [ "$DISABLE_IPV4" = "1" ] || { network_find_wan_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt PREROUTING -t raw -i $DEVICE -p tcp $1 -j NFQUEUE --queue-num $3 --queue-bypass done } [ "$DISABLE_IPV6" = "1" ] || { network_find_wan6_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt6 PREROUTING -t raw -i $DEVICE -p tcp $2 -j NFQUEUE --queue-num $3 --queue-bypass done } } fw_nfqws_post() { # $1 - filter ipv4 # $2 - filter ipv6 # $3 - queue number local DEVICE wan_iface [ "$DISABLE_IPV4" = "1" ] || { network_find_wan_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt POSTROUTING -t mangle -o $DEVICE -p tcp $1 -j NFQUEUE --queue-num $3 --queue-bypass done } [ "$DISABLE_IPV6" = "1" ] || { network_find_wan6_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt6 POSTROUTING -t mangle -o $DEVICE -p tcp $2 -j NFQUEUE --queue-num $3 --queue-bypass done } } IPT_OWNER="-m owner ! --uid-owner $TPWS_USER" fw_tpws() { # $1 - filter ipv4 # $2 - filter ipv6 # $3 - tpws port local DEVICE wan_iface [ "$DISABLE_IPV4" = "1" ] || { network_find_wan_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt OUTPUT -t nat -o $DEVICE $IPT_OWNER -p tcp $1 -j DNAT --to 127.0.0.1:$3 done ipt prerouting_lan_rule -t nat -p tcp $1 -j DNAT --to 127.0.0.1:$3 network_get_device DEVICE lan sysctl -qw net.ipv4.conf.$DEVICE.route_localnet=1 } [ "$DISABLE_IPV6" = "1" ] || { network_find_wan6_all wan_iface for ext_iface in $wan_iface; do network_get_device DEVICE $ext_iface ipt6 OUTPUT -t nat -o $DEVICE $IPT_OWNER -p tcp $2 -j DNAT --to [::1]:$3 done network_get_device DEVICE lan dnat6_target [ "$DNAT6_TARGET" != "-" ] && ipt6 PREROUTING -t nat -i $DEVICE -p tcp $2 -j DNAT --to [$DNAT6_TARGET]:$3 } } create_ipset() { echo "Creating ipset" "$IPSET_CR" "$@" } zapret_apply_firewall() { case "${MODE}" in tpws_hostlist) fw_tpws "--dport 80" "--dport 80" $TPPORT_HTTP ;; tpws_ipset) create_ipset no-update fw_tpws "--dport 80 -m set --match-set zapret dst" "--dport 80 -m set --match-set zapret6 dst" $TPPORT_HTTP ;; tpws_ipset_https) create_ipset no-update fw_tpws "--dport 80 -m set --match-set zapret dst" "--dport 80 -m set --match-set zapret6 dst" $TPPORT_HTTP fw_tpws "--dport 443 -m set --match-set zapret dst" "--dport 443 -m set --match-set zapret6 dst" $TPPORT_HTTPS ;; tpws_all) fw_tpws "--dport 80" "--dport 80" $TPPORT_HTTP ;; tpws_all_https) fw_tpws "--dport 80" "--dport 80" $TPPORT_HTTP fw_tpws "--dport 443" "--dport 443" $TPPORT_HTTPS ;; nfqws_ipset) create_ipset no-update fw_nfqws_pre "--sport 80 -m set --match-set zapret src" "--sport 80 -m set --match-set zapret6 src" $QNUM fw_nfqws_post "--dport 80 -m set --match-set zapret dst" "--dport 80 -m set --match-set zapret6 dst" $QNUM ;; nfqws_ipset_https) create_ipset no-update fw_nfqws_pre "-m multiport --sports 80,443 -m set --match-set zapret src" "-m multiport --sports 80,443 -m set --match-set zapret6 src" $QNUM fw_nfqws_post "--dport 80 -m set --match-set zapret dst" "--dport 80 -m set --match-set zapret6 dst" $QNUM ;; nfqws_all) fw_nfqws_pre "--sport 80" "--sport 80" $QNUM fw_nfqws_post "--dport 80" "--dport 80" $QNUM ;; nfqws_all_https) fw_nfqws_pre "-m multiport --sports 80,443" "-m multiport --sports 80,443" $QNUM fw_nfqws_post "--dport 80" "--dport 80" $QNUM ;; ipset) create_ipset no-update ;; custom) # PLACEHOLDER echo !!! NEED ATTENTION !!! echo Configure iptables for required actions echo Study how other sections work ;; esac }