#!/bin/sh /etc/rc.common
# Copyright (c) 2019 vernesong

START=99
STOP=15

. $IPKG_INSTROOT/usr/share/openclash/openclash_ps.sh
. $IPKG_INSTROOT/usr/share/openclash/ruby.sh
. $IPKG_INSTROOT/usr/share/openclash/log.sh

[ -f /etc/openwrt_release ] && {
RAW_CONFIG_FILE=$(uci -q get openclash.config.config_path)
BACKUP_FILE="/etc/openclash/backup/$(uci -q get openclash.config.config_path |awk -F '/' '{print $5}' 2>/dev/null)"
CONFIG_FILE="/etc/openclash/$(uci -q get openclash.config.config_path |awk -F '/' '{print $5}' 2>/dev/null)"
TMP_CONFIG_FILE="/tmp/yaml_config_tmp_$(uci -q get openclash.config.config_path |awk -F '/' '{print $5}' 2>/dev/null)"
}
LOGTIME=$(echo $(date "+%Y-%m-%d %H:%M:%S"))
CLASH="/etc/openclash/clash"
CLASH_CONFIG="/etc/openclash"
CRON_FILE="/etc/crontabs/root"
CACHE_PATH_OLD="/etc/openclash/.cache"
CACHE_PATH="/etc/openclash/cache.db"
LOG_FILE="/tmp/openclash.log"
START_LOG="/tmp/openclash_start.log"
LOCK_FILE=/tmp/lock/openclash.lock
PROXY_FWMARK="0x162"
PROXY_ROUTE_TABLE="0x162"
FW4="$(command -v fw4)"

set_lock() {
   exec 888>"$LOCK_FILE" 2>/dev/null
   flock -x 888 2>/dev/null
}

del_lock() {
   flock -u 888 2>/dev/null
   rm -rf "$LOCK_FILE"
}

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 -q get openclash.config.auto_update)" -eq 1 ] && [ "$(uci -q get openclash.config.config_auto_update_mode)" -ne 1 ] && echo "0 $(uci -q get openclash.config.auto_update_time) * * $(uci -q get openclash.config.config_update_week_time) /usr/share/openclash/openclash.sh" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_rule.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.other_rule_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.other_rule_update_day_time) * * $(uci -q get openclash.config.other_rule_update_week_time) /usr/share/openclash/openclash_rule.sh" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_ipdb.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.geo_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.geo_update_day_time) * * $(uci -q get openclash.config.geo_update_week_time) /usr/share/openclash/openclash_ipdb.sh" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_geosite.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.geosite_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.geosite_update_day_time) * * $(uci -q get openclash.config.geosite_update_week_time) /usr/share/openclash/openclash_geosite.sh" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_geoip.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.geoip_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.geoip_update_day_time) * * $(uci -q get openclash.config.geoip_update_week_time) /usr/share/openclash/openclash_geoip.sh" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_chnroute.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.chnr_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.chnr_update_day_time) * * $(uci -q get openclash.config.chnr_update_week_time) /usr/share/openclash/openclash_chnroute.sh" >> $CRON_FILE
   }
   [ -z "$(grep "/etc/init.d/openclash" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci -q get openclash.config.auto_restart)" -eq 1 ] && echo "0 $(uci -q get openclash.config.auto_restart_day_time) * * $(uci -q get openclash.config.auto_restart_week_time) /etc/init.d/openclash restart 2>/dev/null" >> $CRON_FILE
   }
   crontab $CRON_FILE
   nohup /usr/share/openclash/openclash_watchdog.sh &
}

del_cron()
{
   sed -i '/openclash.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/openclash_rule.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/openclash_ipdb.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/openclash_geoip.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/openclash_geosite.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/openclash_chnroute.sh/d' $CRON_FILE 2>/dev/null
   sed -i '/\/etc\/init.d\/openclash/d' $CRON_FILE 2>/dev/null
   /etc/init.d/cron restart
}

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"
}

change_dns() {
   if [ "$1" -eq 1 ]; then
      uci -q del openclash.config.dnsmasq_server
      config_load "dhcp"
      config_list_foreach "$(uci show dhcp.@dnsmasq[0].server |awk -F '.' '{print $2}')" "server" save_dnsmasq_server
      uci -q del dhcp.@dnsmasq[-1].server
      uci -q add_list dhcp.@dnsmasq[0].server=127.0.0.1#"$dns_port"
      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)"
      uci -q delete dhcp.@dnsmasq[0].resolvfile
      uci -q set dhcp.@dnsmasq[0].noresolv=1
      uci -q set openclash.config.redirect_dns=1
   else
      uci -q set openclash.config.redirect_dns=0
   fi
   
   if [ "$2" -eq 1 ]; then
      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
      uci -q set openclash.config.cachesize_dns=0
   fi
   
   if [ "$ipv6_dns" == 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 dhcp
   uci -q commit openclash
}

revert_dns() {

   [ "$1" -eq 1 ] && {
      uci -q del dhcp.@dnsmasq[-1].server
      [ -n "${10}" ] && {
         config_load "openclash"
         config_list_foreach "config" "dnsmasq_server" set_dnsmasq_server
      }
      
      if [ "$4" == "0" ] || [ -z "$4" ] || [ -z "$(uci -q show dhcp.@dnsmasq[0].server)" ]; then
         uci -q set dhcp.@dnsmasq[0].noresolv=0
         if [ -n "$5" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile="$5"
         elif [ -n "$3" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile="$3"
         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
         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
         else
            rm -rf /tmp/resolv.conf.auto
            touch /tmp/resolv.conf.auto 2>/dev/null
            cat >> "/tmp/resolv.conf.auto" <<-EOF
# Interface lan
nameserver 114.114.114.114
nameserver 119.29.29.29
EOF
            uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto
         fi
      fi
   }
   
   [ "$6" -eq 1 ] && {
      uci -q set dhcp.@dnsmasq[0].cachesize="$7"
   }
   
   [ "$8" -eq 1 ] && {
     uci -q set dhcp.@dnsmasq[0].filter_aaaa="$9"
   }
   	
   [ "$1" -eq 1 ] && [ "$2" -eq 0 ] && {
      uci -q set openclash.config.redirect_dns=0
   }
   
   [ "$6" -eq 1 ] && [ "$2" -eq 0 ] && {
      uci -q set openclash.config.cachesize_dns=0
   }
   
   [ "$8" -eq 1 ] && [ "$2" -eq 0 ] && {
      uci -q set openclash.config.filter_aaaa_dns=0
   }
   
   uci -q commit dhcp
   uci -q commit openclash
   rm -rf /tmp/dnsmasq.d/dnsmasq_openclash.conf >/dev/null 2>&1
   rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_custom_domain.conf >/dev/null 2>&1
}

kill_clash()
{
   clash_pids=$(pidof clash |sed 's/$//g')
   for clash_pid in $clash_pids; do
      kill -9 "$clash_pid" 2>/dev/null
   done >/dev/null 2>&1
   sleep 1
}

start_fail()
{
   kill_clash
   stop
   del_lock
   exit 0
}

#检查集文件防止启动失败
yml_provider_check()
{
provider_path_line=$(ruby_read "$1" ".key?('$2')")
local provider_path_check
if "$provider_path_line"; then
   while :;
   do
      provider_path_check=$(ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
      Value = YAML.load_file('$1');
      Value['$2'].values.each{|x,v|
      if not x['path'].empty? then
         if x['path'].split('/')[0] == '.' then
            v = '/etc/openclash/'+x['path'].split('./')[1]
         else
            v = x['path']
         end
      end;
      if File::exist?(v) then
         if not YAML.load_file(v).key?('$3') then
            puts false
            break
         end
      else
         puts false
         break
      end
      }
      " 2>/dev/null)
      if [ "$provider_path_check" == "false" ] && [ -n "$(pidof clash)" ]; then
         sleep 2
      else
         break
      fi
   done
fi

if [ -z "$(pidof clash)" ] && [ "$provider_path_check" == "false" ]; then
   if [ "$2" = "proxy-providers" ]; then
      LOG_OUT "Error: Failed To Download Proxy-providers, Please Check The Log Page For Detailed error information!"
   else
      LOG_OUT "Error: Failed To Download Rule-providers, Please Check The Log Page For Detailed error information!"
   fi
   LOG_ALERT
   LOG_OUT "Tip: You Can Try to Restart With Meta Core"
   start_fail
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
      RAW_CONFIG_FILE="/etc/openclash/config/config.yaml"
   else
      RAW_CONFIG_FILE="/etc/openclash/config/$name.yaml"
   fi
   
   uci -q set openclash.config.config_path="$RAW_CONFIG_FILE"
   uci -q commit openclash
   subscribe_enable=1
}

#配置文件选择
config_choose()
{
if [ -z "$RAW_CONFIG_FILE" ] || [ ! -f "$RAW_CONFIG_FILE" ]; then
   CONFIG_NAME=$(ls -lt /etc/openclash/config/ | grep -E '.yaml|.yml' | head -n 1 |awk '{print $9}')
   if [ -n "$CONFIG_NAME" ]; then
      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/yaml_config_tmp_$CONFIG_NAME"
      
   fi
fi 2>/dev/null
CONFIG_NAME=$(echo "$RAW_CONFIG_FILE" |awk -F '/' '{print $5}' 2>/dev/null)
HISTORY_PATH_OLD="/etc/openclash/history/${CONFIG_NAME%.*}"
HISTORY_PATH="/etc/openclash/history/${CONFIG_NAME%.*}.db"

if [ ! -f "$RAW_CONFIG_FILE" ]; then
   config_load "openclash"
   config_foreach sub_info_get "config_subscribe"
   if [ "$subscribe_enable" = "1" ]; then
      LOG_OUT "Config File Does Not Exist, You Have Set Subscription Information, Ready To Download..."
      nohup /usr/share/openclash/openclash.sh &
      del_lock
      exit 0
   else
      LOG_OUT "Error: Config Not Found"
      sleep 3
      del_lock
      exit 0
   fi
fi
}

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
   puts '${LOGTIME} 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_OUT "Error: Ruby Works Abnormally, Please Check The Ruby Library Depends!"
   sleep 3
   start_fail
elif [ ! -f "$TMP_CONFIG_FILE" ] || [ ! -s "$TMP_CONFIG_FILE" ]; then
   LOG_OUT "Error: Config File Format Validation Failed..."
   sleep 3
   start_fail
fi
}

yml_other_rules_get()
{
   local section="$1"
   local enabled config
   config_get_bool "enabled" "$section" "enabled" "1"
   config_get "config" "$section" "config" ""
   
   if [ "$enabled" = "0" ] || [ "$config" != "$2" ]; then
      return
   fi
   
   if [ -n "$rule_name" ]; then
      return
   fi
   
   config_get "rule_name" "$section" "rule_name" ""
}

check_run_quick()
{
   quick_start=true
   check_file="$(echo $RAW_CONFIG_FILE | tr " " "?") /etc/openclash/custom/openclash_custom_domain_dns.list /etc/openclash/custom/openclash_custom_domain_dns_policy.list /etc/openclash/custom/openclash_custom_fake_filter.list /etc/openclash/custom/openclash_custom_fallback_filter.yaml /etc/openclash/custom/openclash_custom_hosts.list /etc/openclash/custom/openclash_custom_rules.list /etc/openclash/custom/openclash_custom_rules_2.list $dev_core_path $tun_core_path $meta_core_path $ipdb_path $geosite_path $geoip_path $chnr_path $chnr6_path /usr/share/openclash/res/ConnersHua.yaml /usr/share/openclash/res/ConnersHua_return.yaml /usr/share/openclash/res/lhie1.yaml /etc/openclash/custom/openclash_force_sniffing_domain.yaml /etc/openclash/custom/openclash_sniffing_domain_filter.yaml /etc/openclash/custom/openclash_sniffing_port_filter.yaml /etc/openclash/custom/openclash_custom_localnetwork_ipv4.list /etc/openclash/custom/openclash_custom_localnetwork_ipv6.list /etc/openclash/custom/openclash_custom_chnroute_pass.list /etc/openclash/custom/openclash_custom_chnroute6_pass.list $cndomain_path"
	 if [ ! -f "$CONFIG_FILE" ] || [ ! -f "/tmp/openclash_config.tmp" ] || [ ! -f "/tmp/openclash.change" ]; then
	    quick_start=false
	    return
	 fi
	 cmp -s "/etc/config/openclash" "/tmp/openclash_config.tmp"
	 if [ "$?" -ne "0" ]; then
	    LOG_OUT "Tip: Because of the file【 /etc/config/openclash 】modificated, Pause quick start..."
	    quick_start=false
	 else
	    if [ -s "/tmp/openclash.change" ]; then
         for i in $check_file; do
            if [ -z "$(grep "$i $(date -r "$i")$" "/tmp/openclash.change")" ]; then
            	LOG_OUT "Tip: Because of the file【 $i 】modificated, Pause quick start..."
            	quick_start=false
            	break
            fi
         done 2>/dev/null
      fi
	 fi
}

write_run_quick()
{
   cmp -s "/etc/config/openclash" "/tmp/openclash_config.tmp"
	 if [ "$?" -ne "0" ]; then
	    cp "/etc/config/openclash" "/tmp/openclash_config.tmp"
	 fi
	 if ! $quick_start; then
	    : > "/tmp/openclash.change"
	    for i in $check_file; do
         echo "$i $(date -r "$i")" >> "/tmp/openclash.change"
      done 2>/dev/null
	 fi
}

custom_rule_provider()
{
   local section="$1"
   local enabled config
   config_get "config" "$section" "config" ""
   config_get_bool "enabled" "$section" "enabled" "1"

   if [ "$enabled" = "0" ]; then
      return
   fi
   
   if [ "$config" = "all" ] || [ "$config" = "$CONFIG_NAME" ]; then
      config_set_custom_rule_provider=1
   fi
}

#运行模式处理
do_run_mode()
{
   en_mode=$(uci -q get openclash.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)" ] && 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" 2>/dev/null
   }
   
   [ -f "/etc/openclash/geoip.dat" ] && {
      mv "/etc/openclash/geoip.dat" "/etc/openclash/GeoIP.dat" 2>/dev/null
   }

   if [ "$small_flash_memory" != "1" ]; then
      dev_core_path="/etc/openclash/core/clash"
      tun_core_path="/etc/openclash/core/clash_tun"
      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"
      cndomain_path="/etc/openclash/accelerated-domains.china.conf"
      mv "/tmp/etc/openclash/Country.mmdb" "$ipdb_path" 2>/dev/null
      mv "/tmp/etc/openclash/china_ip_route.ipset" "$chnr_path" 2>/dev/null
      mv "/tmp/etc/openclash/china_ip6_route.ipset" "$chnr6_path" 2>/dev/null
      mv "/tmp/etc/openclash/GeoSite.dat" "$geosite_path" 2>/dev/null
      mv "/tmp/etc/openclash/GeoIP.dat" "$geoip_path" 2>/dev/null
      mv "/tmp/etc/openclash/accelerated-domains.china.conf" "$cndomain_path" 2>/dev/null
      mv "/tmp/etc/openclash/core/" "/etc/openclash" 2>/dev/null
      if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then
         rm -rf "/tmp/etc/openclash" 2>/dev/null
      fi
   else
      dev_core_path="/tmp/etc/openclash/core/clash"
      tun_core_path="/tmp/etc/openclash/core/clash_tun"
      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"
      cndomain_path="/tmp/etc/openclash/accelerated-domains.china.conf"
      [ ! -h "/etc/openclash/Country.mmdb" ] && mv "/etc/openclash/Country.mmdb" "$ipdb_path" 2>/dev/null
      [ ! -h "/etc/openclash/china_ip_route.ipset" ] && mv "/etc/openclash/china_ip_route.ipset" "$chnr_path" 2>/dev/null
      [ ! -h "/etc/openclash/china_ip6_route.ipset" ] && mv "/etc/openclash/china_ip6_route.ipset" "$chnr6_path" 2>/dev/null
      [ ! -h "/etc/openclash/GeoSite.dat" ] && mv "/etc/openclash/GeoSite.dat" "$geosite_path" 2>/dev/null
      [ ! -h "/etc/openclash/GeoIP.dat" ] && mv "/etc/openclash/GeoIP.dat" "$geoip_path" 2>/dev/null
      [ ! -h "/etc/openclash/accelerated-domains.china.conf" ] && mv "/etc/openclash/accelerated-domains.china.conf" "$cndomain_path" 2>/dev/null
      mv "/etc/openclash/core/" "/tmp/etc/openclash" 2>/dev/null
   fi
    
   rm -rf "/etc/openclash/cache.db" 2>/dev/null
   rm -rf "/etc/openclash/clash" 2>/dev/null
   
   if [ "$enable_meta_core" != "1" ]; then
      if [ -n "$en_mode_tun" ]; then
         ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
         core_type="TUN"
         core_start_log="Tip: Detected The Exclusive Function of The TUN Core, Use TUN Core to Start..."
      fi
   
      if [ "$rule_source" != "0" ]; then
         config_load "openclash"
         config_foreach yml_other_rules_get "other_rules" "$CONFIG_NAME"
      fi
   
      config_load "openclash"
      config_set_custom_rule_provider=0
      for i in "rule_provider_config" "rule_provider_config" "rule_providers" "game_config"; do
         config_foreach custom_rule_provider "$i"
         if [ "$config_set_custom_rule_provider" -eq 1 ]; then
         	break
         fi
      done 2>/dev/null

      if [ "$proxy_mode" = "script" ] || [ "$config_set_custom_rule_provider" -eq 1 ] || [ "$rule_name" = "ConnersHua" ] || [ "$rule_name" = "lhie1" ] || [ -n "$(ruby_read "$RAW_CONFIG_FILE" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ] || [ -n "$(ruby_read "/etc/openclash/custom/openclash_custom_rules.list" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ] || [ -n "$(ruby_read "/etc/openclash/custom/openclash_custom_rules_2.list" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ]; then
         if [ -z "$en_mode_tun" ]; then
            ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
            core_type="TUN"
            core_start_log="Tip: Detected The Exclusive Function of The TUN Core, Use TUN Core to Start..."
         fi
      fi
   else
      ln -s "$meta_core_path" /etc/openclash/clash 2>/dev/null
      core_type="Meta"
      core_start_log="Tip: Detected The Exclusive Function of The Meta Core, Use Meta Core to Start..."
   fi
  
   if [ ! -f "/etc/openclash/clash" ] && [ -f "$dev_core_path" ] && [ -z "$core_type" ]; then
      ln -s "$dev_core_path" /etc/openclash/clash 2>/dev/null
      core_start_log="Tip: No Special Configuration Detected, Use Dev Core to Start..."
   fi
    
   if [ ! -f "/etc/openclash/clash" ] && [ -f "$tun_core_path" ] && [ -z "$core_type" ]; then
      ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
      core_type="TUN"
      core_start_log="Tip: Detected that the Dev Core is not Installed, Use TUN Core to Start..."
   fi
   
   if [ ! -f "/etc/openclash/clash" ] && [ -f "$meta_core_path" ] && [ -z "$core_type" ]; then
      ln -s "$meta_core_path" /etc/openclash/clash 2>/dev/null
      core_type="Meta"
      core_start_log="Tip: Detected that the Dev Core is not Installed, Use Meta Core to Start..."
   fi
   
   [ ! -f "$CLASH" ] && {
      LOG_OUT "Tip: Detected that the Core is not Installed, Ready to Download..."
      rm -rf "/tmp/clash_last_version"
      /usr/share/openclash/openclash_core.sh "$core_type"
      if [ "$core_type" == "TUN" ] && [ ! -f "$tun_core_path" ]; then
         start_fail
      elif [ "$core_type" == "Meta" ] && [ ! -f "$meta_core_path" ]; then
         start_fail
      elif [ -z "$core_type" ] && [ ! -f "$dev_core_path" ]; then
         start_fail
      else
         del_lock
         stop
         exit 0
      fi
   }
   
   [ ! -f "$ipdb_path" ] && {
      LOG_OUT "Tip: Detected that the GEOIP Database is not Installed, Ready to Download..."
      /usr/share/openclash/openclash_ipdb.sh
      if [ ! -f "$ipdb_path" ]; then
         start_fail
      fi
   }
   
   [ ! -f "$geosite_path" ] && [ "$enable_meta_core" = "1" ] && {
      LOG_OUT "Tip: Detected that the GEOSITE Database is not Installed, Ready to Download..."
      /usr/share/openclash/openclash_geosite.sh
      if [ ! -f "$geosite_path" ]; then
         start_fail
      fi
   }
   
   [ ! -f "$geoip_path" ] && [ "$enable_geoip_dat" == "1" ] && {
      LOG_OUT "Tip: Detected that the GEOIP Dat is not Installed, Ready to Download..."
      /usr/share/openclash/openclash_geoip.sh
      if [ "$enable_geoip_dat" == "1" ] && [ ! -f "$geoip_path" ]; then
         start_fail
      fi
   }
   
   if [ "$china_ip_route" = "1" ] || [ "$china_ip6_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
      if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then
         LOG_OUT "Tip: Detected that the Chnroute Cidr or CN Domains List is not Installed, Ready to Download..."
         /usr/share/openclash/openclash_chnroute.sh
      fi
      if [ ! -f "$cndomain_path" ] && [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         LOG_OUT "Tip: Detected that the Chnroute Cidr or CN Domains List 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_OUT "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_OUT "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
      if [ ! -f "$cndomain_path" ] && [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         start_fail
      fi
   fi

   [ ! -x "$tun_core_path" ] && chmod 4755 "$tun_core_path" 2>/dev/null
   [ ! -x "$dev_core_path" ] && chmod 4755 "$dev_core_path" 2>/dev/null
   [ ! -x "$meta_core_path" ] && chmod 4755 "$meta_core_path" 2>/dev/null
  
   [ -f "$ipdb_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$ipdb_path" /etc/openclash/Country.mmdb 2>/dev/null
   }
   
   [ -f "$geosite_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$geosite_path" /etc/openclash/GeoSite.dat 2>/dev/null
   }
   
   [ -f "$geoip_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$geoip_path" /etc/openclash/GeoIP.dat 2>/dev/null
   }

   [ -f "$chnr_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$chnr_path" /etc/openclash/china_ip_route.ipset 2>/dev/null
   }
   
   [ -f "$chnr6_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$chnr6_path" /etc/openclash/china_ip6_route.ipset 2>/dev/null
   }

   [ -f "$cndomain_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$cndomain_path" /etc/openclash/accelerated-domains.china.conf 2>/dev/null
   }
   
   #Restore history cache
   if [ -f "$HISTORY_PATH" ] && [ -f "$HISTORY_PATH_OLD" ]; then
      if [ "$(date -r $HISTORY_PATH +%s)" -ge "$(date -r $HISTORY_PATH_OLD +%s)" ]; 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" 2>/dev/null
            else
               cp "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
            fi
         fi
      else
         cmp -s "$CACHE_PATH_OLD" "$HISTORY_PATH_OLD"
         if [ "$?" -ne "0" ]; then
            cp "$HISTORY_PATH_OLD" "$CACHE_PATH_OLD" 2>/dev/null
         fi
      fi
   else  	
      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" 2>/dev/null
            else
               cp "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
            fi
         fi
      fi
      if [ -f "$HISTORY_PATH_OLD" ]; then
         cmp -s "$CACHE_PATH_OLD" "$HISTORY_PATH_OLD"
         if [ "$?" -ne "0" ]; then
            cp "$HISTORY_PATH_OLD" "$CACHE_PATH_OLD" 2>/dev/null
         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 2>/dev/null
   else
      [ ! -f "$CACHE_PATH" ] && touch "$HISTORY_PATH"
      ln -s "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
   fi
       
   if [ -z "$_koolshare" ]; then
      if ! capsh --is-uid=0 >/dev/null || ! capsh --has-ambient >/dev/null; then
        LOG_OUT "Error: Could Not Load The Capsh Library, Please Verify The Capsh Shell Library Work Well..."
        LOG_OUT "Tip: You Could Download And Re-Install The libcap & libcap-bin Library From The Address Give"
        echo "" >> $LOG_FILE
        echo "---------- https://mirrors.cloud.tencent.com/lede/snapshots/packages/ ----------" >> $LOG_FILE
        echo "" >> $LOG_FILE
        sleep 3
        start_fail
      fi
   fi
   
   #创建原始备份
   if [ ! -f "$2" ]; then
      cp "$1" "$2"
   fi
   
   #保存启动内核类型
   uci -q set openclash.config.core_type="$core_type"
   uci -q commit openclash

}

start_run_core()
{
   LOG_OUT "$core_start_log"
   ulimit -SHn 65535 2>/dev/null
   ulimit -v unlimited 2>/dev/null
   modprobe tun >/dev/null 2>&1
   if ! $quick_start; then
      mv "$TMP_CONFIG_FILE" "$CONFIG_FILE" 2>/dev/null
      rm -rf "$TMP_CONFIG_FILE" 2>/dev/null
   fi
   config_reload=$(uci -q get openclash.config.config_reload)
   if [ -n "$(pidof clash)" ] && [ "$core_type" != "TUN" ] && [ "$core_type" != "Meta" ] && [ "$config_reload" != "0" ]; then
      curl -s --connect-timeout 5 -m 5 -H 'Content-Type: application/json' -H "Authorization: Bearer ${da_password}" -XPUT http://"$lan_ip":"$cn_port"/configs?force=true -d "{\"path\": \"$CONFIG_FILE\"}" 2>/dev/null
   else
      kill_clash
      if [ -z "$_koolshare" ]; then
         #防止赋权失败
         touch "/tmp/openclash.log" 2>/dev/null
         chmod o+w /etc/openclash/proxy_provider/* 2>/dev/null
         chmod o+w /etc/openclash/rule_provider/* 2>/dev/null
         chmod o+w /etc/openclash/history/* 2>/dev/null
         chmod o+w /etc/openclash/cache.db 2>/dev/null
         chmod o+w /tmp/openclash.log 2>/dev/null
         chown nobody:nogroup /etc/openclash/core/* 2>/dev/null
         #使用nobody启动内核方便代理路由自身流量
         capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin,cap_sys_ptrace"
         capsh --caps="${capabilties}+eip" -- -c "capsh --user=nobody --addamb='${capabilties}' -- -c 'nohup $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1 &'" >> $LOG_FILE 2>&1
      else
         nohup $CLASH -d $CLASH_CONFIG -f "$CONFIG_FILE" >> $LOG_FILE 2>&1 &
      fi
   fi
   uci -q set openclash.config.config_reload=1
   uci -q commit openclash
}

check_core_status()
{
   check_time=1
   while ( [ "$check_time" -le 3 ] && [ -n "$(pidof clash)" ] )
   do
      sleep 1
      let check_time++
   done
   if [ -z "$(pidof clash)" ]; then
      LOG_ALERT
   fi
}

#不修改配置文件启动
raw_config_start()
{
   cp "$RAW_CONFIG_FILE" "$CONFIG_FILE"
   dns_port=$(ruby_read "$CONFIG_FILE" "['dns']['listen'].split(':')[1]")
   en_mode=$(ruby_read "$CONFIG_FILE" "['dns']['enhanced-mode']")
   proxy_port=$(ruby_read "$CONFIG_FILE" "['redir-port']")
   
   if [ -z "$dns_port" ] || [ -z "$en_mode" ] || [ -z "$proxy_port" ]; then
      if [ -z "$dns_port" ]; then
         LOG_OUT "Error: Get DNS 'listen' Option Error, OpenClash Can Not Start With Raw Config File"
         sleep 2
      fi
      if [ -z "$en_mode" ]; then
         LOG_OUT "Error: Get DNS 'enhanced-mode' Option Error, OpenClash Can Not Start With Raw Config File"
         sleep 2
      fi
      if [ -z "$proxy_port" ]; then
         LOG_OUT "Error: Get General 'redir-port' Option Error, OpenClash Can Not Start With Raw Config File"
         sleep 2
      fi
      start_fail
   fi
   
   start_run_core
   check_core_status
   
   if ! pidof clash >/dev/null; then
      LOG_OUT "Error: OpenClash Can Not Start, Please Check The Error Info And Try Again!"
      sleep 3
      start_fail
   fi
   
   if [ "$en_mode" = "redir-host" ]; then
      case $en_mode_tun in
      "1")
         uci -q set openclash.config.en_mode=redir-host-tun
      ;;
      "2")
         uci -q set openclash.config.en_mode=redir-host-mix
      ;;
      *)
         uci -q set openclash.config.en_mode=redir-host
      esac
   elif [ "$en_mode" = "fake-ip" ]; then
   	  case $en_mode_tun in
      "1")
         uci -q set openclash.config.en_mode=fake-ip-tun
      ;;
      "2")
         uci -q set openclash.config.en_mode=fake-ip-mix
      ;;
      *)
         uci -q set openclash.config.en_mode=fake-ip
      esac
   fi
   
   dase=$(ruby_read "$CONFIG_FILE" "['secret']")
   uci -q set openclash.config.dashboard_password="$dase"
   
   cn_port=$(ruby_read "$CONFIG_FILE" "['external-controller'].split(':')[1]")
   uci -q set openclash.config.cn_port="$cn_port"
   
   uci -q set openclash.config.proxy_port="$proxy_port"
   uci -q set openclash.config.restricted_mode=1
   
   uci commit openclash
}

try_restore_start()
{
   if [ -z "$(pidof clash)" ]; then
      if [ "$rule_source" = 0 ] && [ "$enable_custom_clash_rules" = 0 ]; then
         LOG_OUT "Error: OpenClash Can Not Start, Try Use Raw Config Restart Again..."
         raw_config_start
      else
         LOG_OUT "Error: OpenClash Can Not Start, Try Use Backup Rules Start Again..."
         ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
         begin
            Value = YAML.load_file('$RAW_CONFIG_FILE');
            Value_1 = YAML.load_file('$CONFIG_FILE');
            if Value.has_key?('rule-providers') then
               Value_1['rule-providers'] = Value.select {|x| 'rule-providers' == x}['rule-providers'];
            end;
            if Value.has_key?('script') then
               Value_1['script'] = Value.select {|x| 'script' == x}['script'];
            end;
            if Value.has_key?('rules') then
               Value_1['rules'] = Value.select {|x| 'rules' == x}['rules'];
            end;
            File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value_1, f)};
         rescue Exception => e
            puts '${LOGTIME} Error: Restore Backup Rules Failed,【' + e.message + '】';
         end
         " 2>/dev/null >> $LOG_FILE
         start_run_core
         check_core_status
         if ! pidof clash >/dev/null; then
            LOG_OUT "Error: OpenClash Can Not Start, Try Use Raw Config Restart Again..."
            raw_config_start
         fi
      fi
   fi
}

#防火墙设置部分
nft_ac_add()
{
   if [ -z "$1" ]; then
      return
   fi

   nft add element inet fw4 "$2" { "$1" } 2>/dev/null
   [ -n "$3" ] && nft add element inet fw4 "$3" { "$1" } 2>/dev/null
}

ac_add()
{
   if [ -z "$1" ]; then
      return
   fi

   ipset add "$2" "$1" 2>/dev/null
   [ -n "$3" ] && ipset add "$3" "$1" 2>/dev/null
}

firewall_rule_exclude()
{
   local section="$1"
   local name src src_port dest dest_port proto target enabled family

   config_get "name" "$section" "name" ""
   config_get "src" "$section" "src" ""
   config_get "src_port" "$section" "src_port" ""
   config_get "dest" "$section" "dest" ""
   config_get "dest_port" "$section" "dest_port" ""
   config_get "dest_ip" "$section" "dest_ip" ""
   config_get "proto" "$section" "proto" ""
   config_get "target" "$section" "target" ""
   config_get "enabled" "$section" "enabled" ""
   config_get "family" "$section" "family" ""

   if [ a"$target" != aACCEPT  ] || [ a"$enabled" == a0 ]; then
      return
   fi

   local e_udp=false
   local e_tcp=false
   for p in $proto; do
       if [ $p == tcp ]; then e_tcp=true; fi
       if [ $p == udp ]; then e_udp=true; fi
       if [ $p == all ]; then e_tcp=true; e_udp=true; fi
   done
   
   if [ -z "$proto" ]; then e_tcp=true; e_udp=true; fi

   if ! $e_udp && ! $e_tcp ; then
       return
   fi
   
   if [ -n "$FW4" ]; then
      if [ -z "$family" ] || [ "$family" == "ipv4" ]; then
         if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  nft insert rule inet fw4 openclash_output position 0 meta nfproto {ipv4} tcp sport "$i" counter return >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash position 0 meta nfproto {ipv4} tcp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash position 0 ip saddr { "$dest_ip" } tcp sport "$i" counter return >/dev/null 2>&1
                  fi
               fi
               if $e_udp ; then
                  nft insert rule inet fw4 openclash_mangle_output position 0 meta nfproto {ipv4} udp sport "$i" counter return >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash_mangle position 0 meta nfproto {ipv4} udp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp sport "$i" counter return >/dev/null 2>&1
                  fi
               fi
            done
         elif [ "$en_mode_tun" -eq 1 ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  nft insert rule inet fw4 openclash_mangle_output position 0 meta nfproto {ipv4} tcp sport "$i" counter return >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash_mangle position 0 meta nfproto {ipv4} tcp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } tcp sport "$i" counter return >/dev/null 2>&1
                  fi
               fi
               if $e_udp ; then
                  nft insert rule inet fw4 openclash_mangle_output position 0 meta nfproto {ipv4} udp sport "$i" counter return >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash_mangle position 0 meta nfproto {ipv4} udp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp sport "$i" counter return >/dev/null 2>&1
                  fi
               fi
            done
         fi
      fi
      
      if [ "$ipv6_enable" -eq 1 ]; then
         if [ -z "$family" ] || [ "$family" == "ipv6" ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash_mangle_v6 position 0 meta nfproto {ipv6} tcp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } tcp sport "$i" counter return >/dev/null 2>&1
                  fi
                  nft insert rule inet fw4 openclash_mangle_output_v6 position 0 meta nfproto {ipv6} tcp sport "$i" counter return >/dev/null 2>&1
               fi
               if $e_udp ; then
                  if [ -z "$dest_ip" ]; then
                     nft insert rule inet fw4 openclash_mangle_v6 position 0 meta nfproto {ipv6} udp sport "$i" counter return >/dev/null 2>&1
                  else
                     nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } udp sport "$i" counter return >/dev/null 2>&1
                  fi
                  nft insert rule inet fw4 openclash_mangle_output_v6 position 0 meta nfproto {ipv6} udp sport "$i" counter return >/dev/null 2>&1
               fi
            done
         fi
      fi
   else
      dest_port=$(echo $dest_port |sed "s/-/:/g" 2>/dev/null)
      dest_ip=$(echo $dest_ip |sed "s/ /,/g" 2>/dev/null)
      
      if [ -z "$family" ] || [ "$family" == "ipv4" ]; then
         if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  iptables -t nat -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     iptables -t nat -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     iptables -t nat -I openclash -p tcp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
               fi
               if $e_udp ; then
                  iptables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     iptables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     iptables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
               fi
            done
         elif [ "$en_mode_tun" -eq 1 ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  iptables -t mangle -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     iptables -t mangle -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     iptables -t mangle -I openclash -p tcp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
               fi
               if $e_udp ; then
                  iptables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  if [ -z "$dest_ip" ]; then
                     iptables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     iptables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
               fi
            done
         fi
      fi
      
      if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
         if [ -z "$family" ] || [ "$family" == "ipv6" ]; then
            for i in $dest_port; do
               if $e_tcp ; then
                  if [ -z "$dest_ip" ]; then
                     ip6tables -t mangle -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     ip6tables -t mangle -I openclash -s "$dest_ip" -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
                  ip6tables -t mangle -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
               fi
               if $e_udp ; then
                  if [ -z "$dest_ip" ]; then
                     ip6tables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  else
                     ip6tables -t mangle -I openclash -s "$dest_ip" -p udp --sport "$i" -j RETURN >/dev/null 2>&1
                  fi
                  ip6tables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
               fi
            done
         fi
      fi
   fi
}

firewall_redirect_exclude()
{
   local section="$1"
   local src_dport dest_port dest_ip proto enabled
   config_get "src_dport" "$section" "src_dport" ""
   config_get "dest_port" "$section" "dest_port" ""
   config_get "dest_ip" "$section" "dest_ip" ""
   config_get "proto" "$section" "proto" ""
   config_get "enabled" "$section" "enabled" ""

   if [ -z "$src_dport" ] || [ a"$enabled" == a0 ]; then
      return
   fi
   local e_udp=false
   local e_tcp=false
   for p in $proto; do
       if [ $p == tcp ]; then e_tcp=true; fi
       if [ $p == udp ]; then e_udp=true; fi
       if [ $p == all ]; then e_tcp=true; e_udp=true; fi
   done
   
   if [ -z "$proto" ]; then e_tcp=true; e_udp=true; fi

   if ! $e_udp && ! $e_tcp ; then
       return
   fi
   
   if [ -n "$FW4" ]; 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 ip saddr { "$dest_ip" } tcp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_output position 0 ip saddr { "$dest_ip" } tcp dport "$src_dport" counter return >/dev/null 2>&1
         fi
         if $e_udp ; then
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
               nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
            fi
         fi
      elif [ "$en_mode_tun" -eq 1 ]; then
         if $e_tcp ; then
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } tcp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } tcp dport "$src_dport" counter return >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               nft insert rule inet fw4 openclash_mangle position 0  ip saddr { "$dest_ip" } tcp sport "$dest_port" counter return >/dev/null 2>&1
               nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } tcp dport "$src_dport" counter return >/dev/null 2>&1
            fi
         fi
         if $e_udp ; then
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_mangle_output position 0 ip saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
               nft insert rule inet fw4 openclash_mangle position 0 ip saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
            fi
         fi
      fi
      
      if [ "$ipv6_enable" -eq 1 ]; then
         if $e_tcp ; then
            if [ -n "$dest_ip" ]; then
               nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } tcp sport "$dest_port" counter return >/dev/null 2>&1
               nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } tcp dport "$src_dport" counter return >/dev/null 2>&1
            fi
            nft insert rule inet fw4 openclash_mangle_output_v6 position 0 ip6 saddr { "$dest_ip" } tcp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_mangle_output_v6 position 0 ip6 saddr { "$dest_ip" } tcp dport "$src_dport" counter return >/dev/null 2>&1
         fi
         if $e_udp ; then
            if [ -n "$dest_ip" ]; then
               nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
               nft insert rule inet fw4 openclash_mangle_v6 position 0 ip6 saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
            fi
            nft insert rule inet fw4 openclash_mangle_output_v6 position 0 ip6 saddr { "$dest_ip" } udp sport "$dest_port" counter return >/dev/null 2>&1
            nft insert rule inet fw4 openclash_mangle_output_v6 position 0 ip6 saddr { "$dest_ip" } udp dport "$src_dport" counter return >/dev/null 2>&1
         fi
      fi
   else
      dest_port=$(echo $dest_port |sed "s/-/:/g" 2>/dev/null)
      src_dport=$(echo $src_dport |sed "s/-/:/g" 2>/dev/null)
      dest_ip=$(echo $dest_ip |sed "s/ /,/g" 2>/dev/null)
      [ -n "$dest_ip" ] && dest_ip="-s ${dest_ip}"

      if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
         if $e_tcp ; then
            iptables -t nat -I openclash_output "$dest_ip" -p tcp --sport "$dest_port" -j RETURN >/dev/null 2>&1
            iptables -t nat -I openclash_output "$dest_ip" -p tcp --dport "$src_dport" -j RETURN >/dev/null 2>&1
         fi
         if $e_udp ; then
            iptables -t mangle -I openclash_output "$dest_ip" -p udp --sport "$dest_port" -j RETURN >/dev/null 2>&1
            iptables -t mangle -I openclash_output "$dest_ip" -p udp --dport "$src_dport" -j RETURN >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               iptables -t mangle -I openclash "$dest_ip" -p udp --dport "$src_dport" -j RETURN >/dev/null 2>&1
               iptables -t mangle -I openclash "$dest_ip" -p udp --sport "$dest_port" -j RETURN >/dev/null 2>&1
            fi
         fi
      elif [ "$en_mode_tun" -eq 1 ]; then
         if $e_tcp ; then
            iptables -t mangle -I openclash_output -p tcp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            iptables -t mangle -I openclash_output -p tcp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               iptables -t mangle -I openclash -p tcp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
               iptables -t mangle -I openclash -p tcp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            fi
         fi
         if $e_udp ; then
            iptables -t mangle -I openclash_output -p udp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            iptables -t mangle -I openclash_output -p udp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
            if [ -n "$dest_ip" ]; then
               iptables -t mangle -I openclash -p udp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
               iptables -t mangle -I openclash -p udp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            fi
         fi
      fi
      
      if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
         if $e_tcp ; then
            if [ -n "$dest_ip" ]; then
               ip6tables -t mangle -I openclash -p tcp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
               ip6tables -t mangle -I openclash -p tcp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            fi
            ip6tables -t mangle -I openclash_output -p tcp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            ip6tables -t mangle -I openclash_output -p tcp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
         fi
         if $e_udp ; then
            if [ -n "$dest_ip" ]; then
               ip6tables -t mangle -I openclash -p udp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
               ip6tables -t mangle -I openclash -p udp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            fi
            ip6tables -t mangle -I openclash_output -p udp "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
            ip6tables -t mangle -I openclash_output -p udp "$dest_ip" --dport "$src_dport" -j RETURN >/dev/null 2>&1
         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" >/dev/null 2>&1
EOF

local settype nftflag
if dnsmasq --version | grep -q 'Compile time options:.* nftset'; then
   settype="nftset"
   nftflag="inet#fw4#"
else
   settype="ipset"
   [ -n "$FW4" ] && LOG_OUT "Warning: Dnsmasq not Support nftset, Use ipset..."
fi

if [ -n "$FW4" ]; then
   LOG_OUT "Tip: Firewall4 was Detected, Use NFTABLE Rules..."
   if [ "$china_ip_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
      nft 'flush set inet fw4 china_ip_route'
      nft -f '/etc/openclash/china_ip_route.ipset' 2>/dev/null
      CHNROUTE_WAIT=0
      while ( [ -z "$(nft list sets |grep "set china_ip_route {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] )
      do
         nft -f '/etc/openclash/china_ip_route.ipset' 2>/dev/null
      done

      mkdir -p /tmp/dnsmasq.d 2>/dev/null
      
      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 '!/^$/&&!/^#/&&/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][0-9]|25[0-4])((\/[0-9][0-9])?)$/{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 '!/^$/&&!/^#/&&/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("    %s,'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list >>/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
      }
      awk '!/^$/&&!/^#/&&!/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][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 >>/tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf 2>/dev/null
      nft 'flush set inet fw4 china_ip_route_pass' 2>/dev/null
      nft -f '/tmp/openclash_china_ip_route_pass.list' 2>/dev/null
      rm -rf /tmp/openclash_china_ip_route_pass.list 2>/dev/null

      if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         cat "/etc/openclash/accelerated-domains.china.conf" |awk -v dns="${custom_china_domain_dns_server}" -F '/' '!/^$/&&!/^#/{print $1"/"$2"/"dns}' >/tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf 2>/dev/null
         for i in `awk '!/^$/&&!/^#/&&!/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("%s\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list`
         do
            sed -i "/server=\/${i}\//d" /tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf 2>/dev/null
         done 2>/dev/null
      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 ] && [ -z "$(nft list chain inet fw4 dstnat |grep 'OpenClash DNS Hijack')"]; then
      nft insert rule inet fw4 dstnat position 0 tcp dport 53 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft insert rule inet fw4 dstnat position 0 udp dport 53 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
   fi
   if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
      LOG_OUT "Tip: Bypass the China IP May Cause the Dnsmasq Load For a Long Time After Restart in FAKE-IP Mode, Hijack the DNS to Core Untill the Dnsmasq Works Well..."
      nft insert rule inet fw4 dstnat position 0 tcp dport 53 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft insert rule inet fw4 dstnat position 0 udp dport 53 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' 2>/dev/null
      nft add rule inet fw4 nat_output position 0 tcp dport 53 meta skuid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft add rule inet fw4 nat_output position 0 udp dport 53 meta skuid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft add rule inet fw4 nat_output position 0 tcp dport 12353 meta skuid != 65534 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
      nft add rule inet fw4 nat_output position 0 udp dport 12353 meta skuid != 65534 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
   fi

   #lan_google_dns_ac
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ]; then
      nft 'add set inet fw4 lan_block_google_dns_ips { type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
      nft 'add set inet fw4 lan_block_google_dns_ipv6s { type ipv6_addr; flags interval; auto-merge; }' 2>/dev/null
      config_load "openclash"
      config_list_foreach "config" "lan_block_google_dns_ips" nft_ac_add "lan_block_google_dns_ips" "lan_block_google_dns_ipv6s"
   fi
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
      nft 'add set inet fw4 lan_block_google_dns_macs { type ether_addr; }' 2>/dev/null
      config_load "openclash"
      config_list_foreach "config" "lan_block_google_dns_macs" nft_ac_add "lan_block_google_dns_macs"
   fi

   #lan_ac
   if [ "$operation_mode" = "redir-host" ] && [ "$en_mode" = "redir-host" ]; then
      if [ "$lan_ac_mode" = "0" ]; then
         if [ -n "$(uci -q get openclash.config.lan_ac_black_ips)" ]; then
            nft 'add set inet fw4 lan_ac_black_ips { type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
            nft 'add set inet fw4 lan_ac_black_ipv6s { type ipv6_addr; flags interval; auto-merge; }' 2>/dev/null
            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 -q get openclash.config.lan_ac_black_macs)" ]; then
            nft 'add set inet fw4 lan_ac_black_macs { type ether_addr; }' 2>/dev/null
            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 -q get openclash.config.lan_ac_white_ips)" ]; then
            nft 'add set inet fw4 lan_ac_white_ips { type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
            nft 'add set inet fw4 lan_ac_white_ipv6s { type ipv6_addr; flags interval; auto-merge; }' 2>/dev/null
            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 -q get openclash.config.lan_ac_white_macs)" ]; then
            nft 'add set inet fw4 lan_ac_white_macs { type ether_addr; }' 2>/dev/null
            config_load "openclash"
            config_list_foreach "config" "lan_ac_white_macs" nft_ac_add "lan_ac_white_macs"
         fi
      fi
   fi

   #wan ac
   if [ -n "$(uci -q get openclash.config.wan_ac_black_ips)" ]; then
      nft 'add set inet fw4 wan_ac_black_ips { type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
      nft 'add set inet fw4 wan_ac_black_ipv6s { type ipv6_addr; flags interval; auto-merge; }' 2>/dev/null
      config_load "openclash"
      config_list_foreach "config" "wan_ac_black_ips" nft_ac_add "wan_ac_black_ips" "wan_ac_black_ipv6s"
   fi

   #lan port ac
   if [ -n "$(uci -q get openclash.config.lan_ac_black_ports)" ]; then
      nft 'add set inet fw4 lan_ac_black_ports { type inet_service; }' 2>/dev/null
      config_load "openclash"
      config_list_foreach "config" "lan_ac_black_ports" nft_ac_add "lan_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" } 2>/dev/null
         done 2>/dev/null
      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 "$lan_ip_cidrs" ]; then
         for lan_ip_cidr in $lan_ip_cidrs; do
            nft add element inet fw4 localnetwork { "$lan_ip_cidr" } 2>/dev/null
         done
      fi

      if [ -n "$wan_ip4s" ]; then
         for wan_ip4 in $wan_ip4s; do
            nft add element inet fw4 localnetwork { "$wan_ip4" } 2>/dev/null
         done
      fi

   #common ports
   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 5222 5228 5229 5230 8080 8443 8880 8888 8889"
      nft 'add set inet fw4 common_ports { type inet_service; }'
      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' 2>/dev/null
      nft 'add chain inet fw4 openclash_post' 2>/dev/null
      nft 'flush chain inet fw4 openclash_post' 2>/dev/null
      nft 'add rule inet fw4 openclash_post ip saddr @localnetwork tcp sport @lan_ac_black_ports counter return' 2>/dev/null
      nft add rule inet fw4 openclash_post meta mark "$PROXY_FWMARK" counter accept 2>/dev/null
      nft 'add rule inet fw4 openclash_post ip daddr @localnetwork counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_post meta nfproto {ipv4} fib saddr type != { local } meta skuid != 65534 counter masquerade' 2>/dev/null
      nft add rule inet fw4 srcnat meta nfproto {ipv4} counter jump openclash_post comment \"OpenClash Bypass Gateway Compatible\" 2>/dev/null
   fi

   #intranet allowed
   if [ "$intranet_allowed" -eq 1 ]; then
      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/) {print $(i+1)}}}' 2>/dev/null |sed 's/"//g')
      if [ -n "$wan_ints" ]; then
         nft 'add chain inet fw4 openclash_wan_input' 2>/dev/null
         nft 'flush chain inet fw4 openclash_wan_input' 2>/dev/null
         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 2>/dev/null
         done
         nft add rule inet fw4 openclash_wan_input udp dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject
         nft add rule inet fw4 openclash_wan_input tcp dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject
      fi
   fi

   if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
      #tcp
      nft 'add chain inet fw4 openclash' 2>/dev/null
      nft 'flush chain inet fw4 openclash' 2>/dev/null
      nft 'add rule inet fw4 openclash ip daddr @localnetwork counter return' 2>/dev/null
      if [ -z "$en_mode_tun" ] && [ "$en_mode" = "fake-ip" ]; then
          nft add rule inet fw4 openclash ip protocol tcp ip daddr {198.18.0.0/16} counter redirect to "$proxy_port" 2>/dev/null
      fi
      nft 'add rule inet fw4 openclash ip saddr @localnetwork tcp sport @lan_ac_black_ports counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash ip daddr @wan_ac_black_ips counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash ip saddr @lan_ac_black_ips counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash ether saddr @lan_ac_black_macs counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash ether saddr != @lan_ac_white_macs counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash ip saddr != @lan_ac_white_ips counter return' 2>/dev/null

      if [ "$en_mode" = "redir-host" ]; then
         nft 'add rule inet fw4 openclash tcp dport != @common_ports counter return' 2>/dev/null
      fi
      if [ "$china_ip_route" = "1" ]; then
         nft 'add rule inet fw4 openclash ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
      fi
      nft add rule inet fw4 openclash ip protocol tcp counter redirect to "$proxy_port" 2>/dev/null
      nft 'add rule inet fw4 dstnat ip protocol tcp counter jump openclash' 2>/dev/null
      if [ -z "$en_mode_tun" ]; then
         #Google dns
         nft insert rule inet fw4 dstnat position 0 ip daddr { 8.8.8.8, 8.8.4.4 } tcp dport 53 counter redirect to "$proxy_port" comment \"OpenClash Google DNS Hijack\" 2>/dev/null
         #udp
         if [ "$enable_udp_proxy" -eq 1 ]; then
            modprobe nft_tproxy >/dev/null 2>&1
            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' 2>/dev/null
            nft 'flush chain inet fw4 openclash_mangle' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ip daddr @localnetwork counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle udp dport 53 counter return' 2>/dev/null
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 openclash_mangle meta l4proto { udp } ip daddr {198.18.0.0/16} mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept 2>/dev/null
            fi
            nft 'add rule inet fw4 openclash_mangle ip saddr @localnetwork udp sport @lan_ac_black_ports counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ip daddr @wan_ac_black_ips counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ip saddr @lan_ac_black_ips counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ether saddr @lan_ac_black_macs counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs counter return' 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle ip saddr != @lan_ac_white_ips counter return' 2>/dev/null

            if [ "$en_mode" = "redir-host" ]; then
               nft 'add rule inet fw4 openclash_mangle udp dport != @common_ports counter return' 2>/dev/null
            fi
            if [ "$china_ip_route" = "1" ]; then
               nft 'add rule inet fw4 openclash_mangle ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
            fi

            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 2>/dev/null
            nft 'add rule inet fw4 mangle_prerouting ip protocol udp counter jump openclash_mangle' 2>/dev/null
            
         elif [ "$en_mode" = "fake-ip" ]; then
            modprobe nft_tproxy >/dev/null 2>&1
            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' 2>/dev/null
            nft 'flush chain inet fw4 openclash_mangle' 2>/dev/null
            nft add rule inet fw4 openclash_mangle meta l4proto { udp } ip daddr {198.18.0.0/16} mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept 2>/dev/null
            nft 'add rule inet fw4 mangle_prerouting ip protocol udp counter jump openclash_mangle' 2>/dev/null

            nft 'add chain inet fw4 openclash_mangle_output' 2>/dev/null
            nft 'flush chain inet fw4 openclash_mangle_output' 2>/dev/null
            nft add rule inet fw4 openclash_mangle_output meta l4proto { udp } ip daddr {198.18.0.0/16} mark set "$PROXY_FWMARK" 2>/dev/null
            nft 'add rule inet fw4 mangle_output ip protocol udp counter jump openclash_mangle_output' 2>/dev/null
         fi

         #quic
         if [ "$disable_udp_quic" -eq 1 ]; then
            nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" 2>/dev/null
         fi
      fi
      
      nft 'add chain inet fw4 openclash_output' 2>/dev/null
      nft 'flush chain inet fw4 openclash_output' 2>/dev/null
      nft 'add rule inet fw4 openclash_output ip daddr @localnetwork counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_output ip saddr @localnetwork tcp sport @lan_ac_black_ports counter return' 2>/dev/null

      if [ "$en_mode" = "fake-ip" ]; then
         nft add rule inet fw4 openclash_output ip protocol tcp ip daddr {198.18.0.0/16} skuid != 65534 counter redirect to "$proxy_port" 2>/dev/null
      fi
      nft add rule inet fw4 openclash_output tcp dport != @common_ports skuid != 65534 counter return 2>/dev/null
      if [ "$en_mode" = "redir-host" ]; then
         nft 'add rule inet fw4 openclash_output ip daddr @wan_ac_black_ips counter return' 2>/dev/null
      fi
      if [ "$china_ip_route" = "1" ]; then
         nft 'add rule inet fw4 openclash_output skuid != 65534 ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
      fi
      nft add rule inet fw4 openclash_output ip protocol tcp skuid != 65534 counter redirect to "$proxy_port" 2>/dev/null
      nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }' 2>/dev/null
      nft 'add rule inet fw4 nat_output ip protocol tcp counter jump openclash_output' 2>/dev/null
   fi

   if [ -n "$en_mode_tun" ]; then
      #TUN模式
      #启动TUN
      TUN_WAIT=0
      TUN_RESTART=1
      ip link set utun up

      LOG_OUT "Tip: Waiting for TUN Interface Start..."
      while ( [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_WAIT" -le 10 ] )
      do
         ip link set utun up
         let TUN_WAIT++
         sleep 2
      done

      if [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_WAIT" -gt 10 ]; then
         while ( [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_RESTART" -le 3 ] )
         do
            LOG_OUT "Warning: TUN Interface Start Failed, Try to Restart Again..."
            kill_clash
            sleep 3
            start_run_core
            check_core_status
            sleep 10
            let TUN_RESTART++
         done
         if [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_RESTART" -gt 3 ]; then
            LOG_OUT "Warning: TUN Interface Start Failed, Please Check The Dependence or Try to Restart Again!"
            start_fail
         fi
      fi

      ip route replace default dev utun table "$PROXY_ROUTE_TABLE"
      ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"

      #设置防火墙
      nft 'add chain inet fw4 openclash_mangle_output' 2>/dev/null
      nft 'flush chain inet fw4 openclash_mangle_output' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_output ip daddr @localnetwork counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_output ip saddr @localnetwork meta l4proto {tcp,udp} th sport @lan_ac_black_ports counter return' 2>/dev/null
      if [ "$en_mode" = "fake-ip" ]; then
         if [ "$en_mode_tun" -eq 1 ]; then
            nft add rule inet fw4 openclash_mangle_output meta l4proto {tcp,udp} th dport { 0-65535 } ip daddr {198.18.0.0/16} mark set "$PROXY_FWMARK" 2>/dev/null
            nft 'add rule inet fw4 openclash_mangle_output meta l4proto {tcp,udp} th dport != @common_ports skuid != 65534 counter return' 2>/dev/null
            if [ "$china_ip_route" = "1" ]; then
               nft 'add rule inet fw4 openclash_mangle_output skuid != 65534 ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
            fi
            nft add rule inet fw4 openclash_mangle_output tcp dport { 0-65535 } skuid != 65534 meta mark set "$PROXY_FWMARK" 2>/dev/null
         else
            if [ "$china_ip_route" = "1" ]; then
               nft 'add rule inet fw4 openclash_mangle_output skuid != 65534 ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
            fi
            nft add rule inet fw4 openclash_mangle_output skuid != 65534 udp dport { 0-65535 } ip daddr {198.18.0.0/16} meta mark set "$PROXY_FWMARK" 2>/dev/null
         fi
      elif [ "$en_mode" = "redir-host" ] && [ "$en_mode_tun" -eq 1 ]; then
         nft 'add rule inet fw4 openclash_mangle_output ip daddr @wan_ac_black_ips counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_output meta l4proto {tcp,udp} th dport != @common_ports skuid != 65534 counter return' 2>/dev/null
         if [ "$china_ip_route" = "1" ]; then
            nft 'add rule inet fw4 openclash_mangle_output skuid != 65534 ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
         fi
         nft add rule inet fw4 openclash_mangle_output tcp dport { 0-65535 } skuid != 65534 meta mark set "$PROXY_FWMARK" 2>/dev/null
      fi
      nft 'add rule inet fw4 mangle_output meta l4proto {tcp,udp} counter jump openclash_mangle_output' 2>/dev/null
      
      nft 'add chain inet fw4 openclash_mangle' 2>/dev/null
      nft 'flush chain inet fw4 openclash_mangle' 2>/dev/null
      nft 'add chain inet fw4 openclash_dns_hijack' 2>/dev/null
      nft 'flush chain inet fw4 openclash_dns_hijack' 2>/dev/null

      #其他流量
      nft 'add rule inet fw4 openclash_mangle meta l4proto {tcp,udp} iifname utun counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ip daddr @localnetwork counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ip saddr @localnetwork meta l4proto {tcp,udp} th sport @lan_ac_black_ports counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ip daddr @wan_ac_black_ips counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ip saddr @lan_ac_black_ips counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ether saddr @lan_ac_black_macs counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ether saddr != @lan_ac_white_macs counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle ip saddr != @lan_ac_white_ips counter return' 2>/dev/null
      
      if [ "$en_mode" = "redir-host" ]; then
         nft 'add rule inet fw4 openclash_mangle meta l4proto {tcp,udp} th dport != @common_ports counter return' 2>/dev/null
      fi
      if [ "$china_ip_route" = "1" ]; then
         nft 'add rule inet fw4 openclash_mangle ip daddr @china_ip_route ip daddr != @china_ip_route_pass counter return' 2>/dev/null
      fi
      nft add rule inet fw4 openclash_mangle meta l4proto {tcp,udp} th dport { 0-65535 } mark set "$PROXY_FWMARK" 2>/dev/null
      
      if [ "$en_mode_tun" -eq 1 ]; then
         nft 'insert rule inet fw4 mangle_prerouting position 0 meta l4proto {tcp,udp} counter jump openclash_mangle' 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} tcp dport 53 counter accept comment \"OpenClash TCP DNS Hijack\" 2>/dev/null
      else
         nft 'insert rule inet fw4 mangle_prerouting position 0 meta nfproto {ipv4} tcp dport 53 counter jump openclash_dns_hijack' 2>/dev/null
         nft add rule inet fw4 openclash_dns_hijack meta nfproto {ipv4} tcp dport 53 mark set "$PROXY_FWMARK" comment \"OpenClash TCP DNS Hijack\" 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} tcp dport 53 counter accept comment \"OpenClash TCP DNS Hijack\" 2>/dev/null
         nft 'insert rule inet fw4 mangle_prerouting position 0 ip protocol udp counter jump openclash_mangle' 2>/dev/null
      fi

      #TUN FORWORD
      nft insert rule inet fw4 forward position 0 meta l4proto {tcp,udp} oifname utun counter accept comment \"OpenClash TUN Forward\" 2>/dev/null
      
      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         nft insert rule inet fw4 forward position 0 oifname utun udp dport 443 ip daddr != @china_ip_route counter reject comment \"OpenClash QUIC REJECT\" 2>/dev/null
      fi
   fi

   #google_dns_block
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ] || [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
      nft 'add set inet fw4 openclash_google_dns_ips { type ipv4_addr; flags interval; auto-merge; }'
      nft 'add element inet fw4 openclash_google_dns_ips { 8.8.8.8, 8.8.4.4 }'
      if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
         nft insert rule inet fw4 dstnat position 0 ip saddr @lan_block_google_dns_ips ip daddr @openclash_google_dns_ips counter accept comment \"OpenClash Google DNS Block\" 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 ether saddr @lan_block_google_dns_macs ip daddr @openclash_google_dns_ips counter accept comment \"OpenClash Google DNS Block\" 2>/dev/null
      fi
      nft insert rule inet fw4 forward position 0 ip saddr @lan_block_google_dns_ips ip daddr @openclash_google_dns_ips counter reject comment \"OpenClash Google DNS Block\" 2>/dev/null
      nft insert rule inet fw4 forward position 0 ether saddr @lan_block_google_dns_macs ip daddr @openclash_google_dns_ips counter reject comment \"OpenClash Google DNS Block\" 2>/dev/null
   fi

   #ipv6
   if [ "$ipv6_enable" -eq 1 ]; then
      if [ "$enable_redirect_dns" -eq 1 ] && [ -z "$(nft list chain inet fw4 dstnat |grep 'OpenClash DNS Hijack')"]; then
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} tcp dport 53 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} udp dport 53 counter redirect to "$DNSPORT" comment \"OpenClash DNS Hijack\" 2>/dev/null
      fi
      if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} tcp dport 53 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} udp dport 53 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
         nft add rule inet fw4 nat_output position 0 meta nfproto {ipv6} tcp dport 53 meta skuid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
         nft add rule inet fw4 nat_output position 0 meta nfproto {ipv6} udp dport 53 meta skuid != 65534 counter redirect to "$dns_port" comment \"OpenClash DNS Hijack\" 2>/dev/null
      fi

      if [ "$china_ip6_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
         nft 'flush set inet fw4 china_ip6_route'
         nft -f '/etc/openclash/china_ip6_route.ipset' 2>/dev/null
         CHNROUTE_WAIT=0
         while ( [ -z "$(nft list sets |grep "set china_ip6_route {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] )
         do
            nft -f '/etc/openclash/china_ip6_route.ipset' 2>/dev/null
         done

         mkdir -p /tmp/dnsmasq.d 2>/dev/null
         
         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 '!/^$/&&!/^#/&&!/^(\*?\.?)*[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*$/{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 '!/^$/&&!/^#/&&!/^(\*?\.?)*[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*$/{printf("    %s,'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>/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
         }
         awk '!/^$/&&!/^#/&&/^(\*?\.?)*[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*$/{printf("'${settype}'=/%s/'${nftflag}'china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>/tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf 2>/dev/null

         nft 'flush set inet fw4 china_ip6_route_pass' 2>/dev/null
         nft -f '/tmp/openclash_china_ip6_route_pass.list' 2>/dev/null
         rm -rf /tmp/openclash_china_ip6_route_pass.list 2>/dev/null

         #Prevent domain repeat
         for i in `grep -wf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf`
         do
            if [ -n "$nftflag" ]; then
               sed -i "s:${i}:${i},6#${nftflag}china_ip6_route_pass:g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf
            else
               sed -i "s:${i}:${i},china_ip6_route_pass:g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf
            fi
            sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf
         done 2>/dev/null
         if [ -n "$nftflag" ]; then
            sed -i "s/\/${nftflag}/\/4#${nftflag}/g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf 2>/dev/null
            sed -i "s/${nftflag}china_ip_route_pass/6#${nftflag}china_ip6_route_pass/g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf 2>/dev/null
         else
            sed -i "s/china_ip_route_pass/china_ip6_route_pass/g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf 2>/dev/null
         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" } 2>/dev/null
         done 2>/dev/null
      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, fc00::/7, fe80::/10, ff00::/8}'
      fi

      if [ -n "$lan_ip6_cidrs" ]; then
         for lan_ip6_cidr in $lan_ip6_cidrs; do
            nft add element inet fw4 localnetwork6 { "$lan_ip6_cidr" } 2>/dev/null
         done
      fi

      if [ -n "$wan_ip6s" ]; then
         for wan_ip6 in $wan_ip6s; do
            nft add element inet fw4 localnetwork6 { "$wan_ip6" } 2>/dev/null
         done
      fi
      
      modprobe nft_tproxy >/dev/null 2>&1
      ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
      ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE"
      
      #Google dns
      nft insert rule inet fw4 dstnat position 0 ip6 daddr { 2001:4860:4860::8888, 2001:4860:4860::8844 } tcp dport 53 counter accept comment \"OpenClash Google DNS Hijack\" 2>/dev/null
      
      nft 'add chain inet fw4 openclash_mangle_v6' 2>/dev/null
      nft 'flush chain inet fw4 openclash_mangle_v6' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_v6 ip6 daddr @localnetwork6 counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_v6 meta nfproto {ipv6} udp dport 53 counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_v6 ip6 saddr @localnetwork6 meta nfproto {ipv6} sport @lan_ac_black_ports counter return' 2>/dev/null
      nft 'add rule inet fw4 openclash_mangle_v6 ip6 daddr @wan_ac_black_ipv6s counter return' 2>/dev/null

      if [ "$en_mode" == "redir-host" ]; then
         nft 'add rule inet fw4 openclash_mangle_v6 meta nfproto {ipv6} th dport != @common_ports counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_v6 ip6 saddr @lan_ac_black_ipv6s counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_v6 ether saddr @lan_ac_black_macs counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_v6 ether saddr != @lan_ac_white_macs counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_v6 ip6 saddr != @lan_ac_white_ipv6s counter return' 2>/dev/null
      fi
      if [ "$china_ip6_route" = "1" ]; then
         nft 'add rule inet fw4 openclash_mangle_v6 ip6 daddr @china_ip6_route ip6 daddr != @china_ip6_route_pass counter return' 2>/dev/null
      fi
      nft add rule inet fw4 openclash_mangle_v6 meta nfproto {ipv6} tcp dport { 0-65535 } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash TCP Tproxy\" 2>/dev/null
      nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv6} jump openclash_mangle_v6' 2>/dev/null

      if [ -z "$_koolshare" ]; then
         nft 'add chain inet fw4 openclash_mangle_output_v6' 2>/dev/null
         nft 'flush chain inet fw4 openclash_mangle_output_v6' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @localnetwork6 counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 saddr @localnetwork6 meta nfproto {ipv6} sport @lan_ac_black_ports counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_output_v6 ip6 daddr @wan_ac_black_ipv6s counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} th dport != @common_ports skuid != 65534 counter return' 2>/dev/null

         if [ "$china_ip6_route" = "1" ]; then
            nft 'add rule inet fw4 openclash_mangle_output_v6 skuid != 65534 ip6 daddr @china_ip6_route ip6 daddr != @china_ip6_route_pass counter return' 2>/dev/null
         fi
         nft add rule inet fw4 openclash_mangle_output_v6 meta nfproto {ipv6} skuid != 65534 tcp dport { 0-65535 } mark set "$PROXY_FWMARK" 2>/dev/null
         nft 'add rule inet fw4 mangle_output meta nfproto {ipv6} counter jump openclash_mangle_output_v6' 2>/dev/null
      fi
      
      #udp
      if [ "$enable_udp_proxy" -eq 1 ] || [ -n "$en_mode_tun" ]; then
         nft add rule inet fw4 openclash_mangle_v6 meta nfproto {ipv6} udp dport { 0-65535 } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"OpenClash UDP Tproxy\" 2>/dev/null
      fi
      
      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         nft insert rule inet fw4 input position 0 udp dport 443 ip6 daddr != @china_ip6_route counter reject comment \"OpenClash QUIC REJECT\" 2>/dev/null
      fi
      
      #bypass gateway compatible
      if [ "$bypass_gateway_compatible" -eq 1 ]; then
         #nft 'delete chain inet fw4 openclash_post_v6' 2>/dev/null
         nft 'add chain inet fw4 openclash_post_v6' 2>/dev/null
         nft 'flush chain inet fw4 openclash_post_v6' 2>/dev/null
         nft 'add rule inet fw4 openclash_post_v6 ip6 saddr @localnetwork6 meta nfproto {ipv6} sport @lan_ac_black_ports counter return' 2>/dev/null
         nft add rule inet fw4 openclash_post_v6 meta nfproto {ipv6} meta mark "$PROXY_FWMARK" counter accept 2>/dev/null
         nft 'add rule inet fw4 openclash_post_v6 ip6 daddr @localnetwork6 counter return' 2>/dev/null
         nft 'add rule inet fw4 openclash_post_v6 meta nfproto {ipv6} fib saddr type != { local } meta skuid != 65534 counter masquerade' 2>/dev/null
         nft add rule inet fw4 srcnat meta nfproto {ipv6} counter jump openclash_post_v6 comment \"OpenClash Bypass Gateway Compatible\" 2>/dev/null
      fi

      #google_dns_block
      if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ] || [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
         nft 'add set inet fw4 openclash_google_dns_ipv6s { type ipv6_addr; flags interval; auto-merge; }'
         nft 'add element inet fw4 openclash_google_dns_ipv6s { 2001:4860:4860::8888, 2001:4860:4860::8844, 2001:4860:4860::6464, 2001:4860:4860::64 }'
         nft insert rule inet fw4 dstnat position 0 ip6 saddr @lan_block_google_dns_ipv6s ip6 daddr @openclash_google_dns_ipv6s counter accept comment \"OpenClash Google DNS Block\" 2>/dev/null
         nft insert rule inet fw4 dstnat position 0 ether saddr @lan_block_google_dns_macs ip6 daddr @openclash_google_dns_ipv6s counter accept comment \"OpenClash Google DNS Block\" 2>/dev/null
         nft insert rule inet fw4 forward position 0 ip6 saddr @lan_block_google_dns_ipv6s ip6 daddr @openclash_google_dns_ipv6s counter reject comment \"OpenClash Google DNS Block\" 2>/dev/null
         nft insert rule inet fw4 forward position 0 ether saddr @lan_block_google_dns_macs ip6 daddr @openclash_google_dns_ipv6s counter reject comment \"OpenClash Google DNS Block\" 2>/dev/null
      fi

      #intranet allowed
      if [ "$intranet_allowed" -eq 1 ]; then
         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/) {print $(i+1)}}}' 2>/dev/null |sed 's/"//g')
         if [ -n "$wan6_ints" ]; then
            nft 'add chain inet fw4 openclash_wan6_input' 2>/dev/null
            nft 'flush chain inet fw4 openclash_wan6_input' 2>/dev/null
            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 2>/dev/null
            done
            nft add rule inet fw4 openclash_wan6_input udp dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject 2>/dev/null
            nft add rule inet fw4 openclash_wan6_input tcp dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject 2>/dev/null
         fi
      fi
   fi 2>/dev/null
else
   if [ "$china_ip_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
      ipset -! flush china_ip_route 2>/dev/null
      ipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null
      mkdir -p /tmp/dnsmasq.d 2>/dev/null
      echo "create china_ip_route_pass hash:net family inet hashsize 1024 maxelem 1000000" >/tmp/openclash_china_ip_route_pass.list
      awk '!/^$/&&!/^#/&&/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][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 2>/dev/null
      awk '!/^$/&&!/^#/&&!/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][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 >>/tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf 2>/dev/null
      ipset -! flush china_ip_route_pass 2>/dev/null
      ipset -! restore </tmp/openclash_china_ip_route_pass.list 2>/dev/null
      rm -rf /tmp/openclash_china_ip_route_pass.list 2>/dev/null

      if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         cat "/etc/openclash/accelerated-domains.china.conf" |awk -v dns="${custom_china_domain_dns_server}" -F '/' '!/^$/&&!/^#/{print $1"/"$2"/"dns}' >/tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf 2>/dev/null
         for i in `awk '!/^$/&&!/^#/&&!/(^([1-9]|1[0-9]|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[1-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-5][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("%s\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute_pass.list`
         do
            sed -i "/server=\/${i}\//d" /tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf 2>/dev/null
         done 2>/dev/null
      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 ] && [ -z "$(iptables -t nat -nL PREROUTING --line-number |grep 'OpenClash DNS Hijack')"]; then
      iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
   fi
   if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
      LOG_OUT "Tip: Bypass the China IP May Cause the Dnsmasq Load For a Long Time After Restart in FAKE-IP Mode, Hijack the DNS to Core Untill the Dnsmasq Works Well..."
      iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I OUTPUT -p udp --dport 53 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I OUTPUT -p tcp --dport 53 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I OUTPUT -p udp --dport 12353 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      iptables -t nat -I OUTPUT -p tcp --dport 12353 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
   fi

   #lan_google_dns_ac
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ]; then
      ipset create lan_block_google_dns_ips hash:net
      ipset create lan_block_google_dns_ipv6s hash:net family inet6
      config_load "openclash"
      config_list_foreach "config" "lan_block_google_dns_ips" ac_add "lan_block_google_dns_ips" "lan_block_google_dns_ipv6s"
   fi
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
      ipset create lan_block_google_dns_macs hash:mac
      config_load "openclash"
      config_list_foreach "config" "lan_block_google_dns_macs" ac_add "lan_block_google_dns_macs"
   fi

   #lan_ac
   if [ "$operation_mode" = "redir-host" ] && [ "$en_mode" = "redir-host" ]; then
      if [ "$lan_ac_mode" = "0" ]; then
         if [ -n "$(uci -q get openclash.config.lan_ac_black_ips)" ]; then
            ipset create lan_ac_black_ips hash:net
            ipset create lan_ac_black_ipv6s hash:net family inet6
            config_load "openclash"
            config_list_foreach "config" "lan_ac_black_ips" ac_add "lan_ac_black_ips" "lan_ac_black_ipv6s"
         fi
         if [ -n "$(uci -q get openclash.config.lan_ac_black_macs)" ]; then
            ipset create lan_ac_black_macs hash:mac
            config_load "openclash"
            config_list_foreach "config" "lan_ac_black_macs" ac_add "lan_ac_black_macs"
         fi
      elif [ "$lan_ac_mode" = "1" ]; then
         if [ -n "$(uci -q get openclash.config.lan_ac_white_ips)" ]; then
            ipset create lan_ac_white_ips hash:net
            ipset create lan_ac_white_ipv6s hash:net family inet6
            config_load "openclash"
            config_list_foreach "config" "lan_ac_white_ips" ac_add "lan_ac_white_ips" "lan_ac_white_ipv6s"
         fi
         if [ -n "$(uci -q get openclash.config.lan_ac_white_macs)" ]; then
            ipset create lan_ac_white_macs hash:mac
            config_load "openclash"
            config_list_foreach "config" "lan_ac_white_macs" ac_add "lan_ac_white_macs"
         fi
      fi
   fi

   #wan ac
   if [ -n "$(uci -q get openclash.config.wan_ac_black_ips)" ]; then
      ipset create wan_ac_black_ips hash:net
      ipset create wan_ac_black_ipv6s hash:net family inet6
      config_load "openclash"
      config_list_foreach "config" "wan_ac_black_ips" ac_add "wan_ac_black_ips" "wan_ac_black_ipv6s"
   fi

   #lan port ac
   if [ -n "$(uci -q get openclash.config.lan_ac_black_ports)" ]; then
      ipset create lan_ac_black_ports bitmap:port range 0-65535
      config_load "openclash"
      config_list_foreach "config" "lan_ac_black_ports" ac_add "lan_ac_black_ports"
   fi

   #local
      ipset create localnetwork hash:net
      if [ -f "/etc/openclash/custom/openclash_custom_localnetwork_ipv4.list" ]; then
         for line in `cat "/etc/openclash/custom/openclash_custom_localnetwork_ipv4.list"`
         do
            ipset add localnetwork "$line"
         done 2>/dev/null
      else
         ipset add localnetwork 0.0.0.0/8
         ipset add localnetwork 127.0.0.0/8
         ipset add localnetwork 10.0.0.0/8
         ipset add localnetwork 169.254.0.0/16
         ipset add localnetwork 192.168.0.0/16
         ipset add localnetwork 224.0.0.0/4
         ipset add localnetwork 240.0.0.0/4
         ipset add localnetwork 172.16.0.0/12
         ipset add localnetwork 100.64.0.0/10
      fi
      
      if [ -n "$lan_ip_cidrs" ]; then
         for lan_ip_cidr in $lan_ip_cidrs; do
            ipset add localnetwork "$lan_ip_cidr" 2>/dev/null
         done
      fi

      if [ -n "$wan_ip4s" ]; then
         for wan_ip4 in $wan_ip4s; do
            ipset add localnetwork "$wan_ip4" 2>/dev/null
         done
      fi

   #common ports
   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 5222 5228 5229 5230 8080 8443 8880 8888 8889"
      ipset create common_ports bitmap:port range 0-65535
      for i in $common_port; do
         ipset add common_ports $i
      done
   fi

   #bypass gateway compatible
   if [ "$bypass_gateway_compatible" -eq 1 ]; then
      iptables -t nat -N openclash_post
      iptables -t nat -F openclash_post
      iptables -t nat -A openclash_post -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash_post -m mark --mark "$PROXY_FWMARK" -j ACCEPT
      iptables -t nat -A openclash_post -m set --match-set localnetwork dst -j RETURN
      iptables -t nat -A openclash_post -m addrtype ! --src-type LOCAL -m owner ! --uid-owner 65534 -j MASQUERADE
      iptables -t nat -A POSTROUTING -m comment --comment "OpenClash Bypass Gateway Compatible" -j openclash_post
   fi

   #intranet allowed
   if [ "$intranet_allowed" -eq 1 ]; then
      wan_ints=$(iptables-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)
      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 >/dev/null 2>&1
         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 >/dev/null 2>&1
      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
      if [ -z "$en_mode_tun" ] && [ "$en_mode" = "fake-ip" ]; then
         iptables -t nat -A openclash -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
      fi
      iptables -t nat -A openclash -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
      iptables -t nat -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
      if [ "$en_mode" = "redir-host" ]; then
         iptables -t nat -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
      fi
      if [ "$china_ip_route" = "1" ]; then
         iptables -t nat -A openclash -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
      fi
      iptables -t nat -A openclash -p tcp -j REDIRECT --to-ports "$proxy_port"
      iptables -t nat -A PREROUTING -p tcp -j openclash
      if [ -z "$en_mode_tun" ]; then
         #Google dns
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.8.8 --dport 53 -j REDIRECT --to-ports "$proxy_port"
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.4.4 --dport 53 -j REDIRECT --to-ports "$proxy_port"
         #udp
         if [ "$enable_udp_proxy" -eq 1 ]; then
            modprobe xt_TPROXY >/dev/null 2>&1
            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 -m set --match-set localnetwork dst -j RETURN
            iptables -t mangle -A openclash -p udp --dport 53 -j RETURN >/dev/null 2>&1
            if [ "$en_mode" = "fake-ip" ]; then
               iptables -t mangle -A openclash -p udp -d 198.18.0.0/16 -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            fi
            iptables -t mangle -A openclash -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
            iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
            iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
            iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
            iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
            iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
            if [ "$en_mode" = "redir-host" ]; then
               iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
            fi
            if [ "$china_ip_route" = "1" ]; then
               iptables -t mangle -A openclash -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
            fi
            
            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
            
         elif [ "$en_mode" = "fake-ip" ]; then
            modprobe xt_TPROXY >/dev/null 2>&1
            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 198.18.0.0/16 -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            iptables -t mangle -A PREROUTING -p udp -j openclash

            iptables -t mangle -N openclash_output
            iptables -t mangle -F openclash_output
            iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p udp -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
            iptables -t mangle -A OUTPUT -p udp -j openclash_output
         fi

         #quic
         if [ "$disable_udp_quic" -eq 1 ]; then
            iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT >/dev/null 2>&1
         fi
      fi
      
      if [ -z "$_koolshare" ]; then
         iptables -t nat -N openclash_output
         iptables -t nat -F openclash_output
         if [ "$en_mode" = "fake-ip" ] && [ -z "$en_mode_tun" ]; then
            iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
         fi
         iptables -t nat -A openclash_output -m set --match-set localnetwork dst -j RETURN
         iptables -t nat -A openclash_output -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
         iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
         if [ "$en_mode" = "redir-host" ]; then
            iptables -t nat -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
         fi
         if [ "$china_ip_route" = "1" ]; then
            iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
         fi
         iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j REDIRECT --to-ports "$proxy_port"
      else
         if [ "$en_mode" = "fake-ip" ]; then
            iptables -t nat -N openclash_output
            iptables -t nat -F openclash_output
            iptables -t nat -A openclash_output -m set --match-set localnetwork dst -j RETURN
            iptables -t nat -A openclash_output -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
            iptables -t nat -A openclash_output -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
         fi
      fi
      iptables -t nat -A OUTPUT -j openclash_output >/dev/null 2>&1
   fi

   if [ -n "$en_mode_tun" ]; then
      #TUN模式
      #启动TUN
      TUN_WAIT=0
      TUN_RESTART=1
      ip link set utun up

      LOG_OUT "Tip: Waiting for TUN Interface Start..."
      while ( [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_WAIT" -le 10 ] )
      do
         ip link set utun up
         let TUN_WAIT++
         sleep 2
      done

      if [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_WAIT" -gt 10 ]; then
         while ( [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_RESTART" -le 3 ] )
         do
            LOG_OUT "Warning: TUN Interface Start Failed, Try to Restart Again..."
            kill_clash
            sleep 3
            start_run_core
            check_core_status
            sleep 10
            let TUN_RESTART++
         done
         if [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_RESTART" -gt 3 ]; then
            LOG_OUT "Warning: TUN Interface Start Failed, Please Check The Dependence or Try to Restart Again!"
            start_fail
         fi
      fi

      ip route replace default dev utun table "$PROXY_ROUTE_TABLE"
      ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"

      #设置防火墙
      if [ "$en_mode" = "fake-ip" ]; then
         iptables -t mangle -N openclash_output
         iptables -t mangle -F openclash_output
         iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN
         iptables -t mangle -A openclash_output -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
         if [ "$en_mode_tun" -eq 1 ]; then
            if [ -z "$_koolshare" ]; then
               iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
               iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
               if [ "$china_ip_route" = "1" ]; then
                  iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
               fi
               iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j MARK --set-mark "$PROXY_FWMARK"
            else
               iptables -t mangle -A openclash_output -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
            fi
         elif [ -z "$_koolshare" ]; then
            if [ "$china_ip_route" = "1" ]; then
               iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
            fi
            iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p udp -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
         fi
         iptables -t mangle -A OUTPUT -j openclash_output
      elif [ -z "$_koolshare" ] && [ "$en_mode" = "redir-host" ] && [ "$en_mode_tun" -eq 1 ]; then
         iptables -t mangle -N openclash_output
         iptables -t mangle -F openclash_output
         iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN
         iptables -t mangle -A openclash_output -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
         iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
         iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
         if [ "$china_ip_route" = "1" ]; then
            iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
         fi
         iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j MARK --set-mark "$PROXY_FWMARK"
         iptables -t mangle -A OUTPUT -j openclash_output
      fi
      
      iptables -t mangle -N openclash
      iptables -t mangle -F openclash
      iptables -t mangle -N openclash_dns_hijack
      iptables -t mangle -F openclash_dns_hijack
      #其他流量
      iptables -t mangle -A openclash -i utun -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set --match-set localnetwork dst -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
      iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
      if [ "$en_mode" = "redir-host" ]; then
         iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
      fi
      if [ "$china_ip_route" = "1" ]; then
         iptables -t mangle -A openclash -m set --match-set china_ip_route dst -m set ! --match-set china_ip_route_pass dst -j RETURN >/dev/null 2>&1
      fi
      iptables -t mangle -A openclash -j MARK --set-mark "$PROXY_FWMARK"
      
      if [ "$en_mode_tun" -eq 1 ]; then
         iptables -t mangle -I PREROUTING -j openclash
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash TCP DNS Hijack" -p tcp --dport 53 -j ACCEPT
      else
         iptables -t mangle -I PREROUTING -p tcp --dport 53 -j openclash_dns_hijack
         iptables -t mangle -A openclash_dns_hijack -m comment --comment "OpenClash TCP DNS Hijack" -p tcp --dport 53 -j MARK --set-mark "$PROXY_FWMARK"
         iptables -t mangle -I PREROUTING -p udp -j openclash
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash TCP DNS Hijack" -p tcp --dport 53 -j ACCEPT
      fi

      #TUN FORWORD
      iptables -I FORWARD -m comment --comment "OpenClash TUN Forward" -o utun -j ACCEPT
      
      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         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 >/dev/null 2>&1
      fi
   fi

   #google_dns_block
   if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ] || [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
      ipset create openclash_google_dns_ips hash:net
      ipset add openclash_google_dns_ips 8.8.8.8
      ipset add openclash_google_dns_ips 8.8.4.4

      if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Block" -m set --match-set lan_block_google_dns_ips src -m set --match-set openclash_google_dns_ips dst -j ACCEPT >/dev/null 2>&1
         iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Block" -m set --match-set lan_block_google_dns_macs src -m set --match-set openclash_google_dns_ips dst -j ACCEPT >/dev/null 2>&1
      fi
      iptables -t filter -I FORWARD -m set --match-set lan_block_google_dns_ips src -m set --match-set openclash_google_dns_ips dst -j REJECT >/dev/null 2>&1
      iptables -t filter -I FORWARD -m set --match-set lan_block_google_dns_macs src -m set --match-set openclash_google_dns_ips dst -j REJECT >/dev/null 2>&1
   fi

   #ipv6
   if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
      if [ "$enable_redirect_dns" -eq 1 ] && [ -z "$(ip6tables -t nat -nL PREROUTING --line-number |grep 'DNS Hijack')"]; then
         ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
         ip6tables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      fi
      if [ "$en_mode" = "fake-ip" ] && [ "$china_ip_route" = "1" ]; then
         ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
         ip6tables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
         ip6tables -t nat -I OUTPUT -p udp --dport 53 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
         ip6tables -t nat -I OUTPUT -p tcp --dport 53 -m owner ! --uid-owner 65534 -j REDIRECT --to-ports "$dns_port" -m comment --comment "OpenClash DNS Hijack" 2>/dev/null
      fi

      if [ "$china_ip6_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
         ipset -! flush china_ip6_route 2>/dev/null
         ipset -! restore </etc/openclash/china_ip6_route.ipset 2>/dev/null
         mkdir -p /tmp/dnsmasq.d 2>/dev/null
         echo "create china_ip6_route_pass hash:net family inet6 hashsize 1024 maxelem 1000000" >/tmp/openclash_china_ip6_route_pass.list
         awk '!/^$/&&!/^#/&&!/^(\*?\.?)*[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*$/{printf("add china_ip6_route_pass %s'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>/tmp/openclash_china_ip6_route_pass.list 2>/dev/null
         awk '!/^$/&&!/^#/&&/^(\*?\.?)*[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*$/{printf("ipset=/%s/china_ip_route_pass'" "'\n",$0)}' /etc/openclash/custom/openclash_custom_chnroute6_pass.list >>/tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf 2>/dev/null
         ipset -! flush china_ip6_route_pass 2>/dev/null
         ipset -! restore </tmp/openclash_china_ip6_route_pass.list 2>/dev/null
         rm -rf /tmp/openclash_china_ip6_route_pass.list 2>/dev/null

         #Prevent domain repeat
         for i in `grep -wf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf`
         do
            sed -i "s:${i}:${i},china_ip6_route_pass:g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf
            sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf
         done 2>/dev/null
         sed -i "s/china_ip_route_pass/china_ip6_route_pass/g" /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf 2>/dev/null
      fi
      
      #local
      ipset create localnetwork6 hash:net family inet6
      if [ -f "/etc/openclash/custom/openclash_custom_localnetwork_ipv6.list" ]; then
         for line in `cat "/etc/openclash/custom/openclash_custom_localnetwork_ipv6.list"`
         do
            ipset add localnetwork6 "$line"
         done 2>/dev/null
      else
         ipset add localnetwork6 ::/128
         ipset add localnetwork6 ::1/128
         ipset add localnetwork6 ::ffff:0:0/96
         ipset add localnetwork6 ::ffff:0:0:0/96
         ipset add localnetwork6 64:ff9b::/96
         ipset add localnetwork6 100::/64
         ipset add localnetwork6 2001::/32
         ipset add localnetwork6 2001:20::/28
         ipset add localnetwork6 2001:db8::/32
         ipset add localnetwork6 2002::/16
         ipset add localnetwork6 fc00::/7
         ipset add localnetwork6 fe80::/10
         ipset add localnetwork6 ff00::/8
      fi

      if [ -n "$lan_ip6_cidrs" ]; then
         for lan_ip6_cidr in $lan_ip6_cidrs; do
            ipset add localnetwork6 "$lan_ip6_cidr" 2>/dev/null
         done
      fi

      if [ -n "$wan_ip6s" ]; then
         for wan_ip6 in $wan_ip6s; do
            ipset add localnetwork6 "$wan_ip6"
         done
      fi
      
      modprobe xt_TPROXY >/dev/null 2>&1
      ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
      ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE"
      
      #Google dns
      ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 2001:4860:4860::8888 --dport 53 -j ACCEPT
      ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 2001:4860:4860::8844 --dport 53 -j ACCEPT
      
      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 -p udp --dport 53 -j RETURN >/dev/null 2>&1
      ip6tables -t mangle -A openclash -m set --match-set localnetwork6 src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
      ip6tables -t mangle -A openclash -m set --match-set wan_ac_black_ipv6s dst -j RETURN >/dev/null 2>&1
      if [ "$en_mode" == "redir-host" ]; then
         ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_ipv6s src -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_ipv6s src -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
      fi
      if [ "$china_ip6_route" = "1" ]; then
         ip6tables -t mangle -A openclash -m set --match-set china_ip6_route dst -m set ! --match-set china_ip6_route_pass dst -j RETURN >/dev/null 2>&1
      fi
      ip6tables -t mangle -A openclash -p tcp -m comment --comment "OpenClash TCP Tproxy" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
      ip6tables -t mangle -A PREROUTING -j openclash

      if [ -z "$_koolshare" ]; then
         ip6tables -t mangle -N openclash_output
         ip6tables -t mangle -F openclash_output
         ip6tables -t mangle -A openclash_output -m set --match-set localnetwork6 dst -j RETURN
         ip6tables -t mangle -A openclash_output -m set --match-set localnetwork6 src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash_output -m set --match-set wan_ac_black_ipv6s dst -j RETURN >/dev/null 2>&1
         ip6tables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
         if [ "$china_ip6_route" = "1" ]; then
            ip6tables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip6_route dst -m set ! --match-set china_ip6_route_pass dst -j RETURN >/dev/null 2>&1
         fi
         ip6tables -t mangle -A openclash_output -p tcp -m owner ! --uid-owner 65534 -j MARK --set-xmark "$PROXY_FWMARK"
         ip6tables -t mangle -A OUTPUT -j openclash_output
      fi
      
      #udp
      if [ "$enable_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
      
      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         ip6tables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip6_route dst -j REJECT >/dev/null 2>&1
      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 -m set --match-set localnetwork src -m set --match-set lan_ac_black_ports src -j RETURN >/dev/null 2>&1
         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 addrtype ! --src-type LOCAL -m owner ! --uid-owner 65534 -j MASQUERADE
         ip6tables -t nat -A POSTROUTING -m comment --comment "OpenClash Bypass Gateway Compatible" -j openclash_post
      fi

      #google_dns_block
      if [ -n "$(uci -q get openclash.config.lan_block_google_dns_ips)" ] || [ -n "$(uci -q get openclash.config.lan_block_google_dns_macs)" ]; then
         ipset create openclash_google_dns_ipv6s hash:net family inet6
         ipset add openclash_google_dns_ipv6s 2001:4860:4860::8888
         ipset add openclash_google_dns_ipv6s 2001:4860:4860::8844
         ipset add openclash_google_dns_ipv6s 2001:4860:4860::6464
         ipset add openclash_google_dns_ipv6s 2001:4860:4860::64

         ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Block" -m set --match-set lan_block_google_dns_ipv6s src -m set --match-set openclash_google_dns_ipv6s dst -j ACCEPT
         ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Block" -m set --match-set lan_block_google_dns_macs src -m set --match-set openclash_google_dns_ipv6s dst -j ACCEPT
         ip6tables -t filter -I FORWARD -m set --match-set lan_block_google_dns_ipv6s src -m set --match-set openclash_google_dns_ipv6s dst -j REJECT >/dev/null 2>&1
         ip6tables -t filter -I FORWARD -m set --match-set lan_block_google_dns_macs src -m set --match-set openclash_google_dns_ipv6s dst -j REJECT >/dev/null 2>&1
      fi
      
      #intranet allowed
      if [ "$intranet_allowed" -eq 1 ]; then
         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)
         if [ -n "$wan_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 "$wan_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 >/dev/null 2>&1
            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 >/dev/null 2>&1
         fi
      fi
   fi 2>/dev/null
fi

#端口转发
config_load "firewall"
config_foreach firewall_redirect_exclude "redirect"
config_foreach firewall_rule_exclude "rule"
}

revert_firewall()
{
   rm -rf /var/etc/openclash.include >/dev/null 2>&1
   rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf >/dev/null 2>&1
   rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf >/dev/null 2>&1
   rm -rf /tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf >/dev/null 2>&1

   ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   
   ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   
   #TUN
   ip route del default dev utun table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
   route delete -net 198.18.0.0/16 dev utun >/dev/null 2>&1
   ip link set dev utun down >/dev/null 2>&1
   ip tuntap del utun mode tun >/dev/null 2>&1

   ip -6 rule del oif utun table 2022 >/dev/null 2>&1
   ip -6 route del default dev utun table 2022 >/dev/null 2>&1
   ip -6 link set dev utun down >/dev/null 2>&1
   ip -6 tuntap del utun mode tun >/dev/null 2>&1

   if [ -n "$FW4" ]; then
      for nft in "input" "forward" "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 >/dev/null 2>&1

      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 >/dev/null 2>&1

      for handle in $(nft -a list sets |grep -E "set localnetwork|china_ip|lan_ac_|wan_ac_black_|_google_dns_|common_ports" |awk -F '# handle ' '{print$2}'); do
         nft delete set inet fw4 handle ${handle}
      done >/dev/null 2>&1
   else
      for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "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 PREROUTING -t mangle" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL INPUT" "ip6tables -nvL POSTROUTING -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 >/dev/null 2>&1
      
      for chain in "openclash" "openclash_output" "openclash_post" "openclash_dns_hijack" "openclash_wan_input"; 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 >/dev/null 2>&1

      ipset destroy localnetwork6 >/dev/null 2>&1
      ipset destroy china_ip6_route >/dev/null 2>&1
      ipset destroy china_ip6_route_pass >/dev/null 2>&1
      ipset destroy lan_ac_white_ipv6s >/dev/null 2>&1
      ipset destroy lan_ac_black_ipv6s >/dev/null 2>&1
      ipset destroy wan_ac_black_ipv6s >/dev/null 2>&1
      ipset destroy openclash_google_dns_ipv6s >/dev/null 2>&1
      ipset destroy lan_block_google_dns_ipv6s >/dev/null 2>&1

      ipset destroy localnetwork >/dev/null 2>&1
      ipset destroy china_ip_route >/dev/null 2>&1
      ipset destroy china_ip_route_pass >/dev/null 2>&1
      ipset destroy lan_ac_white_ips >/dev/null 2>&1
      ipset destroy lan_ac_black_ips >/dev/null 2>&1
      ipset destroy lan_ac_white_macs >/dev/null 2>&1
      ipset destroy lan_ac_black_macs >/dev/null 2>&1
      ipset destroy wan_ac_black_ips >/dev/null 2>&1
      ipset destroy common_ports >/dev/null 2>&1
      ipset destroy lan_block_google_dns_ips >/dev/null 2>&1
      ipset destroy lan_block_google_dns_macs >/dev/null 2>&1
      ipset destroy openclash_google_dns_ips >/dev/null 2>&1
      ipset destroy lan_ac_black_ports >/dev/null 2>&1
   fi
}

get_config()
{
   rule_source=$(uci -q get openclash.config.rule_source)
   enable_custom_clash_rules=$(uci -q get openclash.config.enable_custom_clash_rules)
   da_password=$(uci -q get openclash.config.dashboard_password)
   cn_port=$(uci -q get openclash.config.cn_port)
   proxy_port=$(uci -q get openclash.config.proxy_port)
   tproxy_port=$(uci -q get openclash.config.tproxy_port || echo 7895)
   proxy_mode=$(uci -q get openclash.config.proxy_mode)
   ipv6_enable=$(uci -q get openclash.config.ipv6_enable)
   ipv6_dns=$(uci -q get openclash.config.ipv6_dns || echo 0)
   http_port=$(uci -q get openclash.config.http_port)
   socks_port=$(uci -q get openclash.config.socks_port)
   enable_redirect_dns=$(uci -q get openclash.config.enable_redirect_dns)
   lan_ip=$(uci -q get network.lan.ipaddr |awk -F '/' '{print $1}' 2>/dev/null || 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}' || ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1)
   lan_ip_cidrs=$(ip route | grep "/" | awk '{print $1}' | grep -vE "^198.18" 2>/dev/null)
   lan_ip6_cidrs=$(ip -6 route | grep "/" | awk '{print $1}' | grep -vE "^unreachable" 2>/dev/null)
   wan_ip4s=$(ifconfig | grep 'inet addr' | awk '{print $2}' | cut -d: -f2 | grep -vE "(^198.18|^192.168|^127.0)" 2>/dev/null)
   wan_ip6s=$(ifconfig | grep 'inet6 addr' | awk '{print $3}' 2>/dev/null)
   disable_masq_cache=$(uci -q get openclash.config.disable_masq_cache)
   log_level=$(uci -q get openclash.config.log_level)
   intranet_allowed=$(uci -q get openclash.config.intranet_allowed)
   enable_udp_proxy=$(uci -q get openclash.config.enable_udp_proxy || echo 1)
   disable_udp_quic=$(uci -q get openclash.config.disable_udp_quic)
   operation_mode=$(uci -q get openclash.config.operation_mode)
   lan_ac_mode=$(uci -q get openclash.config.lan_ac_mode)
   enable_rule_proxy=$(uci -q get openclash.config.enable_rule_proxy)
   stack_type=$(uci -q get openclash.config.stack_type)
   china_ip_route=$(uci -q get openclash.config.china_ip_route)
   china_ip6_route=$(uci -q get openclash.config.china_ip6_route)
   small_flash_memory=$(uci -q get openclash.config.small_flash_memory)
   mixed_port=$(uci -q get openclash.config.mixed_port)
   interface_name=$(uci -q get openclash.config.interface_name || echo 0)
   common_ports=$(uci -q get openclash.config.common_ports)
   dns_port=$(uci -q get openclash.config.dns_port)
   stream_domains_prefetch=$(uci -q get openclash.config.stream_domains_prefetch || echo 0)
   store_fakeip=$(uci -q get openclash.config.store_fakeip || echo 1)
   dns_remote=$(uci -q get openclash.config.dns_remote || echo 0)
   bypass_gateway_compatible=$(uci -q get openclash.config.bypass_gateway_compatible || echo 0)
   core_version=$(uci -q get openclash.config.core_version || echo 0)
   router_self_proxy=$(uci -q get openclash.config.router_self_proxy || echo 1)
   enable_meta_core=$(uci -q get openclash.config.enable_meta_core || echo 0)
   enable_meta_sniffer=$(uci -q get openclash.config.enable_meta_sniffer || echo 0)
   enable_meta_sniffer_custom=$(uci -q get openclash.config.enable_meta_sniffer_custom || echo 0)
   geodata_loader=$(uci -q get openclash.config.geodata_loader || echo "memconservative")
   enable_geoip_dat=$(uci -q get openclash.config.enable_geoip_dat || echo 0)
   enable_tcp_concurrent=$(uci -q get openclash.config.enable_tcp_concurrent || echo 0)
   append_default_dns=$(uci -q get openclash.config.append_default_dns || echo 1)
   enable_meta_sniffer_pure_ip=$(uci -q get openclash.config.enable_meta_sniffer_pure_ip || echo 1)
   custom_china_domain_dns_server=$(uci -q get openclash.config.custom_china_domain_dns_server || echo 114.114.114.114)
   _koolshare=$(cat /usr/lib/os-release 2>/dev/null |grep OPENWRT_RELEASE 2>/dev/null |grep -i koolshare 2>/dev/null)
   [ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash.config.dns_port=7874
   uci -q set openclash.config.restricted_mode=0 && uci -q commit openclash
}

start()
{

   enable=$(uci -q get openclash.config.enable)
   [ "$enable" != "1" ] && LOG_OUT "Warning: OpenClash Now Disabled, Need Start From Luci Page, Exit..." && SLOG_CLEAN && del_lock && exit 0

   LOG_OUT "OpenClash Start Running..."
   config_choose
   do_run_mode
   
   LOG_OUT "Step 1: Get The Configuration..."
   get_config
   
   LOG_OUT "Step 2: Check The Components..."
   #检查文件是否存在
   do_run_file "$RAW_CONFIG_FILE" "$BACKUP_FILE"
   
   #快速启动判断
   check_run_quick
   
   if ! $quick_start; then
      LOG_OUT "Step 3: Modify The Config File..."
      config_check
      /usr/share/openclash/yml_change.sh 2>/dev/null "$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" "$stream_domains_prefetch" "$dns_remote" "$enable_meta_core" "$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"
      /usr/share/openclash/yml_rules_change.sh 2>/dev/null "$rule_source" "$enable_custom_clash_rules" "$TMP_CONFIG_FILE" "$enable_rule_proxy" "$CONFIG_NAME" "$router_self_proxy" "$lan_ip" "$proxy_port" "$tproxy_port" "$enable_meta_core"
      /usr/share/openclash/openclash_server_fake_filter.sh >/dev/null 2>&1
      /usr/share/openclash/openclash_custom_domain_dns.sh >/dev/null 2>&1
   fi
   
   LOG_OUT "Step 4: Start Running The Clash Core..."
   start_run_core
   
   LOG_OUT "Step 5: Check The Core Status..."
   check_core_status

   #检测proxy_provider配置文件状态
   LOG_OUT "Step 6: Wait For The File Downloading..."
   if [ "$enable_meta_core" != "1" ]; then
      yml_provider_check "$CONFIG_FILE" "proxy-providers" "proxies"
      yml_provider_check "$CONFIG_FILE" "rule-providers" "payload"
   fi
   try_restore_start
       
   LOG_OUT "Step 7: Set Firewall Rules..."
   set_firewall

   LOG_OUT "Step 8: Restart Dnsmasq..."
   change_dns "$enable_redirect_dns" "$disable_masq_cache"
   /etc/init.d/dnsmasq restart >/dev/null 2>&1
   
   LOG_OUT "Step 9: Add Cron Rules, Start Daemons..."
   add_cron
   if [ "$(uci -q get openclash.config.restricted_mode)" != "1" ]; then
      if [ -z "$(uci -q get dhcp.lan.dhcpv6)" ] || [ "$(uci -q get dhcp.lan.dhcpv6)" == "disabled" ]; then
         LOG_OUT "OpenClash Start Successful!"
         sleep 3
      elif [ "$ipv6_enable" -eq 0 ]; then
         LOG_OUT "Warning: OpenClash Start Successful, Please Note That Network May Abnormal With IPv6's DHCP Server"
         sleep 3
      else
         LOG_OUT "OpenClash Start Successful!"
         sleep 3
      fi
   else
      LOG_OUT "Warning: OpenClash Start Successful With Raw Config File, Please Note That It's Restricted Mode Now"
      sleep 3
   fi
   echo "OpenClash Already Start!"
   write_run_quick
   SLOG_CLEAN
   rm -rf /tmp/yaml_*
}

stop()
{

   enable=$(uci -q get openclash.config.enable)

   LOG_OUT "OpenClash Stoping..."
   LOG_OUT "Step 1: Backup The Current Groups State..."
   /usr/share/openclash/openclash_history_get.sh 2>/dev/null

   LOG_OUT "Step 2: Delete OpenClash Firewall Rules..."
   revert_firewall

   LOG_OUT "Step 3: Close The OpenClash Daemons..."
   watchdog_pids=$(unify_ps_pids "openclash_watchdog.sh")
   for watchdog_pid in $watchdog_pids; do
      kill -9 "$watchdog_pid" >/dev/null 2>&1
   done >/dev/null 2>&1
   
   streaming_unlock_pids=$(unify_ps_pids "openclash_streaming_unlock.lua")
   for streaming_unlock_pid in $streaming_unlock_pids; do
      kill -9 "$streaming_unlock_pid" >/dev/null 2>&1
   done >/dev/null 2>&1
   
   LOG_OUT "Step 4: Close The Clash Core Process..."
   if [ "$enable" != "1" ]; then
      kill_clash
   fi

   LOG_OUT "Step 5: Restart Dnsmasq..."
   redirect_dns=$(uci -q get openclash.config.redirect_dns)
   dnsmasq_server=$(uci -q get openclash.config.dnsmasq_server)
   dnsmasq_noresolv=$(uci -q get openclash.config.dnsmasq_noresolv)
   dnsmasq_resolvfile=$(uci -q get openclash.config.dnsmasq_resolvfile)
   cachesize_dns=$(uci -q get openclash.config.cachesize_dns)
   dnsmasq_cachesize=$(uci -q get openclash.config.dnsmasq_cachesize)
   filter_aaaa_dns=$(uci -q get openclash.config.filter_aaaa_dns)
   dnsmasq_filter_aaaa=$(uci -q get openclash.config.dnsmasq_filter_aaaa)
   default_resolvfile=$(uci -q get openclash.config.default_resolvfile)
   revert_dns "$redirect_dns" "$enable" "$default_resolvfile" "$dnsmasq_noresolv" "$dnsmasq_resolvfile" "$cachesize_dns" "$dnsmasq_cachesize" "$filter_aaaa_dns" "$dnsmasq_filter_aaaa" "$dnsmasq_server"
   /etc/init.d/dnsmasq restart >/dev/null 2>&1

   LOG_OUT "Step 6: Delete OpenClash Residue File..."
   if [ "$enable" != "1" ]; then
      rm -rf /tmp/clash_last_version >/dev/null 2>&1
      rm -rf /tmp/Proxy_Group >/dev/null 2>&1
      rm -rf /tmp/rules_name >/dev/null 2>&1
      rm -rf /tmp/rule_providers_name >/dev/null 2>&1
      rm -rf /tmp/dnsmasq.d/dnsmasq_openclash.conf >/dev/null 2>&1
      rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_custom_domain.conf >/dev/null 2>&1
      rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute_pass.conf >/dev/null 2>&1
      rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_chnroute6_pass.conf >/dev/null 2>&1
      rm -rf /tmp/dnsmasq.d/dnsmasq_accelerated-domains.china.conf >/dev/null 2>&1
      rm -rf /tmp/openclash_last_version >/dev/null 2>&1
      rm -rf /tmp/openclash_config.tmp >/dev/null 2>&1
      rm -rf /tmp/openclash.change >/dev/null 2>&1
      rm -rf /tmp/openclash_debug.log >/dev/null 2>&1
      rm -rf /tmp/etc/openclash >/dev/null 2>&1
      rm -rf /tmp/openclash_edit_file_name >/dev/null 2>&1
      rm -rf /tmp/openclash_*_region>/dev/null 2>&1
      del_lock
      LOG_OUT "OpenClash Already Stop!"
      sleep 3
   fi
   
   del_cron
   rm -rf /tmp/yaml_* >/dev/null 2>&1
   rm -rf $START_LOG >/dev/null 2>&1
   echo "OpenClash Already Stop!"
}


restart()
{
   [ -f "$LOCK_FILE" ] && LOG_OUT "Warning: Multiple Restart Scripts Running, Exit..." && SLOG_CLEAN && exit 0
   mkdir -p /tmp/lock
   touch $LOCK_FILE
   set_lock
   stop
   start
   del_lock
}

reload()
{
   enable=$(uci -q get openclash.config.enable)
   if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "firewall" ]; then
      LOG_OUT "Reload OpenClash Firewall Rules..."
      set_lock
      revert_firewall 2>/dev/null
      do_run_mode 2>/dev/null
      get_config 2>/dev/null
      start_run_core
      check_core_status
      set_firewall 2>/dev/null
      /etc/init.d/dnsmasq restart >/dev/null 2>&1
      SLOG_CLEAN
      del_lock
   fi
}

boot()
{
	delay_start=$(uci -q get openclash.config.delay_start || echo 0)
	enable=$(uci -q get openclash.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
}
