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

START=99
STOP=15
USE_PROCD=1

. $IPKG_INSTROOT/usr/share/openclash-kejibear/openclash_ps.sh
. $IPKG_INSTROOT/usr/share/openclash-kejibear/ruby.sh
. $IPKG_INSTROOT/usr/share/openclash-kejibear/log.sh
. $IPKG_INSTROOT/usr/share/openclash-kejibear/uci.sh
. $IPKG_INSTROOT/usr/share/openclash-kejibear/kjx.sh
. $IPKG_INSTROOT/usr/share/openclash-kejibear/openclash_curl.sh

[ -f /etc/openwrt_release ] && {
FW4=$(command -v fw4)
DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')"
if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then
   DNSMASQ_CONF_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID")"
else
   DNSMASQ_CONF_DIR="/tmp/dnsmasq.d"
fi
DNSMASQ_CONF_DIR=${DNSMASQ_CONF_DIR%*/}
}
CLASH="/etc/openclash-kejibear/clash"
CLASH_CONFIG="/etc/openclash-kejibear"
CRON_FILE="/etc/crontabs/root"
CACHE_PATH="/etc/openclash-kejibear/cache.db"
LOG_FILE="/tmp/openclash-kejibear.log"
START_LOG="/tmp/openclash-kejibear_start.log"
PROXY_FWMARK="0x16b"
PROXY_ROUTE_TABLE="0x16b"
QUICK_START_CHECK=false
QUICK_START=true
# 🔴 内核只准从这几个目录读 external-ui 之类的路径（不在里面就 "path is not subpath of home
# directory or SAFE_PATHS"，整份配置判失败）。正式启动和启动预检的 -t 必须用同一份，
# 预检少了它，每份配置都会被误判为不通过、回退链一层都用不上
KJX_CORE_SAFE_PATHS="/usr/share/openclash-kejibear:/etc/ssl"

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-kejibear/openclash.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci_get_config "auto_update")" -eq 1 ] && [ "$(uci_get_config "config_auto_update_mode")" -ne 1 ] && echo "0 $(uci_get_config "auto_update_time" || 1) * * $(uci_get_config "config_update_week_time" || 0) /usr/share/openclash-kejibear/openclash.sh #openclash-kejibear-cron-task" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_geo.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci_get_config "geo_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geo_update_day_time" || 1) * * $(uci_get_config "geo_update_week_time" || 0) /usr/share/openclash-kejibear/openclash_geo.sh ipdb #openclash-kejibear-cron-task" >> $CRON_FILE
      [ "$(uci_get_config "geosite_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geosite_update_day_time" || 1) * * $(uci_get_config "geosite_update_week_time" || 0) /usr/share/openclash-kejibear/openclash_geo.sh geosite #openclash-kejibear-cron-task" >> $CRON_FILE
      [ "$(uci_get_config "geoip_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geoip_update_day_time" || 1) * * $(uci_get_config "geoip_update_week_time" || 0) /usr/share/openclash-kejibear/openclash_geo.sh geoip #openclash-kejibear-cron-task" >> $CRON_FILE
      [ "$(uci_get_config "geoasn_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "geoasn_update_day_time" || 1) * * $(uci_get_config "geoasn_update_week_time" || 0) /usr/share/openclash-kejibear/openclash_geo.sh geoasn #openclash-kejibear-cron-task" >> $CRON_FILE
   }
   [ -z "$(grep "openclash_chnroute.sh" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci_get_config "chnr_auto_update")" -eq 1 ] && echo "0 $(uci_get_config "chnr_update_day_time" || 1) * * $(uci_get_config "chnr_update_week_time" || 0) /usr/share/openclash-kejibear/openclash_chnroute.sh #openclash-kejibear-cron-task" >> $CRON_FILE
   }
   [ -z "$(grep "/etc/init.d/openclash-kejibear" "$CRON_FILE" 2>/dev/null)" ] && {
      [ "$(uci_get_config "auto_restart")" -eq 1 ] && echo "0 $(uci_get_config "auto_restart_day_time" || 1) * * $(uci_get_config "auto_restart_week_time" || 0) /etc/init.d/openclash-kejibear restart #openclash-kejibear-cron-task" >> $CRON_FILE
   }

   config_load "openclash_kejibear"
   config_foreach add_overwrite_cron "config_overwrite"

   crontab $CRON_FILE
   start_watchdog
}

del_cron()
{
   sed -i '/#openclash-kejibear-cron-task/d' $CRON_FILE
   sed -i '/#openclash-kejibear-overwrite-download/d' $CRON_FILE
   /etc/init.d/cron restart
} >/dev/null 2>&1

save_dnsmasq_server() {
   if [ -z "$1" ] || [ "$1" == "127.0.0.1#${dns_port}" ]; then
     return
   fi

   uci -q add_list openclash_kejibear.config.dnsmasq_server="$1"
}

set_dnsmasq_server() {
   if [ -z "$1" ] || [ "$1" == "127.0.0.1#${dns_port}" ]; then
     return
   fi

   uci -q add_list dhcp.@dnsmasq[0].server="$1"
}

load_ip_route_pass() {
   local settype nftflag
   if dnsmasq --version | grep -q 'Compile time options:.* nftset'; then
      settype="nftset"
      nftflag="inet#fw4#"
   else
      settype="ipset"
      [ -n "$FW4" ] && LOG_WARN "Dnsmasq not Support nftset, Use ipset..."
   fi
   if [ -n "$FW4" ]; then
      if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
         if [ "$enable_redirect_dns" != "2" ]; then
            mkdir -p ${DNSMASQ_CONF_DIR}
            if [ "$settype" = "nftset" ]; then
               nft add set inet fw4 kjx_cnroute_pass '{ type ipv4_addr; flags interval; auto-merge; }'
            else
               ipset -! create kjx_cnroute_pass hash:net family inet hashsize 1024 maxelem 1000000
            fi
            awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("'${settype}'=/%s/'${nftflag}'kjx_cnroute_pass'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
            for ip in $(uci_get_config "china_ip_route_pass"); do
               [ -z "$ip" ] && continue
               echo "$ip" | awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("'${settype}'=/%s/'${nftflag}'kjx_cnroute_pass'" "'\n",$0)}'
            done >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
         fi
      fi

      if [ "$ipv6_enable" -eq 1 ]; then
         if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
            if [ "$enable_redirect_dns" != "2" ]; then
               mkdir -p ${DNSMASQ_CONF_DIR}
               if [ "$settype" = "nftset" ]; then
                  nft add set inet fw4 kjx_cnroute6_pass '{ type ipv6_addr; flags interval; auto-merge; }'
               else
                  ipset -! create kjx_cnroute6_pass hash:net family inet6 hashsize 1024 maxelem 1000000
               fi
               awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("'${settype}'=/%s/'${nftflag}'kjx_cnroute_pass'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute6_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               for ip in $(uci_get_config "china_ip6_route_pass"); do
                  [ -z "$ip" ] && continue
                  echo "$ip" | awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("'${settype}'=/%s/'${nftflag}'kjx_cnroute_pass'" "'\n",$0)}'
               done >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               #Prevent domain repeat
               for i in `grep -wf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf`
               do
                  if [ -n "$nftflag" ]; then
                     sed -i "s:${i}:${i},6#${nftflag}kjx_cnroute6_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
                  else
                     sed -i "s:${i}:${i},kjx_cnroute6_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
                  fi
                  sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               done
               if [ -n "$nftflag" ]; then
                  sed -i "s/\/${nftflag}/\/4#${nftflag}/g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
                  sed -i "s/${nftflag}kjx_cnroute_pass/6#${nftflag}kjx_cnroute6_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               else
                  sed -i "s/kjx_cnroute_pass/kjx_cnroute6_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               fi
            fi
         fi
      fi
   else
      if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
         if [ "$enable_redirect_dns" != "2" ]; then
            mkdir -p ${DNSMASQ_CONF_DIR}
            ipset -! create kjx_cnroute_pass hash:net family inet hashsize 1024 maxelem 1000000
            awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("ipset=/%s/kjx_cnroute_pass'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
            for ip in $(uci_get_config "china_ip_route_pass"); do
               [ -z "$ip" ] && continue
               echo "$ip" | awk '!/^$/&&!/^#/&&!/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("ipset=/%s/kjx_cnroute_pass'" "'\n",$0)}'
            done >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
         fi
      fi

      if [ "$ipv6_enable" -eq 1 ]; then
         if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
            if [ "$enable_redirect_dns" != "2" ]; then
               mkdir -p ${DNSMASQ_CONF_DIR}
               ipset -! create kjx_cnroute6_pass hash:net family inet6 hashsize 1024 maxelem 1000000
               awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("ipset=/%s/kjx_cnroute_pass'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute6_pass.list >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               for ip in $(uci_get_config "china_ip6_route_pass"); do
                  [ -z "$ip" ] && continue
                  echo "$ip" | awk '!/^$/&&!/^#/&&/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("ipset=/%s/kjx_cnroute_pass'" "'\n",$0)}'
               done >>${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               #Prevent domain repeat
               for i in `grep -wf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf`
               do
                  sed -i "s:${i}:${i},kjx_cnroute6_pass:g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
                  sed -i 's:'$i':EXCLUSIVE:;/EXCLUSIVE/d' ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
               done
               sed -i "s/kjx_cnroute_pass/kjx_cnroute6_pass/g" ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf
            fi
         fi
      fi
   fi
}

change_dnsmasq() {
   if ! /etc/init.d/dnsmasq enabled; then
      return
   fi

   # 区域绕过黑名单
   load_ip_route_pass

   # 第二 DNS 服务
   /usr/share/openclash-kejibear/openclash_custom_domain_dns.sh

   if [ "$1" -eq 1 ]; then
      if [ "$(uci_get_config "redirect_dns")" != "1" ]; then
         uci -q del openclash_kejibear.config.dnsmasq_server
         config_load "dhcp"
         config_list_foreach "$(uci -q show dhcp.@dnsmasq[0].server |awk -F '.' '{print $2}')" "server" save_dnsmasq_server
         uci -q set openclash_kejibear.config.dnsmasq_noresolv="$(uci -q get dhcp.@dnsmasq[0].noresolv)"
         uci -q set openclash_kejibear.config.dnsmasq_resolvfile="$(uci -q get dhcp.@dnsmasq[0].resolvfile)"
      fi
      uci -q del dhcp.@dnsmasq[-1].server
      uci -q add_list dhcp.@dnsmasq[0].server=127.0.0.1#"$dns_port"
      uci -q delete dhcp.@dnsmasq[0].resolvfile
      uci -q set dhcp.@dnsmasq[0].noresolv=1
      uci -q set dhcp.@dnsmasq[0].localuse=1
      uci -q set openclash_kejibear.config.redirect_dns=1
      uci -q set openclash_kejibear.config.dnsmasq_cachesize="$(uci -q get dhcp.@dnsmasq[0].cachesize)"
      uci -q set dhcp.@dnsmasq[0].cachesize=0
      uci -q set openclash_kejibear.config.cachesize_dns=1
   else
      # Remove residual Dnsmasq redirect left
      uci -q del_list dhcp.@dnsmasq[0].server="127.0.0.1#$dns_port"
      uci -q set openclash_kejibear.config.redirect_dns=0
      uci -q set openclash_kejibear.config.cachesize_dns=0
   fi

   if [ "$1" -eq 1 ] && [ "$ipv6_dns" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
      #dnsmasq answer ipv6
      uci -q set openclash_kejibear.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_kejibear.config.filter_aaaa_dns=1
   else
      uci -q set openclash_kejibear.config.filter_aaaa_dns=0
   fi

   uci -q commit openclash_kejibear
   uci -q commit dhcp
   /etc/init.d/dnsmasq restart
} >/dev/null 2>&1

revert_dnsmasq()
{
   if ! /etc/init.d/dnsmasq enabled; then
      return
   fi

   redirect_dns=$(uci_get_config "redirect_dns")
   dnsmasq_server=$(uci_get_config "dnsmasq_server")
   dnsmasq_noresolv=$(uci_get_config "dnsmasq_noresolv")
   dnsmasq_resolvfile=$(uci_get_config "dnsmasq_resolvfile")
   cachesize_dns=$(uci_get_config "cachesize_dns")
   dnsmasq_cachesize=$(uci_get_config "dnsmasq_cachesize")
   filter_aaaa_dns=$(uci_get_config "filter_aaaa_dns")
   dnsmasq_filter_aaaa=$(uci_get_config "dnsmasq_filter_aaaa")
   default_resolvfile=$(uci_get_config "default_resolvfile")

   rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_custom_domain.conf
   rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf
   rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf

   [ "$redirect_dns" -eq 1 ] && {
      uci -q del dhcp.@dnsmasq[-1].server
      [ -n "$dnsmasq_server" ] && {
         config_load "openclash_kejibear"
         config_list_foreach "config" "dnsmasq_server" set_dnsmasq_server
      }

      if [ "$dnsmasq_noresolv" == "0" ] || [ -z "$dnsmasq_noresolv" ] || [ -z "$(uci -q show dhcp.@dnsmasq[0].server)" ]; then
         uci -q set dhcp.@dnsmasq[0].noresolv=0
         if [ -n "$dnsmasq_resolvfile" ] && [ -n "$(grep nameserver $dnsmasq_resolvfile)" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile="$dnsmasq_resolvfile"
         elif [ -n "$default_resolvfile" ] && [ -n "$(grep nameserver $default_resolvfile)" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile="$default_resolvfile"
         elif [ -s "/tmp/resolv.conf.d/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.d/resolv.conf.auto)" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto
            uci -q set openclash_kejibear.config.default_resolvfile=/tmp/resolv.conf.d/resolv.conf.auto
         elif [ -s "/tmp/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.auto)" ]; then
            uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto
            uci -q set openclash_kejibear.config.default_resolvfile=/tmp/resolv.conf.auto
         else
            uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto
            uci -q set openclash_kejibear.config.default_resolvfile=/tmp/resolv.conf.d/resolv.conf.auto
         fi
         uci -q set dhcp.@dnsmasq[0].localuse=1
      fi
   }

   [ "$cachesize_dns" -eq 1 ] && {
      uci -q set dhcp.@dnsmasq[0].cachesize="$dnsmasq_cachesize"
      uci -q set openclash_kejibear.config.cachesize_dns=0
      uci -q delete openclash_kejibear.config.dnsmasq_cachesize
   }

   [ "$filter_aaaa_dns" -eq 1 ] && {
      uci -q set dhcp.@dnsmasq[0].filter_aaaa="$dnsmasq_filter_aaaa"
      uci -q set openclash_kejibear.config.filter_aaaa_dns=0
      uci -q delete openclash_kejibear.config.dnsmasq_filter_aaaa
   }

   [ "$redirect_dns" -eq 1 ] && {
      uci -q set openclash_kejibear.config.redirect_dns=0
      uci -q del openclash_kejibear.config.dnsmasq_server
   }

   uci -q commit dhcp
   uci -q commit openclash_kejibear

   masq_port=$(uci -q get dhcp.@dnsmasq[0].port)
   if [ "$(nslookup www.apple.com 127.0.0.1:${masq_port} >/dev/null 2>&1 || echo $?)" = "1" ]; then
      resolv_file=$(uci -q get dhcp.@dnsmasq[0].resolvfile)
      wan_dns=$(/usr/share/openclash-kejibear/openclash_get_network.lua "dns")
      wan6_dns=$(/usr/share/openclash-kejibear/openclash_get_network.lua "dns6")
      mkdir -p "$(dirname "$resolv_file")"
      touch "$resolv_file"
      
      if [ -n "$wan_dns" ]; then
         echo "# Interface lan" > "$resolv_file"
         for dns in $wan_dns; do
            echo "nameserver $dns" >> "$resolv_file"
         done
      fi
      if [ -n "$wan6_dns" ]; then
         echo "# Interface LAN6" > "$resolv_file"
         for dns6 in $wan6_dns; do
            echo "nameserver $dns6" >> "$resolv_file"
         done
      fi
      if [ -z "$wan_dns" ] && [ -z "$wan6_dns" ]; then
         cat > "$resolv_file" <<-EOF
# Interface lan
nameserver 119.29.29.29
nameserver 8.8.8.8
EOF
      fi
   fi

   /etc/init.d/dnsmasq restart

} >/dev/null 2>&1

start_fail()
{
   uci -q set openclash_kejibear.config.enable=0
   uci -q commit openclash_kejibear
   stop
   exit 0
}

sub_info_set()
{
   local section="$1" name
   config_get "name" "$section" "name" ""

   if [ -z "$name" ]; then
      return
   fi

   if [ "$name" == "$2" ] && [ -n "$3" ]; then
      if [ "$sub_info_setted" != "1" ]; then
         uci -q delete openclash_kejibear.$section.url
      fi
      uci -q add_list openclash_kejibear.$section.url="$3"
      uci -q commit openclash_kejibear
      sub_info_setted=1
   fi
}

#获取订阅配置
sub_info_get()
{
   local section="$1" address enabled name
   config_get_bool "enabled" "$section" "enabled" "1"
   config_get "address" "$section" "address" ""
   config_get "name" "$section" "name" ""

   if [ "$subscribe_enable" = "1" ]; then
      return
   fi

   if [ "$enabled" -eq 0 ]; then
      return
   fi

   if [ -z "$address" ]; then
      return
   fi

   if [ -z "$name" ]; then
      SUB_CONFIG_FILE="/etc/openclash-kejibear/config/config.yaml"
   else
      SUB_CONFIG_FILE="/etc/openclash-kejibear/config/$name.yaml"
   fi

   if [ "$SUB_CONFIG_FILE" != "$2" ]; then
      return
   fi

   subscribe_enable=1
}

#配置文件选择
config_choose()
{
if [ ! -f "$RAW_CONFIG_FILE" ]; then
   config_load "openclash_kejibear"
   config_foreach sub_info_get "config_subscribe" "$RAW_CONFIG_FILE"
   if [ "$subscribe_enable" = "1" ]; then
      LOG_OUT "【$RAW_CONFIG_FILE】Config File Does Not Exist, You Have Set Subscription Information, Ready To Download..."
      /usr/share/openclash-kejibear/openclash.sh "$RAW_CONFIG_FILE" &
      exit 0
   fi
fi

if [ -z "$RAW_CONFIG_FILE" ] || [ ! -f "$RAW_CONFIG_FILE" ]; then
   for file_name in /etc/openclash-kejibear/config/*
   do
      if [ -f "$file_name" ]; then
         CONFIG_NAME=$(echo "$file_name" |awk -F '/' '{print $5}' 2>/dev/null)
         uci -q set openclash_kejibear.config.config_path="/etc/openclash-kejibear/config/$CONFIG_NAME"
         uci -q commit openclash_kejibear
         RAW_CONFIG_FILE="/etc/openclash-kejibear/config/$CONFIG_NAME"
         CONFIG_FILE="/etc/openclash-kejibear/$CONFIG_NAME"
         TMP_CONFIG_FILE="/tmp/$CONFIG_NAME"
         LOG_ERROR "Config Not Found, Switch Config File to【$RAW_CONFIG_FILE】"
         break
      fi
   done
fi

if [ ! -f "$RAW_CONFIG_FILE" ]; then
   LOG_ERROR "Config Not Found"
   exit 0
fi

CONFIG_NAME=$(echo "$RAW_CONFIG_FILE" |awk -F '/' '{print $5}' 2>/dev/null)
HISTORY_PATH="/etc/openclash-kejibear/history/${CONFIG_NAME%.*}.db"
} >/dev/null 2>&1

config_check()
{
#创建启动配置
#rm -rf "/etc/openclash-kejibear/*.y*" 2>/dev/null
cp "$RAW_CONFIG_FILE" "$TMP_CONFIG_FILE"

ruby -ryaml -rYAML -I "/usr/share/openclash-kejibear" -E UTF-8 -e "
begin
   YAML.load_file('$RAW_CONFIG_FILE');
rescue Exception => e
   YAML.LOG_ERROR('Unable To Parse Config File,【' + e.message + '】');
   system 'rm -rf ${TMP_CONFIG_FILE}';
end
" 2>/dev/null >> $LOG_FILE
if [ $? -ne 0 ]; then
   LOG_ERROR "Ruby Works Abnormally, Please Check The Ruby Library Depends!"
   start_fail
elif [ ! -f "$TMP_CONFIG_FILE" ] || [ ! -s "$TMP_CONFIG_FILE" ]; then
   LOG_ERROR "Config File Format Validation Failed..."
   start_fail
fi
}

check_run_quick()
{
   if $QUICK_START_CHECK; then
      return
   fi

   QUICK_START_CHECK=true

   cat "/tmp/openclash-kejibear.change" | while read -r i; do
      file_path=$(echo "$i" |awk -F ' #edited time# ' '{print $1}')
      if [ -z "$(grep "$file_path #edited time# $(date -r "$file_path")$" "/tmp/openclash-kejibear.change")" ]; then
         LOG_TIP "Because of the file【 $file_path 】modificated, Pause quick start..."
         rm -rf /tmp/openclash-kejibear.change
         break
      fi
   done

   # 🔴 自定义节点存储是第一次新建的（上次启动时还没有，write_run_quick 没记它）
   if [ -f "$KJX_CUSTOM_NODES_STORE" ] && [ -f "/tmp/openclash-kejibear.change" ] \
      && ! grep -q "^$KJX_CUSTOM_NODES_STORE #edited time# " "/tmp/openclash-kejibear.change"; then
      LOG_TIP "Because of the file【 $KJX_CUSTOM_NODES_STORE 】modificated, Pause quick start..."
      rm -rf /tmp/openclash-kejibear.change
   fi

   # 🔴 上次启动走了预检回退（覆写 / 自定义节点被跳过）：不能快速启动。否则此后每次没改文件的
   # 重启（守护进程拉起、LuCI 重启、定时任务）都沿用那份降级配置、也不再预检 ——
   # 回退要是一时的原因（比如开机时 GeoSite 没下下来导致校验失败），用户的覆写就一直不生效
   if [ -f "$KJX_OVERWRITE_FALLBACK_FLAG" ]; then
      rm -rf /tmp/openclash-kejibear.change
   fi

   if [ ! -f "/tmp/openclash-kejibear.change" ]; then
      QUICK_START=false
   fi
} >/dev/null 2>&1

write_run_quick()
{
   : > "/tmp/openclash-kejibear.change"
   {
      echo "/etc/config/openclash_kejibear"
      echo "$RAW_CONFIG_FILE"
      echo "$CONFIG_FILE"
      ls -d /etc/openclash-kejibear/custom/* 2>/dev/null
      ls -d /etc/openclash-kejibear/overwrite/* 2>/dev/null
      # 🔴 自定义节点存储也算：改了节点不重建运行配置的话，快速启动会沿用上次注入的结果，
      # 用户删掉的节点还在、新加的不出现。只在文件存在时记：不存在的文件记下的是空时间，
      # check_run_quick 的 read 会吃掉行尾空格、永远比不上，等于每次都关掉快速启动。
      # 「上次没有、这次有了」由 check_run_quick 单独判断
      ls -d "$KJX_CUSTOM_NODES_STORE" 2>/dev/null
   } | while read -r file; do
      echo "$file #edited time# $(date -r "$file")" >> "/tmp/openclash-kejibear.change"
   done
} >/dev/null 2>&1

#运行模式处理
do_run_mode()
{
   en_mode=$(uci_get_config "en_mode")

   if [ "$en_mode" = "fake-ip-tun" ]; then
      en_mode_tun="1"
      en_mode="fake-ip"
   fi

   if [ "$en_mode" = "redir-host-tun" ]; then
      en_mode_tun="1"
      en_mode="redir-host"
   fi

   if [ "$en_mode" = "redir-host-mix" ]; then
      en_mode_tun="2"
      en_mode="redir-host"
   fi

   if [ "$en_mode" = "fake-ip-mix" ]; then
      en_mode_tun="2"
      en_mode="fake-ip"
   fi
}

do_run_file()
{

   #Some MIPS devices file system cound not use db
   source "/etc/openwrt_release"
   [ "$small_flash_memory" == "1" ] || [ -n "$(echo $core_version |grep mips)" ] || [ -n "$(echo $DISTRIB_ARCH |grep mips)" ] || [ -n "$(opkg status libc 2>/dev/null |grep 'Architecture' |awk -F ': ' '{print $2}' |grep mips)" ] || [ -n "$(apk list libc 2>/dev/null |grep mips)" ] && mkdir -p /tmp/etc/openclash-kejibear && CACHE_PATH="/tmp/etc/openclash-kejibear/cache.db"

   [ -f "/etc/openclash-kejibear/geosite.dat" ] && {
      mv "/etc/openclash-kejibear/geosite.dat" "/etc/openclash-kejibear/GeoSite.dat"
   }

   [ -f "/etc/openclash-kejibear/geoip.dat" ] && {
      mv "/etc/openclash-kejibear/geoip.dat" "/etc/openclash-kejibear/GeoIP.dat"
   }

   if [ "$small_flash_memory" != "1" ]; then
      meta_core_path="/etc/openclash-kejibear/core/clash_meta"
      ipdb_path="/etc/openclash-kejibear/Country.mmdb"
      chnr_path="/etc/openclash-kejibear/china_ip_route.ipset"
      chnr6_path="/etc/openclash-kejibear/china_ip6_route.ipset"
      geosite_path="/etc/openclash-kejibear/GeoSite.dat"
      geoip_path="/etc/openclash-kejibear/GeoIP.dat"
      asn_path="/etc/openclash-kejibear/ASN.mmdb"
      lgbm_path="/etc/openclash-kejibear/Model.bin"
      mv "/tmp/etc/openclash-kejibear/Country.mmdb" "$ipdb_path"
      mv "/tmp/etc/openclash-kejibear/china_ip_route.ipset" "$chnr_path"
      mv "/tmp/etc/openclash-kejibear/china_ip6_route.ipset" "$chnr6_path"
      mv "/tmp/etc/openclash-kejibear/GeoSite.dat" "$geosite_path"
      mv "/tmp/etc/openclash-kejibear/GeoIP.dat" "$geoip_path"
      mv "/tmp/etc/openclash-kejibear/ASN.mmdb" "$asn_path"
      mv "/tmp/etc/openclash-kejibear/Model.bin" "$lgbm_path"
      mv "/tmp/etc/openclash-kejibear/core/" "/etc/openclash-kejibear"
      if [ "$CACHE_PATH" != "/tmp/etc/openclash-kejibear/cache.db" ]; then
         rm -rf "/tmp/etc/openclash-kejibear"
      fi
   else
      meta_core_path="/tmp/etc/openclash-kejibear/core/clash_meta"
      ipdb_path="/tmp/etc/openclash-kejibear/Country.mmdb"
      chnr_path="/tmp/etc/openclash-kejibear/china_ip_route.ipset"
      chnr6_path="/tmp/etc/openclash-kejibear/china_ip6_route.ipset"
      geosite_path="/tmp/etc/openclash-kejibear/GeoSite.dat"
      geoip_path="/tmp/etc/openclash-kejibear/GeoIP.dat"
      asn_path="/tmp/etc/openclash-kejibear/ASN.mmdb"
      lgbm_path="/tmp/etc/openclash-kejibear/Model.bin"
      [ ! -h "/etc/openclash-kejibear/Country.mmdb" ] && mv "/etc/openclash-kejibear/Country.mmdb" "$ipdb_path"
      [ ! -h "/etc/openclash-kejibear/china_ip_route.ipset" ] && mv "/etc/openclash-kejibear/china_ip_route.ipset" "$chnr_path"
      [ ! -h "/etc/openclash-kejibear/china_ip6_route.ipset" ] && mv "/etc/openclash-kejibear/china_ip6_route.ipset" "$chnr6_path"
      [ ! -h "/etc/openclash-kejibear/GeoSite.dat" ] && mv "/etc/openclash-kejibear/GeoSite.dat" "$geosite_path"
      [ ! -h "/etc/openclash-kejibear/GeoIP.dat" ] && mv "/etc/openclash-kejibear/GeoIP.dat" "$geoip_path"
      [ ! -h "/etc/openclash-kejibear/ASN.mmdb" ] && mv "/etc/openclash-kejibear/ASN.mmdb" "$asn_path"
      [ ! -h "/etc/openclash-kejibear/Model.bin" ] && mv "/etc/openclash-kejibear/Model.bin" "$lgbm_path"
      mv "/etc/openclash-kejibear/core/" "/tmp/etc/openclash-kejibear"
   fi

   rm -rf "/etc/openclash-kejibear/cache.db"
   rm -rf "/etc/openclash-kejibear/clash"

   ln -s "$meta_core_path" /etc/openclash-kejibear/clash

   if [ -n "$OIX_TOKEN" ]; then
      core_type="Oix"
   elif [ "$smart_enable" -eq 1 ] || [ "$core_type" == "Smart" ]; then
      core_type="Smart"
   else
      core_type="Meta"
   fi

   if [ -f "$CLASH" ] && [ ! -x "$CLASH" ]; then
      chmod 4755 "$CLASH"
      chown root:root "$CLASH"
   fi

   # N-KMIRROR：内核不在时先走官方镜像。小闪存机型内核放在内存盘，每次重启都要重下，
   # 而这时代理还没起来 —— 大陆直连 GitHub 基本下不动，下面上游那条多半失败、服务起不来。
   # 镜像也失败才轮到上游那条（它会自己判断要不要下）。
   if [ ! -f "$CLASH" ] && [ -x /usr/share/openclash-kejibear/kjx.sh ]; then
      /usr/share/openclash-kejibear/kjx.sh core_install >/dev/null 2>&1
      # 所有下载都走我们自己的网站：Meta 内核镜像拿不到就直接失败，不再去 GitHub
      # （大陆直连 GitHub 基本下不动，只会让启动多卡几分钟再失败）。
      if [ ! -f "$CLASH" ] && [ "$core_type" = "Meta" ]; then
         LOG_ERROR "Core download failed, please check the router's internet connection and try again"
         start_fail
      fi
   fi

   [ ! -f "$CLASH" ] || { [ "$core_type" = "Smart" ] && [ -z "$($CLASH -v | grep 'smart')" ] && [ -z "$($CLASH -v | grep 'oix')" ]; } || { [ "$core_type" = "Oix" ] && [ -z "$($CLASH -v | grep 'oix')" ]; } && {
      LOG_TIP "【$core_type】Core is not Detected installed, Ready to Download..."
      /usr/share/openclash-kejibear/openclash_core.sh "$core_type"
      if [ ! -f "$meta_core_path" ]; then
         start_fail
      fi
   }

   if [ "$china_ip_route" != "0" ] || [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
      if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then
         LOG_TIP "Detected that the Chnroute Cidr is not Installed, Ready to Download..."
         /usr/share/openclash-kejibear/openclash_chnroute.sh
      fi
      if [ -n "$FW4" ]; then
         if [ -z "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -z "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then
            LOG_TIP "Detected that the Chnroute Cidr List Format is wrong, Ready to Reformat..."
            /usr/share/openclash-kejibear/openclash_chnroute.sh
            if [ -z "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -z "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then
               start_fail
            fi
         fi
      else
         if [ -n "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -n "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then
            LOG_TIP "Detected that the Chnroute Cidr List Format is wrong, Ready to Reformat..."
            /usr/share/openclash-kejibear/openclash_chnroute.sh
            if [ -n "$(cat "$chnr_path" |grep "define china_ip_route")" ] || [ -n "$(cat "$chnr6_path" |grep "define china_ip6_route")" ]; then
               start_fail
            fi
         fi
      fi
      if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then
         start_fail
      fi
   fi

   [ ! -x "$meta_core_path" ] && chmod 4755 "$meta_core_path"

   [ -f "$ipdb_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$ipdb_path" /etc/openclash-kejibear/Country.mmdb
   }

   [ -f "$geosite_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$geosite_path" /etc/openclash-kejibear/GeoSite.dat
   }

   [ -f "$geoip_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$geoip_path" /etc/openclash-kejibear/GeoIP.dat
   }

   [ -f "$lgbm_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$lgbm_path" /etc/openclash-kejibear/Model.bin
   }

   [ -f "$chnr_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$chnr_path" /etc/openclash-kejibear/china_ip_route.ipset
   }

   [ -f "$chnr6_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$chnr6_path" /etc/openclash-kejibear/china_ip6_route.ipset
   }

   [ -f "$asn_path" ] && [ "$small_flash_memory" = "1" ] && {
      ln -s "$asn_path" /etc/openclash-kejibear/ASN.mmdb
   }

   #Restore history cache
   if [ -f "$HISTORY_PATH" ]; then
      cmp -s "$CACHE_PATH" "$HISTORY_PATH"
      if [ "$?" -ne "0" ]; then
         if [ "$CACHE_PATH" != "/tmp/etc/openclash-kejibear/cache.db" ]; then
            ln -s "$HISTORY_PATH" "$CACHE_PATH"
         else
            cp "$HISTORY_PATH" "$CACHE_PATH"
         fi
      fi
   fi

   if [ "$CACHE_PATH" == "/tmp/etc/openclash-kejibear/cache.db" ]; then
      [ ! -f "$CACHE_PATH" ] && touch "$CACHE_PATH"
      ln -s "$CACHE_PATH" /etc/openclash-kejibear/cache.db
   else
      [ ! -f "$CACHE_PATH" ] && touch "$HISTORY_PATH"
      ln -s "$HISTORY_PATH" "$CACHE_PATH"
   fi

   #保存启动内核类型
   uci -q set openclash_kejibear.config.core_type="$core_type"
   uci -q commit openclash_kejibear

} >/dev/null 2>&1

container() {
   [ -f "/proc/1/cgroup" ] && grep -qiE "(docker|containerd|lxc|podman|kubepods|container)" /proc/1/cgroup 2>/dev/null && return 0
   [ -f "/proc/1/environ" ] && grep -qiE "(docker|containerd|lxc|podman|kubepods|container)" /proc/1/environ 2>/dev/null && return 0
   [ -f "/.dockerenv" ] && return 0
   env | grep -qiE "(docker|kubernetes|container)" && return 0
   return 1
}

check_mod()
{
   if container; then
      return 0
   fi

   # Convert module name to uppercase using POSIX-compatible syntax
   # BusyBox tr doesn't support [:lower:]/[:upper:], use a-z/A-Z instead
   module_upper=$(echo "$1" | tr a-z A-Z)
   if [ -f /proc/config.gz ] && zcat /proc/config.gz | grep -q "CONFIG_${module_upper}=y"; then
      return 0
   fi

   if lsmod | grep -q "^$1 "; then
      return 0
   fi

   modprobe $1 2>/dev/null
   if [ $? -eq 0 ]; then
      return 0
   fi

   LOG_ERROR "【$1】module not found, please check your system depends if something abnormal!"
} >/dev/null 2>&1

check_core_status()
{
   TUN_WAIT=0
   TUN_RESTART=1
   CORE_WAIT=0
   CORE_HTTP_CODE=0

   while ( [ -z "$(pidof clash)" ] && [ "$CORE_WAIT" -le 10 ] )
   do
      sleep 1
      let CORE_WAIT++
   done

   if [ -n "$en_mode_tun" ] || [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
      check_mod "tun"

      if [ -n "$en_mode_tun" ]; then
         ip_="ip"
      else
         ip_="ip -6"
      fi

      #wait 300s most for core start
      while ( [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep kjxtun)" ] && [ "$TUN_WAIT" -le 300 ] )
      do
         $ip_ link set kjxtun up
         let TUN_WAIT++
         sleep 1
      done

      if [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep kjxtun)" ] && [ "$TUN_WAIT" -gt 300 ]; then
         while ( [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep kjxtun)" ] && [ "$TUN_RESTART" -le 3 ] )
         do
            LOG_WARN "TUN Interface Start Failed, Try to Restart Again..."
            start_run_core
            let TUN_RESTART++
            sleep 300
         done
         if [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep kjxtun)" ] && [ "$TUN_RESTART" -gt 3 ]; then
            LOG_ERROR "TUN Interface Start Failed, Please Check The Dependence or Try to Restart Again!"
            LOG_ERROR "Core Initial Configuration Timeout, Please Check The Log Infos!"
            start_fail
         fi
      fi

      if [ -n "$(pidof clash)" ]; then
         while ( [ -n "$(pidof clash)" ] && [ -n "$(ip -6 rule show |grep 2022)" ] && [ "$CORE_WAIT" -le 10 ] )
         do
            ip -6 rule del oif kjxtun table 2022
            ip -6 route del default dev kjxtun table 2022
            let CORE_WAIT++
         done
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            ip -6 route add default dev kjxtun table "$PROXY_ROUTE_TABLE"
            ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888
         fi
         if [ -n "$en_mode_tun" ]; then
            ip route add default dev kjxtun table "$PROXY_ROUTE_TABLE"
            ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888
         fi
      fi
   else
      reg4='^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'
      while ( [ -n "$(pidof clash)" ] && [ "$CORE_HTTP_CODE" != "200" ] && [ "$TUN_WAIT" -le 300 ] && [ -n "$(echo ${lan_ip} | grep -Eo ${reg4})" ] )
      do
         CORE_HTTP_CODE=$(curl -m 5 -o /dev/null -s -w '%{http_code}' -H 'Content-Type: application/json' -H "Authorization: Bearer ${da_password}" -XGET http://${lan_ip}:${cn_port}/group)
         let TUN_WAIT++
         sleep 1
      done
      if [ -z "$(echo ${lan_ip} | grep -Eo ${reg4})" ]; then
         LOG_ERROR "LAN IP Address Get Error, Please Check The LAN Interface Setting or Choose the Correct Interface in the Setting!"
         start_fail
      fi
      if [ -n "$(pidof clash)" ] && [ "$CORE_HTTP_CODE" != "200" ]; then
         LOG_ERROR "Core Initial Configuration Timeout, Please Check The Log Infos!"
         start_fail
      fi
   fi
   if [ -z "$(pidof clash)" ]; then
      LOG_ERROR "Core Start Failed, Please Check The Log Infos!"
      start_fail
   fi

   # redirect dns setting after core started, prevent core dns lookup failure
   if [ "$1" == "start" ]; then
      change_dnsmasq "$enable_redirect_dns"
      set_firewall
      LOG_TIP "OpenClash Start Successful!"
   else
      set_firewall
      LOG_TIP "Firewall Reload Successful!"
   fi

   write_run_quick
} >/dev/null 2>&1

start_run_core()
{
   ulimit -SHn 1000000
   ulimit -v unlimited
   ulimit -u unlimited

   if ! $QUICK_START; then
      # 🔴 N-RT①：托管配置的运行时副本要写进闪存了 —— 必须是密文。
      # 上游这里是无条件 mv：只要 ruby 那边没找到公钥，就会把一份**明文**配置
      # 长期留在 /etc/openclash-kejibear/ 下，前面所有的落盘加密全部白做。
      if [ "$KJX_KEEP_RUNTIME" = "1" ] || [ ! -f "$TMP_CONFIG_FILE" ]; then
         # 预检回退到了上一份运行配置（见 kjx_config_preflight），闪存上那份不动；
         # 没有 TMP 是 check_core_status 里 TUN 重试再次调用本函数，那时早已 mv 过了，
         # 不能再把现在这份挪成 .bak
         rm -rf "$TMP_CONFIG_FILE"
      elif kjx_is_managed "$(basename "${CONFIG_FILE:-}")" && ! kjx_runtime_is_encrypted "$TMP_CONFIG_FILE"; then
         LOG_ERROR "Managed runtime config is not encrypted, refusing to write it to flash"
         rm -rf "$TMP_CONFIG_FILE"
      else
      # 🔴 FIX2④：旧的运行配置留一份 .bak 给下次预检回退用（同分区 rename，不多写闪存）。
      # 托管配置的旧副本若不是密文就不留 —— 闪存上不能多出一份明文。
      # .fp 是生成这份配置时的端口 / 运行模式指纹，跟着配置一起轮换（见 kjx_runtime_fingerprint）
      if [ -f "$CONFIG_FILE" ]; then
         if kjx_is_managed "$(basename "$CONFIG_FILE")" && ! kjx_runtime_is_encrypted "$CONFIG_FILE"; then
            rm -f "$CONFIG_FILE" "$CONFIG_FILE.fp"
         else
            mv -f "$CONFIG_FILE" "$CONFIG_FILE.bak"
            mv -f "$CONFIG_FILE.fp" "$CONFIG_FILE.bak.fp" 2>/dev/null || rm -f "$CONFIG_FILE.bak.fp"
         fi
      fi
      if mv "$TMP_CONFIG_FILE" "$CONFIG_FILE"; then
         kjx_runtime_fingerprint > "$CONFIG_FILE.fp"
      else
         # 多占了一份空间，小闪存可能写不下：写不进去就把旧的挪回来，内核至少还有配置可用
         LOG_ERROR "Write runtime config failed, keep the previous one"
         rm -f "$CONFIG_FILE" "$CONFIG_FILE.fp"
         if [ -f "$CONFIG_FILE.bak" ]; then
            mv -f "$CONFIG_FILE.bak" "$CONFIG_FILE"
            mv -f "$CONFIG_FILE.bak.fp" "$CONFIG_FILE.fp" 2>/dev/null
         fi
      fi
      rm -rf "$TMP_CONFIG_FILE"
      fi
   fi
   chown root:root "$CLASH"
   procd_open_instance "openclash"
   procd_set_param env SAFE_PATHS="$KJX_CORE_SAFE_PATHS"
   procd_append_param env CLASH_AGE_SECRET_KEY="$SECRET_KEY"
   procd_append_param env OIX_TOKEN="$OIX_TOKEN"
   procd_append_param env OIX_PARAMS="$OIX_PARAMS"
   procd_set_param command /bin/sh -c "exec $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1"
   procd_set_param user "root"
   procd_set_param group "nogroup"
   procd_set_param limits nproc="unlimited" as="unlimited" memlock="unlimited" nofile="1000000 1000000"
   procd_set_param respawn 300 5 3
   procd_set_param stderr 1
   procd_set_param no_new_privs 1
   procd_close_instance
} >/dev/null 2>&1

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

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

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

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

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

   if [ -n "$wan_ints" ]; then
      wan_ints="$wan_ints $1"
   else
      wan_ints="$1"
   fi
}

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

   if [ -n "$wan6_ints" ]; then
      wan6_ints="$wan6_ints $1"
   else
      wan6_ints="$1"
   fi
}

upnp_exclude()
{
   if [ -s "$upnp_lease_file" ]; then
      cat "$upnp_lease_file" |while read -r line
      do
         if [ -n "$line" ]; then
            upnp_ip=$(echo "$line" |awk -F ':' '{print $3}')
            upnp_dp=$(echo "$line" |awk -F ':' '{print $4}')
            upnp_type=$(echo "$line" |awk -F ':' '{print $1}' |tr '[A-Z]' '[a-z]')
            if [ -n "$upnp_ip" ] && [ -n "$upnp_dp" ] && [ -n "$upnp_type" ]; then
               if [ -n "$FW4" ]; then
                  if [ -z "$(nft list chain inet fw4 kjxclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
                     nft add rule inet fw4 kjxclash_upnp ip saddr { "$upnp_ip" } "$upnp_type" sport "$upnp_dp" counter return
                  fi
               else
                  if [ -z "$(iptables -t mangle -nL kjxclash_upnp |grep "$upnp_ip" |grep "$upnp_dp" |grep "$upnp_type")" ]; then
                     iptables -t mangle -A kjxclash_upnp -p "$upnp_type" -s "$upnp_ip" --sport "$upnp_dp" -j RETURN
                  fi
               fi
            fi
         fi
      done
   fi
} >/dev/null 2>&1

ipv6_suffix_to_nft_format()
{
   local ipv6_with_prefix="$1"

   if ! echo "$ipv6_with_prefix" | grep -q '/'; then
      echo "{ $ipv6_with_prefix }"
      return
   fi

   local addr="${ipv6_with_prefix%%/*}"
   local suffix="${ipv6_with_prefix##*/}"

   if echo "$suffix" | grep -qE '^[0-9]+$'; then
      echo "${addr}/${suffix}"
      return
   fi

   echo "& ${suffix} == ${addr}"
} 2>/dev/null

fw4_has_dns_hijack_rule()
{
   local chain="$1"
   local family="$2"

   case "$family" in
      ipv6)
         nft list chain inet fw4 "$chain" 2>/dev/null |grep 'Kejibear DNS Hijack' |grep -Eq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr'
      ;;
      *)
         nft list chain inet fw4 "$chain" 2>/dev/null |grep 'Kejibear DNS Hijack' |grep -Evq 'meta nfproto[[:space:]]+\{?ipv6\}?|meta nfproto[[:space:]]+ipv6|ip6 nexthdr'
      ;;
   esac
}

firewall_lan_ac_traffic()
{
   local src_port sport_rule dscp_rule sport_ipt dscp_ipt src_ip src_ip_v6 proto target target_ enabled family dscp rule output_rule comment
   config_get "src_port" "$section" "src_port" "0-65535"
   config_get "src_ip" "$section" "src_ip" ""
   config_get "proto" "$section" "proto" "both"
   config_get "target" "$section" "target" "return"
   config_get_bool "enabled" "$section" "enabled" "0"
   config_get "family" "$section" "family" "both"
   config_get "dscp" "$section" "dscp" ""
   config_get "interface" "$section" "interface" ""
   config_get "user" "$section" "user" ""
   config_get "comment" "$section" "comment" "lan_ac_traffic"

   if [ "${enabled}" == "0" ]; then
      return
   fi

   local e_udp=false
   local e_tcp=false
   if [ "${proto}" == "tcp" ]; then e_tcp=true; fi
   if [ "${proto}" == "udp" ]; then e_udp=true; fi
   if [ "${proto}" == "both" ]; then e_tcp=true; e_udp=true; fi

   if [ -n "$FW4" ]; then
      if [ "${src_ip}" == "localnetwork" ]; then
         src_ip="ip saddr @kjx_localnet"
         src_ip_v6="ip6 saddr @kjx_localnet6"
      else
         if [ -n "${src_ip}" ]; then
            src_ip_v6="ip6 saddr $(ipv6_suffix_to_nft_format "${src_ip}")"
            src_ip="ip saddr { ${src_ip} }"
         fi
      fi

      if [ -n "${src_port}" ]; then
         sport_rule="sport ${src_port}"
      fi

      if [ -n "${interface}" ]; then
         interface_rule="iifname \"${interface}\""
      fi

      if [ -n "${user}" ]; then
         user_rule="meta skuid ${user}"
      fi

      if [ -n "${dscp}" ]; then
         dscp_rule="ip dscp ${dscp}"
      fi

      if [ "${target}" == "drop" ]; then
         target_="return"
      else
         target_="${target}"
      fi

      rule_target_v4_="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv4} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target_} comment ${comment}"
      output_rule_target_v4_="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target_} comment ${comment}"
      rule_target_v4="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv4} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target} comment ${comment}"
      output_rule_target_v4="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip daddr != { ${fakeip_range} } ${src_ip} counter ${target} comment ${comment}"

      rule_target_v6_="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv6} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target_} comment ${comment}"
      output_rule_target_v6_="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target_} comment ${comment}"
      rule_target_v6="${sport_rule} ${interface_rule} ${dscp_rule} meta nfproto {ipv6} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target} comment ${comment}"
      output_rule_target_v6="${sport_rule} ${user_rule} ${interface_rule} ${dscp_rule} ip6 daddr != { ${fakeip_range6} } ${src_ip_v6} counter ${target} comment ${comment}"

      if [ "${family}" == "both" ] || [ "${family}" == "ipv4" ]; then
         if [ -z "${en_mode_tun}" ] || [ "${en_mode_tun}" -eq 2 ]; then
            if $e_tcp ; then
               nft insert rule inet fw4 kjxclash_output position 0 tcp ${output_rule_target_v4_}
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash position 0 tcp ${rule_target_v4_}
            fi
            if $e_udp ; then
               nft insert rule inet fw4 kjxclash_mangle_output position 0 udp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_mangle position 0 udp ${rule_target_v4}
            fi
         elif [ "${en_mode_tun}" -eq 1 ]; then
            if $e_tcp ; then
               nft insert rule inet fw4 kjxclash_mangle_output position 0 tcp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_mangle position 0 tcp ${rule_target_v4}
            fi
            if $e_udp ; then
               nft insert rule inet fw4 kjxclash_mangle_output position 0 udp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_mangle position 0 udp ${rule_target_v4}
            fi
         fi
         if $e_tcp ; then
            nft insert rule inet fw4 kjxclash_post position 0 tcp ${output_rule_target_v4_}
         fi
         if $e_udp ; then
            nft insert rule inet fw4 kjxclash_post position 0 udp ${output_rule_target_v4_}
         fi
      fi

      if [ "${ipv6_enable}" -eq 1 ]; then
         if [ "${family}" == "both" ] || [ "${family}" == "ipv6" ]; then
            if $e_tcp ; then
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_v6 position 0 tcp ${rule_target_v6_}
               nft insert rule inet fw4 kjxclash_output_v6 position 0 tcp ${output_rule_target_v6_}
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_mangle_v6 position 0 tcp ${rule_target_v6}
               nft insert rule inet fw4 kjxclash_mangle_output_v6 position 0 tcp ${output_rule_target_v6}
               nft insert rule inet fw4 kjxclash_post_v6 position 0 tcp ${output_rule_target_v6_}
            fi
            if $e_udp ; then
               [ -z "${user_rule}" ] && nft insert rule inet fw4 kjxclash_mangle_v6 position 0 udp ${rule_target_v6}
               nft insert rule inet fw4 kjxclash_mangle_output_v6 position 0 udp ${output_rule_target_v6}
               nft insert rule inet fw4 kjxclash_post_v6 position 0 udp ${output_rule_target_v6_}
            fi
         fi
      fi
   else
      if [ "${src_ip}" == "localnetwork" ]; then
         src_ip="-m set --match-set kjx_localnet src"
         src_ip_v6="-m set --match-set kjx_localnet6 src"
      else
         if [ -n "${src_ip}" ]; then
            src_ip_v6="-s ${src_ip}"
            src_ip="-s ${src_ip}"
         fi
      fi

      src_port=$(echo ${src_port} | sed "s/-/:/g" 2>/dev/null)
      if [ -n "${src_port}" ]; then
         sport_ipt="--sport ${src_port}"
      fi

      if [ "${target}" == "accept" ]; then target="ACCEPT" target_="ACCEPT"; fi
      if [ "${target}" == "return" ]; then target="RETURN" target_="RETURN"; fi
      if [ "${target}" == "drop" ]; then target="DROP" target_="RETURN"; fi

      if [ -n "${interface}" ]; then
         interface_rule="-i ${interface}"
      fi

      if [ -n "${user}" ]; then
         user_rule="-m owner --uid-owner ${user}"
      fi

      if [ -n "${dscp}" ]; then
         if iptables -m dscp --help >/dev/null 2>&1; then
            dscp_ipt="-m dscp --dscp ${dscp}"
         else
            LOG_WARN "iptables DSCP module not available, please try DCSP rule by core instead, skipping DSCP rule for【${comment}】"
         fi
      fi

      rule_target_v4_="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}"
      output_rule_target_v4_="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}"
      rule_target_v4="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}"
      output_rule_target_v4="! -d ${fakeip_range} ${src_ip} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}"

      rule_target_v6_="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}"
      output_rule_target_v6_="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target_} -m comment --comment ${comment}"
      rule_target_v6="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}"
      output_rule_target_v6="! -d ${fakeip_range6} ${src_ip_v6} ${sport_ipt} ${user_rule} ${interface_rule} ${dscp_ipt} -j ${target} -m comment --comment ${comment}"

      if [ "${family}" == "both" ] || [ "${family}" == "ipv4" ]; then
         if [ -z "${en_mode_tun}" ] || [ "${en_mode_tun}" -eq 2 ]; then
            if $e_tcp ; then
               iptables -t nat -I kjxclash_output -p tcp ${output_rule_target_v4_}
               [ -z "${user_rule}" ] && iptables -t nat -I kjxclash -p tcp ${rule_target_v4_}
            fi
            if $e_udp ; then
               iptables -t mangle -I kjxclash_output -p udp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && iptables -t mangle -I kjxclash -p udp ${rule_target_v4}
            fi
         elif [ "${en_mode_tun}" -eq 1 ]; then
            if $e_tcp ; then
               iptables -t mangle -I kjxclash_output -p tcp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && iptables -t mangle -I kjxclash -p tcp ${rule_target_v4}
            fi
            if $e_udp ; then
               iptables -t mangle -I kjxclash_output -p udp ${output_rule_target_v4}
               [ -z "${user_rule}" ] && iptables -t mangle -I kjxclash -p udp ${rule_target_v4}
            fi
         fi
         if $e_tcp ; then
            iptables -t nat -I kjxclash_post -p tcp ${output_rule_target_v4_}
         fi
         if $e_udp ; then
            iptables -t nat -I kjxclash_post -p udp ${output_rule_target_v4_}
         fi
      fi

      if [ "${ipv6_enable}" -eq 1 ]; then
         if [ "${family}" == "both" ] || [ "${family}" == "ipv6" ]; then
            if $e_tcp ; then
               [ -z "${user_rule}" ] && ip6tables -t nat -I kjxclash -p tcp ${rule_target_v6_}
               ip6tables -t nat -I kjxclash_output -p tcp ${output_rule_target_v6_}
               [ -z "${user_rule}" ] && ip6tables -t mangle -I kjxclash -p tcp ${rule_target_v6}
               ip6tables -t mangle -I kjxclash_output -p tcp ${output_rule_target_v6}
               ip6tables -t nat -I kjxclash_post -p tcp ${output_rule_target_v6_}
            fi
            if $e_udp ; then
               [ -z "${user_rule}" ] && ip6tables -t mangle -I kjxclash -p udp ${rule_target_v6}
               ip6tables -t mangle -I kjxclash_output -p udp ${output_rule_target_v6}
               ip6tables -t nat -I kjxclash_post -p udp ${output_rule_target_v6_}
            fi
         fi
      fi
   fi
}

set_firewall()
{

if [ -z "$(uci -q get firewall.openclash_kejibear)" ] || [ -z "$(uci -q get ucitrack.@openclash_kejibear[-1].init)" ]; then
   uci -q delete ucitrack.@openclash_kejibear[-1]
   uci -q add ucitrack openclash_kejibear
   uci -q set ucitrack.@openclash_kejibear[-1].init=openclash-kejibear
   uci -q commit ucitrack
   uci -q delete firewall.openclash_kejibear
   uci -q set firewall.openclash_kejibear=include
   uci -q set firewall.openclash_kejibear.type=script
   uci -q set firewall.openclash_kejibear.path=/var/etc/openclash-kejibear.include
   [ -n "$FW4" ] || uci -q set firewall.openclash_kejibear.reload=1
   uci -q commit firewall
fi

mkdir -p /var/etc
cat > "/var/etc/openclash-kejibear.include" <<-EOF
/etc/init.d/openclash-kejibear reload "firewall"
EOF

#common ports
if [ -n "$common_ports" ] && [ "$common_ports" != "0" ]; then
   if [ "$common_ports" = "1" ]; then
      common_port="21 22 23 53 80 123 143 194 443 465 587 853 993 995 998 2052 2053 2082 2083 2086 2095 2096 2197 5222 5223 5228 5229 5230 8080 8443 8880 8888 8889"
   else
      common_port=$common_ports
   fi
fi

case $enable_redirect_dns in
   "1")
   LOG_TIP "DNS Hijacking Mode is Dnsmasq Redirect..."
   ;;
   "2")
   LOG_TIP "DNS Hijacking Mode is Firewall Redirect..."
   ;;
   *)
   LOG_TIP "DNS Hijacking is Disabled..."
esac

if [ "$ipv6_enable" -eq 1 ]; then
   case $ipv6_mode in
      "1")
      LOG_TIP "IPv6 Proxy Mode is Redirect..."
      ;;
      "2")
      LOG_TIP "IPv6 Proxy Mode is TUN..."
      ;;
      "3")
      LOG_TIP "IPv6 Proxy Mode is Mix..."
      ;;
      *)
      LOG_TIP "IPv6 Proxy Mode is TProxy..."
   esac
fi

#NFTABLES
if [ -n "$FW4" ]; then
   LOG_TIP "Firewall4 was Detected, Use NFTABLE Rules..."

   #china ip route
   if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
      nft 'flush set inet fw4 kjx_cnroute'
      nft -f '/etc/openclash-kejibear/china_ip_route.ipset'
      CHNROUTE_WAIT=0
      while ( [ -z "$(nft list sets |grep "set kjx_cnroute {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] )
      do
         sleep 3
         nft -f '/etc/openclash-kejibear/china_ip_route.ipset'
         let CHNROUTE_WAIT++
      done

      if [ "$enable_redirect_dns" != "2" ]; then
         echo "add set inet fw4 kjx_cnroute_pass { type ipv4_addr; flags interval; auto-merge; }" >/tmp/openclash-kejibear_china_ip_route_pass.list
         [ -z `(awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute_pass.list)` ] || {
            echo "define china_ip_route_pass = {" >>/tmp/openclash-kejibear_china_ip_route_pass.list
            awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s,\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute_pass.list |sed '$ s/.$//' >>/tmp/openclash-kejibear_china_ip_route_pass.list 2>/dev/null
            for ip in $(uci_get_config "china_ip_route_pass"); do
               [ -z "$ip" ] && continue
               echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s,\n",$0)}' |sed '$ s/.$//'
            done >>/tmp/openclash-kejibear_china_ip_route_pass.list 2>/dev/null
            echo "}" >>/tmp/openclash-kejibear_china_ip_route_pass.list
            echo 'add element inet fw4 kjx_cnroute_pass $china_ip_route_pass' >>/tmp/openclash-kejibear_china_ip_route_pass.list
         }
         nft 'flush set inet fw4 kjx_cnroute_pass'
         nft -f '/tmp/openclash-kejibear_china_ip_route_pass.list'
         rm -rf /tmp/openclash-kejibear_china_ip_route_pass.list
      fi
   fi

   #lan_ac
   if [ "$lan_ac_mode" = "0" ]; then
      if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
         nft 'add set inet fw4 kjx_lanb_ips { type ipv4_addr; flags interval; auto-merge; }'
         nft 'add set inet fw4 kjx_lanb_ipv6s { type ipv6_addr; flags interval; auto-merge; }'
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_black_ips" nft_ac_add "kjx_lanb_ips" "kjx_lanb_ipv6s"
      fi
      if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
         nft 'add set inet fw4 kjx_lanb_macs { type ether_addr; }'
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_black_macs" nft_ac_add "kjx_lanb_macs"
      fi
   elif [ "$lan_ac_mode" = "1" ]; then
      if [ -n "$(uci_get_config "lan_ac_white_ips")" ]; then
         nft 'add set inet fw4 kjx_lanw_ips { type ipv4_addr; flags interval; auto-merge; }'
         nft 'add set inet fw4 kjx_lanw_ipv6s { type ipv6_addr; flags interval; auto-merge; }'
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_white_ips" nft_ac_add "kjx_lanw_ips" "kjx_lanw_ipv6s"
      fi
      if [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         nft 'add set inet fw4 kjx_lanw_macs { type ether_addr; }'
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_white_macs" nft_ac_add "kjx_lanw_macs"
      fi
   fi

   #wan ac
   if [ -n "$(uci_get_config "wan_ac_black_ips")" ]; then
      nft 'add set inet fw4 kjx_wanb_ips { type ipv4_addr; flags interval; auto-merge; }'
      nft 'add set inet fw4 kjx_wanb_ipv6s { type ipv6_addr; flags interval; auto-merge; }'
      config_load "openclash_kejibear"
      config_list_foreach "config" "wan_ac_black_ips" nft_ac_add "kjx_wanb_ips" "kjx_wanb_ipv6s"
   fi

   if [ -n "$(uci_get_config "wan_ac_black_ports")" ]; then
      nft 'add set inet fw4 kjx_wanb_ports { type inet_service; flags interval; }'
      config_load "openclash_kejibear"
      config_list_foreach "config" "wan_ac_black_ports" nft_ac_add "kjx_wanb_ports"
   fi

   #local
   nft 'add set inet fw4 kjx_localnet { type ipv4_addr; flags interval; auto-merge; }'
   #nft 'delete set inet fw4 kjx_localnet'
   if [ -f "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv4.list" ]; then
      for line in `cat "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv4.list"`
      do
         nft add element inet fw4 kjx_localnet { "$line" }
      done
   else
      nft 'add element inet fw4 kjx_localnet { 0.0.0.0/8, 127.0.0.0/8, 10.0.0.0/8, 169.254.0.0/16, 192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4, 172.16.0.0/12, 100.64.0.0/10}'
   fi

   if [ -n "$wan_ip4s" ]; then
      for wan_ip4 in $wan_ip4s; do
         nft add element inet fw4 kjx_localnet { "$wan_ip4" }
      done
   fi

   #common ports
   if [ -n "$common_ports" ] && [ "$common_ports" != "0" ]; then
      nft 'add set inet fw4 kjx_cports { type inet_service; flags interval; }'
      for i in $common_port; do
         nft add element inet fw4 kjx_cports { "$i" }
      done
   fi

   #bypass gateway compatible
   if [ "$bypass_gateway_compatible" -eq 1 ]; then
      #nft 'delete chain inet fw4 kjxclash_post'
      nft 'add chain inet fw4 kjxclash_post'
      nft 'flush chain inet fw4 kjxclash_post'
      nft 'add rule inet fw4 kjxclash_post skgid == 65534 counter return'
      nft add rule inet fw4 kjxclash_post mark "$PROXY_FWMARK" counter accept
      nft 'add rule inet fw4 kjxclash_post ip daddr @kjx_localnet counter return'
      nft 'add rule inet fw4 kjxclash_post ct direction reply counter return'
      nft 'add rule inet fw4 kjxclash_post fib saddr type != { local } counter masquerade'
      nft add rule inet fw4 srcnat meta nfproto {ipv4} counter jump kjxclash_post comment \"Kejibear Bypass Gateway Compatible\"
   fi

   #intranet allowed
   if [ "$intranet_allowed" -eq 1 ]; then
      if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then
         config_load "openclash_kejibear"
         config_list_foreach "config" "intranet_allowed_wan_name" wan_name_add
      else
         wan_ints=$(nft list chain inet fw4 input |grep -e "jump input_wan" 2>/dev/null |awk '{for (i=1;i<=NF;i++){if ($i ~ /iifname/ && $(i+1) != "{") {print $(i+1)} if ($i ~ /iifname/ && $(i+1) == "{"){for (j=i+1;j<=NF;j++){if ($j~ /}/) {out="";for (k=i+1;k<=j;k++){out=out" "$k};print out}}}}}' 2>/dev/null |sed 's/"//g'|sed 's/{//g'|sed 's/}//g'|sed 's/,//g')
      fi
      if [ -n "$wan_ints" ]; then
         nft 'add chain inet fw4 kjxclash_wan_input'
         nft 'flush chain inet fw4 kjxclash_wan_input'
         for wan_int in $wan_ints; do
            #nft delete rule inet fw4 input $(nft -a list chain inet fw4 input |grep "@kjx_localnet" |awk -F '# ' '{print$2}')
            nft insert rule inet fw4 input position 0 iifname "$wan_int" ip saddr != @kjx_localnet counter jump kjxclash_wan_input
         done
         nft add rule inet fw4 kjxclash_wan_input th dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject
      else
         LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv4 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..."
      fi
   fi

   DNSPORT=$(uci -q get dhcp.@dnsmasq[0].port)
   if [ -z "$DNSPORT" ]; then
      DNSPORT=$(netstat -nlp |grep -E '127.0.0.1:.*dnsmasq' |awk -F '127.0.0.1:' '{print $2}' |awk '{print $1}' |head -1 || echo 53)
   fi

   if [ "$enable_redirect_dns" -eq 1 ]; then
      if ! fw4_has_dns_hijack_rule dstnat ipv4; then
         if [ "$lan_ac_mode" != "1" ]; then
            ACBLACKDNSFILTER=""
            if [ "$lan_ac_mode" = "0" ]; then
               if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                  ACBLACKDNSFILTER="ip saddr != @kjx_lanb_ips"
               fi
               if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                  ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @kjx_lanb_macs"
               fi
            fi
            nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
         else
            nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip saddr @kjx_lanw_ips counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
            nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ether saddr @kjx_lanw_macs counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
         fi
      fi
      if [ "$router_self_proxy" = 1 ]; then
         nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
         nft insert rule inet fw4 nat_output position 0 skgid != 65534 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip daddr {127.0.0.1} counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
      fi
   elif [ "$enable_redirect_dns" -eq 2 ]; then
      nft 'add chain inet fw4 kjxclash_dns_redirect'
      nft 'flush chain inet fw4 kjxclash_dns_redirect'
      if [ "$lan_ac_mode" != "1" ]; then
         ACBLACKDNSFILTER=""
         if [ "$lan_ac_mode" = "0" ]; then
            if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
               ACBLACKDNSFILTER="ip saddr != @kjx_lanb_ips"
            fi
            if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
               ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @kjx_lanb_macs"
            fi
         fi
         nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
      else
         nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip saddr @kjx_lanw_ips counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
         nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ether saddr @kjx_lanw_macs counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
      fi
      nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 counter jump kjxclash_dns_redirect'
      if [ "$router_self_proxy" = 1 ]; then
         nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
         nft insert rule inet fw4 nat_output position 0 meta nfproto {ipv4} meta l4proto {tcp,udp} th dport 53 ip daddr {127.0.0.1} meta skgid != 65534 counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
      fi
   fi

   if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
      #tcp
      nft 'add chain inet fw4 kjxclash'
      nft 'flush chain inet fw4 kjxclash'
      nft 'add rule inet fw4 kjxclash ip daddr @kjx_localnet counter return'
      nft 'add rule inet fw4 kjxclash ct direction reply counter return'
      if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         nft 'add rule inet fw4 kjxclash ether saddr != @kjx_lanw_macs ip saddr != @kjx_lanw_ips counter return'
      else
         nft 'add rule inet fw4 kjxclash ether saddr != @kjx_lanw_macs counter return'
         nft 'add rule inet fw4 kjxclash ip saddr != @kjx_lanw_ips counter return'
      fi
      nft 'add rule inet fw4 kjxclash ip saddr @kjx_lanb_ips counter return'
      nft 'add rule inet fw4 kjxclash ether saddr @kjx_lanb_macs counter return'
      nft add rule inet fw4 kjxclash ip protocol tcp ip daddr { "$fakeip_range" } counter redirect to "$proxy_port"
      nft 'add rule inet fw4 kjxclash ip daddr @kjx_wanb_ips counter return'
      nft 'add rule inet fw4 kjxclash th dport @kjx_wanb_ports counter return'

      if [ "$en_mode" = "redir-host" ]; then
         nft 'add rule inet fw4 kjxclash th dport != @kjx_cports counter return'
      fi
      if [ "$china_ip_route" != "0" ]; then
         if [ "$china_ip_route" = "1" ]; then
            rule="ip daddr @kjx_cnroute"
         elif [ "$china_ip_route" = "2" ]; then
            rule="ip daddr != @kjx_cnroute"
         fi
         [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
         nft "add rule inet fw4 kjxclash $rule counter return"
      fi

      nft add rule inet fw4 kjxclash ip protocol tcp counter redirect to "$proxy_port"
      nft 'add rule inet fw4 dstnat meta nfproto {ipv4} ip protocol tcp counter jump kjxclash'

      # Accept redirected traffic in input chain (needed when zone input policy is REJECT without DNAT rules)
      if [ -z "$(nft list chain inet fw4 input 2>/dev/null | grep 'ct status dnat accept')" ]; then
         nft insert rule inet fw4 input position 0 ct status dnat accept comment \"Kejibear Redirect Accept\"
      fi

      if [ -z "$en_mode_tun" ]; then
         #udp
         if [ "$enable_udp_proxy" -eq 1 ]; then
            check_mod "nft_tproxy"
            ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
            nft 'add chain inet fw4 kjxclash_mangle'
            nft 'flush chain inet fw4 kjxclash_mangle'
            nft 'add chain inet fw4 kjxclash_upnp'
            nft 'flush chain inet fw4 kjxclash_upnp'
            upnp_exclude
            nft 'add rule inet fw4 kjxclash_mangle ip daddr @kjx_localnet counter return'
            nft 'add rule inet fw4 kjxclash_mangle ct direction reply counter return'
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 kjxclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept
            fi
            nft 'add rule inet fw4 kjxclash_mangle ip daddr @kjx_wanb_ips counter return'
            nft 'add rule inet fw4 kjxclash_mangle th dport @kjx_wanb_ports counter return'
            nft 'add rule inet fw4 kjxclash_mangle ip saddr @kjx_lanb_ips counter return'
            nft 'add rule inet fw4 kjxclash_mangle ether saddr @kjx_lanb_macs counter return'
            if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
               nft 'add rule inet fw4 kjxclash_mangle ether saddr != @kjx_lanw_macs ip saddr != @kjx_lanw_ips counter return'
            else
               nft 'add rule inet fw4 kjxclash_mangle ether saddr != @kjx_lanw_macs counter return'
               nft 'add rule inet fw4 kjxclash_mangle ip saddr != @kjx_lanw_ips counter return'
            fi

            if [ "$en_mode" = "redir-host" ]; then
               nft 'add rule inet fw4 kjxclash_mangle th dport != @kjx_cports counter return'
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="ip daddr @kjx_cnroute"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="ip daddr != @kjx_cnroute"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
               nft "add rule inet fw4 kjxclash_mangle $rule counter return"
            fi

            nft 'add rule inet fw4 kjxclash_mangle ip protocol udp counter jump kjxclash_upnp'
            nft add rule inet fw4 kjxclash_mangle meta l4proto { udp } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept
            nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} ip protocol udp counter jump kjxclash_mangle'
         fi
         if [ "$enable_udp_proxy" -ne 1 ] && [ "$en_mode" = "fake-ip" ]; then
            check_mod "nft_tproxy"
            ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
            nft 'add chain inet fw4 kjxclash_mangle'
            nft 'flush chain inet fw4 kjxclash_mangle'
            nft add rule inet fw4 kjxclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" tproxy ip to 127.0.0.1:"$tproxy_port" counter accept
            nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} ip protocol udp counter jump kjxclash_mangle'
         fi

         #router self proxy udp
         if ([ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]) || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
            nft 'add chain inet fw4 kjxclash_mangle_output'
            nft 'flush chain inet fw4 kjxclash_mangle_output'
            nft 'add rule inet fw4 kjxclash_mangle_output skgid == 65534 counter return'
            nft 'add rule inet fw4 kjxclash_mangle_output ip daddr @kjx_localnet counter return'
            nft 'add rule inet fw4 kjxclash_mangle_output ct direction reply counter return'
            nft 'add rule inet fw4 kjxclash_mangle_output ip daddr @kjx_wanb_ips counter return'
            nft 'add rule inet fw4 kjxclash_mangle_output th dport @kjx_wanb_ports counter return'
            if [ "$en_mode" = "redir-host" ]; then
               nft add rule inet fw4 kjxclash_mangle_output th dport != @kjx_cports counter return
            fi
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 kjxclash_mangle_output meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter accept
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="ip daddr @kjx_cnroute"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="ip daddr != @kjx_cnroute"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
               nft "add rule inet fw4 kjxclash_mangle_output $rule counter return"
            fi
            if [ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]; then
               nft add rule inet fw4 kjxclash_mangle_output mark set "$PROXY_FWMARK" counter accept
            fi
            nft 'add rule inet fw4 mangle_output meta nfproto {ipv4} ip protocol udp counter jump kjxclash_mangle_output'
         fi

         # Accept TPROXY traffic in input chain (needed when zone input policy is REJECT)
         if [ -z "$(nft list chain inet fw4 input 2>/dev/null | grep 'Kejibear TPROXY Accept')" ]; then
            nft insert rule inet fw4 input position 0 meta mark "$PROXY_FWMARK" accept comment \"Kejibear TPROXY Accept\"
         fi

         #quic
         if [ "$disable_udp_quic" -eq 1 ]; then
            if [ "$china_ip_route" = "2" ]; then
               nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
               nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
            else
               nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
               nft insert rule inet fw4 forward position 0 udp dport 443 ip daddr != @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
            fi
         fi
      fi

      #router self proxy tcp
      if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
         nft 'add chain inet fw4 kjxclash_output'
         nft 'flush chain inet fw4 kjxclash_output'
         nft 'add rule inet fw4 kjxclash_output skgid == 65534 counter return'
         nft 'add rule inet fw4 kjxclash_output ip daddr @kjx_localnet counter return'
         nft 'add rule inet fw4 kjxclash_output ct direction reply counter return'
         if [ "$en_mode" = "fake-ip" ] && [ "$en_mode_tun" != "1" ]; then
            nft add rule inet fw4 kjxclash_output ip protocol tcp ip daddr { "$fakeip_range" } counter redirect to "$proxy_port"
         fi
         if [ "$router_self_proxy" = "1" ]; then
            nft 'add rule inet fw4 kjxclash_output ip daddr @kjx_wanb_ips counter return'
            nft 'add rule inet fw4 kjxclash_output th dport @kjx_wanb_ports counter return'
            if [ "$en_mode" = "redir-host" ]; then
               nft add rule inet fw4 kjxclash_output th dport != @kjx_cports counter return
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="ip daddr @kjx_cnroute"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="ip daddr != @kjx_cnroute"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
               nft "add rule inet fw4 kjxclash_output $rule counter return"
            fi
            nft add rule inet fw4 kjxclash_output ip protocol tcp counter redirect to "$proxy_port"
         fi
         nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
         nft 'add rule inet fw4 nat_output meta nfproto {ipv4} ip protocol tcp counter jump kjxclash_output'
      fi
   fi

   if [ -n "$en_mode_tun" ]; then
      #TUN模式
      #设置防火墙
      #router self proxy
      if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
         nft 'add chain inet fw4 kjxclash_mangle_output'
         nft 'flush chain inet fw4 kjxclash_mangle_output'
         nft 'add rule inet fw4 kjxclash_mangle_output skgid == 65534 counter return'
         nft 'add rule inet fw4 kjxclash_mangle_output ip daddr @kjx_localnet counter return'
         nft 'add rule inet fw4 kjxclash_mangle_output ct direction reply counter return'
         if [ "$en_mode_tun" -eq 1 ]; then
            nft add rule inet fw4 kjxclash_mangle_output meta l4proto {tcp,udp} ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter
         else
            nft add rule inet fw4 kjxclash_mangle_output meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter
         fi
         if [ "$en_mode" = "redir-host" ]; then
            nft 'add rule inet fw4 kjxclash_mangle_output th dport != @kjx_cports counter return'
         fi
         if [ "$router_self_proxy" = "1" ]; then
            nft 'add rule inet fw4 kjxclash_mangle_output ip daddr @kjx_wanb_ips counter return'
            nft 'add rule inet fw4 kjxclash_mangle_output th dport @kjx_wanb_ports counter return'
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="ip daddr @kjx_cnroute"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="ip daddr != @kjx_cnroute"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
               nft "add rule inet fw4 kjxclash_mangle_output $rule counter return"
            fi

            #icmp
            nft add rule inet fw4  kjxclash_mangle_output meta nfproto {ipv4} ip protocol icmp icmp type echo-request mark set "$PROXY_FWMARK" counter accept comment \"Kejibear ICMP Mark\"

            if [ "$en_mode_tun" -eq 1 ]; then
               nft add rule inet fw4 kjxclash_mangle_output meta l4proto {tcp,udp} meta mark set "$PROXY_FWMARK" counter
            else
               nft add rule inet fw4 kjxclash_mangle_output meta l4proto { udp } meta mark set "$PROXY_FWMARK" counter
            fi
         fi
         nft 'add rule inet fw4 mangle_output meta nfproto {ipv4} counter jump kjxclash_mangle_output'
      fi

      nft 'add chain inet fw4 kjxclash_mangle'
      nft 'flush chain inet fw4 kjxclash_mangle'
      nft 'add chain inet fw4 kjxclash_upnp'
      nft 'flush chain inet fw4 kjxclash_upnp'
      upnp_exclude

      #其他流量
      nft 'add rule inet fw4 kjxclash_mangle meta l4proto {tcp,udp} iifname kjxtun counter return'
      nft 'add rule inet fw4 kjxclash_mangle ip daddr @kjx_localnet counter return'
      nft 'add rule inet fw4 kjxclash_mangle ct direction reply counter return'
      if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         nft 'add rule inet fw4 kjxclash_mangle ether saddr != @kjx_lanw_macs ip saddr != @kjx_lanw_ips counter return'
      else
         nft 'add rule inet fw4 kjxclash_mangle ether saddr != @kjx_lanw_macs counter return'
         nft 'add rule inet fw4 kjxclash_mangle ip saddr != @kjx_lanw_ips counter return'
      fi
      nft 'add rule inet fw4 kjxclash_mangle ip saddr @kjx_lanb_ips counter return'
      nft 'add rule inet fw4 kjxclash_mangle ether saddr @kjx_lanb_macs counter return'
      if [ "$en_mode_tun" -eq 1 ]; then
         nft add rule inet fw4 kjxclash_mangle meta l4proto {tcp,udp} ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter
      else
         nft add rule inet fw4 kjxclash_mangle meta l4proto { udp } ip daddr { "$fakeip_range" } mark set "$PROXY_FWMARK" counter
      fi
      nft 'add rule inet fw4 kjxclash_mangle ip daddr @kjx_wanb_ips counter return'
      nft 'add rule inet fw4 kjxclash_mangle th dport @kjx_wanb_ports counter return'

      if [ "$en_mode" = "redir-host" ]; then
         nft 'add rule inet fw4 kjxclash_mangle th dport != @kjx_cports counter return'
      fi
      if [ "$china_ip_route" != "0" ]; then
         if [ "$china_ip_route" = "1" ]; then
            rule="ip daddr @kjx_cnroute"
         elif [ "$china_ip_route" = "2" ]; then
            rule="ip daddr != @kjx_cnroute"
         fi
         [ "$enable_redirect_dns" != "2" ] && rule="$rule ip daddr != @kjx_cnroute_pass"
         nft "add rule inet fw4 kjxclash_mangle $rule counter return"
      fi

      #icmp
      nft add rule inet fw4 kjxclash_mangle meta nfproto {ipv4} ip protocol icmp icmp type echo-request mark set "$PROXY_FWMARK" counter accept comment \"Kejibear ICMP Mark\"

      nft 'add rule inet fw4 kjxclash_mangle ip protocol udp counter jump kjxclash_upnp'

      if [ "$en_mode_tun" -eq 1 ]; then
         nft add rule inet fw4 kjxclash_mangle mark set "$PROXY_FWMARK" counter
      else
         nft add rule inet fw4 kjxclash_mangle meta l4proto { udp } mark set "$PROXY_FWMARK" counter
      fi

      nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv4} counter jump kjxclash_mangle'

      #TUN FORWORD
      nft insert rule inet fw4 forward position 0 meta nfproto {ipv4} oifname kjxtun counter accept comment \"Kejibear TUN Forward\"
      nft insert rule inet fw4 forward position 0 meta nfproto {ipv4} iifname kjxtun counter accept comment \"Kejibear TUN Forward\"
      nft insert rule inet fw4 input position 0 meta nfproto {ipv4} iifname kjxtun counter accept comment \"Kejibear TUN Input\"
      nft insert rule inet fw4 srcnat position 0 meta nfproto {ipv4} oifname kjxtun counter return comment \"Kejibear TUN Postrouting\"

      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         if [ "$china_ip_route" = "2" ]; then
            nft insert rule inet fw4 input position 0 udp dport 443 ip daddr @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
            nft insert rule inet fw4 forward position 0 oifname kjxtun udp dport 443 ip daddr @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
         else
            nft insert rule inet fw4 input position 0 udp dport 443 ip daddr != @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
            nft insert rule inet fw4 forward position 0 oifname kjxtun udp dport 443 ip daddr != @kjx_cnroute counter reject comment \"Kejibear QUIC REJECT\"
         fi
      fi
   fi

   #ipv6
   if [ "$ipv6_enable" -eq 1 ]; then
      #china ip route
      if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
         nft 'flush set inet fw4 kjx_cnroute6'
         nft -f '/etc/openclash-kejibear/china_ip6_route.ipset'
         CHNROUTE_WAIT=0
         while ( [ -z "$(nft list sets |grep "set kjx_cnroute6 {")" ] && [ "$CHNROUTE_WAIT" -le 3 ] )
         do
            sleep 3
            nft -f '/etc/openclash-kejibear/china_ip6_route.ipset'
            let CHNROUTE_WAIT++
         done

         if [ "$enable_redirect_dns" != "2" ]; then
            echo "add set inet fw4 kjx_cnroute6_pass { type ipv6_addr; flags interval; auto-merge; }" >/tmp/openclash-kejibear_china_ip6_route_pass.list
            [ -z `(awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s,\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute6_pass.list)` ] || {
               echo "define china_ip6_route_pass = {" >>/tmp/openclash-kejibear_china_ip6_route_pass.list
               awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s,\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute6_pass.list |sed '$ s/.$//' >>/tmp/openclash-kejibear_china_ip6_route_pass.list 2>/dev/null
               for ip in $(uci_get_config "china_ip6_route_pass"); do
                  [ -z "$ip" ] && continue
                  echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("    %s,\n",$0)}' |sed '$ s/.$//'
               done >>/tmp/openclash-kejibear_china_ip6_route_pass.list 2>/dev/null
               echo "}" >>/tmp/openclash-kejibear_china_ip6_route_pass.list
               echo 'add element inet fw4 kjx_cnroute6_pass $china_ip6_route_pass' >>/tmp/openclash-kejibear_china_ip6_route_pass.list
            }
            nft 'flush set inet fw4 kjx_cnroute6_pass'
            nft -f '/tmp/openclash-kejibear_china_ip6_route_pass.list'
            rm -rf /tmp/openclash-kejibear_china_ip6_route_pass.list
         fi
      fi

      if ! fw4_has_dns_hijack_rule dstnat ipv6; then
         if [ "$enable_redirect_dns" -eq 1 ]; then
            if [ "$lan_ac_mode" != "1" ]; then
               ACBLACKDNSFILTER=""
               if [ "$lan_ac_mode" = "0" ]; then
                  if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                     ACBLACKDNSFILTER="ip6 saddr != @kjx_lanb_ipv6s"
                  fi
                  if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                     ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @kjx_lanb_macs"
                  fi
               fi
               nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
            else
               nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 saddr @kjx_lanw_ipv6s counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
               nft insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ether saddr @kjx_lanw_macs counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
            fi
            if [ "$router_self_proxy" = 1 ]; then
               nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
               nft insert rule inet fw4 nat_output position 0 skgid != 65534 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 daddr {::1} counter redirect to "$DNSPORT" comment \"Kejibear DNS Hijack\"
            fi
         elif [ "$enable_redirect_dns" -eq 2 ]; then
            if [ "$lan_ac_mode" != "1" ]; then
               ACBLACKDNSFILTER=""
               if [ "$lan_ac_mode" = "0" ]; then
                  if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                     ACBLACKDNSFILTER="ip6 saddr != @kjx_lanb_ipv6s"
                  fi
                  if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                     ACBLACKDNSFILTER="$ACBLACKDNSFILTER ether saddr != @kjx_lanb_macs"
                  fi
               fi
               nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ${ACBLACKDNSFILTER} counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
            else
               nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 saddr @kjx_lanw_ipv6s counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
               nft add rule inet fw4 kjxclash_dns_redirect meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ether saddr @kjx_lanw_macs counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
            fi
            nft 'insert rule inet fw4 dstnat position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 counter jump kjxclash_dns_redirect'
            if [ "$router_self_proxy" = 1 ]; then
               nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
               nft insert rule inet fw4 nat_output position 0 meta nfproto {ipv6} ip6 nexthdr {tcp,udp} th dport 53 ip6 daddr {::1} meta skgid != 65534 counter redirect to "$dns_port" comment \"Kejibear DNS Hijack\"
            fi
         fi
      fi

      #local
      nft 'add set inet fw4 kjx_localnet6 { type ipv6_addr; flags interval; auto-merge; }'
      #nft 'delete set inet fw4 kjx_localnet6'
      if [ -f "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv6.list" ]; then
         for line in `cat "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv6.list"`
         do
            nft add element inet fw4 kjx_localnet6 { "$line" }
         done
      else
         nft 'add element inet fw4 kjx_localnet6 { ::/128, ::1/128, ::ffff:0:0/96, ::ffff:0:0:0/96, 64:ff9b::/96, 100::/64, 2001::/32, 2001:20::/28, 2001:db8::/32, 2002::/16, fe80::/10, ff00::/8}'
      fi

      if [ -n "$wan_ip6s" ]; then
         for wan_ip6 in $wan_ip6s; do
            nft add element inet fw4 kjx_localnet6 { "$wan_ip6" }
         done
      fi

      if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then
         #tcp
         nft 'add chain inet fw4 kjxclash_v6'
         nft 'flush chain inet fw4 kjxclash_v6'
         nft 'add rule inet fw4 kjxclash_v6 ip6 daddr @kjx_localnet6 counter return'
         nft 'add rule inet fw4 kjxclash_v6 ct direction reply counter return'
         if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
            nft 'add rule inet fw4 kjxclash_v6 ether saddr != @kjx_lanw_macs ip6 saddr != @kjx_lanw_ipv6s counter return'
         else
            nft 'add rule inet fw4 kjxclash_v6 ether saddr != @kjx_lanw_macs counter return'
            nft 'add rule inet fw4 kjxclash_v6 ip6 saddr != @kjx_lanw_ipv6s counter return'
         fi
         nft 'add rule inet fw4 kjxclash_v6 ip6 saddr @kjx_lanb_ipv6s counter return'
         nft 'add rule inet fw4 kjxclash_v6 ether saddr @kjx_lanb_macs counter return'
         nft add rule inet fw4 kjxclash_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } counter redirect to "$proxy_port"
         nft 'add rule inet fw4 kjxclash_v6 ip6 daddr @kjx_wanb_ipv6s counter return'
         nft 'add rule inet fw4 kjxclash_v6 th dport @kjx_wanb_ports counter return'

         if [ "$en_mode" = "redir-host" ]; then
            nft 'add rule inet fw4 kjxclash_v6 th dport != @kjx_cports counter return'
         fi

         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="ip6 daddr @kjx_cnroute6"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="ip6 daddr != @kjx_cnroute6"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @kjx_cnroute6_pass"
            nft "add rule inet fw4 kjxclash_v6 $rule counter return"
         fi
         nft add rule inet fw4 kjxclash_v6 ip6 nexthdr {tcp} counter redirect to "$proxy_port"
         nft 'add rule inet fw4 dstnat ip6 nexthdr {tcp} counter jump kjxclash_v6'
      fi

      #TProxy & TUN & Redirect udp
      if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -ne 1 ]; then
         nft 'add chain inet fw4 kjxclash_mangle_v6'
         nft 'flush chain inet fw4 kjxclash_mangle_v6'
         nft 'add rule inet fw4 kjxclash_mangle_v6 ip6 daddr @kjx_localnet6 counter return'
         nft 'add rule inet fw4 kjxclash_mangle_v6 ct direction reply counter return'
         if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
            nft 'add rule inet fw4 kjxclash_mangle_v6 ether saddr != @kjx_lanw_macs ip6 saddr != @kjx_lanw_ipv6s counter return'
         else
            nft 'add rule inet fw4 kjxclash_mangle_v6 ether saddr != @kjx_lanw_macs counter return'
            nft 'add rule inet fw4 kjxclash_mangle_v6 ip6 saddr != @kjx_lanw_ipv6s counter return'
         fi
         nft 'add rule inet fw4 kjxclash_mangle_v6 ip6 saddr @kjx_lanb_ipv6s counter return'
         nft 'add rule inet fw4 kjxclash_mangle_v6 ether saddr @kjx_lanb_macs counter return'
         if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then
            if [ "$ipv6_mode" -eq 0 ]; then
               nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept
            else
               nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter
            fi
         fi

         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter
         else
            if [ "$enable_v6_udp_proxy" -eq 1 ]; then
               nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept
            fi
         fi
         nft 'add rule inet fw4 kjxclash_mangle_v6 ip6 daddr @kjx_wanb_ipv6s counter return'
         nft 'add rule inet fw4 kjxclash_mangle_v6 th dport @kjx_wanb_ports counter return'
         if [ "$en_mode" == "redir-host" ]; then
            nft 'add rule inet fw4 kjxclash_mangle_v6 th dport != @kjx_cports counter return'
         fi

         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="ip6 daddr @kjx_cnroute6"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="ip6 daddr != @kjx_cnroute6"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @kjx_cnroute6_pass"
            nft "add rule inet fw4 kjxclash_mangle_v6 $rule counter return"
         fi

         #icmpv6
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            nft add rule inet fw4 kjxclash_mangle_v6 meta nfproto {ipv6} ip6 nexthdr icmpv6 icmpv6 type echo-request mark set "$PROXY_FWMARK" counter accept comment \"Kejibear ICMPv6 Redirect\"
         fi
      fi

      #tcp Tproxy && TUN
      if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then
         if [ "$ipv6_mode" -eq 0 ]; then
            nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"Kejibear TCP Tproxy\"
         else
            nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" counter
         fi
      fi

      #udp
      if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
         nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" counter
      else
         if [ "$enable_v6_udp_proxy" -eq 1 ]; then
            nft add rule inet fw4 kjxclash_mangle_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" tproxy ip6 to :"$tproxy_port" counter accept comment \"Kejibear UDP Tproxy\"
         fi
      fi

      nft 'add rule inet fw4 mangle_prerouting meta nfproto {ipv6} counter jump kjxclash_mangle_v6'

      #router self proxy
      if [ "$router_self_proxy" = "1" ]; then
         if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then
            #tcp Redirect Mode
            nft 'add chain inet fw4 kjxclash_output_v6'
            nft 'flush chain inet fw4 kjxclash_output_v6'
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 kjxclash_output ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } counter redirect to "$proxy_port"
            fi
            nft 'add rule inet fw4 kjxclash_output_v6 skgid == 65534 counter return'
            nft 'add rule inet fw4 kjxclash_output_v6 ip6 daddr @kjx_localnet6 counter return'
            nft 'add rule inet fw4 kjxclash_output_v6 ct direction reply counter return'
            nft 'add rule inet fw4 kjxclash_output_v6 ip6 daddr @kjx_wanb_ipv6s counter return'
            nft 'add rule inet fw4 kjxclash_output_v6 th dport @kjx_wanb_ports counter return'
            if [ "$en_mode" = "redir-host" ]; then
               nft 'add rule inet fw4 kjxclash_output_v6 th dport != @kjx_cports counter return'
            fi

            if [ "$china_ip6_route" != "0" ]; then
               if [ "$china_ip6_route" = "1" ]; then
                  rule="ip6 daddr @kjx_cnroute6"
               elif [ "$china_ip6_route" = "2" ]; then
                  rule="ip6 daddr != @kjx_cnroute6"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @kjx_cnroute6_pass"
               nft "add rule inet fw4 kjxclash_output_v6 $rule counter return"
            fi

            nft add rule inet fw4 kjxclash_output_v6 ip6 nexthdr {tcp} counter redirect to "$proxy_port"
            nft 'add chain inet fw4 nat_output { type nat hook output priority -1; }'
            nft 'add rule inet fw4 nat_output meta nfproto {ipv6} counter jump kjxclash_output_v6'
         fi

         #other mode and Redirect Mode udp
         nft 'add chain inet fw4 kjxclash_mangle_output_v6'
         nft 'flush chain inet fw4 kjxclash_mangle_output_v6'
         nft 'add rule inet fw4 kjxclash_mangle_output_v6 skgid == 65534 counter return'
         nft 'add rule inet fw4 kjxclash_mangle_output_v6 ip6 daddr @kjx_localnet6 counter return'
         nft 'add rule inet fw4 kjxclash_mangle_output_v6 ct direction reply counter return'
         if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then
            nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter
         fi
         if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {tcp,udp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter
            fi
         fi
         if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then
            if [ "$en_mode" = "fake-ip" ]; then
               nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {tcp} ip6 daddr { "$fakeip_range6" } mark set "$PROXY_FWMARK" counter
            fi
         fi
         nft 'add rule inet fw4 kjxclash_mangle_output_v6 ip6 daddr @kjx_wanb_ipv6s counter return'
         nft 'add rule inet fw4 kjxclash_mangle_output_v6 th dport @kjx_wanb_ports counter return'
         if [ "$en_mode" = "redir-host" ]; then
            nft 'add rule inet fw4 kjxclash_mangle_output_v6 th dport != @kjx_cports counter return'
         fi

         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="ip6 daddr @kjx_cnroute6"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="ip6 daddr != @kjx_cnroute6"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule ip6 daddr != @kjx_cnroute6_pass"
            nft "add rule inet fw4 kjxclash_mangle_output_v6 $rule counter return"
         fi

         #icmpv6
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            nft add rule inet fw4 kjxclash_mangle_output_v6 meta nfproto {ipv6} ip6 nexthdr icmpv6 icmpv6 type echo-request mark set "$PROXY_FWMARK" counter accept comment \"Kejibear ICMPv6 Redirect\"
         fi

         if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then
            nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {udp} mark set "$PROXY_FWMARK" counter
         fi
         if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then
            nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {tcp,udp} mark set "$PROXY_FWMARK" counter
         fi
         if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then
            nft add rule inet fw4 kjxclash_mangle_output_v6 ip6 nexthdr {tcp} mark set "$PROXY_FWMARK" counter
         fi
         nft 'add rule inet fw4 mangle_output meta nfproto {ipv6} counter jump kjxclash_mangle_output_v6'
      fi

      #route
      if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
         if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -eq 0 ]; then
            check_mod "nft_tproxy"
            ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE"
         fi
      fi

      #TUN FORWORD
      if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
         nft insert rule inet fw4 forward position 0 meta nfproto {ipv6} oifname kjxtun counter accept comment \"Kejibear TUN Forward\"
         nft insert rule inet fw4 forward position 0 meta nfproto {ipv6} iifname kjxtun counter accept comment \"Kejibear TUN Forward\"
         nft insert rule inet fw4 input position 0 meta nfproto {ipv6} iifname kjxtun counter accept comment \"Kejibear TUN Input\"
         nft insert rule inet fw4 srcnat position 0 meta nfproto {ipv6} oifname kjxtun counter return comment \"Kejibear TUN Postrouting\"
      fi

      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         if [ "$china_ip6_route" = "2" ]; then
            rule="ip6 daddr @kjx_cnroute6"
         else
            rule="ip6 daddr != @kjx_cnroute6"
         fi
         nft insert rule inet fw4 input position 0 udp dport 443 $rule counter reject comment \"Kejibear QUIC REJECT\"
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            nft insert rule inet fw4 forward position 0 oifname kjxtun udp dport 443 $rule counter reject comment \"Kejibear QUIC REJECT\"
         else
            nft insert rule inet fw4 forward position 0 udp dport 443 $rule counter reject comment \"Kejibear QUIC REJECT\"
         fi
      fi

      #bypass gateway compatible
      if [ "$bypass_gateway_compatible" -eq 1 ]; then
         #nft 'delete chain inet fw4 kjxclash_post_v6'
         nft 'add chain inet fw4 kjxclash_post_v6'
         nft 'flush chain inet fw4 kjxclash_post_v6'
         nft 'add rule inet fw4 kjxclash_post_v6 skgid == 65534 counter return'
         nft add rule inet fw4 kjxclash_post_v6 mark "$PROXY_FWMARK" counter accept
         nft 'add rule inet fw4 kjxclash_post_v6 ip6 daddr @kjx_localnet6 counter return'
         nft 'add rule inet fw4 kjxclash_post_v6 ct direction reply counter return'
         nft 'add rule inet fw4 kjxclash_post_v6 fib saddr type != { local } counter masquerade'
         nft add rule inet fw4 srcnat meta nfproto {ipv6} counter jump kjxclash_post_v6 comment \"Kejibear Bypass Gateway Compatible\"
      fi

      #intranet allowed
      if [ "$intranet_allowed" -eq 1 ]; then
         if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then
            config_load "openclash_kejibear"
            config_list_foreach "config" "intranet_allowed_wan_name" wan6_name_add
         else
            wan6_ints=$(nft list chain inet fw4 input |grep -e "jump input_wan" 2>/dev/null |awk '{for (i=1;i<=NF;i++){if ($i ~ /iifname/ && $(i+1) != "{") {print $(i+1)} if ($i ~ /iifname/ && $(i+1) == "{"){for (j=i+1;j<=NF;j++){if ($j~ /}/) {out="";for (k=i+1;k<=j;k++){out=out" "$k};print out}}}}}' 2>/dev/null |sed 's/"//g'|sed 's/{//g'|sed 's/}//g'|sed 's/,//g')
         fi
         if [ -n "$wan6_ints" ]; then
            nft 'add chain inet fw4 kjxclash_wan6_input'
            nft 'flush chain inet fw4 kjxclash_wan6_input'
            for wan6_int in $wan6_ints; do
               #nft delete rule inet fw4 input $(nft -a list chain inet fw4 input |grep "@kjx_localnet6" |awk -F '# ' '{print$2}')
               nft insert rule inet fw4 input position 0 iifname "$wan6_int" ip6 saddr != @kjx_localnet6 counter jump kjxclash_wan6_input
            done
            nft add rule inet fw4 kjxclash_wan6_input ip6 nexthdr {tcp,udp} th dport {$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port} counter reject
         else
            LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv6 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..."
         fi
      fi
   fi

   #icmp
   if [ "$en_mode" = "fake-ip" ]; then
      if [ -z "$en_mode_tun" ]; then
         nft insert rule inet fw4 input position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"Kejibear ICMP INPUT REJECT\"
         nft insert rule inet fw4 forward position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"Kejibear ICMP FORWARD REJECT\"
         nft insert rule inet fw4 output position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } $noowner counter reject comment \"Kejibear ICMP OUTPUT REJECT\"
      fi
      if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then
         if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
            nft insert rule inet fw4 input position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"Kejibear ICMPv6 INPUT REJECT\"
            nft insert rule inet fw4 forward position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"Kejibear ICMPv6 FORWARD REJECT\"
            nft insert rule inet fw4 output position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } $noowner counter reject with icmpv6 admin-prohibited comment \"Kejibear ICMPv6 OUTPUT REJECT\"
         fi
      fi
   fi
fi

#IPTABLES
if [ -z "$FW4" ]; then
   #iptables owner module
   if [ "$iptables_compat" -eq 0 ]; then
      owner="-m mark --mark 0x1a0a"
      noowner="-m mark ! --mark 0x1a0a"
      addr_local="! -i lo"
   else
      owner="-m owner --gid-owner 65534"
      noowner="-m owner ! --gid-owner 65534"
      addr_local="-m addrtype ! --src-type LOCAL"
   fi

   #china ip route
   if [ "$china_ip_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
      ipset -! flush kjx_cnroute
      ipset -! restore </etc/openclash-kejibear/china_ip_route.ipset

      if [ "$enable_redirect_dns" != "2" ]; then
         echo "create kjx_cnroute_pass hash:net family inet hashsize 1024 maxelem 1000000" >/tmp/openclash-kejibear_china_ip_route_pass.list
         awk '!/^$/&&!/^#/&&/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("add kjx_cnroute_pass %s'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute_pass.list >>/tmp/openclash-kejibear_china_ip_route_pass.list
         for ip in $(uci_get_config "china_ip_route_pass"); do
            [ -z "$ip" ] && continue
            echo "$ip" | awk '!/^$/&&!/^#/&&/(^([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)(([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])((\/[0-9][0-9])?)$/{printf("add kjx_cnroute_pass %s'" "'\n",$0)}'
         done >>/tmp/openclash-kejibear_china_ip_route_pass.list 2>/dev/null
         ipset -! flush kjx_cnroute_pass
         ipset -! restore </tmp/openclash-kejibear_china_ip_route_pass.list
         rm -rf /tmp/openclash-kejibear_china_ip_route_pass.list
      fi
   fi

   #lan_ac
   if [ "$lan_ac_mode" = "0" ]; then
      if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
         ipset create kjx_lanb_ips hash:net
         ipset create kjx_lanb_ipv6s hash:net family inet6
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_black_ips" ac_add "kjx_lanb_ips" "kjx_lanb_ipv6s"
      fi
      if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
         ipset create kjx_lanb_macs hash:mac
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_black_macs" ac_add "kjx_lanb_macs"
      fi
   elif [ "$lan_ac_mode" = "1" ]; then
      if [ -n "$(uci_get_config "lan_ac_white_ips")" ]; then
         ipset create kjx_lanw_ips hash:net
         ipset create kjx_lanw_ipv6s hash:net family inet6
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_white_ips" ac_add "kjx_lanw_ips" "kjx_lanw_ipv6s"
      fi
      if [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         ipset create kjx_lanw_macs hash:mac
         config_load "openclash_kejibear"
         config_list_foreach "config" "lan_ac_white_macs" ac_add "kjx_lanw_macs"
      fi
   fi

   #wan ac
   if [ -n "$(uci_get_config "wan_ac_black_ips")" ]; then
      ipset create kjx_wanb_ips hash:net
      ipset create kjx_wanb_ipv6s hash:net family inet6
      config_load "openclash_kejibear"
      config_list_foreach "config" "wan_ac_black_ips" ac_add "kjx_wanb_ips" "kjx_wanb_ipv6s"
   fi

   if [ -n "$(uci_get_config "wan_ac_black_ports")" ]; then
      ipset create kjx_wanb_ports bitmap:port range 0-65535
      config_load "openclash_kejibear"
      config_list_foreach "config" "wan_ac_black_ports" ac_add "kjx_wanb_ports"
   fi

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

   if [ -n "$wan_ip4s" ]; then
      for wan_ip4 in $wan_ip4s; do
         ipset add kjx_localnet "$wan_ip4"
      done
   fi

   #common ports
   if [ -n "$common_ports" ] && [ "$common_ports" != "0" ]; then
      ipset create kjx_cports bitmap:port range 0-65535
      for i in $common_port; do
         ipset add kjx_cports $i
      done
   fi

   #bypass gateway compatible
   if [ "$bypass_gateway_compatible" -eq 1 ]; then
      iptables -t nat -N kjxclash_post
      iptables -t nat -F kjxclash_post
      iptables -t nat -A kjxclash_post $owner -j RETURN
      iptables -t nat -A kjxclash_post -m mark --mark "$PROXY_FWMARK" -j ACCEPT
      iptables -t nat -A kjxclash_post -m set --match-set kjx_localnet dst -j RETURN
      iptables -t nat -A kjxclash_post -m conntrack --ctdir REPLY -j RETURN
      iptables -t nat -A kjxclash_post $addr_local -j MASQUERADE
      iptables -t nat -A POSTROUTING -m comment --comment "Kejibear Bypass Gateway Compatible" -j kjxclash_post
   fi

   #intranet allowed
   if [ "$intranet_allowed" -eq 1 ]; then
      if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then
         config_load "openclash_kejibear"
         config_list_foreach "config" "intranet_allowed_wan_name" wan_name_add
      else
         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)
      fi
      if [ -n "$wan_ints" ]; then
         iptables -t filter -N kjxclash_wan_input
         iptables -t filter -F kjxclash_wan_input
         for wan_int in $wan_ints; do
            iptables -t filter -I INPUT -i "$wan_int" -m set ! --match-set kjx_localnet src -j kjxclash_wan_input
         done
         iptables -t filter -A kjxclash_wan_input -p udp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT
         iptables -t filter -A kjxclash_wan_input -p tcp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT
      else
         LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv4 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..."
      fi
   fi

   DNSPORT=$(uci -q get dhcp.@dnsmasq[0].port)
   if [ -z "$DNSPORT" ]; then
      DNSPORT=$(netstat -nlp |grep -E '127.0.0.1:.*dnsmasq' |awk -F '127.0.0.1:' '{print $2}' |awk '{print $1}' |head -1 || echo 53)
   fi

   if [ "$enable_redirect_dns" -eq 1 ]; then
      if [ -z "$(iptables -t nat -nL PREROUTING --line-number |grep 'Kejibear DNS Hijack')" ]; then
         if [ "$lan_ac_mode" != "1" ]; then
            ACBLACKDNSFILTER=""
            if [ "$lan_ac_mode" = "0" ]; then
               if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                  ACBLACKDNSFILTER="-m set ! --match-set kjx_lanb_ips src"
               fi
               if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                  ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set kjx_lanb_macs src"
               fi
            fi
            iptables -t nat -I PREROUTING -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            iptables -t nat -I PREROUTING -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
         else
            iptables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set kjx_lanw_ips src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            iptables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set kjx_lanw_ips src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            iptables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            iptables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
         fi
      fi
      if [ "$router_self_proxy" = 1 ]; then
         iptables -t nat -I OUTPUT $noowner -m comment --comment "Kejibear DNS Hijack" -p tcp --dport 53 -d 127.0.0.1 -j REDIRECT --to-ports "$DNSPORT"
         iptables -t nat -I OUTPUT $noowner -m comment --comment "Kejibear DNS Hijack" -p udp --dport 53 -d 127.0.0.1 -j REDIRECT --to-ports "$DNSPORT"
      fi
   elif [ "$enable_redirect_dns" -eq 2 ]; then
      iptables -t nat -N kjxclash_dns_redirect
      iptables -t nat -F kjxclash_dns_redirect
      if [ "$lan_ac_mode" != "1" ]; then
         ACBLACKDNSFILTER=""
         if [ "$lan_ac_mode" = "0" ]; then
            if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
               ACBLACKDNSFILTER="-m set ! --match-set kjx_lanb_ips src"
            fi
            if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
               ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set kjx_lanb_macs src"
            fi
         fi
         iptables -t nat -A kjxclash_dns_redirect -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
         iptables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
      else
         iptables -t nat -A kjxclash_dns_redirect -p udp --dport 53 -m set --match-set kjx_lanw_ips src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
         iptables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 -m set --match-set kjx_lanw_ips src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
         iptables -t nat -A kjxclash_dns_redirect -p udp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
         iptables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
      fi
      iptables -t nat -I PREROUTING -p udp --dport 53 -j kjxclash_dns_redirect
      iptables -t nat -I PREROUTING -p tcp --dport 53 -j kjxclash_dns_redirect
      if [ "$router_self_proxy" = 1 ]; then
         iptables -t nat -I OUTPUT -p udp --dport 53 -d 127.0.0.1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
         iptables -t nat -I OUTPUT -p tcp --dport 53 -d 127.0.0.1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
      fi
   fi

   if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
      #tcp
      iptables -t nat -N kjxclash
      iptables -t nat -F kjxclash
      iptables -t nat -A kjxclash -m set --match-set kjx_localnet dst -j RETURN
      iptables -t nat -A kjxclash -m conntrack --ctdir REPLY -j RETURN
      iptables -t nat -A kjxclash -p tcp -d "$fakeip_range" -j REDIRECT --to-ports "$proxy_port"
      iptables -t nat -A kjxclash -m set --match-set kjx_wanb_ips dst -j RETURN
      iptables -t nat -A kjxclash -m set --match-set kjx_wanb_ports dst -j RETURN
      iptables -t nat -A kjxclash -m set --match-set kjx_lanb_ips src -j RETURN
      iptables -t nat -A kjxclash -m set --match-set kjx_lanb_macs src -j RETURN
      if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         iptables -t nat -A kjxclash -m set ! --match-set kjx_lanw_ips src -m set ! --match-set kjx_lanw_macs src -j RETURN
      else
         iptables -t nat -A kjxclash -m set ! --match-set kjx_lanw_ips src -j RETURN
         iptables -t nat -A kjxclash -m set ! --match-set kjx_lanw_macs src -j RETURN
      fi
      if [ "$en_mode" = "redir-host" ]; then
         iptables -t nat -A kjxclash -m set ! --match-set kjx_cports dst -j RETURN
      fi
      if [ "$china_ip_route" != "0" ]; then
         if [ "$china_ip_route" = "1" ]; then
            rule="-m set --match-set kjx_cnroute dst"
         elif [ "$china_ip_route" = "2" ]; then
            rule="-m set ! --match-set kjx_cnroute dst"
         fi
         [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
         iptables -t nat -A kjxclash $rule -j RETURN
      fi
      iptables -t nat -A kjxclash -p tcp -j REDIRECT --to-ports "$proxy_port"
      iptables -t nat -A PREROUTING -p tcp -j kjxclash

      # Accept redirected traffic in input chain (needed when zone input policy is REJECT without DNAT rules)
      if [ -z "$(iptables-save -t filter 2>/dev/null | grep 'Kejibear Redirect Accept')" ]; then
         iptables -I INPUT -m conntrack --ctstate DNAT -j ACCEPT -m comment --comment "Kejibear Redirect Accept"
      fi

      if [ -z "$en_mode_tun" ]; then
         #udp
         if [ "$enable_udp_proxy" -eq 1 ]; then
            check_mod "xt_TPROXY"
            ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
            iptables -t mangle -N kjxclash
            iptables -t mangle -F kjxclash
            iptables -t mangle -N kjxclash_upnp
            iptables -t mangle -F kjxclash_upnp
            upnp_exclude
            iptables -t mangle -A kjxclash -m set --match-set kjx_localnet dst -j RETURN
            iptables -t mangle -A kjxclash -m conntrack --ctdir REPLY -j RETURN
            if [ "$en_mode" = "fake-ip" ]; then
               iptables -t mangle -A kjxclash -p udp -d "$fakeip_range" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            fi
            iptables -t mangle -A kjxclash -m set --match-set kjx_wanb_ips dst -j RETURN
            iptables -t mangle -A kjxclash -m set --match-set kjx_wanb_ports dst -j RETURN
            iptables -t mangle -A kjxclash -m set --match-set kjx_lanb_macs src -j RETURN
            iptables -t mangle -A kjxclash -m set --match-set kjx_lanb_ips src -j RETURN
            if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
               iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ips src -m set ! --match-set kjx_lanw_macs src -j RETURN
            else
               iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ips src -j RETURN
               iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_macs src -j RETURN
            fi
            if [ "$en_mode" = "redir-host" ]; then
               iptables -t mangle -A kjxclash -m set ! --match-set kjx_cports dst -j RETURN
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="-m set --match-set kjx_cnroute dst"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="-m set ! --match-set kjx_cnroute dst"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
               iptables -t mangle -A kjxclash $rule -j RETURN
            fi
            iptables -t mangle -A kjxclash -p udp -j kjxclash_upnp
            iptables -t mangle -A kjxclash -p udp -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            iptables -t mangle -A PREROUTING -p udp -j kjxclash
         fi

         if [ "$enable_udp_proxy" -ne 1 ] && [ "$en_mode" = "fake-ip" ]; then
            check_mod "xt_TPROXY"
            ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
            iptables -t mangle -N kjxclash
            iptables -t mangle -F kjxclash
            iptables -t mangle -A kjxclash -p udp -d "$fakeip_range" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            iptables -t mangle -A PREROUTING -p udp -j kjxclash
         fi

         #router self proxy udp
         if ([ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]) || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
            iptables -t mangle -N kjxclash_output
            iptables -t mangle -F kjxclash_output
            iptables -t mangle -A kjxclash_output $owner -j RETURN
            iptables -t mangle -A kjxclash_output -m set --match-set kjx_localnet dst -j RETURN
            iptables -t mangle -A kjxclash_output -m conntrack --ctdir REPLY -j RETURN
            iptables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ips dst -j RETURN
            iptables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ports dst -j RETURN
            if [ "$en_mode" = "fake-ip" ]; then
               iptables -t mangle -A kjxclash_output -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK"
            fi
            if [ "$en_mode" = "redir-host" ]; then
               iptables -t mangle -A kjxclash_output -m set ! --match-set kjx_cports dst -j RETURN
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="-m set --match-set kjx_cnroute dst"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="-m set ! --match-set kjx_cnroute dst"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
               iptables -t mangle -A kjxclash_output $rule -j RETURN
            fi
            if [ "$router_self_proxy" = "1" ] && [ "$enable_udp_proxy" -eq 1 ]; then
               iptables -t mangle -A kjxclash_output -p udp -j MARK --set-mark "$PROXY_FWMARK"
            fi
            iptables -t mangle -A OUTPUT -p udp -j kjxclash_output
         fi

      fi

      # Accept TPROXY traffic in input chain (needed when zone input policy is REJECT)
      if [ -z "$(iptables -nL INPUT 2>/dev/null | grep 'Kejibear TPROXY Accept')" ]; then
         iptables -I INPUT -m mark --mark "$PROXY_FWMARK" -j ACCEPT -m comment --comment "Kejibear TPROXY Accept"
      fi

      if [ -z "$en_mode_tun" ]; then
         #quic
         if [ "$disable_udp_quic" -eq 1 ]; then
            if [ "$china_ip_route" = "2" ]; then
               iptables -I INPUT -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set --match-set kjx_cnroute dst -j REJECT
               iptables -I FORWARD -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set --match-set kjx_cnroute dst -j REJECT
            else
               iptables -I INPUT -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set ! --match-set kjx_cnroute dst -j REJECT
               iptables -I FORWARD -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set ! --match-set kjx_cnroute dst -j REJECT
            fi
         fi
      fi

      #router self proxy tcp
      if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
         iptables -t nat -N kjxclash_output
         iptables -t nat -F kjxclash_output
         iptables -t nat -A kjxclash_output $owner -j RETURN
         if [ "$en_mode" = "fake-ip" ] && [ "$en_mode_tun" != "1" ]; then
            iptables -t nat -A kjxclash_output -p tcp -d "$fakeip_range" -j REDIRECT --to-ports "$proxy_port"
         fi
         if [ "$router_self_proxy" = "1" ]; then
            iptables -t nat -A kjxclash_output -m set --match-set kjx_localnet dst -j RETURN
            iptables -t nat -A kjxclash_output -m conntrack --ctdir REPLY -j RETURN
            iptables -t nat -A kjxclash_output -m set --match-set kjx_wanb_ips dst -j RETURN
            iptables -t nat -A kjxclash_output -m set --match-set kjx_wanb_ports dst -j RETURN
            if [ "$en_mode" = "redir-host" ]; then
               iptables -t nat -A kjxclash_output -m set ! --match-set kjx_cports dst -j RETURN
            fi
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="-m set --match-set kjx_cnroute dst"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="-m set ! --match-set kjx_cnroute dst"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
               iptables -t nat -A kjxclash_output $rule -j RETURN
            fi
            iptables -t nat -A kjxclash_output -p tcp -j REDIRECT --to-ports "$proxy_port"
         fi
         iptables -t nat -A OUTPUT -j kjxclash_output
      fi
   fi

   if [ -n "$en_mode_tun" ]; then
      #TUN模式
      #设置防火墙
      #router self proxy
      if [ "$router_self_proxy" = "1" ] || ([ "$enable_redirect_dns" != "2" ] && [ "$en_mode" = "fake-ip" ]); then
         iptables -t mangle -N kjxclash_output
         iptables -t mangle -F kjxclash_output
         iptables -t mangle -A kjxclash_output $owner -j RETURN
         iptables -t mangle -A kjxclash_output -m set --match-set kjx_localnet dst -j RETURN
         iptables -t mangle -A kjxclash_output -m conntrack --ctdir REPLY -j RETURN
         if [ "$en_mode_tun" -eq 1 ]; then
            iptables -t mangle -A kjxclash_output -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK"
         else
            iptables -t mangle -A kjxclash_output -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK"
         fi
         if [ "$en_mode" = "redir-host" ]; then
            iptables -t mangle -A kjxclash_output -m set ! --match-set kjx_cports dst -j RETURN
         fi
         if [ "$router_self_proxy" = "1" ]; then
            iptables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ips dst -j RETURN
            iptables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ports dst -j RETURN
            if [ "$china_ip_route" != "0" ]; then
               if [ "$china_ip_route" = "1" ]; then
                  rule="-m set --match-set kjx_cnroute dst"
               elif [ "$china_ip_route" = "2" ]; then
                  rule="-m set ! --match-set kjx_cnroute dst"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
               iptables -t mangle -A kjxclash_output $rule -j RETURN
            fi
            if [ "$en_mode_tun" -eq 1 ]; then
               iptables -t mangle -A kjxclash_output -j MARK --set-mark "$PROXY_FWMARK"
            else
               #icmp
               iptables -t mangle -A kjxclash_output -p icmp --icmp-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "Kejibear ICMP Mark"
               iptables -t mangle -A kjxclash_output -p udp -j MARK --set-mark "$PROXY_FWMARK"
            fi
         fi
         iptables -t mangle -A OUTPUT -j kjxclash_output
      fi

      iptables -t mangle -N kjxclash
      iptables -t mangle -F kjxclash
      iptables -t mangle -N kjxclash_upnp
      iptables -t mangle -F kjxclash_upnp
      upnp_exclude
      #其他流量
      iptables -t mangle -A kjxclash -i kjxtun -j RETURN
      iptables -t mangle -A kjxclash -m set --match-set kjx_localnet dst -j RETURN
      iptables -t mangle -A kjxclash -m conntrack --ctdir REPLY -j RETURN
      if [ "$en_mode_tun" -eq 1 ]; then
         iptables -t mangle -A kjxclash -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK"
      else
         iptables -t mangle -A kjxclash -p udp -d "$fakeip_range" -j MARK --set-mark "$PROXY_FWMARK"
      fi
      iptables -t mangle -A kjxclash -m set --match-set kjx_wanb_ips dst -j RETURN
      iptables -t mangle -A kjxclash -m set --match-set kjx_wanb_ports dst -j RETURN
      iptables -t mangle -A kjxclash -m set --match-set kjx_lanb_ips src -j RETURN
      iptables -t mangle -A kjxclash -m set --match-set kjx_lanb_macs src -j RETURN
      if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
         iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ips src -m set ! --match-set kjx_lanw_macs src -j RETURN
      else
         iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ips src -j RETURN
         iptables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_macs src -j RETURN
      fi

      if [ "$en_mode" = "redir-host" ]; then
         iptables -t mangle -A kjxclash -m set ! --match-set kjx_cports dst -j RETURN
      fi
      if [ "$china_ip_route" != "0" ]; then
         if [ "$china_ip_route" = "1" ]; then
            rule="-m set --match-set kjx_cnroute dst"
         elif [ "$china_ip_route" = "2" ]; then
            rule="-m set ! --match-set kjx_cnroute dst"
         fi
         [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute_pass dst"
         iptables -t mangle -A kjxclash $rule -j RETURN
      fi

      iptables -t mangle -A kjxclash -p udp -j kjxclash_upnp

      if [ "$en_mode_tun" -eq 1 ]; then
         iptables -t mangle -A kjxclash -j MARK --set-mark "$PROXY_FWMARK"
      else
         #icmp
         iptables -t mangle -A kjxclash -p icmp --icmp-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "Kejibear ICMP Mark"
         iptables -t mangle -A kjxclash -p udp -j MARK --set-mark "$PROXY_FWMARK"
      fi

      iptables -t mangle -A PREROUTING -j kjxclash

      #TUN FORWORD
      iptables -I FORWARD -m comment --comment "Kejibear TUN Forward" -o kjxtun -j ACCEPT
      iptables -I FORWARD -m comment --comment "Kejibear TUN Forward" -i kjxtun -j ACCEPT
      iptables -I INPUT -m comment --comment "Kejibear TUN Input" -i kjxtun -j ACCEPT
      iptables -t nat -I POSTROUTING -m comment --comment "Kejibear TUN Postrouting" -o kjxtun -j RETURN

      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         if [ "$china_ip_route" = "2" ]; then
            iptables -I INPUT -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set --match-set kjx_cnroute dst -j REJECT
            iptables -I FORWARD -p udp --dport 443 -o kjxtun -m comment --comment "Kejibear QUIC REJECT" -m set --match-set kjx_cnroute dst -j REJECT
         else
            iptables -I INPUT -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" -m set ! --match-set kjx_cnroute dst -j REJECT
            iptables -I FORWARD -p udp --dport 443 -o kjxtun -m comment --comment "Kejibear QUIC REJECT" -m set ! --match-set kjx_cnroute dst -j REJECT
         fi
      fi
   fi

   #ipv6
   if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
      #china ip route
      if [ "$china_ip6_route" != "0" ] || [ "$disable_udp_quic" = "1" ]; then
         ipset -! flush kjx_cnroute6
         ipset -! restore </etc/openclash-kejibear/china_ip6_route.ipset
         if [ "$enable_redirect_dns" != "2" ]; then
            echo "create kjx_cnroute6_pass hash:net family inet6 hashsize 1024 maxelem 1000000" >/tmp/openclash-kejibear_china_ip6_route_pass.list
            awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("add kjx_cnroute6_pass %s'" "'\n",$0)}' /etc/openclash-kejibear/custom/openclash_custom_chnroute6_pass.list >>/tmp/openclash-kejibear_china_ip6_route_pass.list
            for ip in $(uci_get_config "china_ip6_route_pass"); do
               [ -z "$ip" ] && continue
               echo "$ip" | awk '!/^$/&&!/^#/&&!/([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/{printf("add kjx_cnroute6_pass %s'" "'\n",$0)}'
            done >>/tmp/openclash-kejibear_china_ip6_route_pass.list 2>/dev/null
            ipset -! flush kjx_cnroute6_pass
            ipset -! restore </tmp/openclash-kejibear_china_ip6_route_pass.list
            rm -rf /tmp/openclash-kejibear_china_ip6_route_pass.list
         fi
      fi

      if [ -z "$(ip6tables -t nat -nL PREROUTING --line-number |grep 'DNS Hijack')" ]; then
         if [ "$enable_redirect_dns" -eq 1 ]; then
            if [ "$lan_ac_mode" != "1" ]; then
               ACBLACKDNSFILTER=""
               if [ "$lan_ac_mode" = "0" ]; then
                  if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                     ACBLACKDNSFILTER="-m set ! --match-set kjx_lanb_ipv6s src"
                  fi
                  if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                     ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set kjx_lanb_macs src"
                  fi
               fi
               ip6tables -t nat -I PREROUTING -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I PREROUTING -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            else
               ip6tables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set kjx_lanw_ipv6s src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set kjx_lanw_ipv6s src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I PREROUTING -p udp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I PREROUTING -p tcp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            fi
            if [ "$router_self_proxy" = 1 ]; then
               ip6tables -t nat -I OUTPUT -p tcp --dport 53 -d ::1 $noowner -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I OUTPUT -p udp --dport 53 -d ::1 $noowner -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "Kejibear DNS Hijack"
            fi
         elif [ "$enable_redirect_dns" -eq 2 ]; then
            ip6tables -t nat -N kjxclash_dns_redirect
            ip6tables -t nat -F kjxclash_dns_redirect
            if [ "$lan_ac_mode" != "1" ]; then
               ACBLACKDNSFILTER=""
               if [ "$lan_ac_mode" = "0" ]; then
                  if [ -n "$(uci_get_config "lan_ac_black_ips")" ]; then
                     ACBLACKDNSFILTER="-m set ! --match-set kjx_lanb_ipv6s src"
                  fi
                  if [ -n "$(uci_get_config "lan_ac_black_macs")" ]; then
                     ACBLACKDNSFILTER="$ACBLACKDNSFILTER -m set ! --match-set kjx_lanb_macs src"
                  fi
               fi
               ip6tables -t nat -A kjxclash_dns_redirect -p udp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 ${ACBLACKDNSFILTER} -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
            else
               ip6tables -t nat -A kjxclash_dns_redirect -p udp --dport 53 -m set --match-set kjx_lanw_ipv6s src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 -m set --match-set kjx_lanw_ipv6s src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -A kjxclash_dns_redirect -p udp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -A kjxclash_dns_redirect -p tcp --dport 53 -m set --match-set kjx_lanw_macs src -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
            fi
            ip6tables -t nat -I PREROUTING -p udp --dport 53 -j kjxclash_dns_redirect
            ip6tables -t nat -I PREROUTING -p tcp --dport 53 -j kjxclash_dns_redirect
            if [ "$router_self_proxy" = 1 ]; then
               ip6tables -t nat -I OUTPUT -p udp --dport 53 -d ::1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
               ip6tables -t nat -I OUTPUT -p tcp --dport 53 -d ::1 $noowner -j REDIRECT --to-ports "$dns_port" -m comment --comment "Kejibear DNS Hijack"
            fi
         fi
      fi

      #local
      ipset create kjx_localnet6 hash:net family inet6
      if [ -f "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv6.list" ]; then
         for line in `cat "/etc/openclash-kejibear/custom/openclash_custom_localnetwork_ipv6.list"`
         do
            ipset add kjx_localnet6 "$line"
         done
      else
         ipset add kjx_localnet6 ::/128
         ipset add kjx_localnet6 ::1/128
         ipset add kjx_localnet6 ::ffff:0:0/96
         ipset add kjx_localnet6 ::ffff:0:0:0/96
         ipset add kjx_localnet6 64:ff9b::/96
         ipset add kjx_localnet6 100::/64
         ipset add kjx_localnet6 2001::/32
         ipset add kjx_localnet6 2001:20::/28
         ipset add kjx_localnet6 2001:db8::/32
         ipset add kjx_localnet6 2002::/16
         ipset add kjx_localnet6 fe80::/10
         ipset add kjx_localnet6 ff00::/8
      fi

      if [ -n "$wan_ip6s" ]; then
         for wan_ip6 in $wan_ip6s; do
            ipset add kjx_localnet6 "$wan_ip6"
         done
      fi

      if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then
         #tcp
         ip6tables -t nat -N kjxclash
         ip6tables -t nat -F kjxclash
         ip6tables -t nat -A kjxclash -p tcp -d "$fakeip_range6" -j REDIRECT --to-ports "$proxy_port"
         ip6tables -t nat -A kjxclash -m set --match-set kjx_localnet6 dst -j RETURN
         ip6tables -t nat -A kjxclash -m conntrack --ctdir REPLY -j RETURN
         ip6tables -t nat -A kjxclash -m set --match-set kjx_wanb_ipv6s dst -j RETURN
         ip6tables -t nat -A kjxclash -m set --match-set kjx_wanb_ports dst -j RETURN
         ip6tables -t nat -A kjxclash -m set --match-set kjx_lanb_ipv6s src -j RETURN
         ip6tables -t nat -A kjxclash -m set --match-set kjx_lanb_macs src -j RETURN
         if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
            ip6tables -t nat -A kjxclash -m set ! --match-set kjx_lanw_ipv6s src -m set ! --match-set kjx_lanw_macs src -j RETURN
         else
            ip6tables -t nat -A kjxclash -m set ! --match-set kjx_lanw_ipv6s src -j RETURN
            ip6tables -t nat -A kjxclash -m set ! --match-set kjx_lanw_macs src -j RETURN
         fi
         if [ "$en_mode" = "redir-host" ]; then
            ip6tables -t nat -A kjxclash -m set ! --match-set kjx_cports dst -j RETURN
         fi
         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="-m set --match-set kjx_cnroute6 dst"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="-m set ! --match-set kjx_cnroute6 dst"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute6_pass dst"
            ip6tables -t nat -A kjxclash $rule -j RETURN
         fi
         ip6tables -t nat -A kjxclash -p tcp -j REDIRECT --to-ports "$proxy_port"
         ip6tables -t nat -A PREROUTING -p tcp -j kjxclash
      fi

      # Accept redirected IPv6 traffic in input chain (needed when zone input policy is REJECT without DNAT rules)
      if [ -z "$(ip6tables-save -t filter 2>/dev/null | grep 'Kejibear Redirect Accept')" ]; then
         ip6tables -I INPUT -m conntrack --ctstate DNAT -j ACCEPT -m comment --comment "Kejibear Redirect Accept"
      fi

      #TProxy & TUN & Redirect udp
      if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -ne 1 ]; then
         ip6tables -t mangle -N kjxclash
         ip6tables -t mangle -F kjxclash
         ip6tables -t mangle -A kjxclash -m set --match-set kjx_localnet6 dst -j RETURN
         ip6tables -t mangle -A kjxclash -m conntrack --ctdir REPLY -j RETURN
         if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then
            if [ "$ipv6_mode" -eq 0 ]; then
               ip6tables -t mangle -A kjxclash -p tcp -d "$fakeip_range6" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            else
               ip6tables -t mangle -A kjxclash -p tcp -d "$fakeip_range6" -j MARK --set-mark "$PROXY_FWMARK"
            fi
         fi
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -t mangle -A kjxclash -p udp -d "$fakeip_range6" -j MARK --set-mark "$PROXY_FWMARK"
         else
            if [ "$enable_v6_udp_proxy" -eq 1 ]; then
               ip6tables -t mangle -A kjxclash -p udp -d "$fakeip_range6" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
            fi
         fi
         ip6tables -t mangle -A kjxclash -m set --match-set kjx_wanb_ipv6s dst -j RETURN
         ip6tables -t mangle -A kjxclash -m set --match-set kjx_wanb_ports dst -j RETURN
         ip6tables -t mangle -A kjxclash -m set --match-set kjx_lanb_macs src -j RETURN
         ip6tables -t mangle -A kjxclash -m set --match-set kjx_lanb_ipv6s src -j RETURN
         if [ "$lan_ac_mode" = "1" ] && [ -n "$(uci_get_config "lan_ac_white_ips")" ] && [ -n "$(uci_get_config "lan_ac_white_macs")" ]; then
            ip6tables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ipv6s src -m set ! --match-set kjx_lanw_macs src -j RETURN
         else
            ip6tables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_ipv6s src -j RETURN
            ip6tables -t mangle -A kjxclash -m set ! --match-set kjx_lanw_macs src -j RETURN
         fi

         if [ "$en_mode" == "redir-host" ]; then
            ip6tables -t mangle -A kjxclash -m set ! --match-set kjx_cports dst -j RETURN
         fi

         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="-m set --match-set kjx_cnroute6 dst"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="-m set ! --match-set kjx_cnroute6 dst"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute6_pass dst"
            ip6tables -t mangle -A kjxclash $rule -j RETURN
         fi

         #icmpv6
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -t mangle -A kjxclash -p icmpv6 --icmpv6-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "Kejibear ICMPv6 Redirect"
         fi
      fi

      #tcp Tproxy && TUN
      if [ "$ipv6_mode" -ne 1 ] && [ "$ipv6_mode" -ne 3 ]; then
         if [ "$ipv6_mode" -eq 0 ]; then
            ip6tables -t mangle -A kjxclash -p tcp -m comment --comment "Kejibear TCP Tproxy" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
         else
            ip6tables -t mangle -A kjxclash -p tcp -j MARK --set-mark "$PROXY_FWMARK"
         fi
      fi

      #udp
      if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
         ip6tables -t mangle -A kjxclash -p udp -m comment --comment "Kejibear UDP TUN" -j MARK --set-xmark "$PROXY_FWMARK"
      else
         if [ "$enable_v6_udp_proxy" -eq 1 ]; then
            ip6tables -t mangle -A kjxclash -p udp -m comment --comment "Kejibear UDP Tproxy" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
         fi
      fi

      ip6tables -t mangle -A PREROUTING -j kjxclash

      # Accept TPROXY IPv6 traffic in input chain (needed when zone input policy is REJECT)
      if [ -z "$(ip6tables-save -t filter 2>/dev/null | grep 'Kejibear TPROXY Accept')" ]; then
         ip6tables -I INPUT -m mark --mark "$PROXY_FWMARK" -j ACCEPT -m comment --comment "Kejibear TPROXY Accept"
      fi

      #router self proxy
      if [ "$router_self_proxy" = "1" ]; then
         if [ "$ipv6_mode" -eq 1 ] || [ "$ipv6_mode" -eq 3 ]; then
            #tcp Redirect Mode
            ip6tables -t nat -N kjxclash_output
            ip6tables -t nat -F kjxclash_output
            if [ "$en_mode" = "fake-ip" ]; then
               ip6tables -t nat -A kjxclash_output -p tcp -d "$fakeip_range6" -j REDIRECT --to-ports "$proxy_port"
            fi
            ip6tables -t nat -A kjxclash_output $owner -j RETURN
            ip6tables -t nat -A kjxclash_output -m set --match-set kjx_localnet6 dst -j RETURN
            ip6tables -t nat -A kjxclash_output -m conntrack --ctdir REPLY -j RETURN
            ip6tables -t nat -A kjxclash_output -m set --match-set kjx_wanb_ipv6s dst -j RETURN
            ip6tables -t nat -A kjxclash_output -m set --match-set kjx_wanb_ports dst -j RETURN
            if [ "$en_mode" = "redir-host" ]; then
               ip6tables -t nat -A kjxclash_output -m set ! --match-set kjx_cports dst -j RETURN
            fi
            if [ "$china_ip6_route" != "0" ]; then
               if [ "$china_ip6_route" = "1" ]; then
                  rule="-m set --match-set kjx_cnroute6 dst"
               elif [ "$china_ip6_route" = "2" ]; then
                  rule="-m set ! --match-set kjx_cnroute6 dst"
               fi
               [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute6_pass dst"
               ip6tables -t nat -A kjxclash_output $rule -j RETURN
            fi
            ip6tables -t nat -A kjxclash_output -p tcp -j REDIRECT --to-ports "$proxy_port"
            ip6tables -t nat -A OUTPUT -j kjxclash_output
         fi

         #other mode and Redirect Mode udp
         ip6tables -t mangle -N kjxclash_output
         ip6tables -t mangle -F kjxclash_output
         ip6tables -t mangle -A kjxclash_output $owner -j RETURN
         ip6tables -t mangle -A kjxclash_output -m set --match-set kjx_localnet6 dst -j RETURN
         ip6tables -t mangle -A kjxclash_output -m conntrack --ctdir REPLY -j RETURN
         if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -t mangle -A kjxclash_output -p udp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then
            ip6tables -t mangle -A kjxclash_output -p tcp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK"
            ip6tables -t mangle -A kjxclash_output -p udp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then
            ip6tables -t mangle -A kjxclash_output -p tcp -d "$fakeip_range6" -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         ip6tables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ipv6s dst -j RETURN
         ip6tables -t mangle -A kjxclash_output -m set --match-set kjx_wanb_ports dst -j RETURN
         if [ "$en_mode" = "redir-host" ]; then
            ip6tables -t mangle -A kjxclash_output -m set ! --match-set kjx_cports dst -j RETURN
         fi
         if [ "$china_ip6_route" != "0" ]; then
            if [ "$china_ip6_route" = "1" ]; then
               rule="-m set --match-set kjx_cnroute6 dst"
            elif [ "$china_ip6_route" = "2" ]; then
               rule="-m set ! --match-set kjx_cnroute6 dst"
            fi
            [ "$enable_redirect_dns" != "2" ] && rule="$rule -m set ! --match-set kjx_cnroute6_pass dst"
            ip6tables -t mangle -A kjxclash_output $rule -j RETURN
         fi

         #icmpv6
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -t mangle -A kjxclash_output -p icmpv6 --icmpv6-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "Kejibear ICMPv6 Redirect"
         fi

         if ([ "$ipv6_mode" -eq 1 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -t mangle -A kjxclash_output -p udp -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         if ([ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -eq 1 ]) || [ "$ipv6_mode" -eq 2 ]; then
            ip6tables -t mangle -A kjxclash_output -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         if [ "$ipv6_mode" -eq 0 ] && [ "$enable_v6_udp_proxy" -ne 1 ]; then
            ip6tables -t mangle -A kjxclash_output -p tcp -j MARK --set-xmark "$PROXY_FWMARK"
         fi
         ip6tables -t mangle -A OUTPUT -j kjxclash_output
      fi

      #route
      if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
         if [ "$enable_v6_udp_proxy" -eq 1 ] || [ "$ipv6_mode" -eq 0 ]; then
            check_mod "xt_TPROXY"
            ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
            ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE"
         fi
      fi

      #TUN FORWORD
      if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
         ip6tables -I FORWARD -m comment --comment "Kejibear TUN Forward" -o kjxtun -j ACCEPT
         ip6tables -I FORWARD -m comment --comment "Kejibear TUN Forward" -i kjxtun -j ACCEPT
         ip6tables -I INPUT -m comment --comment "Kejibear TUN Input" -i kjxtun -j ACCEPT
         ip6tables -t nat -I POSTROUTING -m comment --comment "Kejibear TUN Postrouting" -o kjxtun -j RETURN
      fi

      #quic
      if [ "$disable_udp_quic" -eq 1 ]; then
         if [ "$china_ip6_route" = "2" ]; then
            rule="-m set --match-set kjx_cnroute6 dst"
         else
            rule="-m set ! --match-set kjx_cnroute6 dst"
         fi
         ip6tables -I INPUT -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" $rule -j REJECT
         if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
            ip6tables -I FORWARD -p udp --dport 443 -o kjxtun -m comment --comment "Kejibear QUIC REJECT" $rule -j REJECT
         else
            ip6tables -I FORWARD -p udp --dport 443 -m comment --comment "Kejibear QUIC REJECT" $rule -j REJECT
         fi
      fi

      #bypass gateway compatible
      if [ "$bypass_gateway_compatible" -eq 1 ]; then
         ip6tables -t nat -N kjxclash_post
         ip6tables -t nat -F kjxclash_post
         ip6tables -t nat -A kjxclash_post $owner -j RETURN
         ip6tables -t nat -A kjxclash_post -m mark --mark "$PROXY_FWMARK" -j ACCEPT
         ip6tables -t nat -A kjxclash_post -m set --match-set kjx_localnet6 dst -j RETURN
         ip6tables -t nat -A kjxclash_post -m conntrack --ctdir REPLY -j RETURN
         ip6tables -t nat -A kjxclash_post $addr_local -j MASQUERADE
         ip6tables -t nat -A POSTROUTING -m comment --comment "Kejibear Bypass Gateway Compatible" -j kjxclash_post
      fi

      #intranet allowed
      if [ "$intranet_allowed" -eq 1 ]; then
         if [ -n "$intranet_allowed_wan_name" ] && [ "$intranet_allowed_wan_name" != "0" ]; then
            config_load "openclash_kejibear"
            config_list_foreach "config" "intranet_allowed_wan_name" wan6_name_add
         else
            wan6_ints=$(ip6tables-save -t filter |grep -e "-j zone_wan_input" 2>/dev/null |awk '{for (i=1;i<=NF;i++) {if ($i ~ /-i/) {print $(i+1)}}}' 2>/dev/null)
         fi
         if [ -n "$wan6_ints" ]; then
            ip6tables -t filter -N kjxclash_wan_input
            ip6tables -t filter -F kjxclash_wan_input
            for wan6_int in $wan6_ints; do
               ip6tables -t filter -I INPUT -i "$wan6_int" -m set ! --match-set kjx_localnet6 src -j kjxclash_wan_input
            done
            ip6tables -t filter -A kjxclash_wan_input -p udp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT
            ip6tables -t filter -A kjxclash_wan_input -p tcp -m multiport --dport "$proxy_port,$tproxy_port,$cn_port,$http_port,$socks_port,$mixed_port,$dns_port" -j REJECT
         else
            LOG_WARN "Can't Settting Only Intranet Allowed Function, Get IPv6 WAN Interfaces error, Please Verify The Firewall's WAN Zone Name is wan, Ignore This IF The Device Does not Have a WAN Interfaces..."
         fi
      fi
   fi

   #icmp reject
   if [ "$en_mode" = "fake-ip" ]; then
      if [ -z "$en_mode_tun" ]; then
         iptables -t filter -I INPUT -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "Kejibear ICMP INPUT REJECT"
         iptables -t filter -I FORWARD -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "Kejibear ICMP FORWARD REJECT"
         iptables -t filter -I OUTPUT  -p icmp --icmp-type echo-request -d "$fakeip_range" $noowner -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "Kejibear ICMP OUTPUT REJECT"
      fi
      if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then
         if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
            ip6tables -t filter -I INPUT -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "Kejibear ICMPv6 INPUT REJECT"
            ip6tables -t filter -I FORWARD -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "Kejibear ICMPv6 FORWARD REJECT"
            ip6tables -t filter -I OUTPUT  -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" $noowner -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "Kejibear ICMPv6 OUTPUT REJECT"
         fi
      fi
   fi
fi

#来源流量访问控制
config_load "openclash_kejibear"
config_foreach firewall_lan_ac_traffic "lan_ac_traffic"

#Custom

if [ -f "/etc/openclash-kejibear/custom/openclash_custom_firewall_rules.sh" ]; then
   chmod +x /etc/openclash-kejibear/custom/openclash_custom_firewall_rules.sh
   /etc/openclash-kejibear/custom/openclash_custom_firewall_rules.sh
fi

} >/dev/null 2>&1

revert_firewall()
{
   rm -rf /var/etc/openclash-kejibear.include

   ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
   ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"

   ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
   ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE"

   #TUN
   ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
   ip route del default dev kjxtun table "$PROXY_ROUTE_TABLE"
   ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
   ip -6 route del default dev kjxtun table "$PROXY_ROUTE_TABLE"

   if [ -n "$FW4" ]; then
      for nft in "input" "forward" "output" "dstnat" "srcnat" "nat_output" "mangle_prerouting" "mangle_output"; do
         local handles=$(nft -a list chain inet fw4 ${nft} |grep -E "kjxclash|Kejibear" |awk -F '# handle ' '{print$2}')
         for handle in $handles; do
            nft delete rule inet fw4 ${nft} handle ${handle}
         done
      done

      for handle in $(nft -a list chains |grep -E "chain kjxclash" |awk -F '# handle ' '{print$2}'); do
         nft delete chain inet fw4 handle ${handle}
      done

      for handle in $(nft -a list sets |grep -E "set kjx_" |awk -F '# handle ' '{print$2}'); do
         nft delete set inet fw4 handle ${handle}
      done
   else
      for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "iptables -nvL OUTPUT" "iptables -nvL POSTROUTING -t nat" "iptables -nvL OUTPUT -t nat" "iptables -nvL OUTPUT -t mangle" "iptables -nvL PREROUTING -t nat" "iptables -nvL PREROUTING -t mangle" "ip6tables -nvL OUTPUT" "ip6tables -nvL INPUT" "ip6tables -nvL FORWARD" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL PREROUTING -t mangle" "ip6tables -nvL POSTROUTING -t nat" "ip6tables -nvL OUTPUT -t nat"; do
         for comment in "kjxclash" "Kejibear"; do
            local lines=$($ipt |sed 1,2d |sed -n "/${comment}/=" 2>/dev/null |sort -rn)
            if [ -n "$lines" ]; then
               for line in $lines; do
                  $(echo "$ipt" |awk -v OFS=" " '{print $1,$4,$5}' |sed 's/[ ]*$//g') -D $(echo "$ipt" |awk '{print $3}') $line
               done
            fi
         done
      done

      for chain in "kjxclash" "kjxclash_output" "kjxclash_post" "kjxclash_wan_input" "kjxclash_dns_redirect" "kjxclash_upnp"; do
         iptables -t nat -F $chain
         iptables -t nat -X $chain
         iptables -t mangle -F $chain
         iptables -t mangle -X $chain
         iptables -t filter -F $chain
         iptables -t filter -X $chain
         ip6tables -t nat -F $chain
         ip6tables -t nat -X $chain
         ip6tables -t mangle -F $chain
         ip6tables -t mangle -X $chain
         ip6tables -t filter -F $chain
         ip6tables -t filter -X $chain
      done

      ipset destroy kjx_localnet6
      ipset destroy kjx_cnroute6
      ipset destroy kjx_cnroute6_pass
      ipset destroy kjx_lanw_ipv6s
      ipset destroy kjx_lanb_ipv6s
      ipset destroy kjx_wanb_ipv6s
      ipset destroy kjx_localnet
      ipset destroy kjx_cnroute
      ipset destroy kjx_cnroute_pass
      ipset destroy kjx_lanw_ips
      ipset destroy kjx_lanb_ips
      ipset destroy kjx_lanw_macs
      ipset destroy kjx_lanb_macs
      ipset destroy kjx_wanb_ips
      ipset destroy kjx_wanb_ports
      ipset destroy kjx_cports
   fi
} >/dev/null 2>&1

add_overwrite_cron()
{
   local section="$1" enable type day hour url name
   config_get_bool "enable" "$section" "enable" "1"
   config_get "type" "$section" "type" "file"
   config_get "url" "$section" "url" ""
   config_get "update_days" "$section" "update_days" ""
   config_get "update_hour" "$section" "update_hour" ""
   config_get "name" "$section" "name" ""

   if [ "$enable" != "1" ] || [ -z "$name" ] || [ "$type" != "http" ] || [ -z "$url" ] || [ -z "$update_days" ] || [ -z "$update_hour" ] || [ "$update_days" = "off" ] || [ "$update_hour" = "off" ]; then
      return
   fi

   # 模块名是文件名，可能带 - . 甚至 shell 元字符，拼进 eval 前先收成合法变量名
   eval "restart_flag=\${OVERWRITE_RESTART_FLAG_$(printf '%s' "$name" | tr -c 'A-Za-z0-9_' '_')}"
   cron_cmd="$cron source /usr/share/openclash-kejibear/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"/etc/openclash-kejibear/overwrite/$name\" \"/etc/openclash-kejibear/overwrite/$name\""
   if [ "$restart_flag" = "1" ]; then
      cron_cmd="$cron_cmd && [ \"\$?\" -eq 0 ] && /etc/init.d/openclash-kejibear restart"
   fi
   cron_cmd="$cron_cmd #openclash-kejibear-overwrite-download"

   echo "0 $update_hour * * $update_days $cron_cmd" >> $CRON_FILE
}

check_type() {
   local key="$1"
   local value="$2"
   local type=$(echo "$allowed_types_map" | grep "^${key}:" | cut -d: -f2)
   case "$type" in
      int)
         echo "$value" | grep -Eq '^[0-9]+$'
         return $?
         ;;
      int_bool)
         [[ "$value" == "0" || "$value" == "1" ]]
         return $?
         ;;
      bool)
         [[ "$value" == "true" || "$value" == "false" ]]
         return $?
         ;;
      cron)
         # 一个 crontab 时间字段：add_cron 把它原样拼进 /etc/crontabs/root，crond 用 sh 跑整行
         echo "$value" | grep -Eq '^[0-9*/,-]+$'
         return $?
         ;;
      string|*)
         # 🔴 覆写模块可以是远程订阅来的，写进 @overwrite[0] 的值会被 uci_get_config 优先取用：
         # yml_change.sh 把它们拼进 ruby -e 的单引号串（'$2' 之类），一个 ' 就能跳出字符串
         # 执行任意 Ruby；\ 能吃掉结尾的引号。引号、反引号、$、反斜杠一律不收
         kjx_no_shell_meta "$value"
         return $?
         ;;
   esac
}

# 🔴 覆写模块的「模块参数」展开，代替上游的 eval "echo \"...\""。
# 上游对 [General] 的值、DOWNLOAD_FILE 的 url/path/...、[YAML] 块的每一行都 eval 一遍，
# 覆写模块又可以是远程订阅来的：一个反引号就是以 root 执行任意命令，\` 能把整个
# /tmp/yaml_overwrite.sh 弄坏，YAML 里双引号被吃掉、正则里的 | 变成管道、密码里的 $ 被展开没了。
# 这里只替换 ${NAME} / $NAME 且 NAME 必须是**本模块 param 里声明过的键**，换成字面值；
# 其余一切（$HOME、反引号、引号、反斜杠）原样保留。参数表经环境变量传入，不经 awk -v
# （-v 会解释值里的反斜杠转义）。stdin → stdout，逐行处理。
# 注意这里只管「展开时不执行」：展开后的值还会拼进 crontab、ruby -e，那些出口另有校验
# （kjx_ovr_download_ok、check_type）；[Overwrite] 段本来就是 shell，模块仍须可信
kjx_ovr_expand()
{
   KJX_OVR_PARAMS="$OVERWRITE_PARAM_LINES" awk '
      BEGIN {
         n = split(ENVIRON["KJX_OVR_PARAMS"], kv, "\n")
         for (i = 1; i <= n; i++) {
            p = index(kv[i], "=")
            if (p > 1) param[substr(kv[i], 1, p - 1)] = substr(kv[i], p + 1)
         }
      }
      {
         s = $0; out = ""
         while ((p = index(s, "$")) > 0) {
            out = out substr(s, 1, p - 1)
            s = substr(s, p)
            name = ""; len = 1
            if (match(s, /^\$\{[A-Za-z_][A-Za-z0-9_]*\}/)) {
               name = substr(s, 3, RLENGTH - 3); len = RLENGTH
            } else if (match(s, /^\$[A-Za-z_][A-Za-z0-9_]*/)) {
               name = substr(s, 2, RLENGTH - 1); len = RLENGTH
            }
            if (name != "" && (name in param)) {
               out = out param[name]
            } else {
               out = out substr(s, 1, len)
            }
            s = substr(s, len + 1)
         }
         print out s
      }'
}

kjx_ovr_expand_str()
{
   printf '%s\n' "$1" | kjx_ovr_expand
}

# 值里没有引号、反引号、$、反斜杠（拼进 sh 双引号串或 ruby 单引号串都不会越界）
kjx_no_shell_meta()
{
   [ "$(printf '%s' "$1" | tr -d "\`\$\\\\'\"")" = "$1" ]
}

# 🔴 DOWNLOAD_FILE 的 url / path / cron / ua 最终会拼进 /etc/crontabs/root 的一行，crond 用 sh
# 执行；path 还是以 root 身份写文件的目标。不 eval 只挡住了启动时那一次：url 里的 $(...)、
# 反引号照样每天在 cron 里执行，cron 字段本身能直接塞命令（"* * * * * reboot;"），
# path 指向一个已存在的文件（/etc/passwd）连下载都跳过、直接加定时任务，force=true 时
# 还能覆盖 /etc/rc.local。所以逐项收紧，不合格整条任务跳过：
#   url  只能是 http(s)，不含空白与上述元字符
#   path 只能落在规则集 / 代理集目录下，不含 ..（内核二进制、custom 下的脚本都在别的目录）
#   cron 0（不加定时任务）或五个时间字段
#   ua   不含上述元字符（可以有空格，拼进去时在双引号里）
kjx_ovr_download_ok()
{
   local url="$1" path="$2" cron="$3" ua="$4"
   case "$url" in
      http://*|https://*) ;;
      *) return 1 ;;
   esac
   case "$path" in
      /etc/openclash-kejibear/rule_provider/?*|/etc/openclash-kejibear/proxy_provider/?*|/etc/openclash-kejibear/game_rules/?*) ;;
      *) return 1 ;;
   esac
   case "$path" in
      *..*) return 1 ;;
   esac
   printf '%s%s' "$url" "$path" | grep -q '[[:space:]]' && return 1
   kjx_no_shell_meta "$url$path$ua" || return 1
   [ "$cron" = "0" ] || echo "$cron" | grep -Eq '^[0-9*/,-]+( [0-9*/,-]+){4}$'
}

overwrite_config_match_check()
{
   local section="$1" name config
   config_get "name" "$section" "name" ""
   config_get "config" "$section" "config" ""

   [ -z "$name" ] || [ "$name" != "$2" ] || [ -z "$config" ] && return

   config_list_foreach "$section" "config" overwrite_config_match_item
}

overwrite_config_match_item()
{
   local config_path_item="$1"

   [ -z "$config_path_item" ] && return
   [ "$config_path_item" = "all" ] && OVERWRITE_CONFIG_MATCHED=1 && return
   [ "$config_path_item" = "$(uci_get_config "config_path")" ] && OVERWRITE_CONFIG_MATCHED=1
}

overwrite_file()
{
   clear_overwrite_set

   overwrite_script="/tmp/yaml_overwrite.sh"
   # 每个模块的 [YAML] 块原样落成独立文件（0600，托管态下可能含敏感内容），
   # 由 ruby_overwrite_module_apply 直接读，不再经过 shell
   overwrite_block_dir="/tmp/yaml_overwrite_blocks"
   rm -rf "$overwrite_block_dir"
   (umask 077; mkdir -p "$overwrite_block_dir")
   cat > "$overwrite_script" <<'EOF'
#!/bin/sh
. /usr/share/openclash-kejibear/ruby.sh
. /usr/share/openclash-kejibear/log.sh
. /lib/functions.sh

EOF

   allowed_keys_types="\
      AGE_SECRET_KEY:string \
      AGE_PUBLIC_KEY:string \
      APPEND_DEFAULT_DNS:int_bool \
      APPEND_WAN_DNS:int_bool \
      AUTO_SMART_SWITCH:int_bool \
      BYPASS_GATEWAY_COMPATIBLE:int_bool \
      CHINA_IP_ROUTE:int \
      CHINA_IP_ROUTE_PASS:string \
      CHINA_IP6_ROUTE:int \
      CHINA_IP6_ROUTE_PASS:string \
      CHNR_AUTO_UPDATE:int_bool \
      CHNR_CUSTOM_URL:string \
      CHNR6_CUSTOM_URL:string \
      CHNR_UPDATE_DAY_TIME:cron \
      CHNR_UPDATE_WEEK_TIME:cron \
      COMMON_PORTS:string \
      CONFIG_FILE:string \
      CORE_TYPE:string \
      CN_PORT:int \
      CUSTOM_FALLBACK_FILTER:int_bool \
      CUSTOM_FAKEIP_FILTER:int_bool \
      CUSTOM_FAKEIP_FILTER_MODE:string \
      CUSTOM_HOST:int_bool \
      CUSTOM_NAME_POLICY:int_bool \
      DA_PASSWORD:string \
      DELAY_START:int \
      DISABLE_QUIC_GO_GSO:int_bool \
      DISABLE_UDP_QUIC:int_bool \
      DNS_PORT:int \
      DOWNLOAD_FILE:string \
      EN_MODE:string \
      ENABLE_CUSTOM_CLASH_RULES:int_bool \
      ENABLE_CUSTOM_DNS:int_bool \
      ENABLE_GEOIP_DAT:int_bool \
      ENABLE_META_SNIFFER:int_bool \
      ENABLE_META_SNIFFER_CUSTOM:int_bool \
      ENABLE_META_SNIFFER_PURE_IP:int_bool \
      ENABLE_REDIRECT_DNS:int_bool \
      ENABLE_RESPECT_RULES:int_bool \
      ENABLE_RULE_PROXY:int_bool \
      ENABLE_TCP_CONCURRENT:int_bool \
      ENABLE_UDP_PROXY:int_bool \
      ENABLE_UNIFIED_DELAY:int_bool \
      ENABLE_V6_UDP_PROXY:int_bool \
      FIND_PROCESS_MODE:string \
      FAKEIP_RANGE:string \
      FAKEIP_RANGE6:string \
      GEOASN_AUTO_UPDATE:int_bool \
      GEOASN_CUSTOM_URL:string \
      GEOASN_UPDATE_DAY_TIME:cron \
      GEOASN_UPDATE_WEEK_TIME:int \
      GEO_CUSTOM_URL:string \
      GEODATA_LOADER:string \
      GEOIP_AUTO_UPDATE:int_bool \
      GEOIP_CUSTOM_URL:string \
      GEOIP_UPDATE_DAY_TIME:int \
      GEOIP_UPDATE_WEEK_TIME:int \
      GEO_AUTO_UPDATE:int_bool \
      GEO_UPDATE_DAY_TIME:cron \
      GEO_UPDATE_WEEK_TIME:int \
      GEOSITE_AUTO_UPDATE:int_bool \
      GEOSITE_CUSTOM_URL:string \
      GEOSITE_UPDATE_DAY_TIME:cron \
      GEOSITE_UPDATE_WEEK_TIME:int \
      GITHUB_ADDRESS_MOD:string \
      GLOBAL_UA:string \
      HTTP_PORT:int \
      INTRANET_ALLOWED:int_bool \
      INTRANET_ALLOWED_WAN_NAME:string \
      INTERFACE_NAME:string \
      IPV6_DNS:int_bool \
      IPV6_ENABLE:int_bool \
      IPV6_MODE:int \
      LAN_INTERFACE_NAME:string \
      LGBM_AUTO_UPDATE:int_bool \
      LGBM_CUSTOM_URL:string \
      LGBM_UPDATE_INTERVAL:int \
      MIXED_PORT:int \
      PROXY_MODE:string \
      PROXY_PORT:int \
      ROUTER_SELF_PROXY:int_bool \
      SMART_COLLECT:int_bool \
      SMART_COLLECT_RATE:string \
      SMART_COLLECT_SIZE:int \
      SMART_ENABLE_LGBM:int_bool \
      SMART_POLICY_PRIORITY:string \
      SMART_PREFER_ASN:int_bool \
      SMART_TOLERANCE:int \
      SKIP_PROXY_ADDRESS:int_bool \
      SMALL_FLASH_MEMORY:int_bool \
      SOCKS_PORT:int \
      STACK_TYPE:string \
      STORE_FAKEIP:int_bool \
      SUB_INFO_URL:string \
      TOLERANCE:int \
      TPROXY_PORT:int \
      URLTEST_ADDRESS_MOD:string \
      URLTEST_INTERVAL_MOD:int \
      RESTART:bool \
   "

   allowed_keys_list=$(echo "$allowed_keys_types" | tr ' ' '\n' | cut -d: -f1)
   allowed_types_map=$(echo "$allowed_keys_types" | tr ' ' '\n')

   uci -q add openclash_kejibear overwrite >/dev/null 2>&1

   overwrite_list=$(uci -q show openclash_kejibear 2>/dev/null | grep "=config_overwrite" | awk -F'[.=]' '{print $2}' | while read -r sid; do
      order=$(uci -q get openclash_kejibear."$sid".order 2>/dev/null)
      [ -z "$order" ] && order=0
      name=$(uci -q get openclash_kejibear."$sid".name 2>/dev/null)
      enable_flag=$(uci -q get openclash_kejibear."$sid".enable 2>/dev/null || echo 0)
      printf "%s|%s|%s|%s\n" "$order" "$name" "$sid" "$enable_flag"
   done | sort -nr -t'|' -k1,1)

   for entry in $overwrite_list; do
      name=$(echo "$entry" | cut -d'|' -f2)
      sid=$(echo "$entry" | cut -d'|' -f3)
      enabled_flag=$(echo "$entry" | cut -d'|' -f4)
      OVERWRITE_CONFIG_MATCHED=0
      config_load "openclash_kejibear"
      config_foreach overwrite_config_match_check "config_overwrite" "$name"

      [ "$OVERWRITE_CONFIG_MATCHED" -eq 0 ] && continue
      [ "$enabled_flag" != "1" ] && continue
      [ -z "$name" ] && continue

      file="/etc/openclash-kejibear/overwrite/${name}"
      [ ! -f "$file" ] && continue

      LOG_TIP "Processing Overwrite Module【$name】"

      # 模块名来自文件名，去掉换行，免得写进脚本注释时断行成可执行语句
      echo "# --- overwrite source: $(printf '%s' "$name" | tr -d '\r\n') (sid=${sid}) ---" >> "$overwrite_script"
      echo "export OPENCLASH_OVERWRITE_SID='${sid}'" >> "$overwrite_script"

      cfg_name=$(basename "$(uci_get_config "config_path")" 2>/dev/null)
      age_config_name="${cfg_name%.*}"
      age_secret_key=""
      age_public_key=""

      # 本模块声明的参数（k=v 每行一个），只给 kjx_ovr_expand 用 —— 只有这里面的键会被替换
      OVERWRITE_PARAM_LINES=""
      param=$(uci -q get openclash_kejibear."$sid".param 2>/dev/null || echo '')
      if [ -n "$param" ]; then
         OLD_IFS="$IFS"
         IFS=';'
         for kv in $param; do
            [ -z "$kv" ] && continue
            k="${kv%%=*}"
            v="${kv#*=}"
            k=$(printf "%s" "$k" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
            v=$(printf "%s" "$v" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
            [ -z "$k" ] && continue
            # 🔴 键名必须是合法变量名：上游 `export ${varname}=${v_escaped}` 不加引号，
            # 值里有空格会被拆成好几个 export 参数。现在键名先校验、整体加引号导出
            # （导出仍保留，[Overwrite] 里的 ruby_* 行是 shell，照旧可以用 $k 引用）
            case "$k" in
               [A-Za-z_]*) ;;
               *) continue ;;
            esac
            case "$k" in
               *[!A-Za-z0-9_]*) continue ;;
            esac
            export "${k}=${v}"
            OVERWRITE_PARAM_LINES="${OVERWRITE_PARAM_LINES}${k}=${v}
"
         done
         IFS="$OLD_IFS"
      fi

      in_general=0
      in_overwrite=0
      in_yaml=0
      download_file_lines=""

      while IFS= read -r line || [ -n "$line" ]; do
         trimmed=$(printf "%s" "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
         case "$trimmed" in
               "[General]"*) in_general=1; in_overwrite=0; in_yaml=0; continue;;
               "[Overwrite]"*) in_general=0; in_overwrite=1; in_yaml=0; continue;;
               "[YAML]"*) in_general=0; in_overwrite=0; in_yaml=1; continue;;
               "["*"]"*) in_general=0; in_overwrite=0; in_yaml=0; continue;;
         esac
         [ -z "$trimmed" ] && continue
         echo "$trimmed" | grep -qE '^[#;]' && continue

         if [ "$in_general" -eq 1 ]; then
            key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g')
            key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ')
            if printf "%s" "$key_u" | grep -q "^DOWNLOAD_FILE$"; then
               download_file_lines="${download_file_lines}
  ${trimmed}"
            fi
         fi
      done < "$file"

      download_failed=0
      download_file_lines_tmp="/tmp/openclash-kejibear_download_file_lines.$$"
      printf "%s\n" "$download_file_lines" | sed '/^$/d' > "$download_file_lines_tmp"

      while IFS= read -r trimmed; do
         key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g')
         val=$(echo "$trimmed" | sed 's/^[^=]*=[[:space:]]*//')
         key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ')
         # 🔴 不再 eval：只做模块参数替换，再剥掉首尾空白和一层引号（上游 eval 顺带剥引号）
         url=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*url[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         path=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*path[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         cron=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*cron[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         force=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*force[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         ua=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*ua[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         restart=$(kjx_ovr_expand_str "$(printf '%s\n' "$val" | sed -nE 's/.*restart[[:space:]]*=[[:space:]]*([^,]*).*/\1/p')" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
         [ -z "$cron" ] && cron=0
         if [ -z "$path" ] || [ -z "$url" ]; then
            LOG_WARN "DOWNLOAD FILE no target in【Download Job => file: $file】"
            download_failed=1
            break
         fi
         if ! kjx_ovr_download_ok "$url" "$path" "$cron" "$ua"; then
            LOG_WARN "DOWNLOAD FILE skipped, url / path / cron / ua not allowed in【Download Job => file: $file】"
            download_failed=1
            break
         fi
         need_download=0
         if [ ! -f "$path" ] || [ "$force" = "true" ]; then
            need_download=1
         fi
         if [ "$need_download" -eq 1 ] && [ -n "$url" ]; then
            LOG_TIP "DOWNLOAD FILE for【Download Job => file: $file, url: $url, path: $path, ua: ${ua:-null}, force: ${force:-false}】"
            if command -v curl >/dev/null 2>&1; then
               if [ -n "$ua" ]; then
                  DOWNLOAD_FILE_CURL "$url" "$path" "$path" "$ua"
               else
                  DOWNLOAD_FILE_CURL "$url" "$path" "$path"
               fi
               rc=$?
            fi
            if [ $rc -eq 1 ] || [ ! -f "$path" ]; then
               LOG_ERROR "DOWNLOAD FILE failed for【Download Job => file: $file, url: $url, path: $path】"
               download_failed=1
               break
            fi
         fi
         if [ "$cron" != "0" ]; then
            LOG_TIP "Add Cron for【Cron Job => time: $cron, url: $url, path: $path, restart: ${restart:-false}】"
            if ! grep -q "$url" $CRON_FILE 2>/dev/null; then
               if [ -n "$ua" ]; then
                  cron_cmd="$cron source /usr/share/openclash-kejibear/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"$path\" \"$path\" \"$ua\""
               else
                  cron_cmd="$cron source /usr/share/openclash-kejibear/openclash_curl.sh && DOWNLOAD_FILE_CURL \"$url\" \"$path\" \"$path\""
               fi
               if [ "$restart" = "1" ] || [ "$restart" = "true" ]; then
                  cron_cmd="$cron_cmd && [ \"\$?\" -eq 0 ] && /etc/init.d/openclash-kejibear restart"
               fi
               cron_cmd="$cron_cmd #openclash-kejibear-overwrite-download"
               echo "$cron_cmd" >> $CRON_FILE
            fi
         fi
      done < "$download_file_lines_tmp"

      rm -f "$download_file_lines_tmp"

      [ "$download_failed" -eq 1 ] && continue

      in_general=0
      in_overwrite=0
      in_yaml=0
      yaml_block_raw="${overwrite_block_dir}/${sid}.raw"
      yaml_block_file="${overwrite_block_dir}/${sid}.yaml"
      rm -f "$yaml_block_raw" "$yaml_block_file"
      while IFS= read -r line || [ -n "$line" ]; do
         trimmed=$(printf "%s" "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
         case "$trimmed" in
               "[General]"*) in_general=1; in_overwrite=0; in_yaml=0; continue;;
               "[Overwrite]"*) in_general=0; in_overwrite=1; in_yaml=0; continue;;
               "[YAML]"*) in_general=0; in_overwrite=0; in_yaml=1; continue;;
               "["*"]"*) in_general=0; in_overwrite=0; in_yaml=0; continue;;
         esac
         [ -z "$trimmed" ] && continue
         echo "$trimmed" | grep -qE '^[#;]' && continue

         if [ "$in_general" -eq 1 ]; then
            key=$(printf "%s" "$trimmed" | awk -F'=' '{gsub(/[[:space:]]+$/,"",$1); print $1}' | sed 's/[[:space:]]*$//;s/ //g')
            key_u=$(printf "%s" "$key" | tr 'a-z' 'A-Z' | tr -d ' ')
            if printf "%s" "$key_u" | grep -q "^DOWNLOAD_FILE$"; then
               continue
            fi
            val=$(echo "$trimmed" | sed 's/^[^=]*=[[:space:]]*//')
            # 🔴 N-OVR：覆写模块（可以是远程订阅）只要写一行 AGE_SECRET_KEY=，
            # 就能把当前生效的托管订阅的密钥换成攻击者的 —— 之后插件用他的公钥
            # 在本机加密落盘，他就能解开；或者解密失败触发反复重建密钥 + 整机重启。
            # CONFIG_FILE 能持久改指活动配置，CORE_TYPE 能绕开「托管锁 Meta」。
            # 托管态下这几个键一律跳过。
            if [ "$key_u" = "AGE_SECRET_KEY" ] || [ "$key_u" = "AGE_PUBLIC_KEY" ] \
               || [ "$key_u" = "CONFIG_FILE" ] || [ "$key_u" = "CORE_TYPE" ]; then
               if kjx_is_managed "$age_config_name"; then
                  LOG_WARN "skip key on managed config【General Key => $name: $key_u】"
                  continue
               fi
            fi
            if printf "%s" "$key_u" | grep -q "^CONFIG_FILE$"; then
               val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
               RAW_CONFIG_FILE=$(kjx_ovr_expand_str "$val_clean")
               uci -q set openclash_kejibear.@overwrite[0].config_path="$RAW_CONFIG_FILE"
               cfg_name=$(basename "$RAW_CONFIG_FILE" 2>/dev/null)
               if [ -n "$cfg_name" ]; then
                  age_config_name="${cfg_name%.*}"
                  CONFIG_FILE="/etc/openclash-kejibear/${cfg_name}"
                  TMP_CONFIG_FILE="/tmp/${cfg_name}"
               fi
            elif printf "%s" "$key_u" | grep -q "^SUB_INFO_URL$"; then
               val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
               url_key=$(kjx_ovr_expand_str "$val_clean")
               [ -z "$url_key" ] && continue
               # 🔴 这个值会进 uci subscribe_info，LuCI 查流量时拼进 curl 命令执行；
               # 覆写模块可以来自远程订阅，不收紧就是一条 root 命令执行的路。
               case "$url_key" in
                  http://*|https://*) ;;
                  *) LOG_WARN "skip invalid SUB_INFO_URL【$name】"; continue ;;
               esac
               if printf '%s' "$url_key" | grep -q '[[:space:]]' || ! kjx_no_shell_meta "$url_key"; then
                  LOG_WARN "skip invalid SUB_INFO_URL【$name】"
                  continue
               fi
               config_load "openclash_kejibear"
               config_foreach sub_info_set "subscribe_info" "${cfg_name%.*}" "$url_key"
               if [ "$sub_info_setted" != "1" ]; then
                  uci -q add openclash_kejibear subscribe_info
                  uci -q set openclash_kejibear.@subscribe_info[-1].name="${cfg_name%.*}"
                  uci -q add_list openclash_kejibear.@subscribe_info[-1].url="$url_key"
               fi
            elif printf "%s" "$key_u" | grep -q "^AGE_SECRET_KEY$"; then
               val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
               val_key=$(kjx_ovr_expand_str "$val_clean")
               [ -z "$val_key" ] && continue
               age_secret_key="$val_key"
            elif printf "%s" "$key_u" | grep -q "^AGE_PUBLIC_KEY$"; then
               val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
               val_key=$(kjx_ovr_expand_str "$val_clean")
               [ -z "$val_key" ] && continue
               age_public_key="$val_key"
            elif printf "%s" "$key_u" | grep -q "^RESTART$"; then
               val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
               val_key=$(kjx_ovr_expand_str "$val_clean")
               if printf "%s" "$val_key" | grep -qE '^(1|true|yes)$'; then
                  eval "OVERWRITE_RESTART_FLAG_$(printf '%s' "$name" | tr -c 'A-Za-z0-9_' '_')=1"
               fi
            else
               if echo "$allowed_keys_list" | grep -xq "$key_u"; then
                  key_l=$(printf "%s" "$key_u" | tr 'A-Z' 'a-z' | tr -d ' ')
                  val_clean=$(printf "%s" "$val" | sed "s/^[[:space:]]*['\"]//;s/['\"][[:space:]]*$//")
                  val_key=$(kjx_ovr_expand_str "$val_clean")
                  if check_type "$key_u" "$val_key"; then
                     uci -q set openclash_kejibear.@overwrite[0]."$key_l"="$val_key"
                  else
                     LOG_WARN "skip General value not allowed【General Key => $name: $key_u】"
                  fi
               else
                  LOG_WARN "skip General key not allowed【General Key => $name: $key_u】"
               fi
            fi
         elif [ "$in_overwrite" -eq 1 ]; then
            # 🔴 [Overwrite] 段按设计就是 shell：原样追加进 /tmp/yaml_overwrite.sh 执行，
            # 这道 ^ruby_ 检查挡不住 `ruby_edit ...; reboot`。也就是说**覆写模块本身必须是可信的**，
            # 远程订阅来的模块照样能以 root 执行命令 —— 上面去掉 eval、收紧 [General] / DOWNLOAD_FILE
            # 只是不让 [General]、[YAML] 这些「看起来是数据」的地方再能执行代码，不是沙箱
            if printf "%s" "$trimmed" | grep -qE '^ruby_[a-z_]+\b'; then
               echo "$trimmed" >> "$overwrite_script"
               LOG_TIP "Load Overwrite Script【Ruby Script => $trimmed】"
            else
               LOG_WARN "skip invalid Overwrite command【Ruby Script => $name: $trimmed】"
            fi
         elif [ "$in_yaml" -eq 1 ]; then
            # 🔴 原样写（保留缩进），参数替换在整块写完后由 kjx_ovr_expand 一次做完
            (umask 077; printf '%s\n' "$line" >> "$yaml_block_raw")
         fi
      done < "$file"

      if [ -n "$age_config_name" ] && { [ -n "$age_secret_key" ] || [ -n "$age_public_key" ]; }; then
         # N-OVR④：再判一次目标名。上面那道按键名的拦截挡不住「先用 CONFIG_FILE
         # 把 age_config_name 改成托管名、再写 AGE 键」这种顺序绕过。
         if kjx_is_managed "$age_config_name"; then
            LOG_WARN "skip age keys on managed config【$age_config_name】"
         else
            uci_set_age_keys_by_name "$age_config_name" "$age_secret_key" "$age_public_key"
         fi
      fi

      if [ -s "$yaml_block_raw" ]; then
         LOG_TIP "Load YAML Override Block【YAML Block => $name】"
         (umask 077; kjx_ovr_expand < "$yaml_block_raw" > "$yaml_block_file")
      fi
      rm -f "$yaml_block_raw"
      [ -s "$yaml_block_file" ] || yaml_block_file=""

      # 🔴 本模块的 [YAML] 块和 ruby_* 段在同一个 Ruby 进程里按顺序做完，
      # 同时写回配置和 marshal（见 ruby.sh ruby_overwrite_module_apply）。
      # 这一行只有我们自己的常量路径和 sid（uci 段名，只含字母数字下划线），不含模块内容
      echo "ruby_overwrite_module_apply \"\$CONFIG_FILE\" '${yaml_block_file}' \"/tmp/yaml_openclash_ruby_parts/\$OPENCLASH_OVERWRITE_SID\" >> \$LOG_FILE 2>&1" >> "$overwrite_script"

      echo "" >> "$overwrite_script"
   done

   if [ -n "$(uci -q show openclash_kejibear.@overwrite[0] | grep -v '=overwrite$')" ]; then
      # 🔴 上游这里是 eval "$(uci show ... | sed 's/=/="/;s/$/"/')" —— 把 uci 值包进双引号再 eval，
      # 覆写模块写进来的字面值（现在 [General] 不再 eval，$(...)、反引号会原样落进 uci）
      # 会在这里被执行一次。改成逐行 read 赋值：值只是数据，不经过任何展开
      while IFS='=' read -r key value; do
         [ -z "$key" ] && continue
         key_clean=$(echo "$key" | sed 's/^openclash_kejibear\.[^.]*\.//')
         value_clean=$(printf '%s\n' "$value" | sed "s/^'//;s/'$//")
         [ -z "$key_clean" ] && continue
         case "$key_clean" in
            *[!A-Za-z0-9_]*|[0-9]*) ;;
            *) IFS= read -r "$key_clean" <<VALUE_EOF
$value_clean
VALUE_EOF
               ;;
         esac
         LOG_TIP "Load Overwrite Script【$key_clean => '$value_clean'】"
      done <<EOF
$(uci -q show openclash_kejibear.@overwrite[0] | grep -v '=overwrite$' | sed 's/^openclash_kejibear\.@overwrite\[0\]\.//g')
EOF
   else
      clear_overwrite_set
   fi
}

clear_overwrite_set()
{
   uci -q delete openclash_kejibear.@overwrite[0]
   uci -q commit openclash_kejibear
}

get_config()
{
   RAW_CONFIG_FILE=$(uci_get_config "config_path")
   CFG_NAME=$(basename "$RAW_CONFIG_FILE" 2>/dev/null)
   CONFIG_FILE="/etc/openclash-kejibear/${CFG_NAME}"
   TMP_CONFIG_FILE="/tmp/${CFG_NAME}"
   CFG_NO_EXT_NAME="${CFG_NAME%.*}"
   SECRET_KEY=$(uci_get_age_secret_keys "$CFG_NO_EXT_NAME")
   # C4：不再读取 oix 键（置空即可，下游的 core_type="Oix" 分支与 procd env
   # 随之恒为空）。存量 uci 键由 uci-defaults 迁移清除。
   OIX_TOKEN=""
   OIX_PARAMS=""
   enable=$(uci_get_config "enable")
   enable_custom_clash_rules=$(uci_get_config "enable_custom_clash_rules")
   da_password=$(uci_get_config "dashboard_password")
   cn_port=$(uci_get_config "cn_port")
   proxy_port=$(uci_get_config "proxy_port")
   tproxy_port=$(uci_get_config "tproxy_port" || echo 7895)
   proxy_mode=$(uci_get_config "proxy_mode")
   ipv6_enable=$(uci_get_config "ipv6_enable")
   ipv6_dns=$(uci_get_config "ipv6_dns" || echo 0)
   ipv6_mode=$(uci_get_config "ipv6_mode" || echo 0)
   enable_v6_udp_proxy=$(uci_get_config "enable_v6_udp_proxy" || echo 0)
   http_port=$(uci_get_config "http_port")
   socks_port=$(uci_get_config "socks_port")
   enable_redirect_dns=$(uci_get_config "enable_redirect_dns" || echo 1)
   if [ "$(uci_get_config "fakeip_range")"  == "0" ]; then
      fakeip_range=$(ruby_read "$RAW_CONFIG_FILE" "['dns']['fake-ip-range']")
   else
      fakeip_range=$(uci_get_config "fakeip_range")
   fi
   [ -z "$fakeip_range" ] && fakeip_range="198.18.0.1/16"

   if [ "$(uci_get_config "fakeip_range6")"  == "0" ]; then
      fakeip_range6=$(ruby_read "$RAW_CONFIG_FILE" "['dns']['fake-ip-range6']")
   else
      fakeip_range6=$(uci_get_config "fakeip_range6")
   fi
   if [ -z "$fakeip_range6" ]; then
      fakeip_range6="fdfe:dcba:9876::1/64"
      fake_ip_range6_enable=0
   else
      fake_ip_range6_enable=1
   fi

   lan_interface_name=$(uci_get_config "lan_interface_name" || echo 0)
   if [ "$lan_interface_name" = "0" ]; then
      lan_ip=$(uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' 2>/dev/null | tr -d '\n' || ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w "inet" 2>/dev/null |grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n' || ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n')
   else
      lan_ip=$(ip address show $lan_interface_name 2>/dev/null | grep -w "inet" 2>/dev/null | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n')
   fi

   wan_ip4s=$(/usr/share/openclash-kejibear/openclash_get_network.lua "wanip" 2>/dev/null)
   wan_ip6s=$(ifconfig | grep 'inet6 addr' | awk '{print $3}' 2>/dev/null)
   log_level=$(uci_get_config "log_level")
   intranet_allowed=$(uci_get_config "intranet_allowed")
   enable_udp_proxy=$(uci_get_config "enable_udp_proxy" || echo 1)
   disable_udp_quic=$(uci_get_config "disable_udp_quic")
   operation_mode=$(uci_get_config "operation_mode")
   lan_ac_mode=$(uci_get_config "lan_ac_mode")
   enable_rule_proxy=$(uci_get_config "enable_rule_proxy")
   stack_type=$(uci_get_config "stack_type")
   stack_type_v6=$(uci_get_config "stack_type_v6" || echo "system")
   china_ip_route=$(uci_get_config "china_ip_route"); [[ "$china_ip_route" != "0" && "$china_ip_route" != "1" && "$china_ip_route" != "2" ]] && china_ip_route=0
   china_ip6_route=$(uci_get_config "china_ip6_route"); [[ "$china_ip6_route" != "0" && "$china_ip6_route" != "1" && "$china_ip6_route" != "2" ]] && china_ip6_route=0
   small_flash_memory=$(uci_get_config "small_flash_memory")
   mixed_port=$(uci_get_config "mixed_port")
   interface_name=$(uci_get_config "interface_name" || echo 0)
   common_ports=$(uci_get_config "common_ports")
   dns_port=$(uci_get_config "dns_port")
   store_fakeip=$(uci_get_config "store_fakeip" || echo 0)
   bypass_gateway_compatible=$(uci_get_config "bypass_gateway_compatible" || echo 0)
   core_version=$(uci_get_config "core_version" || echo 0)
   router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1)
   enable_meta_sniffer=$(uci_get_config "enable_meta_sniffer" || echo 0)
   enable_meta_sniffer_custom=$(uci_get_config "enable_meta_sniffer_custom" || echo 0)
   geodata_loader=$(uci_get_config "geodata_loader" || echo 0)
   enable_geoip_dat=$(uci_get_config "enable_geoip_dat" || echo 0)
   enable_tcp_concurrent=$(uci_get_config "enable_tcp_concurrent" || echo 0)
   append_default_dns=$(uci_get_config "append_default_dns" || echo 0)
   enable_meta_sniffer_pure_ip=$(uci_get_config "enable_meta_sniffer_pure_ip" || echo 0)
   find_process_mode=$(uci_get_config "find_process_mode" || echo 0)
   upnp_lease_file=$(uci -q get upnpd.config.upnp_lease_file)
   enable_unified_delay=$(uci_get_config "enable_unified_delay" || echo 0)
   enable_respect_rules=$(uci_get_config "enable_respect_rules" || echo 0)
   intranet_allowed_wan_name=$(uci_get_config "intranet_allowed_wan_name" || echo 0)
   custom_fakeip_filter_mode=$(uci_get_config "custom_fakeip_filter_mode" || echo "blacklist")
   iptables_compat=$(iptables -m owner -h 2>/dev/null | grep "owner match options" || command -v fw4 || echo 0)
   disable_quic_go_gso=$(uci_get_config "disable_quic_go_gso" || echo 0)
   smart_enable=$(uci_get_config "smart_enable" || echo 0)
   cors_allow=$(uci_get_config "dashboard_forward_domain" || echo 0)
   geo_custom_url=$(uci_get_config "geo_custom_url" || echo 0)
   geoip_custom_url=$(uci_get_config "geoip_custom_url" || echo 0)
   geosite_custom_url=$(uci_get_config "geosite_custom_url" || echo 0)
   geoasn_custom_url=$(uci_get_config "geoasn_custom_url" || echo 0)
   global_ua=$(uci_get_config "global_ua" || echo 0)
   auto_smart_switch=$(uci_get_config "auto_smart_switch" || echo 0)
   lgbm_auto_update=$(uci_get_config "lgbm_auto_update" || echo 0)
   lgbm_custom_url=$(uci_get_config "lgbm_custom_url" || echo "https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin")
   lgbm_update_interval=$(uci_get_config "lgbm_update_interval" || echo 72)
   smart_collect=$(uci_get_config "smart_collect" || echo 0)
   smart_collect_size=$(uci_get_config "smart_collect_size" || echo 100)
   smart_collect_rate=$(uci_get_config "smart_collect_rate" || echo 1)
   smart_policy_priority=$(uci_get_config "smart_policy_priority" || echo 0)
   smart_enable_lgbm=$(uci_get_config "smart_enable_lgbm" || echo 0)
   smart_prefer_asn=$(uci_get_config "smart_prefer_asn" || echo 0)
   smart_tolerance=$(uci_get_config "smart_tolerance" || echo 0)

   [ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash_kejibear.config.dns_port=7874
   uci -q commit openclash_kejibear
}

# 与上游 OpenClash、旧包名科技熊插件（两者都是 /etc/init.d/openclash）运行互斥：
# 两个透明代理会争抢 DNS 劫持、防火墙规则与端口，同时运行必然断网。
# 我们启动时若发现对方在运行或开机自启，就停掉并禁用它（不卸载，用户仍可手动切回）。
kjx_stop_other_openclash()
{
   local other=/etc/init.d/openclash
   [ -x "$other" ] || return 0
   local running=0
   ubus call service list '{"name":"openclash"}' 2>/dev/null | grep -q '"running": true' && running=1
   if [ "$running" = "1" ] || "$other" enabled >/dev/null 2>&1; then
      LOG_WARN "检测到 OpenClash 正在运行或开机自启，已将其停止并禁用（两个代理插件不能同时运行）"
      "$other" stop >/dev/null 2>&1
      "$other" disable >/dev/null 2>&1
      uci -q set openclash.config.enable=0 && uci -q commit openclash
   fi
}

# 把配置里 proxy-providers / rule-providers 的 path 统一收进 ./proxy_provider、./rule_provider
# （原来是启动 Step 3 里的一段内联 ruby，抽成函数是因为预检回退时快照也要照做一遍）
yml_provider_path_fix()
{
   ruby -ryaml -rYAML -I "/usr/share/openclash-kejibear" -E UTF-8 -e "
      begin
         threads = []
         Value = YAML.load_file('$1')
         provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'}
         provider_configs.each do |provider_type, path_prefix|
            if Value.key?(provider_type) && Value[provider_type].is_a?(Hash)
               Value[provider_type].each do |name, config|
                  threads << Thread.new {
                     begin
                        path_val = config['path']
                        if path_val && !path_val.to_s.match?(%r{^\./#{Regexp.escape(path_prefix)}/})
                           config['path'] = File.join('.', path_prefix, File.basename(path_val.to_s))
                        elsif (path_val.nil? || path_val.to_s == '') && config['type'].to_s == 'http'
                           config['path'] = File.join('.', path_prefix, name.to_s)
                        end
                     rescue => e
                        YAML.LOG_ERROR('Edit Provider Path Failed,【%s】' % [e.message])
                     end
                  }
               end
            end
         end
         threads.each(&:join)
         YAML.dump(Value, '$1')
      rescue Exception => e
         YAML.LOG_ERROR('Edit Provider Path Failed,【%s】' % [e.message])
      end
   " >> $LOG_FILE 2>&1

}

# 自定义节点（用户自己买的节点）注入到运行配置，规则见 kjx_custom_nodes.rb。
# 🔴 只对托管订阅做：存储是全局一份、不分订阅，用户切到自己的订阅时不该被塞进这些节点。
# 注入失败（exit 1）时脚本保证配置原样未动，这里不需要再处理；
# 存储里是明文凭据，不给命令行传内容，只传路径（不出现在 ps 里）
KJX_CUSTOM_NODES_STORE="/etc/openclash-kejibear/kjx/custom_nodes.json"

kjx_custom_nodes_apply()
{
   [ -s "$KJX_CUSTOM_NODES_STORE" ] || return 0
   kjx_is_managed "$(basename "${RAW_CONFIG_FILE%.*}")" || return 0
   ruby -I "/usr/share/openclash-kejibear" -E UTF-8 /usr/share/openclash-kejibear/kjx_custom_nodes.rb \
   apply "$TMP_CONFIG_FILE" "$KJX_CUSTOM_NODES_STORE" >> $LOG_FILE 2>&1
}

# ---------------------------------------------------------------------------
# 🔴 FIX2：启动前预检 + 回退，代替「内核起不来 → start_fail 关服务」
#
# 以前没有任何地方对**合并后的运行配置**跑过 `clash -t`（openclash.sh 只测下载下来的原件）。
# 用户覆写 / 自定义覆写脚本 / 自定义节点都是在原件之上改的：覆写里引用了一个策略组，
# 哪天托管配置把这个组改了名，每日更新后的那次重启内核就起不来，check_core_status 走
# start_fail 把 enable 置 0 —— 用户断网，而且重启路由器也不会自己恢复。
#
# 现在的做法（只在 Step 3 真正重建了运行配置时，QUICK_START 用的是上次测过的那份）：
#   ① yml_rules_change 之后、任何用户侧修改之前，给 TMP_CONFIG_FILE 拍一份快照
#   ② kjx_final_config_assert 之后、start_run_core 之前，用内核测合并结果（顺利时只测这一次）
#   ③ 不过 → 快照（不含用户侧修改）能过就用快照；再不行，上一份运行配置能过就留着它不动；
#      都不行才照旧往下走（该失败还是失败，不比以前更糟）
# 只有内核明确说「test failed」才算不过；超时、内核没输出这类说不清的情况一律按原流程走，
# 不能因为预检本身出问题反而把用户的覆写扔掉。
#
# 快照放在 /tmp/yaml_kjx_preflight/ 下、**文件名与运行配置相同**：YAML.rb 是按文件名找 age
# 密钥的，换了名字托管配置就会被当成普通配置以明文 dump。目录 0700，启动末尾的
# rm -rf /tmp/yaml_* 会连同它一起清掉。
#
# 回退标记放 /tmp/kjx/ 而不是 /tmp/openclash-kejibear/：后者是装包时 preinst 备份
# /etc/openclash-kejibear 用的目录名，它事先存在的话 `cp -rf` 会把备份拷进子目录，
# 升级后用户的配置就恢复不回来了。
# ---------------------------------------------------------------------------
KJX_PREFLIGHT_DIR="/tmp/yaml_kjx_preflight"
KJX_PREFLIGHT_OUT="/tmp/yaml_kjx_preflight_out"
KJX_OVERWRITE_FALLBACK_FLAG="/tmp/kjx/overwrite_fallback"
KJX_PREFLIGHT_TIMEOUT=60

# ① 快照：原样复制（托管配置此时就是 YAML.dump 出来的密文，复制过去仍是密文）
kjx_preflight_snapshot()
{
   rm -rf "$KJX_PREFLIGHT_DIR"
   [ -f "$TMP_CONFIG_FILE" ] || return 0
   (umask 077; mkdir -p "$KJX_PREFLIGHT_DIR" && cp "$TMP_CONFIG_FILE" "$KJX_PREFLIGHT_DIR/$CFG_NAME") 2>/dev/null \
   || rm -rf "$KJX_PREFLIGHT_DIR"
}

# 用内核校验一份配置。0 = 通过，1 = 内核明确判定不通过，2 = 说不清（超时/无内核/无输出）
# 限时复用 kjx_with_timeout（系统没有 timeout 命令时它自己看门）。
# 🔴 环境与 start_run_core 给正式内核的完全一致：
#   · SAFE_PATHS —— yml_change 把每份配置的 external-ui 都指到 /usr/share/openclash-kejibear/ui，
#     少了它内核一律判 "path is not subpath of home directory or SAFE_PATHS"，
#     预检回回误报失败、快照和上一份也都过不了，回退链形同虚设（VM 上实测）；
#   · age 私钥走环境变量 CLASH_AGE_SECRET_KEY，不用 -age-secret-key 放命令行 ——
#     /proc/<pid>/cmdline 谁都能读，而一次回退最多要测四回
kjx_core_test()
{
   local cfg="$1"
   [ -x "$CLASH" ] || return 2
   [ -f "$cfg" ] || return 1
   (umask 077; : > "$KJX_PREFLIGHT_OUT")
   (
      export SAFE_PATHS="$KJX_CORE_SAFE_PATHS"
      [ -n "$SECRET_KEY" ] && export CLASH_AGE_SECRET_KEY="$SECRET_KEY"
      kjx_with_timeout "$KJX_PREFLIGHT_TIMEOUT" "$CLASH" -t -d "$CLASH_CONFIG" -f "$cfg"
   ) > "$KJX_PREFLIGHT_OUT" 2>&1
   grep -q "test is successful" "$KJX_PREFLIGHT_OUT" 2>/dev/null && return 0
   grep -q "test failed" "$KJX_PREFLIGHT_OUT" 2>/dev/null && return 1
   return 2
}

# 内核最近一次校验的报错，一行一条（最多 5 条），去掉 time=/level= 前缀并抹掉地址与私钥
kjx_core_test_errors()
{
   grep -E 'level=(error|fatal)|test failed' "$KJX_PREFLIGHT_OUT" 2>/dev/null \
   | grep -v 'test failed' \
   | sed -e 's/^.*level=[a-z]* msg=//' -e 's/^"//;s/"$//' \
   | kjx_sanitize | head -n 5
}

# 运行配置的「端口 / 运行模式」指纹：yml_change 按这些 uci 值生成配置，set_firewall、
# change_dnsmasq 又按**当前**的这些值设防火墙和 dnsmasq。
# 🔴 回退到上一份运行配置前必须比对：用户这次刚改了 Redir/DNS 端口或运行模式（同一次应用里
# 又加了条引用不存在策略组的规则，快照也过不了）时，旧配置能过校验，内核却监听在旧端口上，
# iptables 转发到新端口、dnsmasq 转发给没人监听的端口 —— 服务显示运行中，全屋断网，
# check_core_status 只探 cn_port 也发现不了。上游这种情况是 start_fail，至少看得见、流量走直连。
# 只放端口 / 模式这类跟防火墙 / dnsmasq 对得上号的值，不放密钥和地址（文件在闪存上、会进备份）
kjx_runtime_fingerprint()
{
   echo "en_mode=$en_mode;en_mode_tun=$en_mode_tun;stack_type=$stack_type;stack_type_v6=$stack_type_v6;ipv6_enable=$ipv6_enable;ipv6_mode=$ipv6_mode;ipv6_dns=$ipv6_dns;proxy_port=$proxy_port;tproxy_port=$tproxy_port;dns_port=$dns_port;mixed_port=$mixed_port;http_port=$http_port;socks_port=$socks_port;cn_port=$cn_port;interface_name=$interface_name;core_type=$core_type;enable_redirect_dns=$enable_redirect_dns;router_self_proxy=$router_self_proxy;fakeip_range=$fakeip_range"
}

kjx_overwrite_fallback_mark()
{
   mkdir -p "${KJX_OVERWRITE_FALLBACK_FLAG%/*}" 2>/dev/null
   {
      echo "time=$(date "+%Y-%m-%d %H:%M:%S")"
      echo "mode=$1"
      echo "reason=$2"
   } > "$KJX_OVERWRITE_FALLBACK_FLAG" 2>/dev/null
}

# ②③ 预检入口。KJX_KEEP_RUNTIME=1 表示回退到了上一份运行配置，start_run_core 不再覆盖它
kjx_config_preflight()
{
   local rc reason prev
   KJX_KEEP_RUNTIME=0

   kjx_core_test "$TMP_CONFIG_FILE"
   rc=$?
   if [ "$rc" -ne 1 ]; then
      [ "$rc" -eq 2 ] && LOG_WARN "运行配置预检未能完成（内核超时或无输出），按原流程启动"
      rm -f "$KJX_OVERWRITE_FALLBACK_FLAG"
      rm -rf "$KJX_PREFLIGHT_DIR" "$KJX_PREFLIGHT_OUT"
      return 0
   fi

   reason=$(kjx_core_test_errors | head -n 1)
   [ -z "$reason" ] && reason="test failed"
   LOG_ERROR "合并覆写后的运行配置未通过内核校验："
   kjx_core_test_errors | while IFS= read -r line; do
      LOG_ERROR "  $line"
   done

   # 快照 = 同一份订阅、同样的插件设置，只是没有用户侧修改
   if [ -f "$KJX_PREFLIGHT_DIR/$CFG_NAME" ]; then
      yml_provider_path_fix "$KJX_PREFLIGHT_DIR/$CFG_NAME"
      kjx_final_config_assert "$KJX_PREFLIGHT_DIR/$CFG_NAME"
      if kjx_core_test "$KJX_PREFLIGHT_DIR/$CFG_NAME"; then
         mv -f "$KJX_PREFLIGHT_DIR/$CFG_NAME" "$TMP_CONFIG_FILE"
         # 🔴 这是有意的取舍：整批跳过也包括覆写里的安全加固（代理端口认证、allow-lan: false、
         # bind-address、只监听本机的 external-controller …），以前是内核起不来（断网但不暴露），
         # 现在是带着订阅原样的设置跑起来。所以日志和覆写页的红框都要把这一点说出来
         LOG_WARN "已跳过覆写设置 / 自定义覆写脚本 / 自定义节点：它们合并后的配置未通过校验，本次按未覆写的配置启动。覆写里的安全相关设置（如代理端口认证、allow-lan、bind-address）本次同样没有生效。请检查覆写内容（例如引用了已改名或已删除的策略组）"
         kjx_overwrite_fallback_mark "snapshot" "$reason"
         rm -rf "$KJX_PREFLIGHT_DIR" "$KJX_PREFLIGHT_OUT"
         return 0
      fi
   fi

   # 上一份运行配置：start_run_core 每次替换前会把旧的留成 .bak。
   # 托管配置只认密文（明文副本本就不该在闪存上，也不拿来用）；换过账号 / 密钥重建过的旧副本
   # 用当前私钥解不开，内核校验自然不过，不会被误用。
   # 端口 / 运行模式跟现在对不上的（或没有指纹的，比如升级前留下的）不用，见 kjx_runtime_fingerprint
   for prev in "$CONFIG_FILE" "$CONFIG_FILE.bak"; do
      [ -s "$prev" ] || continue
      if kjx_is_managed "$(basename "$CONFIG_FILE")" && ! kjx_runtime_is_encrypted "$prev"; then
         continue
      fi
      if [ "$(cat "$prev.fp" 2>/dev/null)" != "$(kjx_runtime_fingerprint)" ]; then
         LOG_WARN "上一份运行配置是按不同的端口 / 运行模式设置生成的（或缺少记录），沿用它会与防火墙设置对不上，不回退到它"
         continue
      fi
      kjx_core_test "$prev" || continue
      if [ "$prev" != "$CONFIG_FILE" ]; then
         mv -f "$prev" "$CONFIG_FILE"
         mv -f "$prev.fp" "$CONFIG_FILE.fp"
      fi
      KJX_KEEP_RUNTIME=1
      rm -rf "$TMP_CONFIG_FILE"
      LOG_WARN "新生成的运行配置（含与不含覆写）均未通过校验，已沿用上一次的运行配置启动；覆写设置 / 自定义节点本次未生效，订阅的最新改动也暂未生效"
      kjx_overwrite_fallback_mark "previous" "$reason"
      rm -rf "$KJX_PREFLIGHT_DIR" "$KJX_PREFLIGHT_OUT"
      return 0
   done

   LOG_ERROR "没有可回退的有效配置，按原流程启动"
   rm -f "$KJX_OVERWRITE_FALLBACK_FLAG"
   rm -rf "$KJX_PREFLIGHT_DIR" "$KJX_PREFLIGHT_OUT"
   return 1
}

start_service()
{
   enable=$(uci_get_config "enable")
   [ "$enable" != "1" ] && LOG_WARN "OpenClash Now Disabled, Need Start From Luci Page, Exit..." && exit 0

   kjx_stop_other_openclash

   if procd_running "openclash-kejibear" >/dev/null; then
      LOG_TIP "OpenClash Already Running, Exit..."
      exit 0
   fi

   LOG_TIP "OpenClash Start Running..."

   {
      LOG_OUT "Step 1: Get The Configuration..."
      # Check instead of restart
      check_run_quick
      overwrite_file
      get_config
      config_choose
      do_run_mode

      LOG_OUT "Step 2: Check The Components..."
      do_run_file "$RAW_CONFIG_FILE"

      if ! $QUICK_START; then
         LOG_OUT "Step 3: Modify The Config File..."
         # N-RT②：启动路径也要先过一遍密钥材料检查 —— 与登录、每日更新调的是同一个
         # 函数，四种状态（缺失/不可用/缺公钥/两者矛盾）在三条路径上行为必须一致，
         # 否则会出现「登录时好好的，一重启就坏」这种查不动的故障。
         #
         # 🔴 必须只对托管配置做。无条件调用会给**用户自己的订阅**（乃至插件自带的
         # 默认配置）也生成一对 age 密钥：随后 YAML.dump 发现有公钥就把运行时副本加密，
         # 而内核拿到的 CLASH_AGE_SECRET_KEY 是 get_config 阶段（早于这里）取的空值，
         # 于是内核 fatal："decrypt config error: no identities specified"，服务再也起不来。
         # 实测就是这么炸的，而且炸的是非托管用户 —— 这类人本来完全不该受我们影响。
         if kjx_is_managed "$(basename "${RAW_CONFIG_FILE%.*}")"; then
            kjx_age_keys_ensure "$(basename "${RAW_CONFIG_FILE%.*}")" >/dev/null 2>&1
            # 🔴 密钥可能刚刚被重建（K-1/K-2 两种状态），而 SECRET_KEY 是在 get_config
            # 里取的、早于这一步。不重新取一次，交给内核的就是过期的旧值，
            # 同样会 fatal 在 "no identities specified" —— 这条对托管配置一样成立。
            SECRET_KEY=$(uci_get_age_secret_keys "$CFG_NO_EXT_NAME" | head -n1)
         fi
         config_check
         /usr/share/openclash-kejibear/yml_change.sh \
         "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port"\
         "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns"\
         "$store_fakeip" "$enable_meta_sniffer" "$enable_geoip_dat" "$geodata_loader" "$enable_meta_sniffer_custom"\
         "$interface_name" "$enable_tcp_concurrent" "$core_type" "$append_default_dns" "$enable_meta_sniffer_pure_ip"\
         "$find_process_mode" "$fakeip_range" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay"\
         "$enable_respect_rules" "$custom_fakeip_filter_mode" "$iptables_compat" "$disable_quic_go_gso" "$cors_allow"\
         "$geo_custom_url" "$geoip_custom_url" "$geosite_custom_url" "$geoasn_custom_url"\
         "$lgbm_auto_update" "$lgbm_custom_url" "$lgbm_update_interval" "$smart_collect" "$smart_collect_size"\
         "$fakeip_range6" "$fake_ip_range6_enable" "$global_ua"

         /usr/share/openclash-kejibear/yml_rules_change.sh \
         "$enable_custom_clash_rules" "$TMP_CONFIG_FILE"\
         "$enable_rule_proxy" "$router_self_proxy" "$lan_ip" "$enable_redirect_dns" "$en_mode"\
         "$auto_smart_switch" "$smart_collect" "$smart_collect_rate" "$smart_policy_priority" "$smart_enable_lgbm" "$smart_prefer_asn" "$smart_tolerance"

         # 🔴 FIX2①：插件自己的修改到此为止，下面开始是用户侧的（覆写、自定义覆写脚本、自定义节点）。
         # 先拍快照，合并结果过不了内核校验时拿它兜底（见 kjx_config_preflight）
         kjx_preflight_snapshot

         #Custom overwrite
         # 🔴 这几个中间文件以前只在启动末尾 rm -rf /tmp/yaml_* 时才清：上一次启动中途
         # 退出的话，第一个模块读到的是旧 marshal（旧配置快照），ruby_* 段文件和
         # /tmp/yaml_openclash_ruby_parse 都是追加写，旧段会跟着再执行一遍、越攒越多。
         # 所以跑之前先清。marshal 是解密后的明文配置，覆写一跑完就删，不留到启动结束
         rm -rf /tmp/yaml_overwrite_marshal /tmp/yaml_openclash_ruby_parts /tmp/yaml_openclash_ruby_parse
         if [ -f "/tmp/yaml_overwrite.sh" ]; then
            chmod +x /tmp/yaml_overwrite.sh
            CONFIG_FILE="${TMP_CONFIG_FILE}" /tmp/yaml_overwrite.sh
         fi
         rm -rf /tmp/yaml_overwrite_marshal /tmp/yaml_openclash_ruby_parts /tmp/yaml_overwrite_blocks

         if [ -f "/etc/openclash-kejibear/custom/openclash_custom_overwrite.sh" ]; then
            chmod +x /etc/openclash-kejibear/custom/openclash_custom_overwrite.sh
            /etc/openclash-kejibear/custom/openclash_custom_overwrite.sh "$TMP_CONFIG_FILE"
            ruby_custom_overwrite_apply /tmp/yaml_openclash_ruby_parse >> $LOG_FILE 2>&1
            rm -f /tmp/yaml_openclash_ruby_parse
         fi

         # 🔴 自定义节点放在覆写与自定义覆写脚本之后：用户在覆写里新建的 Selector 组也要
         # 收到节点，剥环看到的也得是最终的组结构；又必须在预检之前，节点写坏了走快照兜底
         kjx_custom_nodes_apply

         #provider path
         yml_provider_path_fix "$TMP_CONFIG_FILE"
      else
         LOG_OUT "Step 3: Quick Start Mode, Skip Modify The Config File..."
      fi

      # C14③/C15(g)：覆写模块、ruby 脚本、自定义覆写脚本都执行完了，
      # 在启动内核之前做最后一次断言（它们都在 yml_change 之后跑，能把值改回去）
      kjx_final_config_assert "$TMP_CONFIG_FILE"

      # 🔴 FIX2②：只在 Step 3 重建了运行配置时预检；QUICK_START 用的是上次已经测过的那份
      KJX_KEEP_RUNTIME=0
      if ! $QUICK_START; then
         kjx_config_preflight
      fi

      LOG_OUT "Step 4: Start Running The Clash Core..."
      start_run_core

      LOG_OUT "Step 5: Add Cron Rules, Start Daemons..."
      add_cron

      LOG_OUT "Step 6: Core Status Checking and Firewall Rules Setting..."
      check_core_status "start" &

      if [ "$ipv6_enable" -eq 0 ] && [ "$(uci -q get dhcp.lan.dhcpv6)" != "disabled" ] && [ -n "$(uci -q get dhcp.lan.dhcpv6)" ]; then
         LOG_WARN "Please Note That Network May Abnormal With IPv6's DHCP Server"
      fi

      rm -rf /tmp/yaml_*
   }

   echo "OpenClash Already Start!"
}

stop_service()
{
   get_config

   LOG_TIP "OpenClash Stoping..."
   LOG_OUT "Step 1: Backup The Current Groups State..."

   {
      /usr/share/openclash-kejibear/openclash_history_get.sh

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

      LOG_OUT "Step 3: Close The OpenClash Services..."
      for process in "openclash_streaming_unlock.lua"; do
         pids=$(unify_ps_pids "$process")
         if [ -n "$pids" ]; then
            for pid in $pids; do
               kill -9 "$pid"
            done
         fi
      done
      # prevent respawn during stopping
      procd_kill "openclash-kejibear"
      for i in $(seq 1 10); do
         procd_running "openclash-kejibear" >/dev/null && sleep 1 || break
      done

      LOG_OUT "Step 4: Restart Dnsmasq..."
      revert_dnsmasq

      LOG_OUT "Step 5: Delete OpenClash Residue File..."
      LOG_TIP "OpenClash Already Stop!"

      if [ "$enable" != "1" ]; then
         rm -rf /tmp/openclash-kejibear_version_history.json \
                /tmp/openclash-kejibear_cdn_info.json \
                /tmp/openclash-kejibear.change \
                /tmp/openclash-kejibear_announcement \
                ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute_pass.conf \
                ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_chnroute6_pass.conf \
                ${DNSMASQ_CONF_DIR}/dnsmasq_kejibear_custom_domain.conf
      fi

      del_cron
      clear_overwrite_set
      rm -rf /tmp/openclash-kejibear_jobs
      rm -rf /tmp/yaml_*
   } >/dev/null 2>&1

   echo "OpenClash Already Stop!"
}

restart()
{
   echo "OpenClash Restart..."
   LOG_TIP "OpenClash Restart..."
   check_run_quick
   stop_service
   start
}

start_watchdog()
{
   procd_open_instance "openclash-watchdog"
   procd_set_param command "/usr/share/openclash-kejibear/openclash_watchdog.sh"
   procd_close_instance
}

reload_service()
{
   get_config
   MAX_RELOAD=10
   if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "firewall" ]; then
      #sleep for avoiding system unready
      sleep 5
      NOW_TS=$(date +%s)
      LAST_LINE=$(grep "Reload OpenClash Firewall Rules...$" "$LOG_FILE" | tail -n 1)
      LAST_TIME=$(echo "$LAST_LINE" | awk '{print $1" "$2}')
      LAST_TS=$(date -d "$LAST_TIME" +%s 2>/dev/null)
      CUR_RELOAD_NUM=$(echo "$LAST_LINE" | grep -oE '【[0-9]+/' | grep -oE '[0-9]+')
      if [ -n "$LAST_TS" ] && [ $((NOW_TS - LAST_TS)) -gt 300 ]; then
         CUR_RELOAD_NUM=0
      fi
      [ -z "$CUR_RELOAD_NUM" ] && CUR_RELOAD_NUM=0
      CUR_RELOAD_NUM=$((CUR_RELOAD_NUM+1))
      [ "$CUR_RELOAD_NUM" -gt "$MAX_RELOAD" ] && CUR_RELOAD_NUM=$MAX_RELOAD
      RELOAD_COUNT=$(grep "Reload OpenClash Firewall Rules...$" "$LOG_FILE" | awk '{print $1" "$2}' | while read t; do
         TS=$(date -d "$t" +%s 2>/dev/null)
         [ -n "$TS" ] && [ $((NOW_TS - TS)) -le 300 ] && echo 1
      done | wc -l)
      if [ "$RELOAD_COUNT" -ge "$MAX_RELOAD" ]; then
         LOG_OUT "【${CUR_RELOAD_NUM}/$MAX_RELOAD】Skip Reload OpenClash Firewall Rules Until 5 Minutes Later..."
         exit 0
      fi
      LOG_OUT "【${CUR_RELOAD_NUM}/$MAX_RELOAD】Reload OpenClash Firewall Rules..."
      revert_firewall
      do_run_mode
      check_core_status &
   fi
   if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "manual" ]; then
      LOG_OUT "Manually Reload Firewall Rules..."
      revert_firewall
      do_run_mode
      check_core_status &
   fi
   if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "revert" ]; then
      revert_firewall
      revert_dnsmasq
   fi
   if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "restore" ]; then
      do_run_mode
      # used for config subscribe, not background for avoiding system unready
      check_core_status
   fi
} >/dev/null 2>&1

boot()
{
   delay_start=$(uci_get_config "delay_start" || echo 0)
   enable=$(uci_get_config "enable")
   if [ "$delay_start" -gt 0 ] && [ "$enable" == "1" ]; then
      LOG_OUT "Enable Delay Start, OpenClash Will Start After【$delay_start】Seconds..."
      sleep "$delay_start"
   fi
   restart
}
