#!/bin/sh /etc/rc.common # Copyright (c) 2019-2026 vernesong START=99 STOP=15 USE_PROCD=1 . $IPKG_INSTROOT/usr/share/openclash/openclash_ps.sh . $IPKG_INSTROOT/usr/share/openclash/ruby.sh . $IPKG_INSTROOT/usr/share/openclash/log.sh . $IPKG_INSTROOT/usr/share/openclash/uci.sh . $IPKG_INSTROOT/usr/share/openclash/openclash_curl.sh [ -f /etc/openwrt_release ] && { FW4=$(command -v fw4) DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')" if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then DNSMASQ_CONF_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID")" else DNSMASQ_CONF_DIR="/tmp/dnsmasq.d" fi DNSMASQ_CONF_DIR=${DNSMASQ_CONF_DIR%*/} } CLASH="/etc/openclash/clash" CLASH_CONFIG="/etc/openclash" CRON_FILE="/etc/crontabs/root" CACHE_PATH="/etc/openclash/cache.db" LOG_FILE="/tmp/openclash.log" START_LOG="/tmp/openclash_start.log" PROXY_FWMARK="0x162" PROXY_ROUTE_TABLE="0x162" QUICK_START_CHECK=false QUICK_START=true add_cron() { [ "$(tail -n1 /etc/crontabs/root | wc -l)" -eq 0 ] && [ -n "$(cat /etc/crontabs/root 2>/dev/null)" ] && echo >> /etc/crontabs/root [ -z "$(grep "openclash.sh" "$CRON_FILE" 2>/dev/null)" ] && { [ "$(uci_get_config "auto_update")" -eq 1 ] && [ "$(uci_get_config "config_auto_update_mode")" -ne 1 ] && echo "0 $(uci_get_config "auto_update_time" || 1) * * $(uci_get_config "config_update_week_time" || 0) /usr/share/openclash/openclash.sh #openclash-cron-task" >> $CRON_FILE } [ -z "$(grep "openclash_geo.sh" "$CRON_FILE" 2>/dev/null)" ] && { [ "$(uci_get_config "geo_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geo_update_day_time" || 1) * * $(uci_get_config "geo_update_week_time" || 0) /usr/share/openclash/openclash_geo.sh ipdb #openclash-cron-task" >> $CRON_FILE [ "$(uci_get_config "geosite_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geosite_update_day_time" || 1) * * $(uci_get_config "geosite_update_week_time" || 0) /usr/share/openclash/openclash_geo.sh geosite #openclash-cron-task" >> $CRON_FILE [ "$(uci_get_config "geoip_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geoip_update_day_time" || 1) * * $(uci_get_config "geoip_update_week_time" || 0) /usr/share/openclash/openclash_geo.sh geoip #openclash-cron-task" >> $CRON_FILE [ "$(uci_get_config "geoasn_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geoasn_update_day_time" || 1) * * $(uci_get_config "geoasn_update_week_time" || 0) /usr/share/openclash/openclash_geo.sh geoasn #openclash-cron-task" >> $CRON_FILE } [ -z "$(grep "openclash_chnroute.sh" "$CRON_FILE" 2>/dev/null)" ] && { [ "$(uci_get_config "chnr_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "chnr_update_day_time" || 1) * * $(uci_get_config "chnr_update_week_time" || 0) /usr/share/openclash/openclash_chnroute.sh #openclash-cron-task" >> $CRON_FILE } [ -z "$(grep "/etc/init.d/openclash" "$CRON_FILE" 2>/dev/null)" ] && { [ "$(uci_get_config "auto_restart")" -eq 1 ] && echo "0 $(uci_get_config "auto_restart_day_time" || 1) * * $(uci_get_config "auto_restart_week_time" || 0) /etc/init.d/openclash restart #openclash-cron-task" >> $CRON_FILE } config_load "openclash" config_foreach add_overwrite_cron "config_overwrite" crontab $CRON_FILE start_watchdog } del_cron() { sed -i '/#openclash-cron-task/d' $CRON_FILE sed -i '/#openclash-overwrite-download/d' $CRON_FILE /etc/init.d/cron restart } >/dev/null 2>&1 save_dnsmasq_server() { if [ -z "$1" ] || [ "$1" == "127.0.0.1#${dns_port}" ]; then return fi uci -q add_list openclash.config.dnsmasq_server="$1" } set_dnsmasq_server() { if [ -z "$1" ] || [ "$1" == "127.0.0.1#${dns_port}" ]; then return fi uci -q add_list dhcp.@dnsmasq[0].server="$1" } load_ip_route_pass() { local settype nftflag if dnsmasq --version | grep -q 'Compile time options:.* nftset'; then settype="nftset" nftflag="inet#fw4#" else settype="ipset" [ -n "$FW4" ] && LOG_WARN "Dnsmasq not Support nftset, Use ipset..." fi if [ -n "$FW4" ]; then if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then if [ "$enable_redirect_dns" != "2" ]; then mkdir -p ${DNSMASQ_CONF_DIR} if [ "$settype" = "nftset" ]; then nft add set inet fw4 china_ip_route_pass '{ type ipv4_addr; flags interval; auto-merge; }' else ipset -! create china_ip_route_pass hash:net family inet hashsize 1024 maxelem 1000000 fi awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("'${settype}'=/%s/'${nftflag}'china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf for ip in $(uci_get_config "china_ip_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("'${settype}'=/%s/'${nftflag}'china_ip_route_pass'" "'\n",$0)}' done >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf fi fi if [ "$ipv6_enable" -eq 1 ]; then if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then if [ "$enable_redirect_dns" != "2" ]; then mkdir -p ${DNSMASQ_CONF_DIR} if [ "$settype" = "nftset" ]; then nft add set inet fw4 china_ip6_route_pass '{ type ipv6_addr; flags interval; auto-merge; }' else ipset -! create china_ip6_route_pass hash:net family inet6 hashsize 1024 maxelem 1000000 fi awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("'${settype}'=/%s/'${nftflag}'china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf for ip in $(uci_get_config "china_ip6_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("'${settype}'=/%s/'${nftflag}'china_ip_route_pass'" "'\n",$0)}' done >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf #Prevent domain repeat for i in `grep -wf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf` do if [ -n "$nftflag" ]; then sed -i "s:${i}:${i},6#${nftflag}china_ip6_route_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf else sed -i "s:${i}:${i},china_ip6_route_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf fi sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf done if [ -n "$nftflag" ]; then sed -i "s/\/${nftflag}/\/4#${nftflag}/g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf sed -i "s/${nftflag}china_ip_route_pass/6#${nftflag}china_ip6_route_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf else sed -i "s/china_ip_route_pass/china_ip6_route_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf fi fi fi fi else if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then if [ "$enable_redirect_dns" != "2" ]; then mkdir -p ${DNSMASQ_CONF_DIR} ipset -! create china_ip_route_pass hash:net family inet hashsize 1024 maxelem 1000000 awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("ipset=/%s/china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf for ip in $(uci_get_config "china_ip_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("ipset=/%s/china_ip_route_pass'" "'\n",$0)}' done >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf fi fi if [ "$ipv6_enable" -eq 1 ]; then if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then if [ "$enable_redirect_dns" != "2" ]; then mkdir -p ${DNSMASQ_CONF_DIR} ipset -! create china_ip6_route_pass hash:net family inet6 hashsize 1024 maxelem 1000000 awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("ipset=/%s/china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf for ip in $(uci_get_config "china_ip6_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("ipset=/%s/china_ip_route_pass'" "'\n",$0)}' done >>${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf #Prevent domain repeat for i in `grep -wf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf` do sed -i "s:${i}:${i},china_ip6_route_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf done sed -i "s/china_ip_route_pass/china_ip6_route_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf fi fi fi fi } change_dnsmasq() { if ! /etc/init.d/dnsmasq enabled; then return fi # 区域绕过黑名单 load_ip_route_pass # 第二 DNS 服务 /usr/share/openclash/openclash_custom_domain_dns.sh if [ "$1" -eq 1 ]; then if [ "$(uci_get_config "redirect_dns")" != "1" ]; then uci -q del openclash.config.dnsmasq_server config_load "dhcp" config_list_foreach "$(uci -q show dhcp.@dnsmasq[0].server |awk -F '.' '{print $2}')" "server" save_dnsmasq_server uci -q set openclash.config.dnsmasq_noresolv="$(uci -q get dhcp.@dnsmasq[0].noresolv)" uci -q set openclash.config.dnsmasq_resolvfile="$(uci -q get dhcp.@dnsmasq[0].resolvfile)" fi uci -q del dhcp.@dnsmasq[-1].server uci -q add_list dhcp.@dnsmasq[0].server=127.0.0.1#"$dns_port" uci -q delete dhcp.@dnsmasq[0].resolvfile uci -q set dhcp.@dnsmasq[0].noresolv=1 uci -q set dhcp.@dnsmasq[0].localuse=1 uci -q set openclash.config.redirect_dns=1 uci -q set openclash.config.dnsmasq_cachesize="$(uci -q get dhcp.@dnsmasq[0].cachesize)" uci -q set dhcp.@dnsmasq[0].cachesize=0 uci -q set openclash.config.cachesize_dns=1 else # Remove residual Dnsmasq redirect left uci -q del_list dhcp.@dnsmasq[0].server="127.0.0.1#$dns_port" uci -q set openclash.config.redirect_dns=0 uci -q set openclash.config.cachesize_dns=0 fi if [ "$1" -eq 1 ] && [ "$ipv6_dns" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then #dnsmasq answer ipv6 uci -q set openclash.config.dnsmasq_filter_aaaa="$(uci -q get dhcp.@dnsmasq[0].filter_aaaa)" uci -q set dhcp.@dnsmasq[0].filter_aaaa=0 uci -q set openclash.config.filter_aaaa_dns=1 else uci -q set openclash.config.filter_aaaa_dns=0 fi uci -q commit openclash uci -q commit dhcp /etc/init.d/dnsmasq restart } >/dev/null 2>&1 revert_dnsmasq() { if ! /etc/init.d/dnsmasq enabled; then return fi redirect_dns=$(uci_get_config "redirect_dns") dnsmasq_server=$(uci_get_config "dnsmasq_server") dnsmasq_noresolv=$(uci_get_config "dnsmasq_noresolv") dnsmasq_resolvfile=$(uci_get_config "dnsmasq_resolvfile") cachesize_dns=$(uci_get_config "cachesize_dns") dnsmasq_cachesize=$(uci_get_config "dnsmasq_cachesize") filter_aaaa_dns=$(uci_get_config "filter_aaaa_dns") dnsmasq_filter_aaaa=$(uci_get_config "dnsmasq_filter_aaaa") default_resolvfile=$(uci_get_config "default_resolvfile") rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_custom_domain.conf rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf [ "$redirect_dns" -eq 1 ] && { uci -q del dhcp.@dnsmasq[-1].server [ -n "$dnsmasq_server" ] && { config_load "openclash" config_list_foreach "config" "dnsmasq_server" set_dnsmasq_server } if [ "$dnsmasq_noresolv" == "0" ] || [ -z "$dnsmasq_noresolv" ] || [ -z "$(uci -q show dhcp.@dnsmasq[0].server)" ]; then uci -q set dhcp.@dnsmasq[0].noresolv=0 if [ -n "$dnsmasq_resolvfile" ] && [ -n "$(grep nameserver $dnsmasq_resolvfile)" ]; then uci -q set dhcp.@dnsmasq[0].resolvfile="$dnsmasq_resolvfile" elif [ -n "$default_resolvfile" ] && [ -n "$(grep nameserver $default_resolvfile)" ]; then uci -q set dhcp.@dnsmasq[0].resolvfile="$default_resolvfile" elif [ -s "/tmp/resolv.conf.d/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.d/resolv.conf.auto)" ]; then uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto uci -q set openclash.config.default_resolvfile=/tmp/resolv.conf.d/resolv.conf.auto elif [ -s "/tmp/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.auto)" ]; then uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto uci -q set openclash.config.default_resolvfile=/tmp/resolv.conf.auto else uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto uci -q set openclash.config.default_resolvfile=/tmp/resolv.conf.d/resolv.conf.auto fi uci -q set dhcp.@dnsmasq[0].localuse=1 fi } [ "$cachesize_dns" -eq 1 ] && { uci -q set dhcp.@dnsmasq[0].cachesize="$dnsmasq_cachesize" uci -q set openclash.config.cachesize_dns=0 uci -q delete openclash.config.dnsmasq_cachesize } [ "$filter_aaaa_dns" -eq 1 ] && { uci -q set dhcp.@dnsmasq[0].filter_aaaa="$dnsmasq_filter_aaaa" uci -q set openclash.config.filter_aaaa_dns=0 uci -q delete openclash.config.dnsmasq_filter_aaaa } [ "$redirect_dns" -eq 1 ] && { uci -q set openclash.config.redirect_dns=0 uci -q del openclash.config.dnsmasq_server } uci -q commit dhcp uci -q commit openclash masq_port=$(uci -q get dhcp.@dnsmasq[0].port) if [ "$(nslookup www.apple.com 127.0.0.1:${masq_port} >/dev/null 2>&1 || echo $?)" = "1" ]; then resolv_file=$(uci -q get dhcp.@dnsmasq[0].resolvfile) wan_dns=$(/usr/share/openclash/openclash_get_network.lua "dns") wan6_dns=$(/usr/share/openclash/openclash_get_network.lua "dns6") mkdir -p "$(dirname "$resolv_file")" touch "$resolv_file" if [ -n "$wan_dns" ]; then echo "# Interface lan" > "$resolv_file" for dns in $wan_dns; do echo "nameserver $dns" >> "$resolv_file" done fi if [ -n "$wan6_dns" ]; then echo "# Interface LAN6" > "$resolv_file" for dns6 in $wan6_dns; do echo "nameserver $dns6" >> "$resolv_file" done fi if [ -z "$wan_dns" ] && [ -z "$wan6_dns" ]; then cat > "$resolv_file" <<-EOF # Interface lan nameserver 119.29.29.29 nameserver 8.8.8.8 EOF fi fi /etc/init.d/dnsmasq restart } >/dev/null 2>&1 start_fail() { uci -q set openclash.config.enable=0 uci -q commit openclash stop exit 0 } sub_info_set() { local section="$1" name config_get "name" "$section" "name" "" if [ -z "$name" ]; then return fi if [ "$name" == "$2" ] && [ -n "$3" ]; then if [ "$sub_info_setted" != "1" ]; then uci -q delete openclash.$section.url fi uci -q add_list openclash.$section.url="$3" uci -q commit openclash sub_info_setted=1 fi } #获取订阅配置 sub_info_get() { local section="$1" address enabled name config_get_bool "enabled" "$section" "enabled" "1" config_get "address" "$section" "address" "" config_get "name" "$section" "name" "" if [ "$subscribe_enable" = "1" ]; then return fi if [ "$enabled" -eq 0 ]; then return fi if [ -z "$address" ]; then return fi if [ -z "$name" ]; then SUB_CONFIG_FILE="/etc/openclash/config/config.yaml" else SUB_CONFIG_FILE="/etc/openclash/config/$name.yaml" fi if [ "$SUB_CONFIG_FILE" != "$2" ]; then return fi subscribe_enable=1 } #配置文件选择 config_choose() { if [ ! -f "$RAW_CONFIG_FILE" ]; then config_load "openclash" config_foreach sub_info_get "config_subscribe" "$RAW_CONFIG_FILE" if [ "$subscribe_enable" = "1" ]; then LOG_OUT "【$RAW_CONFIG_FILE】Config File Does Not Exist, You Have Set Subscription Information, Ready To Download..." /usr/share/openclash/openclash.sh "$RAW_CONFIG_FILE" & exit 0 fi fi if [ -z "$RAW_CONFIG_FILE" ] || [ ! -f "$RAW_CONFIG_FILE" ]; then for file_name in /etc/openclash/config/* do if [ -f "$file_name" ]; then CONFIG_NAME=$(echo "$file_name" |awk -F '/' '{print $5}' 2>/dev/null) uci -q set openclash.config.config_path="/etc/openclash/config/$CONFIG_NAME" uci -q commit openclash RAW_CONFIG_FILE="/etc/openclash/config/$CONFIG_NAME" CONFIG_FILE="/etc/openclash/$CONFIG_NAME" TMP_CONFIG_FILE="/tmp/$CONFIG_NAME" LOG_ERROR "Config Not Found, Switch Config File to【$RAW_CONFIG_FILE】" break fi done fi if [ ! -f "$RAW_CONFIG_FILE" ]; then LOG_ERROR "Config Not Found" exit 0 fi CONFIG_NAME=$(echo "$RAW_CONFIG_FILE" |awk -F '/' '{print $5}' 2>/dev/null) HISTORY_PATH="/etc/openclash/history/${CONFIG_NAME%.*}.db" } >/dev/null 2>&1 config_check() { #创建启动配置 #rm -rf "/etc/openclash/*.y*" 2>/dev/null cp "$RAW_CONFIG_FILE" "$TMP_CONFIG_FILE" ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin YAML.load_file('$RAW_CONFIG_FILE'); rescue Exception => e YAML.LOG_ERROR('Unable To Parse Config File,【' + e.message + '】'); system 'rm -rf ${TMP_CONFIG_FILE}'; end " 2>/dev/null >> $LOG_FILE if [ $? -ne 0 ]; then LOG_ERROR "Ruby Works Abnormally, Please Check The Ruby Library Depends!" start_fail elif [ ! -f "$TMP_CONFIG_FILE" ] || [ ! -s "$TMP_CONFIG_FILE" ]; then LOG_ERROR "Config File Format Validation Failed..." start_fail fi } check_run_quick() { if $QUICK_START_CHECK; then return fi QUICK_START_CHECK=true cat "/tmp/openclash.change" | while read -r i; do file_path=$(echo "$i" |awk -F ' #edited time# ' '{print $1}') if [ -z "$(grep "$file_path #edited time# $(date -r "$file_path")$" "/tmp/openclash.change")" ]; then LOG_TIP "Because of the file【 $file_path 】modificated, Pause quick start..." rm -rf /tmp/openclash.change break fi done if [ ! -f "/tmp/openclash.change" ]; then QUICK_START=false fi } >/dev/null 2>&1 write_run_quick() { : > "/tmp/openclash.change" { echo "/etc/config/openclash" echo "$RAW_CONFIG_FILE" echo "$CONFIG_FILE" ls -d /etc/openclash/custom/* 2>/dev/null ls -d /etc/openclash/overwrite/* 2>/dev/null } | while read -r file; do echo "$file #edited time# $(date -r "$file")" >> "/tmp/openclash.change" done } >/dev/null 2>&1 #运行模式处理 do_run_mode() { en_mode=$(uci_get_config "en_mode") if [ "$en_mode" = "fake-ip-tun" ]; then en_mode_tun="1" en_mode="fake-ip" fi if [ "$en_mode" = "redir-host-tun" ]; then en_mode_tun="1" en_mode="redir-host" fi if [ "$en_mode" = "redir-host-mix" ]; then en_mode_tun="2" en_mode="redir-host" fi if [ "$en_mode" = "fake-ip-mix" ]; then en_mode_tun="2" en_mode="fake-ip" fi } do_run_file() { #Some MIPS devices file system cound not use db source "/etc/openwrt_release" [ "$small_flash_memory" == "1" ] || [ -n "$(echo $core_version |grep mips)" ] || [ -n "$(echo $DISTRIB_ARCH |grep mips)" ] || [ -n "$(opkg status libc 2>/dev/null |grep 'Architecture' |awk -F ': ' '{print $2}' |grep mips)" ] || [ -n "$(apk list libc 2>/dev/null |grep mips)" ] && mkdir -p /tmp/etc/openclash && CACHE_PATH="/tmp/etc/openclash/cache.db" [ -f "/etc/openclash/geosite.dat" ] && { mv "/etc/openclash/geosite.dat" "/etc/openclash/GeoSite.dat" } [ -f "/etc/openclash/geoip.dat" ] && { mv "/etc/openclash/geoip.dat" "/etc/openclash/GeoIP.dat" } if [ "$small_flash_memory" != "1" ]; then meta_core_path="/etc/openclash/core/clash_meta" ipdb_path="/etc/openclash/Country.mmdb" chnr_path="/etc/openclash/china_ip_route.ipset" chnr6_path="/etc/openclash/china_ip6_route.ipset" geosite_path="/etc/openclash/GeoSite.dat" geoip_path="/etc/openclash/GeoIP.dat" asn_path="/etc/openclash/ASN.mmdb" lgbm_path="/etc/openclash/Model.bin" mv "/tmp/etc/openclash/Country.mmdb" "$ipdb_path" mv "/tmp/etc/openclash/china_ip_route.ipset" "$chnr_path" mv "/tmp/etc/openclash/china_ip6_route.ipset" "$chnr6_path" mv "/tmp/etc/openclash/GeoSite.dat" "$geosite_path" mv "/tmp/etc/openclash/GeoIP.dat" "$geoip_path" mv "/tmp/etc/openclash/ASN.mmdb" "$asn_path" mv "/tmp/etc/openclash/Model.bin" "$lgbm_path" mv "/tmp/etc/openclash/core/" "/etc/openclash" if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then rm -rf "/tmp/etc/openclash" fi else meta_core_path="/tmp/etc/openclash/core/clash_meta" ipdb_path="/tmp/etc/openclash/Country.mmdb" chnr_path="/tmp/etc/openclash/china_ip_route.ipset" chnr6_path="/tmp/etc/openclash/china_ip6_route.ipset" geosite_path="/tmp/etc/openclash/GeoSite.dat" geoip_path="/tmp/etc/openclash/GeoIP.dat" asn_path="/tmp/etc/openclash/ASN.mmdb" lgbm_path="/tmp/etc/openclash/Model.bin" [ ! -h "/etc/openclash/Country.mmdb" ] && mv "/etc/openclash/Country.mmdb" "$ipdb_path" [ ! -h "/etc/openclash/china_ip_route.ipset" ] && mv "/etc/openclash/china_ip_route.ipset" "$chnr_path" [ ! -h "/etc/openclash/china_ip6_route.ipset" ] && mv "/etc/openclash/china_ip6_route.ipset" "$chnr6_path" [ ! -h "/etc/openclash/GeoSite.dat" ] && mv "/etc/openclash/GeoSite.dat" "$geosite_path" [ ! -h "/etc/openclash/GeoIP.dat" ] && mv "/etc/openclash/GeoIP.dat" "$geoip_path" [ ! -h "/etc/openclash/ASN.mmdb" ] && mv "/etc/openclash/ASN.mmdb" "$asn_path" [ ! -h "/etc/openclash/Model.bin" ] && mv "/etc/openclash/Model.bin" "$lgbm_path" mv "/etc/openclash/core/" "/tmp/etc/openclash" fi rm -rf "/etc/openclash/cache.db" rm -rf "/etc/openclash/clash" ln -s "$meta_core_path" /etc/openclash/clash if [ -n "$OIX_TOKEN" ]; then core_type="Oix" elif [ "$smart_enable" -eq 1 ] || [ "$core_type" == "Smart" ]; then core_type="Smart" else core_type="Meta" fi if [ -f "$CLASH" ] && [ ! -x "$CLASH" ]; then chmod 4755 "$CLASH" chown root:root "$CLASH" fi [ ! -f "$CLASH" ] || { [ "$core_type" = "Smart" ] && [ -z "$($CLASH -v | grep 'smart')" ] && [ -z "$($CLASH -v | grep 'oix')" ]; } || { [ "$core_type" = "Oix" ] && [ -z "$($CLASH -v | grep 'oix')" ]; } && { LOG_TIP "【$core_type】Core is not Detected installed, Ready to Download..." /usr/share/openclash/openclash_core.sh "$core_type" if [ ! -f "$meta_core_path" ]; then start_fail fi } if [ "$china_ip_route" != "0" ] || [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then LOG_TIP "Detected that the Chnroute Cidr is not Installed, Ready to Download..." /usr/share/openclash/openclash_chnroute.sh fi if [ -n "$FW4" ]; then if [ -z "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -z "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then LOG_TIP "Detected that the Chnroute Cidr List Format is wrong, Ready to Reformat..." /usr/share/openclash/openclash_chnroute.sh if [ -z "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -z "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then start_fail fi fi else if [ -n "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -n "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then LOG_TIP "Detected that the Chnroute Cidr List Format is wrong, Ready to Reformat..." /usr/share/openclash/openclash_chnroute.sh if [ -n "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -n "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then start_fail fi fi fi if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then start_fail fi fi [ ! -x "$meta_core_path" ] && chmod 4755 "$meta_core_path" [ -f "$ipdb_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$ipdb_path" /etc/openclash/Country.mmdb } [ -f "$geosite_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$geosite_path" /etc/openclash/GeoSite.dat } [ -f "$geoip_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$geoip_path" /etc/openclash/GeoIP.dat } [ -f "$lgbm_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$lgbm_path" /etc/openclash/Model.bin } [ -f "$chnr_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$chnr_path" /etc/openclash/china_ip_route.ipset } [ -f "$chnr6_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$chnr6_path" /etc/openclash/china_ip6_route.ipset } [ -f "$asn_path" ] && [ "$small_flash_memory" = "1" ] && { ln -s "$asn_path" /etc/openclash/ASN.mmdb } #Restore history cache if [ -f "$HISTORY_PATH" ]; then cmp -s "$CACHE_PATH" "$HISTORY_PATH" if [ "$?" -ne "0" ]; then if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then ln -s "$HISTORY_PATH" "$CACHE_PATH" else cp "$HISTORY_PATH" "$CACHE_PATH" fi fi fi if [ "$CACHE_PATH" == "/tmp/etc/openclash/cache.db" ]; then [ ! -f "$CACHE_PATH" ] && touch "$CACHE_PATH" ln -s "$CACHE_PATH" /etc/openclash/cache.db else [ ! -f "$CACHE_PATH" ] && touch "$HISTORY_PATH" ln -s "$HISTORY_PATH" "$CACHE_PATH" fi #保存启动内核类型 uci -q set openclash.config.core_type="$core_type" uci -q commit openclash } >/dev/null 2>&1 container() { [ -f "/proc/1/cgroup" ] && grep -qiE "(docker|containerd|lxc|podman|kubepods|container)" /proc/1/cgroup 2>/dev/null && return 0 [ -f "/proc/1/environ" ] && grep -qiE "(docker|containerd|lxc|podman|kubepods|container)" /proc/1/environ 2>/dev/null && return 0 [ -f "/.dockerenv" ] && return 0 env | grep -qiE "(docker|kubernetes|container)" && return 0 return 1 } check_mod() { if container; then return 0 fi # Convert module name to uppercase using POSIX-compatible syntax # BusyBox tr doesn't support [:lower:]/[:upper:], use a-z/A-Z instead module_upper=$(echo "$1" | tr a-z A-Z) if [ -f /proc/config.gz ] && zcat /proc/config.gz | grep -q "CONFIG_${module_upper}=y"; then return 0 fi if lsmod | grep -q "^$1 "; then return 0 fi modprobe $1 2>/dev/null if [ $? -eq 0 ]; then return 0 fi LOG_ERROR "【$1】module not found, please check your system depends if something abnormal!" } >/dev/null 2>&1 check_core_status() { TUN_WAIT=0 TUN_RESTART=1 CORE_WAIT=0 CORE_HTTP_CODE=0 while ( [ -z "$(pidof clash)" ] && [ "$CORE_WAIT" -le 10 ] ) do sleep 1 let CORE_WAIT++ done if [ -n "$en_mode_tun" ] || [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then check_mod "tun" if [ -n "$en_mode_tun" ]; then ip_="ip" else ip_="ip -6" fi #wait 300s most for core start while ( [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep utun)" ] && [ "$TUN_WAIT" -le 300 ] ) do $ip_ link set utun up let TUN_WAIT++ sleep 1 done if [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep utun)" ] && [ "$TUN_WAIT" -gt 300 ]; then while ( [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep utun)" ] && [ "$TUN_RESTART" -le 3 ] ) do LOG_WARN "TUN Interface Start Failed, Try to Restart Again..." start_run_core let TUN_RESTART++ sleep 300 done if [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep utun)" ] && [ "$TUN_RESTART" -gt 3 ]; then LOG_ERROR "TUN Interface Start Failed, Please Check The Dependence or Try to Restart Again!" LOG_ERROR "Core Initial Configuration Timeout, Please Check The Log Infos!" start_fail fi fi if [ -n "$(pidof clash)" ]; then while ( [ -n "$(pidof clash)" ] && [ -n "$(ip -6 rule show |grep 2022)" ] && [ "$CORE_WAIT" -le 10 ] ) do ip -6 rule del oif utun table 2022 ip -6 route del default dev utun table 2022 let CORE_WAIT++ done if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip -6 route add default dev utun table "$PROXY_ROUTE_TABLE" ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888 fi if [ -n "$en_mode_tun" ]; then ip route add default dev utun table "$PROXY_ROUTE_TABLE" ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888 fi fi else reg4='^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$' while ( [ -n "$(pidof clash)" ] && [ "$CORE_HTTP_CODE" != "200" ] && [ "$TUN_WAIT" -le 300 ] && [ -n "$(echo ${lan_ip} | grep -Eo ${reg4})" ] ) do CORE_HTTP_CODE=$(curl -m 5 -o /dev/null -s -w '%{http_code}' -H 'Content-Type: application/json' -H "Authorization: Bearer ${da_password}" -XGET http://${lan_ip}:${cn_port}/group) let TUN_WAIT++ sleep 1 done if [ -z "$(echo ${lan_ip} | grep -Eo ${reg4})" ]; then LOG_ERROR "LAN IP Address Get Error, Please Check The LAN Interface Setting or Choose the Correct Interface in the Setting!" start_fail fi if [ -n "$(pidof clash)" ] && [ "$CORE_HTTP_CODE" != "200" ]; then LOG_ERROR "Core Initial Configuration Timeout, Please Check The Log Infos!" start_fail fi fi if [ -z "$(pidof clash)" ]; then LOG_ERROR "Core Start Failed, Please Check The Log Infos!" start_fail fi # redirect dns setting after core started, prevent core dns lookup failure if [ "$1" == "start" ]; then change_dnsmasq "$enable_redirect_dns" set_firewall LOG_TIP "OpenClash Start Successful!" else set_firewall LOG_TIP "Firewall Reload Successful!" fi write_run_quick } >/dev/null 2>&1 start_run_core() { ulimit -SHn 1000000 ulimit -v unlimited ulimit -u unlimited if ! $QUICK_START; then mv "$TMP_CONFIG_FILE" "$CONFIG_FILE" rm -rf "$TMP_CONFIG_FILE" fi chown root:root "$CLASH" procd_open_instance "openclash" procd_set_param env SAFE_PATHS=/usr/share/openclash:/etc/ssl procd_append_param env CLASH_AGE_SECRET_KEY="$SECRET_KEY" procd_append_param env OIX_TOKEN="$OIX_TOKEN" procd_append_param env OIX_PARAMS="$OIX_PARAMS" procd_set_param command /bin/sh -c "exec $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1" procd_set_param user "root" procd_set_param group "nogroup" procd_set_param limits nproc="unlimited" as="unlimited" memlock="unlimited" nofile="1000000 1000000" procd_set_param respawn 300 5 3 procd_set_param stderr 1 procd_set_param no_new_privs 1 procd_close_instance } >/dev/null 2>&1 #防火墙设置部分 nft_ac_add() { if [ -z "$1" ]; then return fi nft add element inet fw4 "$2" { "$1" } [ -n "$3" ] && nft add element inet fw4 "$3" { "$1" } } >/dev/null 2>&1 ac_add() { if [ -z "$1" ]; then return fi ipset add "$2" "$1" [ -n "$3" ] && ipset add "$3" "$1" } >/dev/null 2>&1 wan_name_add() { if [ -z "$1" ]; then return fi if [ -n "$wan_ints" ]; then wan_ints="$wan_ints $1" else wan_ints="$1" fi } wan6_name_add() { if [ -z "$1" ]; then return fi if [ -n "$wan6_ints" ]; then wan6_ints="$wan6_ints $1" else wan6_ints="$1" fi } upnp_exclude() { if [ -s "$upnp_lease_file" ]; then cat "$upnp_lease_file" |while read -r line do if [ -n "$line" ]; then upnp_ip=$(echo "$line" |awk -F ':' '{print $3}') upnp_dp=$(echo "$line" |awk -F ':' '{print $4}') upnp_type=$(echo "$line" |awk -F ':' '{print $1}' |tr '[A-Z]' '[a-z]') if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then if [ -n "$FW4" ]; then if [ -z "$(nft list chain inet fw4 openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then nft add rule inet fw4 openclash_upnp ip saddr { "$upnp_ip" } "$upnp_type" sport "$upnp_dp" counter return fi else if [ -z "$(iptables -t mangle -nL openclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then iptables -t mangle -A openclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN fi fi fi fi done fi } >/dev/null 2>&1 ipv6_suffix_to_nft_format() { local ipv6_with_prefix="$1" if ! echo "$ipv6_with_prefix" | grep -q '/'; then echo "{ $ipv6_with_prefix }" return fi local addr="${ipv6_with_prefix%%/*}" local suffix="${ipv6_with_prefix##*/}" if echo "$suffix" | grep -qE '^[0-9]+$'; then echo "${addr}/${suffix}" return fi echo "& ${suffix} == ${addr}" } 2>/dev/null fw4_has_dns_hijack_rule() { local chain="$1" local family="$2" case "$family" in ipv6) nft list chain inet fw4 "$chain" 2>/dev/null |grep 'OpenClash DNS Hijack' |grep -Eq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr' ;; *) nft list chain inet fw4 "$chain" 2>/dev/null |grep 'OpenClash DNS Hijack' |grep -Evq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr' ;; esac } firewall_lan_ac_traffic() { local src_port sport_rule dscp_rule sport_ipt dscp_ipt src_ip src_ip_v6 proto target target_ enabled family dscp rule output_rule comment config_get "src_port" "$section" "src_port" "0-65535" config_get "src_ip" "$section" "src_ip" "" config_get "proto" "$section" "proto" "both" config_get "target" "$section" "target" "return" config_get_bool "enabled" "$section" "enabled" "0" config_get "family" "$section" "family" "both" config_get "dscp" "$section" "dscp" "" config_get "interface" "$section" "interface" "" config_get "user" "$section" "user" "" config_get "comment" "$section" "comment" "lan_ac_traffic" if [ "${enabled}" == "0" ]; then return fi local e_udp=false local e_tcp=false if [ "${proto}" == "tcp" ]; then e_tcp=true; fi if [ "${proto}" == "udp" ]; then e_udp=true; fi if [ "${proto}" == "both" ]; then e_tcp=true; e_udp=true; fi if [ -n "$FW4" ]; then if [ "${src_ip}" == "localnetwork" ]; then src_ip="ip saddr @localnetwork" src_ip_v6="ip6 saddr @localnetwork6" else if [ -n "${src_ip}" ]; then src_ip_v6="ip6 saddr $(ipv6_suffix_to_nft_format "${src_ip}")" src_ip="ip saddr { ${src_ip} }" fi fi if [ -n "${src_port}" ]; then sport_rule="sport ${src_port}" fi if [ -n "${interface}" ]; then interface_rule="iifname \"${interface}\"" fi if [ -n "${user}" ]; then user_rule="meta skuid ${user}" fi if [ -n "${dscp}" ]; then dscp_rule="ip dscp ${dscp}" fi if [ "${target}" == "drop" ]; then target_="return" else target_="${target}" fi rule_target_v4_="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv4} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target_} comment ${comment}" output_rule_target_v4_="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target_} comment ${comment}" rule_target_v4="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv4} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target} comment ${comment}" output_rule_target_v4="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target} comment ${comment}" rule_target_v6_="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv6} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target_} comment ${comment}" output_rule_target_v6_="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target_} comment ${comment}" rule_target_v6="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv6} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target} comment ${comment}" output_rule_target_v6="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target} comment ${comment}" if [ "${family}" == "both" ] || [ "${family}" == "ipv4" ]; then if [ -z "${en_mode_tun}" ] || [ "${en_mode_tun}" -eq 2 ]; then if $e_tcp ; then nft insert rule inet fw4 openclash_output position 0 tcp ${output_rule_target_v4_} [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash position 0 tcp ${rule_target_v4_} fi if $e_udp ; then nft insert rule inet fw4 openclash_mangle_output position 0 udp ${output_rule_target_v4} [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_mangle position 0 udp ${rule_target_v4} fi elif [ "${en_mode_tun}" -eq 1 ]; then if $e_tcp ; then nft insert rule inet fw4 openclash_mangle_output position 0 tcp ${output_rule_target_v4} [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_mangle position 0 tcp ${rule_target_v4} fi if $e_udp ; then nft insert rule inet fw4 openclash_mangle_output position 0 udp ${output_rule_target_v4} [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_mangle position 0 udp ${rule_target_v4} fi fi if $e_tcp ; then nft insert rule inet fw4 openclash_post position 0 tcp ${output_rule_target_v4_} fi if $e_udp ; then nft insert rule inet fw4 openclash_post position 0 udp ${output_rule_target_v4_} fi fi if [ "${ipv6_enable}" -eq 1 ]; then if [ "${family}" == "both" ] || [ "${family}" == "ipv6" ]; then if $e_tcp ; then [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_v6 position 0 tcp ${rule_target_v6_} nft insert rule inet fw4 openclash_output_v6 position 0 tcp ${output_rule_target_v6_} [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_mangle_v6 position 0 tcp ${rule_target_v6} nft insert rule inet fw4 openclash_mangle_output_v6 position 0 tcp ${output_rule_target_v6} nft insert rule inet fw4 openclash_post_v6 position 0 tcp ${output_rule_target_v6_} fi if $e_udp ; then [ -z "${user_rule}" ] && nft insert rule inet fw4 openclash_mangle_v6 position 0 udp ${rule_target_v6} nft insert rule inet fw4 openclash_mangle_output_v6 position 0 udp ${output_rule_target_v6} nft insert rule inet fw4 openclash_post_v6 position 0 udp ${output_rule_target_v6_} fi fi fi else if [ "${src_ip}" == "localnetwork" ]; then src_ip="-m set --match-set localnetwork src" src_ip_v6="-m set --match-set localnetwork6 src" else if [ -n "${src_ip}" ]; then src_ip_v6="-s ${src_ip}" src_ip="-s ${src_ip}" fi fi src_port=$(echo ${src_port} | sed "s/-/:/g" 2>/dev/null) if [ -n "${src_port}" ]; then sport_ipt="--sport ${src_port}" fi if [ "${target}" == "accept" ]; then target="ACCEPT" target_="ACCEPT"; fi if [ "${target}" == "return" ]; then target="RETURN" target_="RETURN"; fi if [ "${target}" == "drop" ]; then target="DROP" target_="RETURN"; fi if [ -n "${interface}" ]; then interface_rule="-i ${interface}" fi if [ -n "${user}" ]; then user_rule="-m owner --uid-owner ${user}" fi if [ -n "${dscp}" ]; then if iptables -m dscp --help >/dev/null 2>&1; then dscp_ipt="-m dscp --dscp ${dscp}" else LOG_WARN "iptables DSCP module not available, please try DCSP rule by core instead, skipping DSCP rule for【${comment}】" fi fi rule_target_v4_="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}" output_rule_target_v4_="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}" rule_target_v4="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}" output_rule_target_v4="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}" rule_target_v6_="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}" output_rule_target_v6_="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}" rule_target_v6="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}" output_rule_target_v6="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}" if [ "${family}" == "both" ] || [ "${family}" == "ipv4" ]; then if [ -z "${en_mode_tun}" ] || [ "${en_mode_tun}" -eq 2 ]; then if $e_tcp ; then iptables -t nat -I openclash_output -p tcp ${output_rule_target_v4_} [ -z "${user_rule}" ] && iptables -t nat -I openclash -p tcp ${rule_target_v4_} fi if $e_udp ; then iptables -t mangle -I openclash_output -p udp ${output_rule_target_v4} [ -z "${user_rule}" ] && iptables -t mangle -I openclash -p udp ${rule_target_v4} fi elif [ "${en_mode_tun}" -eq 1 ]; then if $e_tcp ; then iptables -t mangle -I openclash_output -p tcp ${output_rule_target_v4} [ -z "${user_rule}" ] && iptables -t mangle -I openclash -p tcp ${rule_target_v4} fi if $e_udp ; then iptables -t mangle -I openclash_output -p udp ${output_rule_target_v4} [ -z "${user_rule}" ] && iptables -t mangle -I openclash -p udp ${rule_target_v4} fi fi if $e_tcp ; then iptables -t nat -I openclash_post -p tcp ${output_rule_target_v4_} fi if $e_udp ; then iptables -t nat -I openclash_post -p udp ${output_rule_target_v4_} fi fi if [ "${ipv6_enable}" -eq 1 ]; then if [ "${family}" == "both" ] || [ "${family}" == "ipv6" ]; then if $e_tcp ; then [ -z "${user_rule}" ] && ip6tables -t nat -I openclash -p tcp ${rule_target_v6_} ip6tables -t nat -I openclash_output -p tcp ${output_rule_target_v6_} [ -z "${user_rule}" ] && ip6tables -t mangle -I openclash -p tcp ${rule_target_v6} ip6tables -t mangle -I openclash_output -p tcp ${output_rule_target_v6} ip6tables -t nat -I openclash_post -p tcp ${output_rule_target_v6_} fi if $e_udp ; then [ -z "${user_rule}" ] && ip6tables -t mangle -I openclash -p udp ${rule_target_v6} ip6tables -t mangle -I openclash_output -p udp ${output_rule_target_v6} ip6tables -t nat -I openclash_post -p udp ${output_rule_target_v6_} fi fi fi fi } set_firewall() { if [ -z "$(uci -q get firewall.openclash)" ] || [ -z "$(uci -q get ucitrack.@openclash[-1].init)" ]; then uci -q delete ucitrack.@openclash[-1] uci -q add ucitrack openclash uci -q set ucitrack.@openclash[-1].init=openclash uci -q commit ucitrack uci -q delete firewall.openclash uci -q set firewall.openclash=include uci -q set firewall.openclash.type=script uci -q set firewall.openclash.path=/var/etc/openclash.include [ -n "$FW4" ] || uci -q set firewall.openclash.reload=1 uci -q commit firewall fi mkdir -p /var/etc cat > "/var/etc/openclash.include" <<-EOF /etc/init.d/openclash reload "firewall" EOF #common ports if [ -n "$common_ports" ] && [ "$common_ports" != "0" ]; then if [ "$common_ports" = "1" ]; then common_port="21 22 23 53 80 123 143 194 443 465 587 853 993 995 998 2052 2053 2082 2083 2086 2095 2096 2197 5222 5223 5228 5229 5230 8080 8443 8880 8888 8889" else common_port=$common_ports fi fi case $enable_redirect_dns in "1") LOG_TIP "DNS Hijacking Mode is Dnsmasq Redirect..." ;; "2") LOG_TIP "DNS Hijacking Mode is Firewall Redirect..." ;; *) LOG_TIP "DNS Hijacking is Disabled..." esac if [ "$ipv6_enable" -eq 1 ]; then case $ipv6_mode in "1") LOG_TIP "IPv6 Proxy Mode is Redirect..." ;; "2") LOG_TIP "IPv6 Proxy Mode is TUN..." ;; "3") LOG_TIP "IPv6 Proxy Mode is Mix..." ;; *) LOG_TIP "IPv6 Proxy Mode is TProxy..." esac fi #NFTABLES if [ -n "$FW4" ]; then LOG_TIP "Firewall4 was Detected, Use NFTABLE Rules..." #china ip route if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then nft 'flush set inet fw4 china_ip_route' nft -f '/etc/openclash/china_ip_route.ipset' CHNROUTE_WAIT=0 while ( [ -z "$(nft list sets |grep "set china_ip_route {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] ) do sleep 3 nft -f '/etc/openclash/china_ip_route.ipset' let CHNROUTE_WAIT++ done if [ "$enable_redirect_dns" != "2" ]; then echo "add set inet fw4 china_ip_route_pass { type ipv4_addr; flags interval; auto-merge; }" >/tmp/openclash_china_ip_route_pass.list [ -z `(awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list)` ] || { echo "define china_ip_route_pass = {" >>/tmp/openclash_china_ip_route_pass.list awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s,\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list |sed '$ s/.$//' >>/tmp/openclash_china_ip_route_pass.list 2>/dev/null for ip in $(uci_get_config "china_ip_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s,\n",$0)}' |sed '$ s/.$//' done >>/tmp/openclash_china_ip_route_pass.list 2>/dev/null echo "}" >>/tmp/openclash_china_ip_route_pass.list echo 'add element inet fw4 china_ip_route_pass $china_ip_route_pass' >>/tmp/openclash_china_ip_route_pass.list } nft 'flush set inet fw4 china_ip_route_pass' nft -f '/tmp/openclash_china_ip_route_pass.list' rm -rf /tmp/openclash_china_ip_route_pass.list fi fi #lan_ac if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then nft 'add set inet fw4 lan_ac_black_ips { type ipv4_addr; flags interval; auto-merge; }' nft 'add set inet fw4 lan_ac_black_ipv6s { type ipv6_addr; flags interval; auto-merge; }' config_load "openclash" config_list_foreach "config" "lan_ac_black_ips" nft_ac_add "lan_ac_black_ips" "lan_ac_black_ipv6s" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then nft 'add set inet fw4 lan_ac_black_macs { type ether_addr; }' config_load "openclash" config_list_foreach "config" "lan_ac_black_macs" nft_ac_add "lan_ac_black_macs" fi elif [ "$lan_ac_mode" = "1" ]; then if [ -n "$(uci_get_config "lan_ac_white_ips")" ]; then nft 'add set inet fw4 lan_ac_white_ips { type ipv4_addr; flags interval; auto-merge; }' nft 'add set inet fw4 lan_ac_white_ipv6s { type ipv6_addr; flags interval; auto-merge; }' config_load "openclash" config_list_foreach "config" "lan_ac_white_ips" nft_ac_add "lan_ac_white_ips" "lan_ac_white_ipv6s" fi if [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add set inet fw4 lan_ac_white_macs { type ether_addr; }' config_load "openclash" config_list_foreach "config" "lan_ac_white_macs" nft_ac_add "lan_ac_white_macs" fi fi #wan ac if [ -n "$(uci_get_config "wan_ac_black_ips")" ]; then nft 'add set inet fw4 wan_ac_black_ips { type ipv4_addr; flags interval; auto-merge; }' nft 'add set inet fw4 wan_ac_black_ipv6s { type ipv6_addr; flags interval; auto-merge; }' config_load "openclash" config_list_foreach "config" "wan_ac_black_ips" nft_ac_add "wan_ac_black_ips" "wan_ac_black_ipv6s" fi if [ -n "$(uci_get_config "wan_ac_black_ports")" ]; then nft 'add set inet fw4 wan_ac_black_ports { type inet_service; flags interval; }' config_load "openclash" config_list_foreach "config" "wan_ac_black_ports" nft_ac_add "wan_ac_black_ports" fi #local nft 'add set inet fw4 localnetwork { type ipv4_addr; flags interval; auto-merge; }' #nft 'delete set inet fw4 localnetwork' if [ -f "/etc/openclash/custom/openclash_custom_localnetwork_ipv4.list" ]; then for line in `cat "/etc/openclash/custom/openclash_custom_localnetwork_ipv4.list"` do nft add element inet fw4 localnetwork { "$line" } done else nft 'add element inet fw4 localnetwork { 0.0.0.0/8, 127.0.0.0/8, 10.0.0.0/8, 169.254.0.0/16, 192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4, 172.16.0.0/12, 100.64.0.0/10}' fi if [ -n "$wan_ip4s" ]; then for wan_ip4 in $wan_ip4s; do nft add element inet fw4 localnetwork { "$wan_ip4" } done fi #common ports if [ -n "$common_ports" ] && [ "$common_ports" != "0" ]; then nft 'add set inet fw4 common_ports { type inet_service; flags interval; }' for i in $common_port; do nft add element inet fw4 common_ports { "$i" } done fi #bypass gateway compatible if [ "$bypass_gateway_compatible" -eq 1 ]; then #nft 'delete chain inet fw4 openclash_post' nft 'add chain inet fw4 openclash_post' nft 'flush chain inet fw4 openclash_post' nft 'add rule inet fw4 openclash_post skgid == 65534 counter return' nft add rule inet fw4 openclash_post mark "$PROXY_FWMARK" counter accept nft 'add rule inet fw4 openclash_post ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_post ct direction reply counter return' nft 'add rule inet fw4 openclash_post fib saddr type != { local } counter masquerade' nft add rule inet fw4 srcnat meta nfproto {ipv4} counter jump openclash_post comment \"OpenClash Bypass Gateway Compatible\" fi #intranet allowed if [ "$intranet_allowed" -eq 1 ]; then if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then config_load "openclash" config_list_foreach "config" "intranet_allowed_wan_name" wan_name_add else wan_ints=$(nft list chain inet fw4 input |grep -e "jump input_wan" 2>/dev/null |awk '{for (i=1;i<=NF;i++){if ($i ~ /iifname/ && $(i+1) != "{") {print $(i+1)} if ($i ~ /iifname/ && $(i+1) == "{"){for (j=i+1;j<=NF;j++){if ($j~ /}/) {out="";for (k=i+1;k<=j;k++){out=out" "$k};print out}}}}}' 2>/dev/null |sed 's/"//g'|sed 's/{//g'|sed 's/}//g'|sed 's/,//g') fi if [ -n "$wan_ints" ]; then nft 'add chain inet fw4 openclash_wan_input' nft 'flush chain inet fw4 openclash_wan_input' for wan_int in $wan_ints; do #nft delete rule inet fw4 input $(nft -a list chain inet fw4 input |grep "@localnetwork" |awk -F '# ' '{print$2}') nft insert rule inet fw4 input position 0 iifname "$wan_int" ip saddr != @localnetwork counter jump openclash_wan_input done nft add rule inet fw4 openclash_wan_input th dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject else LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv4 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..." fi fi DNSPORT=$(uci -q get dhcp.@dnsmasq[0].port) if [ -z "$DNSPORT" ]; then DNSPORT=$(netstat -nlp |grep -E '127.0.0.1:.*dnsmasq' |awk -F '127.0.0.1:' '{print $2}' |awk '{print $1}' |head -1 || echo 53) fi if [ "$enable_redirect_dns" -eq 1 ]; then if ! fw4_has_dns_hijack_rule dstnat ipv4; then if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="ip saddr != @lan_ac_black_ips" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @lan_ac_black_macs" fi fi nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" else nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip saddr @lan_ac_white_ips counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" fi fi if [ "$router_self_proxy" = 1 ]; then nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft insert rule inet fw4 nat_output position 0 skgid != 65534 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip daddr {127.0.0.1} counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" fi elif [ "$enable_redirect_dns" -eq 2 ]; then nft 'add chain inet fw4 openclash_dns_redirect' nft 'flush chain inet fw4 openclash_dns_redirect' if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="ip saddr != @lan_ac_black_ips" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @lan_ac_black_macs" fi fi nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" else nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip saddr @lan_ac_white_ips counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" fi nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 counter jump openclash_dns_redirect' if [ "$router_self_proxy" = 1 ]; then nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft insert rule inet fw4 nat_output position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip daddr {127.0.0.1} meta skgid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" fi fi if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then #tcp nft 'add chain inet fw4 openclash' nft 'flush chain inet fw4 openclash' nft 'add rule inet fw4 openclash ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash ct direction reply counter return' if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add rule inet fw4 openclash ether saddr != @lan_ac_white_macs ip saddr != @lan_ac_white_ips counter return' else nft 'add rule inet fw4 openclash ether saddr != @lan_ac_white_macs counter return' nft 'add rule inet fw4 openclash ip saddr != @lan_ac_white_ips counter return' fi nft 'add rule inet fw4 openclash ip saddr @lan_ac_black_ips counter return' nft 'add rule inet fw4 openclash ether saddr @lan_ac_black_macs counter return' nft add rule inet fw4 openclash ip protocol tcp ip daddr { "$fakeip_range" } counter redirect to "$proxy_port" nft 'add rule inet fw4 openclash ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash th dport != @common_ports counter return' fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash $rule counter return" fi nft add rule inet fw4 openclash ip protocol tcp counter redirect to "$proxy_port" nft 'add rule inet fw4 dstnat meta nfproto {ipv4} ip protocol tcp counter jump openclash' # Accept redirected traffic in input chain (needed when zone input policy is REJECT without DNAT rules) if [ -z "$(nft list chain inet fw4 input 2>/dev/null | grep 'ct status dnat accept')" ]; then nft insert rule inet fw4 input position 0 ct status dnat accept comment \"OpenClash Redirect Accept\" fi if [ -z "$en_mode_tun" ]; then #udp if [ "$enable_udp_proxy" -eq 1 ]; then check_mod "nft_tproxy" ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" nft 'add chain inet fw4 openclash_mangle' nft 'flush chain inet fw4 openclash_mangle' nft 'add chain inet fw4 openclash_upnp' nft 'flush chain inet fw4 openclash_upnp' upnp_exclude nft 'add rule inet fw4 openclash_mangle ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_mangle ct direction reply counter return' if [ "$en_mode" = "fake-ip" ]; then nft add rule inet fw4 openclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept fi nft 'add rule inet fw4 openclash_mangle ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle th dport @wan_ac_black_ports counter return' nft 'add rule inet fw4 openclash_mangle ip saddr @lan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle ether saddr @lan_ac_black_macs counter return' if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs ip saddr != @lan_ac_white_ips counter return' else nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs counter return' nft 'add rule inet fw4 openclash_mangle ip saddr != @lan_ac_white_ips counter return' fi if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_mangle th dport != @common_ports counter return' fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash_mangle $rule counter return" fi nft 'add rule inet fw4 openclash_mangle ip protocol udp counter jump openclash_upnp' nft add rule inet fw4 openclash_mangle meta l4proto { udp } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} ip protocol udp counter jump openclash_mangle' fi if [ "$enable_udp_proxy" -ne 1 ] && [ "$en_mode" = "fake-ip" ]; then check_mod "nft_tproxy" ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" nft 'add chain inet fw4 openclash_mangle' nft 'flush chain inet fw4 openclash_mangle' nft add rule inet fw4 openclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} ip protocol udp counter jump openclash_mangle' fi #router self proxy udp if ([ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]) || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then nft 'add chain inet fw4 openclash_mangle_output' nft 'flush chain inet fw4 openclash_mangle_output' nft 'add rule inet fw4 openclash_mangle_output skgid == 65534 counter return' nft 'add rule inet fw4 openclash_mangle_output ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_mangle_output ct direction reply counter return' nft 'add rule inet fw4 openclash_mangle_output ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle_output th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft add rule inet fw4 openclash_mangle_output th dport != @common_ports counter return fi if [ "$en_mode" = "fake-ip" ]; then nft add rule inet fw4 openclash_mangle_output meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter accept fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash_mangle_output $rule counter return" fi if [ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]; then nft add rule inet fw4 openclash_mangle_output mark set "$PROXY_FWMARK" counter accept fi nft 'add rule inet fw4 mangle_output meta nfproto {ipv4} ip protocol udp counter jump openclash_mangle_output' fi # Accept TPROXY traffic in input chain (needed when zone input policy is REJECT) if [ -z "$(nft list chain inet fw4 input 2>/dev/null | grep 'OpenClash TPROXY Accept')" ]; then nft insert rule inet fw4 input position 0 meta mark "$PROXY_FWMARK" accept comment \"OpenClash TPROXY Accept\" fi #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip_route" = "2" ]; then nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" else nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" fi fi fi #router self proxy tcp if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then nft 'add chain inet fw4 openclash_output' nft 'flush chain inet fw4 openclash_output' nft 'add rule inet fw4 openclash_output skgid == 65534 counter return' nft 'add rule inet fw4 openclash_output ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_output ct direction reply counter return' if [ "$en_mode" = "fake-ip" ] && [ "$en_mode_tun" != "1" ]; then nft add rule inet fw4 openclash_output ip protocol tcp ip daddr { "$fakeip_range" } counter redirect to "$proxy_port" fi if [ "$router_self_proxy" = "1" ]; then nft 'add rule inet fw4 openclash_output ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_output th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft add rule inet fw4 openclash_output th dport != @common_ports counter return fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash_output $rule counter return" fi nft add rule inet fw4 openclash_output ip protocol tcp counter redirect to "$proxy_port" fi nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft 'add rule inet fw4 nat_output meta nfproto {ipv4} ip protocol tcp counter jump openclash_output' fi fi if [ -n "$en_mode_tun" ]; then #TUN模式 #设置防火墙 #router self proxy if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then nft 'add chain inet fw4 openclash_mangle_output' nft 'flush chain inet fw4 openclash_mangle_output' nft 'add rule inet fw4 openclash_mangle_output skgid == 65534 counter return' nft 'add rule inet fw4 openclash_mangle_output ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_mangle_output ct direction reply counter return' if [ "$en_mode_tun" -eq 1 ]; then nft add rule inet fw4 openclash_mangle_output meta l4proto {tcp,udp} ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter else nft add rule inet fw4 openclash_mangle_output meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter fi if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_mangle_output th dport != @common_ports counter return' fi if [ "$router_self_proxy" = "1" ]; then nft 'add rule inet fw4 openclash_mangle_output ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle_output th dport @wan_ac_black_ports counter return' if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash_mangle_output $rule counter return" fi #icmp nft add rule inet fw4 openclash_mangle_output meta nfproto {ipv4} ip protocol icmp icmp type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMP Mark\" if [ "$en_mode_tun" -eq 1 ]; then nft add rule inet fw4 openclash_mangle_output meta l4proto {tcp,udp} meta mark set "$PROXY_FWMARK" counter else nft add rule inet fw4 openclash_mangle_output meta l4proto { udp } meta mark set "$PROXY_FWMARK" counter fi fi nft 'add rule inet fw4 mangle_output meta nfproto {ipv4} counter jump openclash_mangle_output' fi nft 'add chain inet fw4 openclash_mangle' nft 'flush chain inet fw4 openclash_mangle' nft 'add chain inet fw4 openclash_upnp' nft 'flush chain inet fw4 openclash_upnp' upnp_exclude #其他流量 nft 'add rule inet fw4 openclash_mangle meta l4proto {tcp,udp} iifname utun counter return' nft 'add rule inet fw4 openclash_mangle ip daddr @localnetwork counter return' nft 'add rule inet fw4 openclash_mangle ct direction reply counter return' if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs ip saddr != @lan_ac_white_ips counter return' else nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs counter return' nft 'add rule inet fw4 openclash_mangle ip saddr != @lan_ac_white_ips counter return' fi nft 'add rule inet fw4 openclash_mangle ip saddr @lan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle ether saddr @lan_ac_black_macs counter return' if [ "$en_mode_tun" -eq 1 ]; then nft add rule inet fw4 openclash_mangle meta l4proto {tcp,udp} ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter else nft add rule inet fw4 openclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter fi nft 'add rule inet fw4 openclash_mangle ip daddr @wan_ac_black_ips counter return' nft 'add rule inet fw4 openclash_mangle th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_mangle th dport != @common_ports counter return' fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="ip daddr @china_ip_route" elif [ "$china_ip_route" = "2" ]; then rule="ip daddr != @china_ip_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @china_ip_route_pass" nft "add rule inet fw4 openclash_mangle $rule counter return" fi #icmp nft add rule inet fw4 openclash_mangle meta nfproto {ipv4} ip protocol icmp icmp type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMP Mark\" nft 'add rule inet fw4 openclash_mangle ip protocol udp counter jump openclash_upnp' if [ "$en_mode_tun" -eq 1 ]; then nft add rule inet fw4 openclash_mangle mark set "$PROXY_FWMARK" counter else nft add rule inet fw4 openclash_mangle meta l4proto { udp } mark set "$PROXY_FWMARK" counter fi nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} counter jump openclash_mangle' #TUN FORWORD nft insert rule inet fw4 forward position 0 meta nfproto {ipv4} oifname utun counter accept comment \"OpenClash TUN Forward\" nft insert rule inet fw4 forward position 0 meta nfproto {ipv4} iifname utun counter accept comment \"OpenClash TUN Forward\" nft insert rule inet fw4 input position 0 meta nfproto {ipv4} iifname utun counter accept comment \"OpenClash TUN Input\" nft insert rule inet fw4 srcnat position 0 meta nfproto {ipv4} oifname utun counter return comment \"OpenClash TUN Postrouting\" #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip_route" = "2" ]; then nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 ip daddr @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" else nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" fi fi fi #ipv6 if [ "$ipv6_enable" -eq 1 ]; then #china ip route if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then nft 'flush set inet fw4 china_ip6_route' nft -f '/etc/openclash/china_ip6_route.ipset' CHNROUTE_WAIT=0 while ( [ -z "$(nft list sets |grep "set china_ip6_route {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] ) do sleep 3 nft -f '/etc/openclash/china_ip6_route.ipset' let CHNROUTE_WAIT++ done if [ "$enable_redirect_dns" != "2" ]; then echo "add set inet fw4 china_ip6_route_pass { type ipv6_addr; flags interval; auto-merge; }" >/tmp/openclash_china_ip6_route_pass.list [ -z `(awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s,\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list)` ] || { echo "define china_ip6_route_pass = {" >>/tmp/openclash_china_ip6_route_pass.list awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s,\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list |sed '$ s/.$//' >>/tmp/openclash_china_ip6_route_pass.list 2>/dev/null for ip in $(uci_get_config "china_ip6_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf(" %s,\n",$0)}' |sed '$ s/.$//' done >>/tmp/openclash_china_ip6_route_pass.list 2>/dev/null echo "}" >>/tmp/openclash_china_ip6_route_pass.list echo 'add element inet fw4 china_ip6_route_pass $china_ip6_route_pass' >>/tmp/openclash_china_ip6_route_pass.list } nft 'flush set inet fw4 china_ip6_route_pass' nft -f '/tmp/openclash_china_ip6_route_pass.list' rm -rf /tmp/openclash_china_ip6_route_pass.list fi fi if ! fw4_has_dns_hijack_rule dstnat ipv6; then if [ "$enable_redirect_dns" -eq 1 ]; then if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="ip6 saddr != @lan_ac_black_ipv6s" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @lan_ac_black_macs" fi fi nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" else nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 saddr @lan_ac_white_ipv6s counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" fi if [ "$router_self_proxy" = 1 ]; then nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft insert rule inet fw4 nat_output position 0 skgid != 65534 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 daddr {::1} counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" fi elif [ "$enable_redirect_dns" -eq 2 ]; then if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="ip6 saddr != @lan_ac_black_ipv6s" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @lan_ac_black_macs" fi fi nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" else nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 saddr @lan_ac_white_ipv6s counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" nft add rule inet fw4 openclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ether saddr @lan_ac_white_macs counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" fi nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 counter jump openclash_dns_redirect' if [ "$router_self_proxy" = 1 ]; then nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft insert rule inet fw4 nat_output position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 daddr {::1} meta skgid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" fi fi fi #local nft 'add set inet fw4 localnetwork6 { type ipv6_addr; flags interval; auto-merge; }' #nft 'delete set inet fw4 localnetwork6' if [ -f "/etc/openclash/custom/openclash_custom_localnetwork_ipv6.list" ]; then for line in `cat "/etc/openclash/custom/openclash_custom_localnetwork_ipv6.list"` do nft add element inet fw4 localnetwork6 { "$line" } done else nft 'add element inet fw4 localnetwork6 { ::/128, ::1/128, ::ffff:0:0/96, ::ffff:0:0:0/96, 64:ff9b::/96, 100::/64, 2001::/32, 2001:20::/28, 2001:db8::/32, 2002::/16, fe80::/10, ff00::/8}' fi if [ -n "$wan_ip6s" ]; then for wan_ip6 in $wan_ip6s; do nft add element inet fw4 localnetwork6 { "$wan_ip6" } done fi if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then #tcp nft 'add chain inet fw4 openclash_v6' nft 'flush chain inet fw4 openclash_v6' nft 'add rule inet fw4 openclash_v6 ip6 daddr @localnetwork6 counter return' nft 'add rule inet fw4 openclash_v6 ct direction reply counter return' if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add rule inet fw4 openclash_v6 ether saddr != @lan_ac_white_macs ip6 saddr != @lan_ac_white_ipv6s counter return' else nft 'add rule inet fw4 openclash_v6 ether saddr != @lan_ac_white_macs counter return' nft 'add rule inet fw4 openclash_v6 ip6 saddr != @lan_ac_white_ipv6s counter return' fi nft 'add rule inet fw4 openclash_v6 ip6 saddr @lan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_v6 ether saddr @lan_ac_black_macs counter return' nft add rule inet fw4 openclash_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } counter redirect to "$proxy_port" nft 'add rule inet fw4 openclash_v6 ip6 daddr @wan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_v6 th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_v6 th dport != @common_ports counter return' fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="ip6 daddr @china_ip6_route" elif [ "$china_ip6_route" = "2" ]; then rule="ip6 daddr != @china_ip6_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @china_ip6_route_pass" nft "add rule inet fw4 openclash_v6 $rule counter return" fi nft add rule inet fw4 openclash_v6 ip6 nexthdr {tcp} counter redirect to "$proxy_port" nft 'add rule inet fw4 dstnat ip6 nexthdr {tcp} counter jump openclash_v6' fi #TProxy & TUN & Redirect udp if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -ne 1 ]; then nft 'add chain inet fw4 openclash_mangle_v6' nft 'flush chain inet fw4 openclash_mangle_v6' nft 'add rule inet fw4 openclash_mangle_v6 ip6 daddr @localnetwork6 counter return' nft 'add rule inet fw4 openclash_mangle_v6 ct direction reply counter return' if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then nft 'add rule inet fw4 openclash_mangle_v6 ether saddr != @lan_ac_white_macs ip6 saddr != @lan_ac_white_ipv6s counter return' else nft 'add rule inet fw4 openclash_mangle_v6 ether saddr != @lan_ac_white_macs counter return' nft 'add rule inet fw4 openclash_mangle_v6 ip6 saddr != @lan_ac_white_ipv6s counter return' fi nft 'add rule inet fw4 openclash_mangle_v6 ip6 saddr @lan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_mangle_v6 ether saddr @lan_ac_black_macs counter return' if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$ipv6_mode" -eq 0 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept else nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter fi fi if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter else if [ "$enable_v6_udp_proxy" -eq 1 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept fi fi nft 'add rule inet fw4 openclash_mangle_v6 ip6 daddr @wan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_mangle_v6 th dport @wan_ac_black_ports counter return' if [ "$en_mode" == "redir-host" ]; then nft 'add rule inet fw4 openclash_mangle_v6 th dport != @common_ports counter return' fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="ip6 daddr @china_ip6_route" elif [ "$china_ip6_route" = "2" ]; then rule="ip6 daddr != @china_ip6_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @china_ip6_route_pass" nft "add rule inet fw4 openclash_mangle_v6 $rule counter return" fi #icmpv6 if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_v6 meta nfproto {ipv6} ip6 nexthdr icmpv6 icmpv6 type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMPv6 Redirect\" fi fi #tcp Tproxy && TUN if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$ipv6_mode" -eq 0 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash TCP Tproxy\" else nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" counter fi fi #udp if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" counter else if [ "$enable_v6_udp_proxy" -eq 1 ]; then nft add rule inet fw4 openclash_mangle_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash UDP Tproxy\" fi fi nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv6} counter jump openclash_mangle_v6' #router self proxy if [ "$router_self_proxy" = "1" ]; then if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then #tcp Redirect Mode nft 'add chain inet fw4 openclash_output_v6' nft 'flush chain inet fw4 openclash_output_v6' if [ "$en_mode" = "fake-ip" ]; then nft add rule inet fw4 openclash_output ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } counter redirect to "$proxy_port" fi nft 'add rule inet fw4 openclash_output_v6 skgid == 65534 counter return' nft 'add rule inet fw4 openclash_output_v6 ip6 daddr @localnetwork6 counter return' nft 'add rule inet fw4 openclash_output_v6 ct direction reply counter return' nft 'add rule inet fw4 openclash_output_v6 ip6 daddr @wan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_output_v6 th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_output_v6 th dport != @common_ports counter return' fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="ip6 daddr @china_ip6_route" elif [ "$china_ip6_route" = "2" ]; then rule="ip6 daddr != @china_ip6_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @china_ip6_route_pass" nft "add rule inet fw4 openclash_output_v6 $rule counter return" fi nft add rule inet fw4 openclash_output_v6 ip6 nexthdr {tcp} counter redirect to "$proxy_port" nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' nft 'add rule inet fw4 nat_output meta nfproto {ipv6} counter jump openclash_output_v6' fi #other mode and Redirect Mode udp nft 'add chain inet fw4 openclash_mangle_output_v6' nft 'flush chain inet fw4 openclash_mangle_output_v6' nft 'add rule inet fw4 openclash_mangle_output_v6 skgid == 65534 counter return' nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @localnetwork6 counter return' nft 'add rule inet fw4 openclash_mangle_output_v6 ct direction reply counter return' if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter fi if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then if [ "$en_mode" = "fake-ip" ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {tcp,udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter fi fi if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then if [ "$en_mode" = "fake-ip" ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter fi fi nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @wan_ac_black_ipv6s counter return' nft 'add rule inet fw4 openclash_mangle_output_v6 th dport @wan_ac_black_ports counter return' if [ "$en_mode" = "redir-host" ]; then nft 'add rule inet fw4 openclash_mangle_output_v6 th dport != @common_ports counter return' fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="ip6 daddr @china_ip6_route" elif [ "$china_ip6_route" = "2" ]; then rule="ip6 daddr != @china_ip6_route" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @china_ip6_route_pass" nft "add rule inet fw4 openclash_mangle_output_v6 $rule counter return" fi #icmpv6 if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} ip6 nexthdr icmpv6 icmpv6 type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMPv6 Redirect\" fi if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" counter fi if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {tcp,udp} mark set "$PROXY_FWMARK" counter fi if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then nft add rule inet fw4 openclash_mangle_output_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" counter fi nft 'add rule inet fw4 mangle_output meta nfproto {ipv6} counter jump openclash_mangle_output_v6' fi #route if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -eq 0 ]; then check_mod "nft_tproxy" ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE" fi fi #TUN FORWORD if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft insert rule inet fw4 forward position 0 meta nfproto {ipv6} oifname utun counter accept comment \"OpenClash TUN Forward\" nft insert rule inet fw4 forward position 0 meta nfproto {ipv6} iifname utun counter accept comment \"OpenClash TUN Forward\" nft insert rule inet fw4 input position 0 meta nfproto {ipv6} iifname utun counter accept comment \"OpenClash TUN Input\" nft insert rule inet fw4 srcnat position 0 meta nfproto {ipv6} oifname utun counter return comment \"OpenClash TUN Postrouting\" fi #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip6_route" = "2" ]; then rule="ip6 daddr @china_ip6_route" else rule="ip6 daddr != @china_ip6_route" fi nft insert rule inet fw4 input position 0 udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\" if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\" else nft insert rule inet fw4 forward position 0 udp dport 443 $rule counter reject comment \"OpenClash QUIC REJECT\" fi fi #bypass gateway compatible if [ "$bypass_gateway_compatible" -eq 1 ]; then #nft 'delete chain inet fw4 openclash_post_v6' nft 'add chain inet fw4 openclash_post_v6' nft 'flush chain inet fw4 openclash_post_v6' nft 'add rule inet fw4 openclash_post_v6 skgid == 65534 counter return' nft add rule inet fw4 openclash_post_v6 mark "$PROXY_FWMARK" counter accept nft 'add rule inet fw4 openclash_post_v6 ip6 daddr @localnetwork6 counter return' nft 'add rule inet fw4 openclash_post_v6 ct direction reply counter return' nft 'add rule inet fw4 openclash_post_v6 fib saddr type != { local } counter masquerade' nft add rule inet fw4 srcnat meta nfproto {ipv6} counter jump openclash_post_v6 comment \"OpenClash Bypass Gateway Compatible\" fi #intranet allowed if [ "$intranet_allowed" -eq 1 ]; then if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then config_load "openclash" config_list_foreach "config" "intranet_allowed_wan_name" wan6_name_add else wan6_ints=$(nft list chain inet fw4 input |grep -e "jump input_wan" 2>/dev/null |awk '{for (i=1;i<=NF;i++){if ($i ~ /iifname/ && $(i+1) != "{") {print $(i+1)} if ($i ~ /iifname/ && $(i+1) == "{"){for (j=i+1;j<=NF;j++){if ($j~ /}/) {out="";for (k=i+1;k<=j;k++){out=out" "$k};print out}}}}}' 2>/dev/null |sed 's/"//g'|sed 's/{//g'|sed 's/}//g'|sed 's/,//g') fi if [ -n "$wan6_ints" ]; then nft 'add chain inet fw4 openclash_wan6_input' nft 'flush chain inet fw4 openclash_wan6_input' for wan6_int in $wan6_ints; do #nft delete rule inet fw4 input $(nft -a list chain inet fw4 input |grep "@localnetwork6" |awk -F '# ' '{print$2}') nft insert rule inet fw4 input position 0 iifname "$wan6_int" ip6 saddr != @localnetwork6 counter jump openclash_wan6_input done nft add rule inet fw4 openclash_wan6_input ip6 nexthdr {tcp,udp} th dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject else LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv6 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..." fi fi fi #icmp if [ "$en_mode" = "fake-ip" ]; then if [ -z "$en_mode_tun" ]; then nft insert rule inet fw4 input position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP INPUT REJECT\" nft insert rule inet fw4 forward position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP FORWARD REJECT\" nft insert rule inet fw4 output position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } $noowner counter reject comment \"OpenClash ICMP OUTPUT REJECT\" fi if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then nft insert rule inet fw4 input position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 INPUT REJECT\" nft insert rule inet fw4 forward position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 FORWARD REJECT\" nft insert rule inet fw4 output position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } $noowner counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 OUTPUT REJECT\" fi fi fi fi #IPTABLES if [ -z "$FW4" ]; then #iptables owner module if [ "$iptables_compat" -eq 0 ]; then owner="-m mark --mark 0x1a0a" noowner="-m mark ! --mark 0x1a0a" addr_local="! -i lo" else owner="-m owner --gid-owner 65534" noowner="-m owner ! --gid-owner 65534" addr_local="-m addrtype ! --src-type LOCAL" fi #china ip route if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then ipset -! flush china_ip_route ipset -! restore /tmp/openclash_china_ip_route_pass.list awk '!/^$/&&!/^#/&&/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("add china_ip_route_pass %s'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list >>/tmp/openclash_china_ip_route_pass.list for ip in $(uci_get_config "china_ip_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("add china_ip_route_pass %s'" "'\n",$0)}' done >>/tmp/openclash_china_ip_route_pass.list 2>/dev/null ipset -! flush china_ip_route_pass ipset -! restore /dev/null |awk '{for (i=1;i<=NF;i++) {if ($i ~ /-i/) {print $(i+1)}}}' 2>/dev/null) fi if [ -n "$wan_ints" ]; then iptables -t filter -N openclash_wan_input iptables -t filter -F openclash_wan_input for wan_int in $wan_ints; do iptables -t filter -I INPUT -i "$wan_int" -m set ! --match-set localnetwork src -j openclash_wan_input done iptables -t filter -A openclash_wan_input -p udp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT iptables -t filter -A openclash_wan_input -p tcp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT else LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv4 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..." fi fi DNSPORT=$(uci -q get dhcp.@dnsmasq[0].port) if [ -z "$DNSPORT" ]; then DNSPORT=$(netstat -nlp |grep -E '127.0.0.1:.*dnsmasq' |awk -F '127.0.0.1:' '{print $2}' |awk '{print $1}' |head -1 || echo 53) fi if [ "$enable_redirect_dns" -eq 1 ]; then if [ -z "$(iptables -t nat -nL PREROUTING --line-number |grep 'OpenClash DNS Hijack')" ]; then if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="-m set ! --match-set lan_ac_black_ips src" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set lan_ac_black_macs src" fi fi iptables -t nat -I PREROUTING -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -I PREROUTING -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" else iptables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set lan_ac_white_ips src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set lan_ac_white_ips src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set lan_ac_white_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set lan_ac_white_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" fi fi if [ "$router_self_proxy" = 1 ]; then iptables -t nat -I OUTPUT $noowner -m comment --comment "OpenClash DNS Hijack" -p tcp --dport 53 -d 127.0.0.1 -j REDIRECT --to-ports "$DNSPORT" iptables -t nat -I OUTPUT $noowner -m comment --comment "OpenClash DNS Hijack" -p udp --dport 53 -d 127.0.0.1 -j REDIRECT --to-ports "$DNSPORT" fi elif [ "$enable_redirect_dns" -eq 2 ]; then iptables -t nat -N openclash_dns_redirect iptables -t nat -F openclash_dns_redirect if [ "$lan_ac_mode" != "1" ]; then ACBLACKDNSFILTER="" if [ "$lan_ac_mode" = "0" ]; then if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then ACBLACKDNSFILTER="-m set ! --match-set lan_ac_black_ips src" fi if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set lan_ac_black_macs src" fi fi iptables -t nat -A openclash_dns_redirect -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -A openclash_dns_redirect -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" else iptables -t nat -A openclash_dns_redirect -p udp --dport 53 -m set --match-set lan_ac_white_ips src -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -A openclash_dns_redirect -p tcp --dport 53 -m set --match-set lan_ac_white_ips src -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -A openclash_dns_redirect -p udp --dport 53 -m set --match-set lan_ac_white_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -A openclash_dns_redirect -p tcp --dport 53 -m set --match-set lan_ac_white_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" fi iptables -t nat -I PREROUTING -p udp --dport 53 -j openclash_dns_redirect iptables -t nat -I PREROUTING -p tcp --dport 53 -j openclash_dns_redirect if [ "$router_self_proxy" = 1 ]; then iptables -t nat -I OUTPUT -p udp --dport 53 -d 127.0.0.1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" iptables -t nat -I OUTPUT -p tcp --dport 53 -d 127.0.0.1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" fi fi if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then #tcp iptables -t nat -N openclash iptables -t nat -F openclash iptables -t nat -A openclash -m set --match-set localnetwork dst -j RETURN iptables -t nat -A openclash -m conntrack --ctdir REPLY -j RETURN iptables -t nat -A openclash -p tcp -d "$fakeip_range" -j REDIRECT --to-ports "$proxy_port" iptables -t nat -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t nat -A openclash -m set --match-set wan_ac_black_ports dst -j RETURN iptables -t nat -A openclash -m set --match-set lan_ac_black_ips src -j RETURN iptables -t nat -A openclash -m set --match-set lan_ac_black_macs src -j RETURN if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then iptables -t nat -A openclash -m set ! --match-set lan_ac_white_ips src -m set ! --match-set lan_ac_white_macs src -j RETURN else iptables -t nat -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN iptables -t nat -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN fi if [ "$en_mode" = "redir-host" ]; then iptables -t nat -A openclash -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t nat -A openclash $rule -j RETURN fi iptables -t nat -A openclash -p tcp -j REDIRECT --to-ports "$proxy_port" iptables -t nat -A PREROUTING -p tcp -j openclash # Accept redirected traffic in input chain (needed when zone input policy is REJECT without DNAT rules) if [ -z "$(iptables-save -t filter 2>/dev/null | grep 'OpenClash Redirect Accept')" ]; then iptables -I INPUT -m conntrack --ctstate DNAT -j ACCEPT -m comment --comment "OpenClash Redirect Accept" fi if [ -z "$en_mode_tun" ]; then #udp if [ "$enable_udp_proxy" -eq 1 ]; then check_mod "xt_TPROXY" ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" iptables -t mangle -N openclash iptables -t mangle -F openclash iptables -t mangle -N openclash_upnp iptables -t mangle -F openclash_upnp upnp_exclude iptables -t mangle -A openclash -m set --match-set localnetwork dst -j RETURN iptables -t mangle -A openclash -m conntrack --ctdir REPLY -j RETURN if [ "$en_mode" = "fake-ip" ]; then iptables -t mangle -A openclash -p udp -d "$fakeip_range" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" fi iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t mangle -A openclash -m set --match-set wan_ac_black_ports dst -j RETURN iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -m set ! --match-set lan_ac_white_macs src -j RETURN else iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN fi if [ "$en_mode" = "redir-host" ]; then iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t mangle -A openclash $rule -j RETURN fi iptables -t mangle -A openclash -p udp -j openclash_upnp iptables -t mangle -A openclash -p udp -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" iptables -t mangle -A PREROUTING -p udp -j openclash fi if [ "$enable_udp_proxy" -ne 1 ] && [ "$en_mode" = "fake-ip" ]; then check_mod "xt_TPROXY" ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" iptables -t mangle -N openclash iptables -t mangle -F openclash iptables -t mangle -A openclash -p udp -d "$fakeip_range" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" iptables -t mangle -A PREROUTING -p udp -j openclash fi #router self proxy udp if ([ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]) || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then iptables -t mangle -N openclash_output iptables -t mangle -F openclash_output iptables -t mangle -A openclash_output $owner -j RETURN iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN iptables -t mangle -A openclash_output -m conntrack --ctdir REPLY -j RETURN iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ports dst -j RETURN if [ "$en_mode" = "fake-ip" ]; then iptables -t mangle -A openclash_output -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK" fi if [ "$en_mode" = "redir-host" ]; then iptables -t mangle -A openclash_output -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t mangle -A openclash_output $rule -j RETURN fi if [ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]; then iptables -t mangle -A openclash_output -p udp -j MARK --set-mark "$PROXY_FWMARK" fi iptables -t mangle -A OUTPUT -p udp -j openclash_output fi fi # Accept TPROXY traffic in input chain (needed when zone input policy is REJECT) if [ -z "$(iptables -nL INPUT 2>/dev/null | grep 'OpenClash TPROXY Accept')" ]; then iptables -I INPUT -m mark --mark "$PROXY_FWMARK" -j ACCEPT -m comment --comment "OpenClash TPROXY Accept" fi if [ -z "$en_mode_tun" ]; then #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip_route" = "2" ]; then iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT else iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT iptables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT fi fi fi #router self proxy tcp if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then iptables -t nat -N openclash_output iptables -t nat -F openclash_output iptables -t nat -A openclash_output $owner -j RETURN if [ "$en_mode" = "fake-ip" ] && [ "$en_mode_tun" != "1" ]; then iptables -t nat -A openclash_output -p tcp -d "$fakeip_range" -j REDIRECT --to-ports "$proxy_port" fi if [ "$router_self_proxy" = "1" ]; then iptables -t nat -A openclash_output -m set --match-set localnetwork dst -j RETURN iptables -t nat -A openclash_output -m conntrack --ctdir REPLY -j RETURN iptables -t nat -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t nat -A openclash_output -m set --match-set wan_ac_black_ports dst -j RETURN if [ "$en_mode" = "redir-host" ]; then iptables -t nat -A openclash_output -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t nat -A openclash_output $rule -j RETURN fi iptables -t nat -A openclash_output -p tcp -j REDIRECT --to-ports "$proxy_port" fi iptables -t nat -A OUTPUT -j openclash_output fi fi if [ -n "$en_mode_tun" ]; then #TUN模式 #设置防火墙 #router self proxy if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then iptables -t mangle -N openclash_output iptables -t mangle -F openclash_output iptables -t mangle -A openclash_output $owner -j RETURN iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN iptables -t mangle -A openclash_output -m conntrack --ctdir REPLY -j RETURN if [ "$en_mode_tun" -eq 1 ]; then iptables -t mangle -A openclash_output -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK" else iptables -t mangle -A openclash_output -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK" fi if [ "$en_mode" = "redir-host" ]; then iptables -t mangle -A openclash_output -m set ! --match-set common_ports dst -j RETURN fi if [ "$router_self_proxy" = "1" ]; then iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ports dst -j RETURN if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t mangle -A openclash_output $rule -j RETURN fi if [ "$en_mode_tun" -eq 1 ]; then iptables -t mangle -A openclash_output -j MARK --set-mark "$PROXY_FWMARK" else #icmp iptables -t mangle -A openclash_output -p icmp --icmp-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMP Mark" iptables -t mangle -A openclash_output -p udp -j MARK --set-mark "$PROXY_FWMARK" fi fi iptables -t mangle -A OUTPUT -j openclash_output fi iptables -t mangle -N openclash iptables -t mangle -F openclash iptables -t mangle -N openclash_upnp iptables -t mangle -F openclash_upnp upnp_exclude #其他流量 iptables -t mangle -A openclash -i utun -j RETURN iptables -t mangle -A openclash -m set --match-set localnetwork dst -j RETURN iptables -t mangle -A openclash -m conntrack --ctdir REPLY -j RETURN if [ "$en_mode_tun" -eq 1 ]; then iptables -t mangle -A openclash -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK" else iptables -t mangle -A openclash -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK" fi iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN iptables -t mangle -A openclash -m set --match-set wan_ac_black_ports dst -j RETURN iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -m set ! --match-set lan_ac_white_macs src -j RETURN else iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN fi if [ "$en_mode" = "redir-host" ]; then iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip_route" != "0" ]; then if [ "$china_ip_route" = "1" ]; then rule="-m set --match-set china_ip_route dst" elif [ "$china_ip_route" = "2" ]; then rule="-m set ! --match-set china_ip_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip_route_pass dst" iptables -t mangle -A openclash $rule -j RETURN fi iptables -t mangle -A openclash -p udp -j openclash_upnp if [ "$en_mode_tun" -eq 1 ]; then iptables -t mangle -A openclash -j MARK --set-mark "$PROXY_FWMARK" else #icmp iptables -t mangle -A openclash -p icmp --icmp-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMP Mark" iptables -t mangle -A openclash -p udp -j MARK --set-mark "$PROXY_FWMARK" fi iptables -t mangle -A PREROUTING -j openclash #TUN FORWORD iptables -I FORWARD -m comment --comment "OpenClash TUN Forward" -o utun -j ACCEPT iptables -I FORWARD -m comment --comment "OpenClash TUN Forward" -i utun -j ACCEPT iptables -I INPUT -m comment --comment "OpenClash TUN Input" -i utun -j ACCEPT iptables -t nat -I POSTROUTING -m comment --comment "OpenClash TUN Postrouting" -o utun -j RETURN #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip_route" = "2" ]; then iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT iptables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" -m set --match-set china_ip_route dst -j REJECT else iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT iptables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT fi fi fi #ipv6 if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then #china ip route if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then ipset -! flush china_ip6_route ipset -! restore /tmp/openclash_china_ip6_route_pass.list awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("add china_ip6_route_pass %s'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>/tmp/openclash_china_ip6_route_pass.list for ip in $(uci_get_config "china_ip6_route_pass"); do [ -z "$ip" ] && continue echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("add china_ip6_route_pass %s'" "'\n",$0)}' done >>/tmp/openclash_china_ip6_route_pass.list 2>/dev/null ipset -! flush china_ip6_route_pass ipset -! restore /dev/null | grep 'OpenClash Redirect Accept')" ]; then ip6tables -I INPUT -m conntrack --ctstate DNAT -j ACCEPT -m comment --comment "OpenClash Redirect Accept" fi #TProxy & TUN & Redirect udp if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -ne 1 ]; then ip6tables -t mangle -N openclash ip6tables -t mangle -F openclash ip6tables -t mangle -A openclash -m set --match-set localnetwork6 dst -j RETURN ip6tables -t mangle -A openclash -m conntrack --ctdir REPLY -j RETURN if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$ipv6_mode" -eq 0 ]; then ip6tables -t mangle -A openclash -p tcp -d "$fakeip_range6" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" else ip6tables -t mangle -A openclash -p tcp -d "$fakeip_range6" -j MARK --set-mark "$PROXY_FWMARK" fi fi if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash -p udp -d "$fakeip_range6" -j MARK --set-mark "$PROXY_FWMARK" else if [ "$enable_v6_udp_proxy" -eq 1 ]; then ip6tables -t mangle -A openclash -p udp -d "$fakeip_range6" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" fi fi ip6tables -t mangle -A openclash -m set --match-set wan_ac_black_ipv6s dst -j RETURN ip6tables -t mangle -A openclash -m set --match-set wan_ac_black_ports dst -j RETURN ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_ipv6s src -j RETURN if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_ipv6s src -m set ! --match-set lan_ac_white_macs src -j RETURN else ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_ipv6s src -j RETURN ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN fi if [ "$en_mode" == "redir-host" ]; then ip6tables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="-m set --match-set china_ip6_route dst" elif [ "$china_ip6_route" = "2" ]; then rule="-m set ! --match-set china_ip6_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip6_route_pass dst" ip6tables -t mangle -A openclash $rule -j RETURN fi #icmpv6 if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash -p icmpv6 --icmpv6-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMPv6 Redirect" fi fi #tcp Tproxy && TUN if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$ipv6_mode" -eq 0 ]; then ip6tables -t mangle -A openclash -p tcp -m comment --comment "OpenClash TCP Tproxy" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" else ip6tables -t mangle -A openclash -p tcp -j MARK --set-mark "$PROXY_FWMARK" fi fi #udp if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash -p udp -m comment --comment "OpenClash UDP TUN" -j MARK --set-xmark "$PROXY_FWMARK" else if [ "$enable_v6_udp_proxy" -eq 1 ]; then ip6tables -t mangle -A openclash -p udp -m comment --comment "OpenClash UDP Tproxy" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK" fi fi ip6tables -t mangle -A PREROUTING -j openclash # Accept TPROXY IPv6 traffic in input chain (needed when zone input policy is REJECT) if [ -z "$(ip6tables-save -t filter 2>/dev/null | grep 'OpenClash TPROXY Accept')" ]; then ip6tables -I INPUT -m mark --mark "$PROXY_FWMARK" -j ACCEPT -m comment --comment "OpenClash TPROXY Accept" fi #router self proxy if [ "$router_self_proxy" = "1" ]; then if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then #tcp Redirect Mode ip6tables -t nat -N openclash_output ip6tables -t nat -F openclash_output if [ "$en_mode" = "fake-ip" ]; then ip6tables -t nat -A openclash_output -p tcp -d "$fakeip_range6" -j REDIRECT --to-ports "$proxy_port" fi ip6tables -t nat -A openclash_output $owner -j RETURN ip6tables -t nat -A openclash_output -m set --match-set localnetwork6 dst -j RETURN ip6tables -t nat -A openclash_output -m conntrack --ctdir REPLY -j RETURN ip6tables -t nat -A openclash_output -m set --match-set wan_ac_black_ipv6s dst -j RETURN ip6tables -t nat -A openclash_output -m set --match-set wan_ac_black_ports dst -j RETURN if [ "$en_mode" = "redir-host" ]; then ip6tables -t nat -A openclash_output -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="-m set --match-set china_ip6_route dst" elif [ "$china_ip6_route" = "2" ]; then rule="-m set ! --match-set china_ip6_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip6_route_pass dst" ip6tables -t nat -A openclash_output $rule -j RETURN fi ip6tables -t nat -A openclash_output -p tcp -j REDIRECT --to-ports "$proxy_port" ip6tables -t nat -A OUTPUT -j openclash_output fi #other mode and Redirect Mode udp ip6tables -t mangle -N openclash_output ip6tables -t mangle -F openclash_output ip6tables -t mangle -A openclash_output $owner -j RETURN ip6tables -t mangle -A openclash_output -m set --match-set localnetwork6 dst -j RETURN ip6tables -t mangle -A openclash_output -m conntrack --ctdir REPLY -j RETURN if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash_output -p udp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK" fi if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then ip6tables -t mangle -A openclash_output -p tcp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK" ip6tables -t mangle -A openclash_output -p udp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK" fi if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then ip6tables -t mangle -A openclash_output -p tcp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK" fi ip6tables -t mangle -A openclash_output -m set --match-set wan_ac_black_ipv6s dst -j RETURN ip6tables -t mangle -A openclash_output -m set --match-set wan_ac_black_ports dst -j RETURN if [ "$en_mode" = "redir-host" ]; then ip6tables -t mangle -A openclash_output -m set ! --match-set common_ports dst -j RETURN fi if [ "$china_ip6_route" != "0" ]; then if [ "$china_ip6_route" = "1" ]; then rule="-m set --match-set china_ip6_route dst" elif [ "$china_ip6_route" = "2" ]; then rule="-m set ! --match-set china_ip6_route dst" fi [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set china_ip6_route_pass dst" ip6tables -t mangle -A openclash_output $rule -j RETURN fi #icmpv6 if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash_output -p icmpv6 --icmpv6-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMPv6 Redirect" fi if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then ip6tables -t mangle -A openclash_output -p udp -j MARK --set-xmark "$PROXY_FWMARK" fi if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then ip6tables -t mangle -A openclash_output -j MARK --set-xmark "$PROXY_FWMARK" fi if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then ip6tables -t mangle -A openclash_output -p tcp -j MARK --set-xmark "$PROXY_FWMARK" fi ip6tables -t mangle -A OUTPUT -j openclash_output fi #route if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -eq 0 ]; then check_mod "xt_TPROXY" ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE" fi fi #TUN FORWORD if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -I FORWARD -m comment --comment "OpenClash TUN Forward" -o utun -j ACCEPT ip6tables -I FORWARD -m comment --comment "OpenClash TUN Forward" -i utun -j ACCEPT ip6tables -I INPUT -m comment --comment "OpenClash TUN Input" -i utun -j ACCEPT ip6tables -t nat -I POSTROUTING -m comment --comment "OpenClash TUN Postrouting" -o utun -j RETURN fi #quic if [ "$disable_udp_quic" -eq 1 ]; then if [ "$china_ip6_route" = "2" ]; then rule="-m set --match-set china_ip6_route dst" else rule="-m set ! --match-set china_ip6_route dst" fi ip6tables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then ip6tables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT else ip6tables -I FORWARD -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" $rule -j REJECT fi fi #bypass gateway compatible if [ "$bypass_gateway_compatible" -eq 1 ]; then ip6tables -t nat -N openclash_post ip6tables -t nat -F openclash_post ip6tables -t nat -A openclash_post $owner -j RETURN ip6tables -t nat -A openclash_post -m mark --mark "$PROXY_FWMARK" -j ACCEPT ip6tables -t nat -A openclash_post -m set --match-set localnetwork6 dst -j RETURN ip6tables -t nat -A openclash_post -m conntrack --ctdir REPLY -j RETURN ip6tables -t nat -A openclash_post $addr_local -j MASQUERADE ip6tables -t nat -A POSTROUTING -m comment --comment "OpenClash Bypass Gateway Compatible" -j openclash_post fi #intranet allowed if [ "$intranet_allowed" -eq 1 ]; then if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then config_load "openclash" config_list_foreach "config" "intranet_allowed_wan_name" wan6_name_add else wan6_ints=$(ip6tables-save -t filter |grep -e "-j zone_wan_input" 2>/dev/null |awk '{for (i=1;i<=NF;i++) {if ($i ~ /-i/) {print $(i+1)}}}' 2>/dev/null) fi if [ -n "$wan6_ints" ]; then ip6tables -t filter -N openclash_wan_input ip6tables -t filter -F openclash_wan_input for wan6_int in $wan6_ints; do ip6tables -t filter -I INPUT -i "$wan6_int" -m set ! --match-set localnetwork6 src -j openclash_wan_input done ip6tables -t filter -A openclash_wan_input -p udp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT ip6tables -t filter -A openclash_wan_input -p tcp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT else LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv6 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..." fi fi fi #icmp reject if [ "$en_mode" = "fake-ip" ]; then if [ -z "$en_mode_tun" ]; then iptables -t filter -I INPUT -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP INPUT REJECT" iptables -t filter -I FORWARD -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP FORWARD REJECT" iptables -t filter -I OUTPUT -p icmp --icmp-type echo-request -d "$fakeip_range" $noowner -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP OUTPUT REJECT" fi if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then ip6tables -t filter -I INPUT -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 INPUT REJECT" ip6tables -t filter -I FORWARD -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 FORWARD REJECT" ip6tables -t filter -I OUTPUT -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" $noowner -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 OUTPUT REJECT" fi fi fi fi #来源流量访问控制 config_load "openclash" config_foreach firewall_lan_ac_traffic "lan_ac_traffic" #Custom if [ -f "/etc/openclash/custom/openclash_custom_firewall_rules.sh" ]; then chmod +x /etc/openclash/custom/openclash_custom_firewall_rules.sh /etc/openclash/custom/openclash_custom_firewall_rules.sh fi } >/dev/null 2>&1 revert_firewall() { rm -rf /var/etc/openclash.include ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" #TUN ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip route del default dev utun table "$PROXY_ROUTE_TABLE" ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" ip -6 route del default dev utun table "$PROXY_ROUTE_TABLE" if [ -n "$FW4" ]; then for nft in "input" "forward" "output" "dstnat" "srcnat" "nat_output" "mangle_prerouting" "mangle_output"; do local handles=$(nft -a list chain inet fw4 ${nft} |grep -E "openclash|OpenClash" |awk -F '# handle ' '{print$2}') for handle in $handles; do nft delete rule inet fw4 ${nft} handle ${handle} done done for handle in $(nft -a list chains |grep -E "chain openclash|OpenClash" |awk -F '# handle ' '{print$2}'); do nft delete chain inet fw4 handle ${handle} done for handle in $(nft -a list sets |grep -E "set localnetwork|china_ip|lan_ac_|wan_ac_black_|common_ports" |awk -F '# handle ' '{print$2}'); do nft delete set inet fw4 handle ${handle} done else for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "iptables -nvL OUTPUT" "iptables -nvL POSTROUTING -t nat" "iptables -nvL OUTPUT -t nat" "iptables -nvL OUTPUT -t mangle" "iptables -nvL PREROUTING -t nat" "iptables -nvL PREROUTING -t mangle" "ip6tables -nvL OUTPUT" "ip6tables -nvL INPUT" "ip6tables -nvL FORWARD" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL PREROUTING -t mangle" "ip6tables -nvL POSTROUTING -t nat" "ip6tables -nvL OUTPUT -t nat"; do for comment in "openclash" "OpenClash"; do local lines=$($ipt |sed 1,2d |sed -n "/${comment}/=" 2>/dev/null |sort -rn) if [ -n "$lines" ]; then for line in $lines; do $(echo "$ipt" |awk -v OFS=" " '{print $1,$4,$5}' |sed 's/[ ]*$//g') -D $(echo "$ipt" |awk '{print $3}') $line done fi done done for chain in "openclash" "openclash_output" "openclash_post" "openclash_wan_input" "openclash_dns_redirect" "openclash_upnp"; do iptables -t nat -F $chain iptables -t nat -X $chain iptables -t mangle -F $chain iptables -t mangle -X $chain iptables -t filter -F $chain iptables -t filter -X $chain ip6tables -t nat -F $chain ip6tables -t nat -X $chain ip6tables -t mangle -F $chain ip6tables -t mangle -X $chain ip6tables -t filter -F $chain ip6tables -t filter -X $chain done ipset destroy localnetwork6 ipset destroy china_ip6_route ipset destroy china_ip6_route_pass ipset destroy lan_ac_white_ipv6s ipset destroy lan_ac_black_ipv6s ipset destroy wan_ac_black_ipv6s ipset destroy localnetwork ipset destroy china_ip_route ipset destroy china_ip_route_pass ipset destroy lan_ac_white_ips ipset destroy lan_ac_black_ips ipset destroy lan_ac_white_macs ipset destroy lan_ac_black_macs ipset destroy wan_ac_black_ips ipset destroy wan_ac_black_ports ipset destroy common_ports fi } >/dev/null 2>&1 add_overwrite_cron() { local section="$1" enable type day hour url name config_get_bool "enable" "$section" "enable" "1" config_get "type" "$section" "type" "file" config_get "url" "$section" "url" "" config_get "update_days" "$section" "update_days" "" config_get "update_hour" "$section" "update_hour" "" config_get "name" "$section" "name" "" if [ "$enable" != "1" ] || [ -z "$name" ] || [ "$type" != "http" ] || [ -z "$url" ] || [ -z "$update_days" ] || [ -z "$update_hour" ] || [ "$update_days" = "off" ] || [ "$update_hour" = "off" ]; then return fi eval "restart_flag=\${OVERWRITE_RESTART_FLAG_${name}}" cron_cmd="$cron source /usr/share/openclash/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"/etc/openclash/overwrite/$name\" \"/etc/openclash/overwrite/$name\"" if [ "$restart_flag" = "1" ]; then cron_cmd="$cron_cmd && [ \"\$?\" -eq 0 ] && /etc/init.d/openclash restart" fi cron_cmd="$cron_cmd #openclash-overwrite-download" echo "0 $update_hour * * $update_days $cron_cmd" >> $CRON_FILE } check_type() { local key="$1" local value="$2" local type=$(echo "$allowed_types_map" | grep "^${key}:" | cut -d: -f2) case "$type" in int) echo "$value" | grep -Eq '^[0-9]+$' return $? ;; int_bool) [[ "$value" == "0" || "$value" == "1" ]] return $? ;; bool) [[ "$value" == "true" || "$value" == "false" ]] return $? ;; string|*) return 0 ;; esac } overwrite_config_match_check() { local section="$1" name config config_get "name" "$section" "name" "" config_get "config" "$section" "config" "" [ -z "$name" ] || [ "$name" != "$2" ] || [ -z "$config" ] && return config_list_foreach "$section" "config" overwrite_config_match_item } overwrite_config_match_item() { local config_path_item="$1" [ -z "$config_path_item" ] && return [ "$config_path_item" = "all" ] && OVERWRITE_CONFIG_MATCHED=1 && return [ "$config_path_item" = "$(uci_get_config "config_path")" ] && OVERWRITE_CONFIG_MATCHED=1 } overwrite_file() { clear_overwrite_set overwrite_script="/tmp/yaml_overwrite.sh" cat > "$overwrite_script" <<'EOF' #!/bin/sh . /usr/share/openclash/ruby.sh . /usr/share/openclash/log.sh . /lib/functions.sh EOF allowed_keys_types="\ AGE_SECRET_KEY:string \ AGE_PUBLIC_KEY:string \ APPEND_DEFAULT_DNS:int_bool \ APPEND_WAN_DNS:int_bool \ AUTO_SMART_SWITCH:int_bool \ BYPASS_GATEWAY_COMPATIBLE:int_bool \ CHINA_IP_ROUTE:int \ CHINA_IP_ROUTE_PASS:string \ CHINA_IP6_ROUTE:int \ CHINA_IP6_ROUTE_PASS:string \ CHNR_AUTO_UPDATE:int_bool \ CHNR_CUSTOM_URL:string \ CHNR6_CUSTOM_URL:string \ CHNR_UPDATE_DAY_TIME:string \ CHNR_UPDATE_WEEK_TIME:string \ COMMON_PORTS:string \ CONFIG_FILE:string \ CORE_TYPE:string \ CN_PORT:int \ CUSTOM_FALLBACK_FILTER:int_bool \ CUSTOM_FAKEIP_FILTER:int_bool \ CUSTOM_FAKEIP_FILTER_MODE:string \ CUSTOM_HOST:int_bool \ CUSTOM_NAME_POLICY:int_bool \ DA_PASSWORD:string \ DELAY_START:int \ DISABLE_QUIC_GO_GSO:int_bool \ DISABLE_UDP_QUIC:int_bool \ DNS_PORT:int \ DOWNLOAD_FILE:string \ EN_MODE:string \ ENABLE_CUSTOM_CLASH_RULES:int_bool \ ENABLE_CUSTOM_DNS:int_bool \ ENABLE_GEOIP_DAT:int_bool \ ENABLE_META_SNIFFER:int_bool \ ENABLE_META_SNIFFER_CUSTOM:int_bool \ ENABLE_META_SNIFFER_PURE_IP:int_bool \ ENABLE_REDIRECT_DNS:int_bool \ ENABLE_RESPECT_RULES:int_bool \ ENABLE_RULE_PROXY:int_bool \ ENABLE_TCP_CONCURRENT:int_bool \ ENABLE_UDP_PROXY:int_bool \ ENABLE_UNIFIED_DELAY:int_bool \ ENABLE_V6_UDP_PROXY:int_bool \ FIND_PROCESS_MODE:string \ FAKEIP_RANGE:string \ FAKEIP_RANGE6:string \ GEOASN_AUTO_UPDATE:int_bool \ GEOASN_CUSTOM_URL:string \ GEOASN_UPDATE_DAY_TIME:string \ GEOASN_UPDATE_WEEK_TIME:int \ GEO_CUSTOM_URL:string \ GEODATA_LOADER:string \ GEOIP_AUTO_UPDATE:int_bool \ GEOIP_CUSTOM_URL:string \ GEOIP_UPDATE_DAY_TIME:int \ GEOIP_UPDATE_WEEK_TIME:int \ GEO_AUTO_UPDATE:int_bool \ GEO_UPDATE_DAY_TIME:string \ GEO_UPDATE_WEEK_TIME:int \ GEOSITE_AUTO_UPDATE:int_bool \ GEOSITE_CUSTOM_URL:string \ GEOSITE_UPDATE_DAY_TIME:string \ GEOSITE_UPDATE_WEEK_TIME:int \ GITHUB_ADDRESS_MOD:string \ GLOBAL_UA:string \ HTTP_PORT:int \ INTRANET_ALLOWED:int_bool \ INTRANET_ALLOWED_WAN_NAME:string \ INTERFACE_NAME:string \ IPV6_DNS:int_bool \ IPV6_ENABLE:int_bool \ IPV6_MODE:int \ LAN_INTERFACE_NAME:string \ LGBM_AUTO_UPDATE:int_bool \ LGBM_CUSTOM_URL:string \ LGBM_UPDATE_INTERVAL:int \ MIXED_PORT:int \ OIX_TOKEN:string \ OIX_PARAMS:string \ PROXY_MODE:string \ PROXY_PORT:int \ ROUTER_SELF_PROXY:int_bool \ SMART_COLLECT:int_bool \ SMART_COLLECT_RATE:string \ SMART_COLLECT_SIZE:int \ SMART_ENABLE_LGBM:int_bool \ SMART_POLICY_PRIORITY:string \ SMART_PREFER_ASN:int_bool \ SMART_TOLERANCE:int \ SKIP_PROXY_ADDRESS:int_bool \ SMALL_FLASH_MEMORY:int_bool \ SOCKS_PORT:int \ STACK_TYPE:string \ STORE_FAKEIP:int_bool \ SUB_INFO_URL:string \ TOLERANCE:int \ TPROXY_PORT:int \ URLTEST_ADDRESS_MOD:string \ URLTEST_INTERVAL_MOD:int \ RESTART:bool \ " allowed_keys_list=$(echo "$allowed_keys_types" | tr ' ' '\n' | cut -d: -f1) allowed_types_map=$(echo "$allowed_keys_types" | tr ' ' '\n') uci -q add openclash overwrite >/dev/null 2>&1 overwrite_list=$(uci -q show openclash 2>/dev/null | grep "=config_overwrite" | awk -F'[.=]' '{print $2}' | while read -r sid; do order=$(uci -q get openclash."$sid".order 2>/dev/null) [ -z "$order" ] && order=0 name=$(uci -q get openclash."$sid".name 2>/dev/null) enable_flag=$(uci -q get openclash."$sid".enable 2>/dev/null || echo 0) printf "%s|%s|%s|%s\n" "$order" "$name" "$sid" "$enable_flag" done | sort -nr -t'|' -k1,1) for entry in $overwrite_list; do name=$(echo "$entry" | cut -d'|' -f2) sid=$(echo "$entry" | cut -d'|' -f3) enabled_flag=$(echo "$entry" | cut -d'|' -f4) OVERWRITE_CONFIG_MATCHED=0 config_load "openclash" config_foreach overwrite_config_match_check "config_overwrite" "$name" [ "$OVERWRITE_CONFIG_MATCHED" -eq 0 ] && continue [ "$enabled_flag" != "1" ] && continue [ -z "$name" ] && continue file="/etc/openclash/overwrite/${name}" [ ! -f "$file" ] && continue LOG_TIP "Processing Overwrite Module【$name】" echo "# --- overwrite source: ${name} (sid=${sid}) ---" >> "$overwrite_script" echo "export OPENCLASH_OVERWRITE_SID='${sid}'" >> "$overwrite_script" cfg_name=$(basename "$(uci_get_config "config_path")" 2>/dev/null) age_config_name="${cfg_name%.*}" age_secret_key="" age_public_key="" param=$(uci -q get openclash."$sid".param 2>/dev/null || echo '') if [ -n "$param" ]; then OLD_IFS="$IFS" IFS=';' for kv in $param; do [ -z "$kv" ] && continue k="${kv%%=*}" v="${kv#*=}" k=$(printf "%s" "$k" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') v=$(printf "%s" "$v" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') [ -z "$k" ] && continue varname="$k" v_escaped=$(printf "%s" "$v" | sed "s/'/'\"'\"'/g") export ${varname}=${v_escaped} done IFS="$OLD_IFS" fi in_general=0 in_overwrite=0 in_yaml=0 download_file_lines="" while IFS= read -r line || [ -n "$line" ]; do trimmed=$(printf "%s" "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') case "$trimmed" in "[General]"*) in_general=1; in_overwrite=0; in_yaml=0; continue;; "[Overwrite]"*) in_general=0; in_overwrite=1; in_yaml=0; continue;; "[YAML]"*) in_general=0; in_overwrite=0; in_yaml=1; continue;; "["*"]"*) in_general=0; in_overwrite=0; in_yaml=0; continue;; esac [ -z "$trimmed" ] && continue echo "$trimmed" | grep -qE '^[#;]' && continue if [ "$in_general" -eq 1 ]; then key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g') key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ') if printf "%s" "$key_u" | grep -q "^DOWNLOAD_FILE$"; then download_file_lines="${download_file_lines} ${trimmed}" fi fi done < "$file" download_failed=0 download_file_lines_tmp="/tmp/openclash_download_file_lines.$$" printf "%s\n" "$download_file_lines" | sed '/^$/d' > "$download_file_lines_tmp" while IFS= read -r trimmed; do key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g') val=$(echo "$trimmed" | sed 's/^[^=]*=[[:space:]]*//') key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ') url=$(eval "echo \"$(echo "$val" | sed -nE 's/.*url[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") path=$(eval "echo \"$(echo "$val" | sed -nE 's/.*path[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") cron=$(eval "echo \"$(echo "$val" | sed -nE 's/.*cron[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") force=$(eval "echo \"$(echo "$val" | sed -nE 's/.*force[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") ua=$(eval "echo \"$(echo "$val" | sed -nE 's/.*ua[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") restart=$(eval "echo \"$(echo "$val" | sed -nE 's/.*restart[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')\"") [ -z "$cron" ] && cron=0 if [ -z "$path" ] || [ -z "$url" ]; then LOG_WARN "DOWNLOAD FILE no target in【Download Job => file: $file】" download_failed=1 break fi need_download=0 if [ ! -f "$path" ] || [ "$force" = "true" ]; then need_download=1 fi if [ "$need_download" -eq 1 ] && [ -n "$url" ]; then LOG_TIP "DOWNLOAD FILE for【Download Job => file: $file, url: $url, path: $path, ua: ${ua:-null}, force: ${force:-false}】" if command -v curl >/dev/null 2>&1; then if [ -n "$ua" ]; then DOWNLOAD_FILE_CURL "$url" "$path" "$path" "$ua" else DOWNLOAD_FILE_CURL "$url" "$path" "$path" fi rc=$? fi if [ $rc -eq 1 ] || [ ! -f "$path" ]; then LOG_ERROR "DOWNLOAD FILE failed for【Download Job => file: $file, url: $url, path: $path】" download_failed=1 break fi fi if [ "$cron" != "0" ]; then LOG_TIP "Add Cron for【Cron Job => time: $cron, url: $url, path: $path, restart: ${restart:-false}】" if ! grep -q "$url" $CRON_FILE 2>/dev/null; then if [ -n "$ua" ]; then cron_cmd="$cron source /usr/share/openclash/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"$path\" \"$path\" \"$ua\"" else cron_cmd="$cron source /usr/share/openclash/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"$path\" \"$path\"" fi if [ "$restart" = "1" ] || [ "$restart" = "true" ]; then cron_cmd="$cron_cmd && [ \"\$?\" -eq 0 ] && /etc/init.d/openclash restart" fi cron_cmd="$cron_cmd #openclash-overwrite-download" echo "$cron_cmd" >> $CRON_FILE fi fi done < "$download_file_lines_tmp" rm -f "$download_file_lines_tmp" [ "$download_failed" -eq 1 ] && continue in_general=0 in_overwrite=0 in_yaml=0 yaml_content="" while IFS= read -r line || [ -n "$line" ]; do trimmed=$(printf "%s" "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') case "$trimmed" in "[General]"*) in_general=1; in_overwrite=0; in_yaml=0; continue;; "[Overwrite]"*) in_general=0; in_overwrite=1; in_yaml=0; continue;; "[YAML]"*) in_general=0; in_overwrite=0; in_yaml=1; continue;; "["*"]"*) in_general=0; in_overwrite=0; in_yaml=0; continue;; esac [ -z "$trimmed" ] && continue echo "$trimmed" | grep -qE '^[#;]' && continue if [ "$in_general" -eq 1 ]; then key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g') key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ') if printf "%s" "$key_u" | grep -q "^DOWNLOAD_FILE$"; then continue fi val=$(echo "$trimmed" | sed 's/^[^=]*=[[:space:]]*//') if printf "%s" "$key_u" | grep -q "^CONFIG_FILE$"; then val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") RAW_CONFIG_FILE=$(eval "echo \"$val_clean\"") uci -q set openclash.@overwrite[0].config_path="$RAW_CONFIG_FILE" cfg_name=$(basename "$RAW_CONFIG_FILE" 2>/dev/null) if [ -n "$cfg_name" ]; then age_config_name="${cfg_name%.*}" CONFIG_FILE="/etc/openclash/${cfg_name}" TMP_CONFIG_FILE="/tmp/${cfg_name}" fi elif printf "%s" "$key_u" | grep -q "^SUB_INFO_URL$"; then val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") url_key=$(eval "echo \"$val_clean\"") [ -z "$url_key" ] && continue config_load "openclash" config_foreach sub_info_set "subscribe_info" "${cfg_name%.*}" "$url_key" if [ "$sub_info_setted" != "1" ]; then uci -q add openclash subscribe_info uci -q set openclash.@subscribe_info[-1].name="${cfg_name%.*}" uci -q add_list openclash.@subscribe_info[-1].url="$url_key" fi elif printf "%s" "$key_u" | grep -q "^AGE_SECRET_KEY$"; then val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") val_key=$(eval "echo \"$val_clean\"") [ -z "$val_key" ] && continue age_secret_key="$val_key" elif printf "%s" "$key_u" | grep -q "^AGE_PUBLIC_KEY$"; then val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") val_key=$(eval "echo \"$val_clean\"") [ -z "$val_key" ] && continue age_public_key="$val_key" elif printf "%s" "$key_u" | grep -q "^RESTART$"; then val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") val_key=$(eval "echo \"$val_clean\"") if printf "%s" "$val_key" | grep -qE '^(1|true|yes)$'; then eval OVERWRITE_RESTART_FLAG_${name}=1 fi else if echo "$allowed_keys_list" | grep -xq "$key_u"; then key_l=$(printf "%s" "$key_u" | tr 'A-Z' 'a-z' | tr -d ' ') val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//") val_key=$(eval "echo \"$val_clean\"") if check_type "$key_u" "$val_clean"; then uci -q set openclash.@overwrite[0]."$key_l"="$val_key" fi else LOG_WARN "skip General key not allowed【General Key => $name: $key_u】" fi fi elif [ "$in_overwrite" -eq 1 ]; then if printf "%s" "$trimmed" | grep -qE '^ruby_[a-z_]+\b'; then echo "$trimmed" >> "$overwrite_script" LOG_TIP "Load Overwrite Script【Ruby Script => $trimmed】" else LOG_WARN "skip invalid Overwrite command【Ruby Script => $name: $trimmed】" fi elif [ "$in_yaml" -eq 1 ]; then yaml_content="${yaml_content}$(eval "echo \"$line\"")"$'\n' fi done < "$file" if [ -n "$age_config_name" ] && { [ -n "$age_secret_key" ] || [ -n "$age_public_key" ]; }; then uci_set_age_keys_by_name "$age_config_name" "$age_secret_key" "$age_public_key" fi if [ -n "$yaml_content" ]; then LOG_TIP "Load YAML Override Block【YAML Block => $name】" cat >> "$overwrite_script" <<'EOF' ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " # YAML Override Block Processing begin yaml_override_content = <<-'YAML_CONTENT' EOF echo "$yaml_content" >> "$overwrite_script" cat >> "$overwrite_script" <<'EOF' YAML_CONTENT begin yaml_data = YAML.load(yaml_override_content) if yaml_data.is_a?(Hash) if File.exist?('/tmp/yaml_overwrite_marshal') Value = Marshal.load(File.open('/tmp/yaml_overwrite_marshal', 'rb') { |f| f.read }) else Value = YAML.load_file('$CONFIG_FILE') end Overwrite_Value = YAML.overwrite(Value, yaml_data) YAML.dump(Overwrite_Value, '$CONFIG_FILE') File.open('/tmp/yaml_overwrite_marshal', 'wb') { |f| Marshal.dump(Overwrite_Value, f) } else YAML.LOG_WARN('Invalid YAML Override format, skipped...') end rescue => e YAML.LOG_ERROR('Parse YAML Override failed:【%s】' % [e.message]) end rescue => e YAML.LOG_ERROR('Parse YAML Override failed:【%s】' % [e.message]) end " >> $LOG_FILE 2>&1 EOF fi cat >> "$overwrite_script" <<'EOF' if [ -f "/tmp/yaml_openclash_ruby_parts/$OPENCLASH_OVERWRITE_SID" ]; then ruby_code=$(cat "/tmp/yaml_openclash_ruby_parts/$OPENCLASH_OVERWRITE_SID") ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin if File.exist?('/tmp/yaml_overwrite_marshal') Value = Marshal.load(File.open('/tmp/yaml_overwrite_marshal', 'rb') { |f| f.read }) else Value = YAML.load_file('$CONFIG_FILE') end threads = [] $ruby_code threads.each(&:join) YAML.dump(Value, '$CONFIG_FILE') rescue Exception => e YAML.LOG_ERROR('Set Custom Overwrite Script Failed,【%s】' % [e.message]) end " >> $LOG_FILE 2>&1 fi EOF echo "" >> "$overwrite_script" done if [ -n "$(uci -q show openclash.@overwrite[0] | grep -v '=overwrite$')" ]; then eval "$(uci -q show openclash.@overwrite[0] | grep -v '=overwrite$' | sed 's/^openclash\.@overwrite\[0\]\.//g' | sed 's/=/="/;s/$/"/')" while IFS='=' read -r key value; do [ -z "$key" ] && continue key_clean=$(echo "$key" | sed 's/^openclash\.[^.]*\.//') value_clean=$(echo "$value" | sed "s/^'//;s/'$//") [ -z "$key_clean" ] && continue LOG_TIP "Load Overwrite Script【$key_clean => '$value_clean'】" done </dev/null) CONFIG_FILE="/etc/openclash/${CFG_NAME}" TMP_CONFIG_FILE="/tmp/${CFG_NAME}" CFG_NO_EXT_NAME="${CFG_NAME%.*}" SECRET_KEY=$(uci_get_age_secret_keys "$CFG_NO_EXT_NAME") OIX_TOKEN=$(uci_get_config "oix_token") OIX_PARAMS=$(uci_get_config "oix_params") enable=$(uci_get_config "enable") enable_custom_clash_rules=$(uci_get_config "enable_custom_clash_rules") da_password=$(uci_get_config "dashboard_password") cn_port=$(uci_get_config "cn_port") proxy_port=$(uci_get_config "proxy_port") tproxy_port=$(uci_get_config "tproxy_port" || echo 7895) proxy_mode=$(uci_get_config "proxy_mode") ipv6_enable=$(uci_get_config "ipv6_enable") ipv6_dns=$(uci_get_config "ipv6_dns" || echo 0) ipv6_mode=$(uci_get_config "ipv6_mode" || echo 0) enable_v6_udp_proxy=$(uci_get_config "enable_v6_udp_proxy" || echo 0) http_port=$(uci_get_config "http_port") socks_port=$(uci_get_config "socks_port") enable_redirect_dns=$(uci_get_config "enable_redirect_dns" || echo 1) if [ "$(uci_get_config "fakeip_range")" == "0" ]; then fakeip_range=$(ruby_read "$RAW_CONFIG_FILE" "['dns']['fake-ip-range']") else fakeip_range=$(uci_get_config "fakeip_range") fi [ -z "$fakeip_range" ] && fakeip_range="198.18.0.1/16" if [ "$(uci_get_config "fakeip_range6")" == "0" ]; then fakeip_range6=$(ruby_read "$RAW_CONFIG_FILE" "['dns']['fake-ip-range6']") else fakeip_range6=$(uci_get_config "fakeip_range6") fi if [ -z "$fakeip_range6" ]; then fakeip_range6="fdfe:dcba:9876::1/64" fake_ip_range6_enable=0 else fake_ip_range6_enable=1 fi lan_interface_name=$(uci_get_config "lan_interface_name" || echo 0) if [ "$lan_interface_name" = "0" ]; then lan_ip=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' 2>/dev/null | tr -d '\n' || ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w "inet" 2>/dev/null |grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n' || ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n') else lan_ip=$(ip address show $lan_interface_name 2>/dev/null | grep -w "inet" 2>/dev/null | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n') fi wan_ip4s=$(/usr/share/openclash/openclash_get_network.lua "wanip" 2>/dev/null) wan_ip6s=$(ifconfig | grep 'inet6 addr' | awk '{print $3}' 2>/dev/null) log_level=$(uci_get_config "log_level") intranet_allowed=$(uci_get_config "intranet_allowed") enable_udp_proxy=$(uci_get_config "enable_udp_proxy" || echo 1) disable_udp_quic=$(uci_get_config "disable_udp_quic") operation_mode=$(uci_get_config "operation_mode") lan_ac_mode=$(uci_get_config "lan_ac_mode") enable_rule_proxy=$(uci_get_config "enable_rule_proxy") stack_type=$(uci_get_config "stack_type") stack_type_v6=$(uci_get_config "stack_type_v6" || echo "system") china_ip_route=$(uci_get_config "china_ip_route"); [[ "$china_ip_route" != "0" && "$china_ip_route" != "1" && "$china_ip_route" != "2" ]] && china_ip_route=0 china_ip6_route=$(uci_get_config "china_ip6_route"); [[ "$china_ip6_route" != "0" && "$china_ip6_route" != "1" && "$china_ip6_route" != "2" ]] && china_ip6_route=0 small_flash_memory=$(uci_get_config "small_flash_memory") mixed_port=$(uci_get_config "mixed_port") interface_name=$(uci_get_config "interface_name" || echo 0) common_ports=$(uci_get_config "common_ports") dns_port=$(uci_get_config "dns_port") store_fakeip=$(uci_get_config "store_fakeip" || echo 0) bypass_gateway_compatible=$(uci_get_config "bypass_gateway_compatible" || echo 0) core_version=$(uci_get_config "core_version" || echo 0) router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1) enable_meta_sniffer=$(uci_get_config "enable_meta_sniffer" || echo 0) enable_meta_sniffer_custom=$(uci_get_config "enable_meta_sniffer_custom" || echo 0) geodata_loader=$(uci_get_config "geodata_loader" || echo 0) enable_geoip_dat=$(uci_get_config "enable_geoip_dat" || echo 0) enable_tcp_concurrent=$(uci_get_config "enable_tcp_concurrent" || echo 0) append_default_dns=$(uci_get_config "append_default_dns" || echo 0) enable_meta_sniffer_pure_ip=$(uci_get_config "enable_meta_sniffer_pure_ip" || echo 0) find_process_mode=$(uci_get_config "find_process_mode" || echo 0) upnp_lease_file=$(uci -q get upnpd.config.upnp_lease_file) enable_unified_delay=$(uci_get_config "enable_unified_delay" || echo 0) enable_respect_rules=$(uci_get_config "enable_respect_rules" || echo 0) intranet_allowed_wan_name=$(uci_get_config "intranet_allowed_wan_name" || echo 0) custom_fakeip_filter_mode=$(uci_get_config "custom_fakeip_filter_mode" || echo "blacklist") iptables_compat=$(iptables -m owner -h 2>/dev/null | grep "owner match options" || command -v fw4 || echo 0) disable_quic_go_gso=$(uci_get_config "disable_quic_go_gso" || echo 0) smart_enable=$(uci_get_config "smart_enable" || echo 0) cors_allow=$(uci_get_config "dashboard_forward_domain" || echo 0) geo_custom_url=$(uci_get_config "geo_custom_url" || echo 0) geoip_custom_url=$(uci_get_config "geoip_custom_url" || echo 0) geosite_custom_url=$(uci_get_config "geosite_custom_url" || echo 0) geoasn_custom_url=$(uci_get_config "geoasn_custom_url" || echo 0) global_ua=$(uci_get_config "global_ua" || echo 0) auto_smart_switch=$(uci_get_config "auto_smart_switch" || echo 0) lgbm_auto_update=$(uci_get_config "lgbm_auto_update" || echo 0) lgbm_custom_url=$(uci_get_config "lgbm_custom_url" || echo "https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin") lgbm_update_interval=$(uci_get_config "lgbm_update_interval" || echo 72) smart_collect=$(uci_get_config "smart_collect" || echo 0) smart_collect_size=$(uci_get_config "smart_collect_size" || echo 100) smart_collect_rate=$(uci_get_config "smart_collect_rate" || echo 1) smart_policy_priority=$(uci_get_config "smart_policy_priority" || echo 0) smart_enable_lgbm=$(uci_get_config "smart_enable_lgbm" || echo 0) smart_prefer_asn=$(uci_get_config "smart_prefer_asn" || echo 0) smart_tolerance=$(uci_get_config "smart_tolerance" || echo 0) [ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash.config.dns_port=7874 uci -q commit openclash } start_service() { enable=$(uci_get_config "enable") [ "$enable" != "1" ] && LOG_WARN "OpenClash Now Disabled, Need Start From Luci Page, Exit..." && exit 0 if procd_running "openclash" >/dev/null; then LOG_TIP "OpenClash Already Running, Exit..." exit 0 fi LOG_TIP "OpenClash Start Running..." { LOG_OUT "Step 1: Get The Configuration..." # Check instead of restart check_run_quick overwrite_file get_config config_choose do_run_mode LOG_OUT "Step 2: Check The Components..." do_run_file "$RAW_CONFIG_FILE" if ! $QUICK_START; then LOG_OUT "Step 3: Modify The Config File..." config_check /usr/share/openclash/yml_change.sh \ "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port"\ "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns"\ "$store_fakeip" "$enable_meta_sniffer" "$enable_geoip_dat" "$geodata_loader" "$enable_meta_sniffer_custom"\ "$interface_name" "$enable_tcp_concurrent" "$core_type" "$append_default_dns" "$enable_meta_sniffer_pure_ip"\ "$find_process_mode" "$fakeip_range" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay"\ "$enable_respect_rules" "$custom_fakeip_filter_mode" "$iptables_compat" "$disable_quic_go_gso" "$cors_allow"\ "$geo_custom_url" "$geoip_custom_url" "$geosite_custom_url" "$geoasn_custom_url"\ "$lgbm_auto_update" "$lgbm_custom_url" "$lgbm_update_interval" "$smart_collect" "$smart_collect_size"\ "$fakeip_range6" "$fake_ip_range6_enable" "$global_ua" /usr/share/openclash/yml_rules_change.sh \ "$enable_custom_clash_rules" "$TMP_CONFIG_FILE"\ "$enable_rule_proxy" "$router_self_proxy" "$lan_ip" "$enable_redirect_dns" "$en_mode"\ "$auto_smart_switch" "$smart_collect" "$smart_collect_rate" "$smart_policy_priority" "$smart_enable_lgbm" "$smart_prefer_asn" "$smart_tolerance" #Custom overwrite if [ -f "/tmp/yaml_overwrite.sh" ]; then chmod +x /tmp/yaml_overwrite.sh CONFIG_FILE="${TMP_CONFIG_FILE}" /tmp/yaml_overwrite.sh rm -rf /tmp/yaml_openclash_ruby_parts fi if [ -f "/etc/openclash/custom/openclash_custom_overwrite.sh" ]; then chmod +x /etc/openclash/custom/openclash_custom_overwrite.sh /etc/openclash/custom/openclash_custom_overwrite.sh "$TMP_CONFIG_FILE" if [ -f "/tmp/yaml_openclash_ruby_parse" ]; then sed -n "s/.*yaml_file_path=['\"]\([^'\"]*\)['\"].*/\1/p" /tmp/yaml_openclash_ruby_parse | sort | uniq | while read -r yaml_file; do [ -z "$yaml_file" ] && continue ruby_code=$(grep "yaml_file_path=['\"]$yaml_file['\"]" /tmp/yaml_openclash_ruby_parse | sed "s/^threads << Thread.new do //;s/ end$//") [ -z "$ruby_code" ] && continue if [ -f "$yaml_file" ]; then ( ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin Value = YAML.load_file('$yaml_file'); threads = [] $ruby_code threads.each(&:join) YAML.dump(Value, '$yaml_file') rescue Exception => e YAML.LOG_ERROR('Set Custom Overwrite Script Failed,【%s】' % [e.message]) end " >> $LOG_FILE 2>&1 ) fi done fi fi #provider path ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin threads = [] Value = YAML.load_file('$TMP_CONFIG_FILE') provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'} provider_configs.each do |provider_type, path_prefix| if Value.key?(provider_type) && Value[provider_type].is_a?(Hash) Value[provider_type].each do |name, config| threads << Thread.new { begin path_val = config['path'] if path_val && !path_val.to_s.match?(%r{^\./#{Regexp.escape(path_prefix)}/}) config['path'] = File.join('.', path_prefix, File.basename(path_val.to_s)) elsif (path_val.nil? || path_val.to_s == '') && config['type'].to_s == 'http' config['path'] = File.join('.', path_prefix, name.to_s) end rescue => e YAML.LOG_ERROR('Edit Provider Path Failed,【%s】' % [e.message]) end } end end end threads.each(&:join) YAML.dump(Value, '$TMP_CONFIG_FILE') rescue Exception => e YAML.LOG_ERROR('Edit Provider Path Failed,【%s】' % [e.message]) end " >> $LOG_FILE 2>&1 else LOG_OUT "Step 3: Quick Start Mode, Skip Modify The Config File..." fi LOG_OUT "Step 4: Start Running The Clash Core..." start_run_core LOG_OUT "Step 5: Add Cron Rules, Start Daemons..." add_cron LOG_OUT "Step 6: Core Status Checking and Firewall Rules Setting..." check_core_status "start" & if [ "$ipv6_enable" -eq 0 ] && [ "$(uci -q get dhcp.lan.dhcpv6)" != "disabled" ] && [ -n "$(uci -q get dhcp.lan.dhcpv6)" ]; then LOG_WARN "Please Note That Network May Abnormal With IPv6's DHCP Server" fi rm -rf /tmp/yaml_* } echo "OpenClash Already Start!" } stop_service() { get_config LOG_TIP "OpenClash Stoping..." LOG_OUT "Step 1: Backup The Current Groups State..." { /usr/share/openclash/openclash_history_get.sh LOG_OUT "Step 2: Delete OpenClash Firewall Rules..." revert_firewall LOG_OUT "Step 3: Close The OpenClash Services..." for process in "openclash_streaming_unlock.lua"; do pids=$(unify_ps_pids "$process") if [ -n "$pids" ]; then for pid in $pids; do kill -9 "$pid" done fi done # prevent respawn during stopping procd_kill "openclash" for i in $(seq 1 10); do procd_running "openclash" >/dev/null && sleep 1 || break done LOG_OUT "Step 4: Restart Dnsmasq..." revert_dnsmasq LOG_OUT "Step 5: Delete OpenClash Residue File..." LOG_TIP "OpenClash Already Stop!" if [ "$enable" != "1" ]; then rm -rf /tmp/openclash_version_history.json \ /tmp/openclash_cdn_info.json \ /tmp/openclash.change \ /tmp/openclash_announcement \ ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf \ ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf \ ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_custom_domain.conf fi del_cron clear_overwrite_set rm -rf /tmp/openclash_jobs rm -rf /tmp/yaml_* } >/dev/null 2>&1 echo "OpenClash Already Stop!" } restart() { echo "OpenClash Restart..." LOG_TIP "OpenClash Restart..." check_run_quick stop_service start } start_watchdog() { procd_open_instance "openclash-watchdog" procd_set_param command "/usr/share/openclash/openclash_watchdog.sh" procd_close_instance } reload_service() { get_config MAX_RELOAD=10 if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "firewall" ]; then #sleep for avoiding system unready sleep 5 NOW_TS=$(date +%s) LAST_LINE=$(grep "Reload OpenClash Firewall Rules...$" "$LOG_FILE" | tail -n 1) LAST_TIME=$(echo "$LAST_LINE" | awk '{print $1" "$2}') LAST_TS=$(date -d "$LAST_TIME" +%s 2>/dev/null) CUR_RELOAD_NUM=$(echo "$LAST_LINE" | grep -oE '【[0-9]+/' | grep -oE '[0-9]+') if [ -n "$LAST_TS" ] && [ $((NOW_TS - LAST_TS)) -gt 300 ]; then CUR_RELOAD_NUM=0 fi [ -z "$CUR_RELOAD_NUM" ] && CUR_RELOAD_NUM=0 CUR_RELOAD_NUM=$((CUR_RELOAD_NUM+1)) [ "$CUR_RELOAD_NUM" -gt "$MAX_RELOAD" ] && CUR_RELOAD_NUM=$MAX_RELOAD RELOAD_COUNT=$(grep "Reload OpenClash Firewall Rules...$" "$LOG_FILE" | awk '{print $1" "$2}' | while read t; do TS=$(date -d "$t" +%s 2>/dev/null) [ -n "$TS" ] && [ $((NOW_TS - TS)) -le 300 ] && echo 1 done | wc -l) if [ "$RELOAD_COUNT" -ge "$MAX_RELOAD" ]; then LOG_OUT "【${CUR_RELOAD_NUM}/$MAX_RELOAD】Skip Reload OpenClash Firewall Rules Until 5 Minutes Later..." exit 0 fi LOG_OUT "【${CUR_RELOAD_NUM}/$MAX_RELOAD】Reload OpenClash Firewall Rules..." revert_firewall do_run_mode check_core_status & fi if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "manual" ]; then LOG_OUT "Manually Reload Firewall Rules..." revert_firewall do_run_mode check_core_status & fi if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "revert" ]; then revert_firewall revert_dnsmasq fi if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "restore" ]; then do_run_mode # used for config subscribe, not background for avoiding system unready check_core_status fi } >/dev/null 2>&1 boot() { delay_start=$(uci_get_config "delay_start" || echo 0) enable=$(uci_get_config "enable") if [ "$delay_start" -gt 0 ] && [ "$enable" == "1" ]; then LOG_OUT "Enable Delay Start, OpenClash Will Start After【$delay_start】Seconds..." sleep "$delay_start" fi restart }