mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-11 17:29:16 +05:00
349 lines
8.7 KiB
Bash
349 lines
8.7 KiB
Bash
|
[ -n "$ZAPRET_NFT_TABLE" ] || ZAPRET_NFT_TABLE=zapret
|
||
|
|
||
|
# required for : nft -f -
|
||
|
create_dev_stdin
|
||
|
|
||
|
nft_create_table()
|
||
|
{
|
||
|
nft add table inet $ZAPRET_NFT_TABLE
|
||
|
}
|
||
|
nft_del_table()
|
||
|
{
|
||
|
nft delete table inet $ZAPRET_NFT_TABLE 2>/dev/null
|
||
|
}
|
||
|
nft_list_table()
|
||
|
{
|
||
|
nft -t list table inet $ZAPRET_NFT_TABLE
|
||
|
}
|
||
|
|
||
|
nft_create_set()
|
||
|
{
|
||
|
# $1 - set name
|
||
|
# $2 - params
|
||
|
nft create set inet $ZAPRET_NFT_TABLE $1 "{ $2 }" 2>/dev/null
|
||
|
}
|
||
|
nft_del_set()
|
||
|
{
|
||
|
# $1 - set name
|
||
|
nft delete set inet $ZAPRET_NFT_TABLE $1
|
||
|
}
|
||
|
nft_flush_set()
|
||
|
{
|
||
|
# $1 - set name
|
||
|
nft flush set inet $ZAPRET_NFT_TABLE $1
|
||
|
}
|
||
|
nft_set_exists()
|
||
|
{
|
||
|
# $1 - set name
|
||
|
nft -t list set inet $ZAPRET_NFT_TABLE $1 2>/dev/null >/dev/null
|
||
|
}
|
||
|
|
||
|
nft_del_all_chains_from_table()
|
||
|
{
|
||
|
# $1 - table_name with or without family
|
||
|
|
||
|
# delete all chains with possible references to each other
|
||
|
# cannot just delete all in the list because of references
|
||
|
# avoid infinite loops
|
||
|
local chains deleted=1 error=1
|
||
|
while [ -n "$deleted" -a -n "$error" ]; do
|
||
|
chains=$(nft -t list table $1 2>/dev/null | sed -nre "s/^[ ]*chain ([^ ]+) \{/\1/p" | xargs)
|
||
|
[ -n "$chains" ] || break
|
||
|
deleted=
|
||
|
error=
|
||
|
for chain in $chains; do
|
||
|
if nft delete chain $1 $chain 2>/dev/null; then
|
||
|
deleted=1
|
||
|
else
|
||
|
error=1
|
||
|
fi
|
||
|
done
|
||
|
done
|
||
|
}
|
||
|
|
||
|
nft_del_chains()
|
||
|
{
|
||
|
nft_del_all_chains_from_table "inet $ZAPRET_NFT_TABLE"
|
||
|
}
|
||
|
nft_create_chains()
|
||
|
{
|
||
|
cat << EOF | nft -f -
|
||
|
add chain inet $ZAPRET_NFT_TABLE dnat_output { type nat hook output priority -101; }
|
||
|
flush chain inet $ZAPRET_NFT_TABLE dnat_output
|
||
|
add chain inet $ZAPRET_NFT_TABLE dnat_pre { type nat hook prerouting priority -101; }
|
||
|
flush chain inet $ZAPRET_NFT_TABLE dnat_pre
|
||
|
add chain inet $ZAPRET_NFT_TABLE forward { type filter hook forward priority -1; }
|
||
|
flush chain inet $ZAPRET_NFT_TABLE forward
|
||
|
add chain inet $ZAPRET_NFT_TABLE input { type filter hook input priority -1; }
|
||
|
flush chain inet $ZAPRET_NFT_TABLE input
|
||
|
add chain inet $ZAPRET_NFT_TABLE flow_offload
|
||
|
flush chain inet $ZAPRET_NFT_TABLE flow_offload
|
||
|
add chain inet $ZAPRET_NFT_TABLE localnet_protect
|
||
|
flush chain inet $ZAPRET_NFT_TABLE localnet_protect
|
||
|
add rule inet $ZAPRET_NFT_TABLE localnet_protect ip daddr $TPWS_LOCALHOST4 return comment "route_localnet allow access to tpws"
|
||
|
add rule inet $ZAPRET_NFT_TABLE localnet_protect ip daddr 127.0.0.0/8 drop comment "route_localnet remote access protection"
|
||
|
add rule inet $ZAPRET_NFT_TABLE input iifname != lo jump localnet_protect
|
||
|
add chain inet $ZAPRET_NFT_TABLE postrouting { type filter hook postrouting priority -151; }
|
||
|
flush chain inet $ZAPRET_NFT_TABLE postrouting
|
||
|
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
|
||
|
add set inet $ZAPRET_NFT_TABLE wanif { type ifname; }
|
||
|
add set inet $ZAPRET_NFT_TABLE wanif6 { type ifname; }
|
||
|
EOF
|
||
|
}
|
||
|
nft_del_flowtable()
|
||
|
{
|
||
|
nft delete flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
|
||
|
}
|
||
|
nft_create_or_update_flowtable()
|
||
|
{
|
||
|
# $1 = flags ('offload' for hw offload)
|
||
|
# $2,$3,$4,... - interfaces
|
||
|
# can be called multiple times to add interfaces. interfaces can only be added , not removed
|
||
|
local flags=$1 devices
|
||
|
shift
|
||
|
make_comma_list devices "$@"
|
||
|
[ -n "$devices" ] && devices="devices={$devices};"
|
||
|
[ -n "$flags" ] && flags="flags $flags;"
|
||
|
nft add flowtable inet $ZAPRET_NFT_TABLE ft "{ hook ingress priority -1; $flags $devices }"
|
||
|
}
|
||
|
nft_flush_ifsets()
|
||
|
{
|
||
|
cat << EOF | nft -f - 2>/dev/null
|
||
|
flush set inet $ZAPRET_NFT_TABLE lanif
|
||
|
flush set inet $ZAPRET_NFT_TABLE wanif
|
||
|
flush set inet $ZAPRET_NFT_TABLE wanif6
|
||
|
EOF
|
||
|
}
|
||
|
nft_list_ifsets()
|
||
|
{
|
||
|
nft list set inet $ZAPRET_NFT_TABLE lanif
|
||
|
nft list set inet $ZAPRET_NFT_TABLE wanif
|
||
|
nft list set inet $ZAPRET_NFT_TABLE wanif6
|
||
|
nft list flowtable inet $ZAPRET_NFT_TABLE ft
|
||
|
}
|
||
|
|
||
|
nft_create_firewall()
|
||
|
{
|
||
|
nft_create_table
|
||
|
nft_del_flowtable
|
||
|
nft_create_chains
|
||
|
}
|
||
|
nft_del_firewall()
|
||
|
{
|
||
|
nft_del_chains
|
||
|
nft_del_flowtable
|
||
|
nft_flush_ifsets
|
||
|
}
|
||
|
|
||
|
nft_add_rule()
|
||
|
{
|
||
|
# $1 - chain
|
||
|
# $2,$3,... - rule(s)
|
||
|
local chain="$1"
|
||
|
shift
|
||
|
nft add rule inet $ZAPRET_NFT_TABLE $chain "$@"
|
||
|
}
|
||
|
nft_add_set_elements()
|
||
|
{
|
||
|
# $1 - set name
|
||
|
# $2,$3,... - element(s)
|
||
|
local set="$1" elements
|
||
|
shift
|
||
|
make_comma_list elements "$@"
|
||
|
[ -z "$elements" ] || nft add element inet $ZAPRET_NFT_TABLE $set "{ $elements }"
|
||
|
}
|
||
|
nft_reverse_nfqws_rule()
|
||
|
{
|
||
|
echo "$@" | sed -e 's/oifname /iifname /g' -e 's/dport /sport /g' -e 's/daddr /saddr /g' -e 's/ct original /ct reply /g' -e "s/mark and $DESYNC_MARK == 0//g"
|
||
|
}
|
||
|
nft_clean_nfqws_rule()
|
||
|
{
|
||
|
echo "$@" | sed -e "s/mark and $DESYNC_MARK == 0//g"
|
||
|
}
|
||
|
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\"
|
||
|
}
|
||
|
|
||
|
nft_hw_offload_supported()
|
||
|
{
|
||
|
# $1,$2,... - interface names
|
||
|
local devices res=1
|
||
|
make_comma_list devices "$@"
|
||
|
[ -n "$devices" ] && devices="devices={$devices};"
|
||
|
nft add table ${ZAPRET_NFT_TABLE}_test && nft add flowtable ${ZAPRET_NFT_TABLE}_test ft "{ flags offload; $devices }" 2>/dev/null && res=0
|
||
|
nft delete table ${ZAPRET_NFT_TABLE}_test 2>/dev/null
|
||
|
return $res
|
||
|
}
|
||
|
|
||
|
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_filter_apply_port_target()
|
||
|
{
|
||
|
# $1 - var name of nftables filter
|
||
|
local f
|
||
|
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
|
||
|
f="tcp dport {80,443}"
|
||
|
elif [ "$MODE_HTTPS" = "1" ]; then
|
||
|
f="tcp dport 443"
|
||
|
elif [ "$MODE_HTTP" = "1" ]; then
|
||
|
f="tcp dport 80"
|
||
|
else
|
||
|
echo WARNING !!! HTTP and HTTPS are both disabled
|
||
|
fi
|
||
|
eval $1="\"\$$1 $f\""
|
||
|
}
|
||
|
nft_filter_apply_ipset_target4()
|
||
|
{
|
||
|
# $1 - var name of ipv4 nftables filter
|
||
|
if [ "$MODE_FILTER" = "ipset" ]; then
|
||
|
eval $1="\"\$$1 ip daddr @zapret\""
|
||
|
fi
|
||
|
}
|
||
|
nft_filter_apply_ipset_target6()
|
||
|
{
|
||
|
# $1 - var name of ipv6 nftables filter
|
||
|
if [ "$MODE_FILTER" = "ipset" ]; then
|
||
|
eval $1="\"\$$1 ip6 daddr @zapret6\""
|
||
|
fi
|
||
|
}
|
||
|
nft_filter_apply_ipset_target()
|
||
|
{
|
||
|
# $1 - var name of ipv4 nftables filter
|
||
|
# $2 - var name of ipv6 nftables filter
|
||
|
nft_filter_apply_ipset_target4 $1
|
||
|
nft_filter_apply_ipset_target6 $2
|
||
|
}
|
||
|
|
||
|
nft_only()
|
||
|
{
|
||
|
linux_fwtype
|
||
|
|
||
|
case "$FWTYPE" in
|
||
|
nftables)
|
||
|
"$@"
|
||
|
;;
|
||
|
esac
|
||
|
}
|
||
|
|
||
|
zapret_reload_ifsets()
|
||
|
{
|
||
|
nft_only nft_create_table ; nft_fill_ifsets
|
||
|
return 0
|
||
|
}
|
||
|
zapret_list_ifsets()
|
||
|
{
|
||
|
nft_only nft_list_ifsets
|
||
|
return 0
|
||
|
}
|
||
|
zapret_list_table()
|
||
|
{
|
||
|
nft_only nft_list_table
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
zapret_apply_firewall_nft()
|
||
|
{
|
||
|
echo Applying nftables
|
||
|
|
||
|
local mode="${MODE_OVERRIDE:-$MODE}"
|
||
|
|
||
|
[ "$mode" = "tpws-socks" ] && return 0
|
||
|
|
||
|
local first_packet_only="ct original packets 1-4"
|
||
|
local desync="mark and $DESYNC_MARK == 0"
|
||
|
local f4 f6 qn qns qn6 qns6
|
||
|
|
||
|
create_ipset no-update
|
||
|
nft_create_firewall
|
||
|
nft_fill_ifsets
|
||
|
|
||
|
case "$mode" in
|
||
|
tpws)
|
||
|
if [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ]; then
|
||
|
echo both http and https are disabled. not applying redirection.
|
||
|
else
|
||
|
nft_filter_apply_port_target f4
|
||
|
f6=$f4
|
||
|
nft_filter_apply_ipset_target f4 f6
|
||
|
nft_fw_tpws "$f4" "$f6" $TPPORT
|
||
|
fi
|
||
|
;;
|
||
|
nfqws)
|
||
|
# quite complex but we need to minimize nfqws processes to save RAM
|
||
|
get_nfqws_qnums qn qns qn6 qns6
|
||
|
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn" ] && [ "$qn" = "$qns" ]; then
|
||
|
nft_filter_apply_port_target f4
|
||
|
f4="$f4 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target4 f4
|
||
|
nft_fw_nfqws_post4 "$f4 $desync" $qn
|
||
|
else
|
||
|
if [ -n "$qn" ]; then
|
||
|
f4="tcp dport 80"
|
||
|
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f4="$f4 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target4 f4
|
||
|
nft_fw_nfqws_post4 "$f4 $desync" $qn
|
||
|
fi
|
||
|
if [ -n "$qns" ]; then
|
||
|
f4="tcp dport 443 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target4 f4
|
||
|
nft_fw_nfqws_post4 "$f4 $desync" $qns
|
||
|
fi
|
||
|
fi
|
||
|
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn6" ] && [ "$qn6" = "$qns6" ]; then
|
||
|
nft_filter_apply_port_target f6
|
||
|
f6="$f6 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target6 f6
|
||
|
nft_fw_nfqws_post6 "$f6 $desync" $qn6
|
||
|
else
|
||
|
if [ -n "$qn6" ]; then
|
||
|
f6="tcp dport 80"
|
||
|
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f6="$f6 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target6 f6
|
||
|
nft_fw_nfqws_post6 "$f6 $desync" $qn6
|
||
|
fi
|
||
|
if [ -n "$qns6" ]; then
|
||
|
f6="tcp dport 443 $first_packet_only"
|
||
|
nft_filter_apply_ipset_target6 f6
|
||
|
nft_fw_nfqws_post6 "$f6 $desync" $qns6
|
||
|
fi
|
||
|
fi
|
||
|
;;
|
||
|
custom)
|
||
|
existf zapret_custom_firewall_nft && zapret_custom_firewall_nft
|
||
|
;;
|
||
|
esac
|
||
|
|
||
|
[ "$FLOWOFFLOAD" = 'software' -o "$FLOWOFFLOAD" = 'hardware' ] && nft_apply_flow_offloading
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
zapret_unapply_firewall_nft()
|
||
|
{
|
||
|
echo Clearing nftables
|
||
|
|
||
|
unprepare_route_localnet
|
||
|
nft_del_firewall
|
||
|
return 0
|
||
|
}
|
||
|
zapret_do_firewall_nft()
|
||
|
{
|
||
|
# $1 - 1 - add, 0 - del
|
||
|
|
||
|
if [ "$1" = 0 ] ; then
|
||
|
zapret_unapply_firewall_nft
|
||
|
else
|
||
|
zapret_apply_firewall_nft
|
||
|
fi
|
||
|
|
||
|
return 0
|
||
|
}
|