From dd71849c0c146bae262eaf4ada6b1d74a69188a3 Mon Sep 17 00:00:00 2001
From: zxl hhyccc <45259624+zxlhhyccc@users.noreply.github.com>
Date: Tue, 3 Sep 2024 09:13:17 +0800
Subject: [PATCH] add 'fake-ip-filter-mode' in 'dns' (#4011)

* add fake-ip-filter-mode in dns

* chore: refine code

---------

Co-authored-by: vernesong <42875168+vernesong@users.noreply.github.com>
---
 .../model/cbi/openclash/config-overwrite.lua  |  7 +++++
 .../po/zh-cn/openclash.zh-cn.po               | 15 +++++++++++
 luci-app-openclash/root/etc/init.d/openclash  |  3 ++-
 .../root/usr/share/openclash/res/default.yaml |  7 ++++-
 .../root/usr/share/openclash/yml_change.sh    | 27 +++++++++++++++----
 5 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua b/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua
index 2e60fc473a..5c6033ba58 100644
--- a/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua
+++ b/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua
@@ -226,6 +226,13 @@ if op_mode == "fake-ip" then
 o = s:taboption("dns", Flag, "custom_fakeip_filter", translate("Fake-IP-Filter"))
 o.default = 0
 
+o = s:taboption("dns", ListValue, "custom_fakeip_filter_mode", translate("Fake-IP-Filter-Mode"))
+o.description = translate("Fake-IP is not returned if the matching succeeds when blacklist mode or Fake-IP is returned if the matching succeeds when whitelist mode")
+o.default = "blacklist"
+o:value("blacklist", translate("Blacklist Mode"))
+o:value("whitelist", translate("Whitelist Mode"))
+o:depends("custom_fakeip_filter", "1")
+
 custom_fake_black = s:taboption("dns", Value, "custom_fake_filter")
 custom_fake_black.template = "cbi/tvalue"
 custom_fake_black.description = translate("Domain Names In The List Do Not Return Fake-IP, One rule per line")
diff --git a/luci-app-openclash/po/zh-cn/openclash.zh-cn.po b/luci-app-openclash/po/zh-cn/openclash.zh-cn.po
index 93e3514936..653e0024fc 100644
--- a/luci-app-openclash/po/zh-cn/openclash.zh-cn.po
+++ b/luci-app-openclash/po/zh-cn/openclash.zh-cn.po
@@ -3356,3 +3356,18 @@ msgstr "指定正确的 LAN 接口名称"
 
 msgid "For More Useful Meta Core Functions Go Wiki"
 msgstr "如需要了解更多关于 Meta 内核的功能,请前往 Wiki"
+
+msgid "Tip: Because Need Ensure Bypassing IP Option Work, Deleted The Fake-IP-Filter Rule"
+msgstr "提示:为保证绕过 IP 正常工作,已在 Fake-IP-Filter 中删除规则"
+
+msgid "Tip: Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule"
+msgstr "提示:为保证绕过 IP 正常工作,已在 Fake-IP-Filter 中添加规则"
+
+msgid "Fake-IP is not returned if the matching succeeds when blacklist mode or Fake-IP is returned if the matching succeeds when whitelist mode"
+msgstr "黑名单模式表示如果匹配成功则不返回 Fake-IP, 白名单模式时只有匹配成功才返回 Fake-IP"
+
+msgid "Blacklist Mode"
+msgstr "黑名单模式"
+
+msgid "Whitelist Mode"
+msgstr "白名单模式"
\ No newline at end of file
diff --git a/luci-app-openclash/root/etc/init.d/openclash b/luci-app-openclash/root/etc/init.d/openclash
index 6aae15f68a..8712959998 100644
--- a/luci-app-openclash/root/etc/init.d/openclash
+++ b/luci-app-openclash/root/etc/init.d/openclash
@@ -2880,6 +2880,7 @@ get_config()
    keep_alive_interval=$(uci -q get openclash.config.keep_alive_interval || echo "0")
    proxy_dns_group=$(uci -q get openclash.config.proxy_dns_group || echo "Disable")
    intranet_allowed_wan_name=$(uci -q get openclash.config.intranet_allowed_wan_name || echo "0")
+   custom_fakeip_filter_mode=$(uci -q get openclash.config.custom_fakeip_filter_mode || echo "blacklist")
    [ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash.config.dns_port=7874
    uci -q commit openclash
 }
@@ -2907,7 +2908,7 @@ start()
    if ! $quick_start; then
       LOG_OUT "Step 3: Modify The Config File..."
       config_check
-      /usr/share/openclash/yml_change.sh 2>/dev/null "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port" "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns" "$store_fakeip" "$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" "$global_client_fingerprint" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay" "$keep_alive_interval" "$proxy_dns_group"
+      /usr/share/openclash/yml_change.sh 2>/dev/null "$en_mode" "$da_password" "$cn_port" "$proxy_port" "$TMP_CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port" "$log_level" "$proxy_mode" "$en_mode_tun" "$stack_type" "$dns_port" "$mixed_port" "$tproxy_port" "$ipv6_dns" "$store_fakeip" "$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" "$global_client_fingerprint" "$ipv6_mode" "$stack_type_v6" "$enable_unified_delay" "$keep_alive_interval" "$proxy_dns_group" "$custom_fakeip_filter_mode"
       /usr/share/openclash/yml_rules_change.sh 2>/dev/null "$rule_source" "$enable_custom_clash_rules" "$TMP_CONFIG_FILE" "$enable_rule_proxy" "$CONFIG_NAME" "$router_self_proxy" "$lan_ip" "$proxy_port" "$tproxy_port" "$enable_redirect_dns" "$fakeip_range" "$en_mode"
       /usr/share/openclash/openclash_custom_domain_dns.sh >/dev/null 2>&1
       #Custom overwrite
diff --git a/luci-app-openclash/root/usr/share/openclash/res/default.yaml b/luci-app-openclash/root/usr/share/openclash/res/default.yaml
index cbe767a2c8..834f33f901 100644
--- a/luci-app-openclash/root/usr/share/openclash/res/default.yaml
+++ b/luci-app-openclash/root/usr/share/openclash/res/default.yaml
@@ -106,6 +106,11 @@ dns:
   # fake-ip-filter:
   #   - '*.lan'
   #   - localhost.ptlogin2.qq.com
+
+  # The matching mode of fake-ip-filter is set to a blacklist by default.
+  # That is, fake-ip is not returned if the matching succeeds
+  # It can be set to whitelist, that is, fake-ip is returned only after the match is successful
+  fake-ip-filter-mode: blacklist
   
   # Supports UDP, TCP, DoT, DoH. You can specify the port to connect to.
   # All DNS questions are sent directly to the nameserver, without proxies
@@ -469,4 +474,4 @@ rules:
   - DST-PORT,80,DIRECT
   - SRC-PORT,7777,DIRECT
   - RULE-SET,apple,REJECT # Premium only
-  - MATCH,auto
\ No newline at end of file
+  - MATCH,auto
diff --git a/luci-app-openclash/root/usr/share/openclash/yml_change.sh b/luci-app-openclash/root/usr/share/openclash/yml_change.sh
index eb3b30e349..3869f8defc 100644
--- a/luci-app-openclash/root/usr/share/openclash/yml_change.sh
+++ b/luci-app-openclash/root/usr/share/openclash/yml_change.sh
@@ -675,6 +675,11 @@ end;
 begin
 Thread.new{
    if '$custom_fakeip_filter' == '1' then
+      if '${35}' == 'whitelist' then
+      Value['dns']['fake-ip-filter-mode']='whitelist';
+      else
+         Value['dns']['fake-ip-filter-mode']='blacklist';
+      end;
       if '$1' == 'fake-ip' then
          if File::exist?('/etc/openclash/custom/openclash_custom_fake_filter.list') then
             Value_4 = IO.readlines('/etc/openclash/custom/openclash_custom_fake_filter.list');
@@ -702,12 +707,24 @@ Thread.new{
    end;
    if '$1' == 'fake-ip' then
       if '$china_ip_route' != '0' then
-         if Value['dns'].has_key?('fake-ip-filter') and not Value['dns']['fake-ip-filter'].to_a.empty? then
-            Value['dns']['fake-ip-filter'].insert(-1,'geosite:category-games@cn');
-            Value['dns']['fake-ip-filter'].insert(-1,'geosite:cn');
-            Value['dns']['fake-ip-filter']=Value['dns']['fake-ip-filter'].uniq;
+         if Value['dns']['fake-ip-filter-mode'] == 'blacklist' or not Value['dns'].has_key?('fake-ip-filter-mode') then
+            if Value['dns'].has_key?('fake-ip-filter') and not Value['dns']['fake-ip-filter'].to_a.empty? then
+               Value['dns']['fake-ip-filter'].insert(-1,'geosite:category-games@cn');
+               Value['dns']['fake-ip-filter'].insert(-1,'geosite:cn');
+               Value['dns']['fake-ip-filter']=Value['dns']['fake-ip-filter'].uniq;
+            else
+               Value['dns'].merge!({'fake-ip-filter'=>['geosite:category-games@cn,geosite:cn']});
+            end;
+            puts '${LOGTIME} Tip: Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【 geosite:category-games@cn,geosite:cn 】';
          else
-            Value['dns'].merge!({'fake-ip-filter'=>['geosite:category-games@cn,geosite:cn']});
+            if Value['dns'].has_key?('fake-ip-filter') and not Value['dns']['fake-ip-filter'].to_a.empty? then
+               Value['dns']['fake-ip-filter'].each{|x|
+                  if x =~ /(geosite:?).*(@cn|:cn)/ then
+                     Value['dns']['fake-ip-filter'].delete(x);
+                     puts '${LOGTIME} Tip: Because Need Ensure Bypassing IP Option Work, Deleted The Fake-IP-Filter Rule【' + x + '】';
+                  end;
+               };
+            end;
          end;
       end;
    end;