198 lines
5.9 KiB
Bash
Executable File
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"
|
|
}
|