small-package/UA2F/openwrt/files/ua2f.init

198 lines
5.9 KiB
Bash
Executable File

#!/bin/sh /etc/rc.common
# Copyright (C) 2020 Zxilly <zhouxinyu1001@gmail.com>
# Copyright (C) 2021 Tianling Shen <cnsztl@immortalwrt.org>
USE_PROCD=1
START=99
NAME="ua2f"
PROG="/usr/bin/$NAME"
IPT_M="iptables -t mangle"
IPT6_M="ip6tables -t mangle"
FW_DIR="/var/etc"
FW_CONF="$FW_DIR/ua2f.include"
HAS_IPT6="$(command -v ip6tables)"
HAS_NFT="$(command -v nft)"
if type extra_command >"/dev/null" 2>&1; then
extra_command "setup_firewall"
else
EXTRA_COMMANDS="setup_firewall"
fi
setup_firewall() {
config_load "$NAME"
local handle_fw
config_get_bool handle_fw "firewall" "handle_fw" "0"
if [ "$handle_fw" -ne "1" ]; then
echo "Auto setup firewall disabled. You should set up it manually."
return 1
fi
local handle_tls handle_intranet handle_mmtls
config_get_bool handle_tls "firewall" "handle_tls" "0"
config_get_bool handle_intranet "firewall" "handle_intranet" "0"
config_get_bool handle_mmtls "firewall" "handle_mmtls" "0"
if [ -n "$HAS_NFT" ]; then
nft -f- <<-EOF
table inet ua2f {
set localaddr_v4 {
type ipv4_addr;
flags interval;
auto-merge;
elements = {
0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8,
169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24,
192.0.2.0/24, 192.31.196.0/24, 192.52.193.0/24,
192.88.99.0/24, 192.168.0.0/16, 192.175.48.0/24,
198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24,
224.0.0.0/4, 240.0.0.0/4
};
}
set localaddr_v6 {
type ipv6_addr;
flags interval;
auto-merge;
elements = {
::/128, ::1/128, ::ffff:0:0/96, 100::/64, 64:ff9b::/96,
2001::/32, 2001:10::/28, 2001:20::/28, 2001:db8::/28, 2002::/16,
fc00::/7, fe80::/10, ff00::/8
};
}
chain prerouting {
type filter hook prerouting priority mangle -5; policy accept;
$([ "$handle_intranet" -ne "1" ] || echo 'ip daddr @localaddr_v4 counter return;')
$([ "$handle_intranet" -ne "1" ] || echo 'ip6 daddr @localaddr_v6 counter return;')
tcp dport 22 counter return comment "!ua2f: bypass SSH";
$([ "$handle_tls" -eq "1" ] || echo 'tcp dport 443 counter return comment "!ua2f: bypass HTTPS";')
tcp dport 80 counter ct mark set 44;
ct mark 43 counter return comment "!ua2f: bypass non-http stream";
meta l4proto tcp ct direction original counter queue num 10010 bypass;
}
}
EOF
else
# Flush existing rules
$IPT_M -D FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f 2>"/dev/null"
if $IPT_M -N ua2f; then
if [ "$handle_intranet" -ne "1" ]; then
$IPT_M -A ua2f -d 10.0.0.0/8 -j RETURN
$IPT_M -A ua2f -d 172.16.0.0/12 -j RETURN
$IPT_M -A ua2f -d 192.168.0.0/16 -j RETURN
$IPT_M -A ua2f -d 0.0.0.0/8 -j RETURN
$IPT_M -A ua2f -d 127.0.0.0/8 -j RETURN
$IPT_M -A ua2f -d 169.254.0.0/16 -j RETURN
$IPT_M -A ua2f -d 224.0.0.0/4 -j RETURN
$IPT_M -A ua2f -d 240.0.0.0/4 -j RETURN # 不处理流向保留地址的包
fi
[ "$handle_tls" -eq "1" ] || $IPT_M -A ua2f -p tcp --dport 443 -j RETURN # 不处理 HTTPS
$IPT_M -A ua2f -p tcp --dport 80 -j CONNMARK --set-mark 44
$IPT_M -A ua2f -m connmark --mark 43 -j RETURN # 不处理标记为非 http 的流
[ "$handle_mmtls" -eq "1" ] || $IPT_M -A ua2f -p tcp --dport 80 -m string --string "/mmtls/" --algo bm -j RETURN # 不处理微信的mmtls
$IPT_M -A ua2f -j NFQUEUE --queue-num 10010 --queue-bypass
fi
$IPT_M -A FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f
if [ -n "$HAS_IPT6" ]; then
# Flush existing rules
$IPT6_M -D FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f 2>"/dev/null"
if $IPT6_M -N ua2f; then
if [ "$handle_intranet" -ne "1" ]; then
$IPT6_M -A ua2f -d ::/128 -j RETURN
$IPT6_M -A ua2f -d ::1/128 -j RETURN
$IPT6_M -A ua2f -d ::ffff:0:0/96 -j RETURN
$IPT6_M -A ua2f -d 100::/64 -j RETURN
$IPT6_M -A ua2f -d 64:ff9b::/96 -j RETURN
$IPT6_M -A ua2f -d 2001::/32 -j RETURN
$IPT6_M -A ua2f -d 2001:10::/28 -j RETURN
$IPT6_M -A ua2f -d 2001:20::/28 -j RETURN
$IPT6_M -A ua2f -d 2001:db8::/28 -j RETURN
$IPT6_M -A ua2f -d 2002::/16 -j RETURN
$IPT6_M -A ua2f -d fc00::/7 -j RETURN
$IPT6_M -A ua2f -d fe80::/10 -j RETURN
$IPT6_M -A ua2f -d ff00::/8 -j RETURN # 不处理流向保留地址的包
fi
[ "$handle_tls" -eq "1" ] || $IPT6_M -A ua2f -p tcp --dport 443 -j RETURN # 不处理 HTTPS
$IPT6_M -A ua2f -p tcp --dport 80 -j CONNMARK --set-mark 44
$IPT6_M -A ua2f -m connmark --mark 43 -j RETURN # 不处理标记为非 http 的流
[ "$handle_mmtls" -eq "1" ] || $IPT6_M -A ua2f -p tcp --dport 80 -m string --string "/mmtls/" --algo bm -j RETURN # 不处理微信的mmtls
$IPT6_M -A ua2f -j NFQUEUE --queue-num 10010 --queue-bypass
fi
$IPT6_M -A FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f
fi
fi
}
start_service() {
config_load "$NAME"
local enabled
config_get_bool enabled "enabled" "enabled" "0"
if [ "$enabled" -ne "1" ]; then
echo "UA2F disabled. You should enable it manually."
return 1
fi
procd_open_instance "$NAME"
procd_set_param command "$PROG"
local handle_fw
config_get_bool handle_fw "firewall" "handle_fw" "0"
if [ "$handle_fw" -eq "1" ]; then
setup_firewall
[ -n "$HAS_NFT" ] || {
mkdir -p "$FW_DIR"
echo -e "/etc/init.d/$NAME setup_firewall" > "$FW_CONF"
}
fi
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param respawn
procd_close_instance
}
stop_service() {
if [ -n "$HAS_NFT" ]; then
nft flush table inet ua2f
nft delete table inet ua2f
else
$IPT_M -D FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f 2>"/dev/null"
$IPT_M -F ua2f 2>"/dev/null"
$IPT_M -X ua2f 2>"/dev/null"
if [ -n "$HAS_IPT6" ]; then
$IPT6_M -D FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f 2>"/dev/null"
$IPT6_M -F ua2f 2>"/dev/null"
$IPT6_M -X ua2f 2>"/dev/null"
fi
echo > "$FW_CONF"
fi
}
reload_service() {
stop
start
}
service_triggers() {
procd_add_reload_trigger "$NAME"
}