diff --git a/common/ipt.sh b/common/ipt.sh index d1c835c..fc74a20 100644 --- a/common/ipt.sh +++ b/common/ipt.sh @@ -83,6 +83,167 @@ filter_apply_ipset_target() } +prepare_tpws_fw4() +{ + # otherwise linux kernel will treat 127.0.0.0/8 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.0/8 + + [ "$DISABLE_IPV4" = "1" ] || { + iptables -N input_rule_zapret 2>/dev/null + ipt input_rule_zapret -d $TPWS_LOCALHOST4 -j RETURN + ipta input_rule_zapret -d 127.0.0.0/8 -j DROP + ipt INPUT ! -i lo -j input_rule_zapret + + prepare_route_localnet + } +} +unprepare_tpws_fw4() +{ + [ "$DISABLE_IPV4" = "1" ] || { + unprepare_route_localnet + + ipt_del INPUT ! -i lo -j input_rule_zapret + iptables -F input_rule_zapret 2>/dev/null + iptables -X input_rule_zapret 2>/dev/null + } +} +unprepare_tpws_fw() +{ + unprepare_tpws_fw4 +} + + +ipt_print_op() +{ + if [ "$1" = "1" ]; then + echo "Adding ip$4tables rule for $3 : $2" + else + echo "Deleting ip$4tables rule for $3 : $2" + fi +} + +_fw_tpws4() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv4 + # $3 - tpws port + # $4 - lan interface names space separated + # $5 - wan interface names space separated + [ "$DISABLE_IPV4" = "1" ] || { + local i rule + + [ "$1" = 1 ] && prepare_tpws_fw4 + + ipt_print_op $1 "$2" "tpws (port $3)" + + rule="-p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3" + for i in $4 ; do + ipt_add_del $1 PREROUTING -t nat -i $i $rule + done + + rule="-m owner ! --uid-owner $WS_USER $rule" + if [ -n "$5" ]; then + for i in $5; do + ipt_add_del $1 OUTPUT -t nat -o $i $rule + done + else + ipt_add_del $1 OUTPUT -t nat $rule + fi + } +} +_fw_tpws6() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv6 + # $3 - tpws port + # $4 - lan interface names space separated + # $5 - wan interface names space separated + + [ "$DISABLE_IPV6" = "1" ] || { + local i rule DNAT6 + + ipt_print_op $1 "$2" "tpws (port $3)" 6 + + rule="-p tcp $2 $IPSET_EXCLUDE6 dst" + for i in $4 ; do + _dnat6_target $i DNAT6 + [ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3 + done + + rule="-m owner ! --uid-owner $WS_USER $rule -j DNAT --to [::1]:$3" + if [ -n "$5" ]; then + for i in $5; do + ipt6_add_del $1 OUTPUT -t nat -o $i $rule + done + else + ipt6_add_del $1 OUTPUT -t nat $rule + fi + } +} +fw_tpws() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv4 + # $3 - iptable filter for ipv6 + # $4 - tpws port + fw_tpws4 $1 "$2" $4 + fw_tpws6 $1 "$3" $4 +} + + +_fw_nfqws_post4() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv4 + # $3 - queue number + # $4 - wan interface names space separated + [ "$DISABLE_IPV4" = "1" ] || { + local i + + ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" + + rule="-p tcp $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass" + if [ -n "$4" ] ; then + for i in $4; do + ipt_add_del $1 POSTROUTING -t mangle -o $i $rule + done + else + ipt_add_del $1 POSTROUTING -t mangle $rule + fi + } +} +_fw_nfqws_post6() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv6 + # $3 - queue number + # $4 - wan interface names space separated + [ "$DISABLE_IPV6" = "1" ] || { + local i + + ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6 + + rule="-p tcp $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass" + if [ -n "$4" ] ; then + for i in $4; do + ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule + done + else + ipt6_add_del $1 POSTROUTING -t mangle $rule + fi + } +} +fw_nfqws_post() +{ + # $1 - 1 - add, 0 - del + # $2 - iptable filter for ipv4 + # $3 - iptable filter for ipv6 + # $4 - queue number + fw_nfqws_post4 $1 "$2" $4 + fw_nfqws_post6 $1 "$3" $4 +} + + zapret_do_firewall_ipt() { # $1 - 1 - add, 0 - del diff --git a/common/linux_iphelper.sh b/common/linux_iphelper.sh index c734456..35af497 100644 --- a/common/linux_iphelper.sh +++ b/common/linux_iphelper.sh @@ -49,3 +49,63 @@ wait_ifup() do :; done false } + +_dnat6_target() +{ + # $1 - interface name + # $2 - var to store target ip6 + # 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) + + local DNAT6_TARGET DVAR=DNAT6_TARGET_$1 + DVAR=$(echo $DVAR | sed 's/[^a-zA-Z0-9_]/_/g') + eval DNAT6_TARGET="\$$DVAR" + [ -n "$2" ] && eval $2='' + [ -n "$DNAT6_TARGET" ] || { + local ct=0 + while + DNAT6_TARGET=$(get_ipv6_linklocal $1) + [ -n "$DNAT6_TARGET" ] && break + [ "$ct" -ge "$LINKLOCAL_WAIT_SEC" ] && break + echo $1: waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ... + ct=$(($ct+1)) + sleep 1 + do :; done + + [ -n "$DNAT6_TARGET" ] || { + echo $1: no link local. getting global + DNAT6_TARGET=$(get_ipv6_global $1) + [ -n "$DNAT6_TARGET" ] || { + echo $1: could not get any address + DNAT6_TARGET=- + } + } + eval $DVAR="$DNAT6_TARGET" + } + [ -n "$2" ] && eval $2="$DNAT6_TARGET" +} + +_set_route_localnet() +{ + # $1 - 1 = enable, 0 = disable + # $2,$3,... - interface names + + [ "$DISABLE_IPV4" = "1" ] || { + local enable="$1" + shift + while [ -n "$1" ]; do + sysctl -q -w net.ipv4.conf.$1.route_localnet="$enable" + shift + done + } +} +prepare_route_localnet() +{ + set_route_localnet 1 "$@" +} +unprepare_route_localnet() +{ + set_route_localnet 0 "$@" +} diff --git a/common/nft.sh b/common/nft.sh index 129a25e..0b8dc79 100644 --- a/common/nft.sh +++ b/common/nft.sh @@ -164,7 +164,8 @@ nft_add_nfqws_flow_exempt_rule() { # $1 - rule (must be all filters in one var) nft_add_rule flow_offload $(nft_clean_nfqws_rule $1) return comment \"direct flow offloading exemption\" - nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\" + # do not need this because of oifname @wanif/@wanif6 filter in forward chain + #nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\" } nft_hw_offload_supported() @@ -181,7 +182,11 @@ nft_hw_offload_supported() nft_apply_flow_offloading() { # ft can be absent - nft_add_rule flow_offload meta l4proto "{ tcp, udp }" flow add @ft 2>/dev/null && nft_add_rule forward jump flow_offload + nft_add_rule flow_offload meta l4proto "{ tcp, udp }" flow add @ft 2>/dev/null && { + # allow only outgoing packets to initiate flow offload + nft_add_rule forward oifname @wanif jump flow_offload + nft_add_rule forward oifname @wanif6 jump flow_offload + } } @@ -260,7 +265,8 @@ flush set inet $ZAPRET_NFT_TABLE lanif" case "$FLOWOFFLOAD" in software) ALLDEVS=$(unique $1 $2 $3) - nft_create_or_update_flowtable '' $ALLDEVS + # unbound flowtable may cause error in older nft version + nft_create_or_update_flowtable '' $ALLDEVS 2>/dev/null ;; hardware) ALLDEVS=$(unique $1 $2 $3) @@ -285,6 +291,93 @@ nft_only() esac } + +nft_print_op() +{ + echo "Adding nftables ipv$3 rule for $2 : $1" +} +_nft_fw_tpws4() +{ + # $1 - filter ipv4 + # $2 - tpws port + # $4 - not-empty if wan interface filtering required + + [ "$DISABLE_IPV4" = "1" ] || { + local filter="$1" port="$2" + nft_print_op "$filter" "tpws (port $2)" 4 + nft_add_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }meta l4proto tcp $filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port + nft_add_rule dnat_pre iifname @lanif meta l4proto tcp $filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port + prepare_route_localnet + } +} +_nft_fw_tpws6() +{ + # $1 - filter ipv6 + # $2 - tpws port + # $3 - lan interface names space separated + # $4 - not-empty if wan interface filtering required + + [ "$DISABLE_IPV6" = "1" ] || { + local filter="$1" port="$2" DNAT6 i + nft_print_op "$filter" "tpws (port $port)" 6 + nft_add_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }meta l4proto tcp $filter ip6 daddr != @nozapret6 dnat ip6 to [::1]:$port + _set_route_localnet 1 $3 + for i in $3; do + _dnat6_target $i DNAT6 + [ -n "$DNAT6" -a "$DNAT6" != '-' ] && nft_add_rule dnat_pre iifname $i meta l4proto tcp $filter ip6 daddr != @nozapret6 dnat ip6 to [$DNAT6]:$port + shift + done + } +} +nft_fw_tpws() +{ + # $1 - filter ipv4 + # $2 - filter ipv6 + # $3 - tpws port + + nft_fw_tpws4 "$1" $3 + nft_fw_tpws6 "$2" $3 +} + +_nft_fw_nfqws_post4() +{ + # $1 - filter ipv4 + # $2 - queue number + # $3 - not-empty if wan interface filtering required + + [ "$DISABLE_IPV4" = "1" ] || { + local filter="$1" port="$2" rule + nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4 + rule="${3:+oifname @wanif }meta l4proto tcp $filter ip daddr != @nozapret" + nft_add_rule postrouting $rule queue num $port bypass + nft_add_nfqws_flow_exempt_rule "$rule" + } +} +_nft_fw_nfqws_post6() +{ + # $1 - filter ipv6 + # $2 - queue number + # $3 - not-empty if wan interface filtering required + + [ "$DISABLE_IPV6" = "1" ] || { + local filter="$1" port="$2" rule + nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6 + rule="${3:+oifname @wanif6 }meta l4proto tcp $filter ip6 daddr != @nozapret6" + nft_add_rule postrouting $rule queue num $port bypass + nft_add_nfqws_flow_exempt_rule "$rule" + } +} +nft_fw_nfqws_post() +{ + # $1 - filter ipv4 + # $2 - filter ipv6 + # $3 - queue number + + nft_fw_nfqws_post4 "$1" $3 + nft_fw_nfqws_post6 "$2" $3 +} + + zapret_reload_ifsets() { nft_only nft_create_table ; nft_fill_ifsets_overload diff --git a/init.d/openwrt/functions b/init.d/openwrt/functions index 4eddfe8..b6b1195 100644 --- a/init.d/openwrt/functions +++ b/init.d/openwrt/functions @@ -44,261 +44,109 @@ NFQWS_OPT_DESYNC_HTTPS6="${NFQWS_OPT_DESYNC_HTTPS6:-$NFQWS_OPT_DESYNC_HTTPS}" # we use low level function from network.sh to avoid this limitation # it can change theoretically and stop working -network_find_wan_all() +network_find_wan4_all() { __network_ifstatus "$1" "" "[@.route[@.target='0.0.0.0' && !@.table]].interface" "" 10 2>/dev/null && return network_find_wan $1 } +network_find_wan_all() +{ + network_find_wan4_all "$@" +} network_find_wan6_all() { __network_ifstatus "$1" "" "[@.route[@.target='::' && !@.table]].interface" "" 10 2>/dev/null && return network_find_wan6 $1 } -route_localnet() -{ - for lan in $OPENWRT_LAN; do - network_get_device DEVICE $lan - [ -n "$DEVICE" ] || continue - sysctl -qw net.ipv4.conf.$DEVICE.route_localnet=1 - done -} - dnat6_target() { # $1 - lan network name # $2 - var to store target ip6 - # 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) - local DNAT6_TARGET DVAR=DNAT6_TARGET_$1 - DVAR=$(echo $DVAR | sed 's/[^a-zA-Z0-9_]/_/g') - eval DNAT6_TARGET="\$$DVAR" - [ -n "$2" ] && eval $2='' - - [ -n "$DNAT6_TARGET" ] || { - # no reason to query if its down - network_is_up $1 || return - - local DEVICE - network_get_device DEVICE $1 - - local ct=0 - while - DNAT6_TARGET=$(get_ipv6_linklocal $DEVICE) - [ -n "$DNAT6_TARGET" ] && break - [ "$ct" -ge "$LINKLOCAL_WAIT_SEC" ] && break - echo $DEVICE: waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ... - ct=$(($ct+1)) - sleep 1 - do :; done - - [ -n "$DNAT6_TARGET" ] || { - echo $DEVICE: no link local. getting global - DNAT6_TARGET=$(get_ipv6_global $DEVICE) - [ -n "$DNAT6_TARGET" ] || { - echo $DEVICE: could not get any address - DNAT6_TARGET=- - } - } - eval $DVAR="$DNAT6_TARGET" + network_is_up $1 || { + [ -n "$2" ] && eval $2='' + return } - [ -n "$2" ] && eval $2="$DNAT6_TARGET" -} + local DEVICE + network_get_device DEVICE $1 + + _dnat6_target $DEVICE $2 +} set_route_localnet() { # $1 - 1 = enable, 0 = disable - [ "$DISABLE_IPV4" = "1" ] || { - local lan DEVICE - for lan in $OPENWRT_LAN; do - network_get_device DEVICE $lan - [ -n "$DEVICE" ] || continue - sysctl -q -w net.ipv4.conf.$DEVICE.route_localnet=$1 - done - } -} -prepare_route_localnet() -{ - set_route_localnet 1 -} -unprepare_route_localnet() -{ - set_route_localnet 0 -} -prepare_tpws_fw4() -{ - # otherwise linux kernel will treat 127.0.0.0/8 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.0/8 - - [ "$DISABLE_IPV4" = "1" ] || { - iptables -N input_rule_zapret 2>/dev/null - ipt input_rule_zapret -d $TPWS_LOCALHOST4 -j RETURN - ipta input_rule_zapret -d 127.0.0.0/8 -j DROP - ipt INPUT ! -i lo -j input_rule_zapret - - prepare_route_localnet - } -} -unprepare_tpws_fw4() -{ - [ "$DISABLE_IPV4" = "1" ] || { - unprepare_route_localnet - - ipt_del INPUT ! -i lo -j input_rule_zapret - iptables -F input_rule_zapret 2>/dev/null - iptables -X input_rule_zapret 2>/dev/null - } -} -unprepare_tpws_fw() -{ - unprepare_tpws_fw4 + local DLAN + call_for_multiple_items network_get_device DLAN "$OPENWRT_LAN" + _set_route_localnet $1 $DLAN } -fw_nfqws_pre4() + +fw_nfqws_post_x() { # $1 - 1 - add, 0 - del - # $2 - filter ipv4 + # $2 - filter # $3 - queue number + # $4 - ip version : 4 or 6 - local DEVICE wan_iface + network_find_wan${4}_all ifaces + call_for_multiple_items network_get_device DWAN "$ifaces" - [ "$DISABLE_IPV4" = "1" ] || { - network_find_wan_all wan_iface - for ext_iface in $wan_iface; do - network_get_device DEVICE $ext_iface - ipt_add_del $1 PREROUTING -t mangle -i $DEVICE -p tcp $2 $IPSET_EXCLUDE src -j NFQUEUE --queue-num $3 --queue-bypass - done - } -} -fw_nfqws_pre6() -{ - # $1 - 1 - add, 0 - del - # $2 - filter ipv6 - # $3 - queue number - - local DEVICE wan_iface - - [ "$DISABLE_IPV6" = "1" ] || { - network_find_wan6_all wan_iface - for ext_iface in $wan_iface; do - network_get_device DEVICE $ext_iface - ipt6_add_del $1 PREROUTING -t mangle -i $DEVICE -p tcp $2 $IPSET_EXCLUDE6 src -j NFQUEUE --queue-num $3 --queue-bypass - done - } -} -fw_nfqws_pre() -{ - # $1 - 1 - add, 0 - del - # $2 - filter ipv4 - # $3 - filter ipv6 - # $4 - queue number - - fw_nfqws_pre4 $1 "$2" $4 - fw_nfqws_pre6 $1 "$3" $4 + _fw_nfqws_post${4} $1 "$2" $3 "$(unique $DWAN)" } fw_nfqws_post4() { - # $1 - 1 - add, 0 - del - # $2 - filter ipv4 - # $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_add_del $1 POSTROUTING -t mangle -o $DEVICE -p tcp $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass - done - } + fw_nfqws_post_x $1 "$2" $3 4 } fw_nfqws_post6() { - # $1 - 1 - add, 0 - del - # $2 - filter ipv6 - # $3 - queue number - - local DEVICE wan_iface - - [ "$DISABLE_IPV6" = "1" ] || { - network_find_wan6_all wan_iface - for ext_iface in $wan_iface; do - network_get_device DEVICE $ext_iface - ipt6_add_del $1 POSTROUTING -t mangle -o $DEVICE -p tcp $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass - done - } + fw_nfqws_post_x $1 "$2" $3 6 } -fw_nfqws_post() +fw_tpws_x() { # $1 - 1 - add, 0 - del - # $2 - filter ipv4 - # $3 - filter ipv6 - # $4 - queue number + # $2 - filter + # $3 - tpws port + # $4 - ip version : 4 or 6 - fw_nfqws_post4 $1 "$2" $4 - fw_nfqws_post6 $1 "$3" $4 + local script ifaces DLAN DWAN + + call_for_multiple_items network_get_device DLAN "$OPENWRT_LAN" + + network_find_wan${4}_all ifaces + call_for_multiple_items network_get_device DWAN "$ifaces" + + _fw_tpws${4} $1 "$2" $3 "$DLAN" "$(unique $DWAN)" } - - -IPT_OWNER="-m owner ! --uid-owner $WS_USER" fw_tpws4() { - # $1 - 1 - add, 0 - del - # $2 - filter ipv4 - # $3 - tpws port - - local lan DEVICE ext_iface 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_add_del $1 OUTPUT -t nat -o $DEVICE $IPT_OWNER -p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3 - done - [ "$1" = 1 ] && prepare_tpws_fw4 - for lan in $OPENWRT_LAN; do - network_get_device DEVICE $lan - [ -n "$DEVICE" ] || continue - ipt_add_del $1 PREROUTING -t nat -i $DEVICE -p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3 - done - } + fw_tpws_x $1 "$2" $3 4 } fw_tpws6() { - # $1 - 1 - add, 0 - del - # $2 - filter ipv6 - # $3 - tpws port - - local lan DEVICE ext_iface wan_iface DNAT6 - - [ "$DISABLE_IPV6" = "1" ] || { - network_find_wan6_all wan_iface - for ext_iface in $wan_iface; do - network_get_device DEVICE $ext_iface - ipt6_add_del $1 OUTPUT -t nat -o $DEVICE $IPT_OWNER -p tcp $2 $IPSET_EXCLUDE6 dst -j DNAT --to [::1]:$3 - done - for lan in $OPENWRT_LAN; do - network_get_device DEVICE $lan - [ -n "$DEVICE" ] || continue - dnat6_target $lan DNAT6 - [ "$DNAT6" != '-' ] && ipt6_add_del $1 PREROUTING -t nat -i $DEVICE -p tcp $2 $IPSET_EXCLUDE6 dst -j DNAT --to [$DNAT6]:$3 - done - } + fw_tpws_x $1 "$2" $3 6 } -fw_tpws() -{ - # $1 - 1 - add, 0 - del - # $2 - filter ipv4 - # $3 - filter ipv6 - # $4 - tpws port - fw_tpws4 $1 "$2" $4 - fw_tpws6 $1 "$3" $4 +nft_fw_tpws4() +{ + _nft_fw_tpws4 "$1" $2 always_apply_wan_filter +} +nft_fw_tpws6() +{ + local script ifaces DLAN + call_for_multiple_items network_get_device DLAN "$OPENWRT_LAN" + _nft_fw_tpws6 "$1" $2 "$DLAN" always_apply_wan_filter +} +nft_fw_nfqws_post4() +{ + _nft_fw_nfqws_post4 "$1" $2 always_apply_wan_filter +} +nft_fw_nfqws_post6() +{ + _nft_fw_nfqws_post6 "$1" $2 always_apply_wan_filter } @@ -384,13 +232,14 @@ flow_offloading_unexempt() } + nft_fill_ifsets_overload() { local script ifaces DLAN DWAN DWAN6 call_for_multiple_items network_get_device DLAN "$OPENWRT_LAN" - network_find_wan_all ifaces + network_find_wan4_all ifaces call_for_multiple_items network_get_device DWAN "$ifaces" network_find_wan6_all ifaces @@ -399,75 +248,12 @@ nft_fill_ifsets_overload() nft_fill_ifsets "$DLAN" "$DWAN" "$DWAN6" } -nft_fw_tpws4() -{ - # $1 - filter ipv4 - # $2 - tpws port - - [ "$DISABLE_IPV4" = "1" ] || { - nft_add_rule dnat_output skuid != $WS_USER oifname @wanif meta l4proto tcp $1 ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$2 - nft_add_rule dnat_pre iifname @lanif meta l4proto tcp $1 ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$2 - prepare_route_localnet - } -} nft_fw_tpws6() { # $1 - filter ipv6 # $2 - tpws port - local lan DEVICE DNAT6 - [ "$DISABLE_IPV6" = "1" ] || { - nft_add_rule dnat_output skuid != $WS_USER oifname @wanif6 meta l4proto tcp $1 ip6 daddr != @nozapret6 dnat ip6 to [::1]:$2 - for lan in $OPENWRT_LAN; do - network_get_device DEVICE $lan - [ -n "$DEVICE" ] || continue - dnat6_target $lan DNAT6 - [ "$DNAT6" != '-' ] && nft_add_rule dnat_pre iifname $DEVICE meta l4proto tcp $1 ip6 daddr != @nozapret6 dnat ip6 to [$DNAT6]:$2 - done - } -} -nft_fw_tpws() -{ - # $1 - filter ipv4 - # $2 - filter ipv6 - # $3 - tpws port - - nft_fw_tpws4 "$1" $3 - nft_fw_tpws6 "$2" $3 -} - -nft_fw_nfqws_post4() -{ - # $1 - filter ipv4 - # $2 - queue number - - local rule - - [ "$DISABLE_IPV4" = "1" ] || { - rule="oifname @wanif meta l4proto tcp $1 ip daddr != @nozapret" - nft_add_rule postrouting $rule queue num $2 bypass - nft_add_nfqws_flow_exempt_rule "$rule" - } -} -nft_fw_nfqws_post6() -{ - # $1 - filter ipv6 - # $2 - queue number - - local rule - - [ "$DISABLE_IPV6" = "1" ] || { - rule="oifname @wanif6 meta l4proto tcp $1 ip6 daddr != @nozapret6" - nft_add_rule postrouting $rule queue num $2 bypass - nft_add_nfqws_flow_exempt_rule "$rule" - } -} -nft_fw_nfqws_post() -{ - # $1 - filter ipv4 - # $2 - filter ipv6 - # $3 - queue number - - nft_fw_nfqws_post4 "$1" $3 - nft_fw_nfqws_post6 "$2" $3 + local DLAN + call_for_multiple_items network_get_device DLAN "$OPENWRT_LAN" + _nft_fw_tpws6 "$1" $2 "$DLAN" } diff --git a/init.d/sysv/functions b/init.d/sysv/functions index fbc2253..ed84af4 100644 --- a/init.d/sysv/functions +++ b/init.d/sysv/functions @@ -98,245 +98,52 @@ IPSET_EXCLUDE="-m set ! --match-set nozapret" IPSET_EXCLUDE6="-m set ! --match-set nozapret6" -# 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 ::) - dnat6_target() { - # $1 - lan network name - # $2 - var to store target ip6 - # 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) - - local DNAT6_TARGET DVAR=DNAT6_TARGET_$1 - DVAR=$(echo $DVAR | sed 's/[^a-zA-Z0-9_]/_/g') - eval DNAT6_TARGET="\$$DVAR" - [ -n "$2" ] && eval $2='' - [ -n "$DNAT6_TARGET" ] || { - local ct=0 - while - DNAT6_TARGET=$(get_ipv6_linklocal $1) - [ -n "$DNAT6_TARGET" ] && break - [ "$ct" -ge "$LINKLOCAL_WAIT_SEC" ] && break - echo $1: waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ... - ct=$(($ct+1)) - sleep 1 - do :; done - - [ -n "$DNAT6_TARGET" ] || { - echo $1: no link local. getting global - DNAT6_TARGET=$(get_ipv6_global $1) - [ -n "$DNAT6_TARGET" ] || { - echo $1: could not get any address - DNAT6_TARGET=- - } - } - eval $DVAR="$DNAT6_TARGET" - } - [ -n "$2" ] && eval $2="$DNAT6_TARGET" + _dnat6_target "$@" } - set_route_localnet() { - # $1 - 1 = enable, 0 = disable - - [ "$DISABLE_IPV4" = "1" ] || { - local lan - for lan in $IFACE_LAN ; do - sysctl -q -w net.ipv4.conf.$lan.route_localnet=$1 - done - } -} -prepare_route_localnet() -{ - set_route_localnet 1 -} -unprepare_route_localnet() -{ - set_route_localnet 0 -} -prepare_tpws_fw4() -{ - # otherwise linux kernel will treat 127.0.0.0/8 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.0/8 - [ "$DISABLE_IPV4" = "1" ] || { - [ -n "$IFACE_LAN" ] && { - local lan - iptables -N input_rule_zapret 2>/dev/null - iptables -F input_rule_zapret - iptables -A input_rule_zapret -d $TPWS_LOCALHOST4 -j RETURN - iptables -A input_rule_zapret -d 127.0.0.0/8 -j DROP - ipt INPUT ! -i lo -j input_rule_zapret - prepare_route_localnet - } - } -} -unprepare_tpws_fw4() -{ - [ "$DISABLE_IPV4" = "1" ] || { - [ -n "$IFACE_LAN" ] && { - local lan - unprepare_route_localnet - ipt_del INPUT ! -i lo -j input_rule_zapret - iptables -F input_rule_zapret 2>/dev/null - iptables -X input_rule_zapret 2>/dev/null - } - } -} -unprepare_tpws_fw() -{ - unprepare_tpws_fw4 + _set_route_localnet $1 "$IFACE_LAN" } - -ipt_print_op() -{ - if [ "$1" = "1" ]; then - echo "Adding ip$4tables rule for $3 : $2" - else - echo "Deleting ip$4tables rule for $3 : $2" - fi -} - -fw_tpws4() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - tpws port - [ "$DISABLE_IPV4" = "1" ] || { - [ "$1" = 1 ] && prepare_tpws_fw4 - ipt_print_op $1 "$2" "tpws (port $3)" - for lan in $IFACE_LAN ; do - ipt_add_del $1 PREROUTING -t nat -i $lan -p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3 - done - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt_add_del $1 OUTPUT -t nat -o $wan -m owner ! --uid-owner $WS_USER -p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3 - done - else - ipt_add_del $1 OUTPUT -t nat -m owner ! --uid-owner $WS_USER -p tcp $2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3 - fi - } -} -fw_tpws6() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv6 - # $3 - tpws port - [ "$DISABLE_IPV6" = "1" ] || { - ipt_print_op $1 "$2" "tpws (port $3)" 6 - local DNAT6 - for lan in $IFACE_LAN ; do - dnat6_target $lan DNAT6 - [ "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $lan -p tcp $2 $IPSET_EXCLUDE6 dst -j DNAT --to [$DNAT6]:$3 - done - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt6_add_del $1 OUTPUT -t nat -o $wan -m owner ! --uid-owner $WS_USER -p tcp $2 $IPSET_EXCLUDE6 dst -j DNAT --to [::1]:$3 - done - else - ipt6_add_del $1 OUTPUT -t nat -m owner ! --uid-owner $WS_USER -p tcp $2 $IPSET_EXCLUDE6 dst -j DNAT --to [::1]:$3 - fi - } -} -fw_tpws() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - iptable filter for ipv6 - # $4 - tpws port - fw_tpws4 $1 "$2" $4 - fw_tpws6 $1 "$3" $4 -} - - -fw_nfqws_pre4() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - queue number - [ "$DISABLE_IPV4" = "1" ] || { - ipt_print_op $1 "$2" "nfqws prerouting (qnum $3)" - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt_add_del $1 PREROUTING -t mangle -i $wan -p tcp $2 $IPSET_EXCLUDE src -j NFQUEUE --queue-num $3 --queue-bypass - done - else - ipt_add_del $1 PREROUTING -t mangle -p tcp $2 $IPSET_EXCLUDE src -j NFQUEUE --queue-num $3 --queue-bypass - fi - } -} -fw_nfqws_pre6() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv6 - # $3 - queue number - [ "$DISABLE_IPV6" = "1" ] || { - ipt_print_op $1 "$2" "nfqws prerouting (qnum $3)" 6 - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt6_add_del $1 PREROUTING -t mangle -i $wan -p tcp $2 $IPSET_EXCLUDE6 src -j NFQUEUE --queue-num $3 --queue-bypass - done - else - ipt6_add_del $1 PREROUTING -t mangle -p tcp $2 $IPSET_EXCLUDE6 src -j NFQUEUE --queue-num $3 --queue-bypass - fi - } -} -fw_nfqws_pre() -{ - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - iptable filter for ipv6 - # $4 - queue number - fw_nfqws_pre4 $1 "$2" $4 - fw_nfqws_pre6 $1 "$3" $4 -} fw_nfqws_post4() { - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - queue number - [ "$DISABLE_IPV4" = "1" ] || { - ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt_add_del $1 POSTROUTING -t mangle -o $wan -p tcp $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass - done - else - ipt_add_del $1 POSTROUTING -t mangle -p tcp $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass - fi - } + _fw_nfqws_post4 $1 "$2" $3 "$IFACE_WAN" } fw_nfqws_post6() { - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv6 - # $3 - queue number - [ "$DISABLE_IPV6" = "1" ] || { - ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6 - if [ -n "$IFACE_WAN" ]; then - for wan in $IFACE_WAN; do - ipt6_add_del $1 POSTROUTING -t mangle -o $wan -p tcp $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass - done - else - ipt6_add_del $1 POSTROUTING -t mangle -p tcp $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass - fi - } + _fw_nfqws_post6 $1 "$2" $3 "$IFACE_WAN" } -fw_nfqws_post() +fw_tpws4() { - # $1 - 1 - add, 0 - del - # $2 - iptable filter for ipv4 - # $3 - iptable filter for ipv6 - # $4 - queue number - fw_nfqws_post4 $1 "$2" $4 - fw_nfqws_post6 $1 "$3" $4 + _fw_tpws4 $1 "$2" $3 "$IFACE_LAN" "$IFACE_WAN" } +fw_tpws6() +{ + _fw_tpws6 $1 "$2" $3 "$IFACE_LAN" "$IFACE_WAN" +} +nft_fw_tpws4() +{ + _nft_fw_tpws4 "$1" $2 "$IFACE_WAN" +} +nft_fw_tpws6() +{ + _nft_fw_tpws6 "$1" $2 "$IFACE_LAN" "$IFACE_WAN" +} +nft_fw_nfqws_post4() +{ + _nft_fw_nfqws_post4 "$1" $2 "$IFACE_WAN" +} +nft_fw_nfqws_post6() +{ + _nft_fw_nfqws_post6 "$1" $2 "$IFACE_WAN" +} +nft_fill_ifsets_overload() +{ + nft_fill_ifsets "$IFACE_LAN" "$IFACE_WAN" "$IFACE_WAN" +} + filter_apply_hostlist_target() { @@ -520,90 +327,3 @@ zapret_stop_daemons() zapret_do_daemons 0 "$@" } - -nft_fill_ifsets_overload() -{ - nft_fill_ifsets "$IFACE_LAN" "$IFACE_WAN" "$IFACE_WAN" -} - -nft_print_op() -{ - echo "Adding nftables ipv$3 rule for $2 : $1" -} - -nft_fw_tpws4() -{ - # $1 - filter ipv4 - # $2 - tpws port - - [ "$DISABLE_IPV4" = "1" ] || { - nft_print_op "$1" "tpws (port $2)" 4 - nft_add_rule dnat_output skuid != $WS_USER ${IFACE_WAN:+oifname @wanif }meta l4proto tcp $1 ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$2 - [ -n "$IFACE_LAN" ] && { - prepare_route_localnet - nft_add_rule dnat_pre iifname @lanif meta l4proto tcp $1 ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$2 - } - } -} -nft_fw_tpws6() -{ - # $1 - filter ipv6 - # $2 - tpws port - - local lan DNAT6 - [ "$DISABLE_IPV6" = "1" ] || { - nft_print_op "$1" "tpws (port $2)" 6 - nft_add_rule dnat_output skuid != $WS_USER ${IFACE_WAN:+oifname @wanif6 }meta l4proto tcp $1 ip6 daddr != @nozapret6 dnat ip6 to [::1]:$2 - for lan in $IFACE_LAN ; do - dnat6_target $lan DNAT6 - [ "$DNAT6" != '-' ] && nft_add_rule dnat_pre iifname $lan meta l4proto tcp $1 ip6 daddr != @nozapret6 dnat ip6 to [$DNAT6]:$2 - done - } -} -nft_fw_tpws() -{ - # $1 - filter ipv4 - # $2 - filter ipv6 - # $3 - tpws port - - nft_fw_tpws4 "$1" $3 - nft_fw_tpws6 "$2" $3 -} - -nft_fw_nfqws_post4() -{ - # $1 - filter ipv4 - # $2 - queue number - - local rule - - [ "$DISABLE_IPV4" = "1" ] || { - nft_print_op "$1" "nfqws postrouting (qnum $2)" 4 - rule="${IFACE_WAN:+oifname @wanif }meta l4proto tcp $1 ip daddr != @nozapret" - nft_add_rule postrouting $rule queue num $2 bypass - nft_add_nfqws_flow_exempt_rule "$rule" - } -} -nft_fw_nfqws_post6() -{ - # $1 - filter ipv6 - # $2 - queue number - - local rule - - [ "$DISABLE_IPV6" = "1" ] || { - nft_print_op "$1" "nfqws postrouting (qnum $2)" 6 - rule="${IFACE_WAN:+oifname @wanif6 }meta l4proto tcp $1 ip6 daddr != @nozapret6" - nft_add_rule postrouting $rule queue num $2 bypass - nft_add_nfqws_flow_exempt_rule "$rule" - } -} -nft_fw_nfqws_post() -{ - # $1 - filter ipv4 - # $2 - filter ipv6 - # $3 - queue number - - nft_fw_nfqws_post4 "$1" $3 - nft_fw_nfqws_post6 "$2" $3 -}