Commit 382e705

HPCesia <me@hpcesia.com>
2026-07-12 13:12:23
Use mihomo tun instead of dae
1 parent c995d08
modules/hosts/kevin/networking.nix
@@ -1,12 +1,20 @@
-{
+{den, ...}: {
   den.hosts.kevin = {
     address = {
       ipv4.tailscale = "100.119.83.79";
       ipv6.tailscale = "fd7a:115c:a1e0:cdc1:45b1:c962:aac4:e0dc";
     };
+    settings.services.proxy.mihomo = {
+      autoStart = false;
+      interfaces.wan = "wlp0s20f3";
+    };
   };
 
   den.aspects.kevin = {
+    includes = [
+      den.aspects.services.proxy.mihomo
+    ];
+
     nixos = {
       networking.networkmanager.enable = true;
     };
modules/hosts/tribios/networking.nix
@@ -4,18 +4,24 @@
       ipv4.tailscale = "100.127.6.231";
       ipv6.tailscale = "fd7a:115c:a1e0:675d:6820:4fa0:fddc:a59";
     };
-    settings.services.proxy.dae.interfaces = {
-      wan = ["auto"];
-      lan = ["br-lan"];
+    settings.services.proxy.mihomo = {
+      autoStart = true;
+      tailscaleWebControl = true;
+      interfaces = {
+        wan = "enP3p49s0";
+        lan = ["br-lan"];
+      };
     };
   };
 
   den.aspects.tribios = {
     includes = [
-      den.aspects.services.proxy
+      den.aspects.services.proxy.mihomo
     ];
 
     nixos = {
+      systemd.services.mihomo.after = ["systemd-networkd.service"];
+
       boot.kernel.sysctl = {
         "net.ipv4.ip_forward" = 1;
         "net.ipv4.conf.all.send_redirects" = 0;
modules/services/proxy/mihomo/default.nix
@@ -0,0 +1,90 @@
+{
+  den,
+  lib,
+  inputs,
+  ...
+}: {
+  den.aspects.services.proxy.mihomo = {
+    settings = {
+      autoStart = lib.mkEnableOption "Auto start mihomo service";
+      tailscaleWebControl = lib.mkEnableOption "Allow connect external controller from tailscale subnet";
+      interfaces = {
+        wan = lib.mkOption {
+          description = "The WAN interface to bind.";
+          type = lib.types.str;
+          default = null;
+        };
+        lan = lib.mkOption {
+          description = "The LAN interface to bind.";
+          type = lib.types.listOf lib.types.str;
+          default = [];
+        };
+      };
+    };
+
+    includes = with den.aspects.services.proxy.mihomo; [
+      dns
+      proxies
+      proxy-groups
+      rules
+      sniffer
+      tun
+    ];
+
+    cache = {
+      directories = [
+        {
+          directory = "/var/lib/mihomo";
+          user = "mihomo";
+          group = "mihomo";
+        }
+      ];
+    };
+
+    nixos = {
+      host,
+      pkgs,
+      ...
+    }: let
+      cfg = host.settings.services.proxy.mihomo;
+    in {
+      imports = [inputs.nur-hpcesia.nixosModules.mihomo];
+
+      services.mihomo = {
+        enable = true;
+        webui = pkgs.metacubexd;
+        processesInfo = true;
+
+        config = {
+          mixed-port = 7890;
+          mode = "rule";
+          ipv6 = false;
+          find-process-mode = "strict";
+          log-level = "warning";
+          interface-name = cfg.interfaces.wan;
+          unified-delay = true;
+          tcp-concurrent = true;
+          geodata-mode = true; # `.dat`
+          geox-url = {
+            geoip = "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat";
+            geosite = "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat";
+          };
+          external-controller = "${
+            if cfg.tailscaleWebControl
+            then host.address.ipv4.tailscale
+            else "127.0.0.1"
+          }:7900";
+          external-controller-cors = {
+            allow-origins = ["*"];
+            allow-private-network = true;
+          };
+        };
+      };
+
+      systemd.services."mihomo" = {
+        after = lib.optional (cfg.tailscaleWebControl) "tailscaled.service";
+        wantedBy = lib.mkIf (!cfg.autoStart) (lib.mkForce []);
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/dns.nix
@@ -0,0 +1,66 @@
+{
+  den.aspects.services.proxy.mihomo.dns = {
+    nixos = {
+      services.mihomo = {
+        config = {
+          dns = {
+            enable = true;
+            listen = ":1053";
+            prefer-h3 = false;
+            ipv6 = false;
+            enhanced-mode = "redir-host";
+            force-dns-mapping = true;
+            respect-rules = true;
+            fake-ip-range = "198.18.0.1/16";
+            fake-ip-filter-mode = "blacklist";
+            fake-ip-filter = [
+              "+.+m2m"
+              "+.$injections.adguard.org"
+              "+.$local.adguard.org"
+              "+.+bogon"
+              "+.+lan"
+              "+.+local"
+              "+.+localdomain"
+              "+.home.arpa"
+              "dns.msftncsi.com"
+              "*.srv.nintendo.net"
+              "*.stun.playstation.net"
+              "xbox.*.microsoft.com"
+              "*.xboxlive.com"
+              "*.turn.twilio.com"
+              "*.stun.twilio.com"
+              "stun.syncthing.net"
+              "stun.*"
+              "*.sslip.io"
+              "*.nip.io"
+              "gate.trin.one"
+            ];
+            nameserver = [
+              "https://8.8.8.8/dns-query"
+              "https://1.1.1.1/dns-query"
+            ];
+            nameserver-policy = {
+              # Tailscale
+              "+.net.trin.one" = "100.100.100.100";
+              ".ts.net" = "100.100.100.100";
+              "*" = "100.100.100.100"; # MagicDNS for machine name
+
+              "geosite:cn,private" = [
+                "https://223.5.5.5/dns-query"
+                "https://119.29.29.29/dns-query"
+              ];
+            };
+            proxy-server-nameserver = [
+              "https://223.5.5.5/dns-query"
+              "https://119.29.29.29/dns-query"
+            ];
+            direct-nameserver = [
+              "https://223.5.5.5/dns-query"
+              "https://223.6.6.6/dns-query"
+            ];
+          };
+        };
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/providers-hong_xing.age
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ AkfcYR/bKvdE3tz9X7f7/E+hAlycxlO5t54xNWiqSR5G
+EfbqiRZd51WbMxO3glbUIpk96oF+g6jmYAfnNplTcII
+-> Ct~qcB-grease isXi sZuy5 .4)FI_
+lFEBjA
+--- 4Bc8MyFX+vmSWf3cZIz3OFYSrGnpyMShZWGDhrbTJVM
+d.b��H� c�	��ڔ��B�mu�ɪj����‡:MK��As)���t�V���p?ϫM��S���1����T��5�z�R�����6�I*`I2cԚ�3�lΊ�H.y��S�P���5$rxi�m
\ No newline at end of file
modules/services/proxy/mihomo/providers-mo_jie.age
Binary file
modules/services/proxy/mihomo/proxies.nix
@@ -0,0 +1,51 @@
+{
+  den.aspects.services.proxy.mihomo.proxies = {
+    nixos = {config, ...}: {
+      services.mihomo = {
+        config = {
+          proxy-providers = let
+            providerParam = {
+              type = "http";
+              interval = 86400;
+              health-check = {
+                enable = true;
+                url = "http://cp.cloudflare.com";
+                interval = 300;
+              };
+            };
+          in {
+            mo_jie =
+              providerParam
+              // {
+                url._secret = config.vaultix.secrets.mihomo-providers-mo_jie.path;
+                path = "./proxy_provider/providers-mo_jie.yaml";
+                override.additional-prefix = "[MJ]";
+              };
+            hong_xing =
+              providerParam
+              // {
+                url._secret = config.vaultix.secrets.mihomo-providers-hong_xing.path;
+                path = "./proxy_provider/providers-hong_xing.yaml";
+                override.additional-prefix = "[HX]";
+              };
+          };
+          proxies = [
+          ];
+        };
+      };
+
+      vaultix.secrets = {
+        mihomo-providers-mo_jie = {
+          file = ./providers-mo_jie.age;
+          owner = "mihomo";
+          group = "mihomo";
+        };
+        mihomo-providers-hong_xing = {
+          file = ./providers-hong_xing.age;
+          owner = "mihomo";
+          group = "mihomo";
+        };
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/proxy-groups.nix
@@ -0,0 +1,133 @@
+{
+  den.aspects.services.proxy.mihomo.proxy-groups = {
+    nixos = {
+      services.mihomo = {
+        config = {
+          proxy-groups = let
+            nonsenseKeywords = "回国|校园|网站|地址|剩余|过期|时间|有效|网址|禁止|邮箱|发布|客服|订阅|节点";
+
+            filterHK = "^(?=.*((?i)🇭🇰|香港|\\b(HK|Hong)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterTW = "^(?=.*((?i)🇹🇼|台湾|\\b(TW|Tai|Taiwan)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterJP = "^(?=.*((?i)🇯🇵|日本|川日|东京|大阪|泉日|埼玉|\\b(JP|Japan)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterKR = "^(?=.*((?i)🇰🇷|韩国|韓|首尔|\\b(KR|Korea)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterSG = "^(?=.*((?i)🇸🇬|新加坡|狮|\\b(SG|Singapore)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterUS = "^(?=.*((?i)🇺🇸|美国|波特兰|达拉斯|俄勒冈|凤凰城|费利蒙|硅谷|拉斯维加斯|洛杉矶|圣何塞|圣克拉拉|西雅图|芝加哥|\\b(US|United States)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterUK = "^(?=.*((?i)🇬🇧|英国|伦敦|\\b(UK|United Kingdom)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterFR = "^(?=.*((?i)🇫🇷|法国|\\b(FR|France)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterDE = "^(?=.*((?i)🇩🇪|德国|\\b(DE|Germany)(\\d+)?\\b))(?!.*((?i)${nonsenseKeywords})).*$";
+            filterOthers = "^(?!.*(🇭🇰|HK|Hong|香港|🇹🇼|TW|Taiwan|Wan|🇯🇵|JP|Japan|日本|🇸🇬|SG|Singapore|狮城|🇺🇸|US|United States|America|美国|🇩🇪|DE|Germany|德国|🇬🇧|UK|United Kingdom|英国|🇰🇷|KR|Korea|韩国|韓|🇫🇷|FR|France|法国)).*$";
+            filterAll = "^(?=.*(.))(?!.*((?i)群|邀请|返利|循环|官网|客服|网站|网址|获取|订阅|流量|到期|机场|下次|版本|官址|备用|过期|已用|联系|邮箱|工单|贩卖|通知|倒卖|防止|国内|地址|频道|无法|说明|使用|提示|特别|访问|支持|教程|关注|更新|作者|加入|(\\b(USE|USED|TOTAL|EXPIRE|EMAIL|Panel|Channel|Author)\\b|(\\d{4}-\\d{2}-\\d{2}|\\d+G)))).*$";
+
+            select = {
+              type = "select";
+              url = "http://connectivitycheck.platform.hicloud.com/generate_204";
+              disable-udp = false;
+              hidden = false;
+              include-all = true;
+            };
+            urlTest = {
+              type = "url-test";
+              url = "http://connectivitycheck.platform.hicloud.com/generate_204";
+              interval = 300;
+              tolerance = 50;
+              disable-udp = false;
+              hidden = true;
+              include-all = true;
+            };
+
+            regions = {
+              HK = {
+                flag = "🇭🇰";
+                filter = filterHK;
+              };
+              TW = {
+                flag = "🇹🇼";
+                filter = filterTW;
+              };
+              JP = {
+                flag = "🇯🇵";
+                filter = filterJP;
+              };
+              KR = {
+                flag = "🇰🇷";
+                filter = filterKR;
+              };
+              SG = {
+                flag = "🇸🇬";
+                filter = filterSG;
+              };
+              US = {
+                flag = "🇺🇸";
+                filter = filterUS;
+              };
+              UK = {
+                flag = "🇬🇧";
+                filter = filterUK;
+              };
+              FR = {
+                flag = "🇫🇷";
+                filter = filterFR;
+              };
+              DE = {
+                flag = "🇩🇪";
+                filter = filterDE;
+              };
+            };
+          in
+            [
+              {
+                name = "SELECT";
+                type = "select";
+                proxies = ["AUTO" "MANUAL" "DIRECT"];
+                url = "http://connectivitycheck.platform.hicloud.com/generate_204";
+                icon = "https://raw.githubusercontent.com/Orz-3/mini/master/Color/Static.png";
+              }
+              {
+                name = "MANUAL";
+                type = "select";
+                proxies = ["Others - MANUAL"] ++ (map (x: "${regions.${x}.flag} - MANUAL") (builtins.attrNames regions));
+                url = "http://connectivitycheck.platform.hicloud.com/generate_204";
+                icon = "https://raw.githubusercontent.com/Orz-3/mini/master/Color/Cylink.png";
+              }
+              {
+                name = "AUTO";
+                type = "select";
+                proxies = map (x: "${regions.${x}.flag} - AUTO") (builtins.attrNames regions);
+                url = "http://connectivitycheck.platform.hicloud.com/generate_204";
+                icon = "https://raw.githubusercontent.com/Orz-3/mini/master/Color/Urltest.png";
+              }
+            ]
+            ++ (map (x:
+              urlTest
+              // {
+                name = "${regions.${x}.flag} - AUTO";
+                filter = regions.${x}.filter;
+              }) (builtins.attrNames regions))
+            ++ (map (x:
+              select
+              // {
+                name = "${regions.${x}.flag} - MANUAL";
+                filter = regions.${x}.filter;
+              }) (builtins.attrNames regions))
+            ++ [
+              (select
+                // {
+                  name = "Others - MANUAL";
+                  filter = filterOthers;
+                })
+              (urlTest
+                // {
+                  name = "AllIn - AUTO";
+                  filter = filterAll;
+                })
+              (select
+                // {
+                  name = "AllIn - MANUAL";
+                  filter = filterAll;
+                })
+            ];
+        };
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/rules.nix
@@ -0,0 +1,248 @@
+{
+  den.aspects.services.proxy.mihomo.rules = {
+    nixos = {
+      services.mihomo = {
+        config = {
+          rules = [
+            # === Non-IP ===
+            # Private
+            "RULE-SET,reject_non_ip,REJECT"
+            "RULE-SET,reject_domainset,REJECT"
+            "RULE-SET,reject_non_ip_drop,REJECT-DROP"
+            "RULE-SET,reject_non_ip_no_drop,REJECT"
+            "RULE-SET,tailscale_non_ip,DIRECT"
+            "RULE-SET,lan_non_ip,DIRECT"
+
+            "RULE-SET,cdn_domainset,SELECT"
+            "RULE-SET,cdn_non_ip,SELECT"
+            "RULE-SET,stream_non_ip,🇺🇸 - AUTO"
+            "RULE-SET,telegram_non_ip,🇺🇸 - AUTO"
+            "RULE-SET,apple_cdn,DIRECT"
+            "RULE-SET,download_domainset,SELECT"
+            "RULE-SET,download_non_ip,SELECT"
+            "RULE-SET,microsoft_cdn_non_ip,DIRECT"
+            "RULE-SET,apple_cn_non_ip,DIRECT"
+            "RULE-SET,apple_services,DIRECT"
+            "RULE-SET,microsoft_non_ip,DIRECT"
+            "RULE-SET,ai_non_ip,🇺🇸 - AUTO"
+            "RULE-SET,global_non_ip,SELECT"
+            "RULE-SET,domestic_non_ip,DIRECT"
+            "RULE-SET,direct_non_ip,DIRECT"
+
+            # Game
+            "DOMAIN-SUFFIX,cm.steampowered.com,DIRECT"
+            "DOMAIN-SUFFIX,steamserver.net,DIRECT"
+            "GEOSITE,steam@cn,DIRECT"
+            "GEOSITE,category-game-platforms-download@cn,DIRECT"
+            "GEOSITE,category-games-cn,DIRECT"
+
+            "DOMAIN-SUFFIX,codeberg.org,DIRECT"
+            "DOMAIN-SUFFIX,kagi.com,DIRECT"
+            "DOMAIN-SUFFIX,mxrouting.net,DIRECT"
+
+            # === IP ===
+            "RULE-SET,reject_ip,REJECT"
+            "RULE-SET,telegram_ip,🇺🇸 - AUTO"
+            "RULE-SET,stream_ip,🇺🇸 - AUTO"
+            "RULE-SET,lan_ip,DIRECT"
+            "RULE-SET,domestic_ip,DIRECT"
+            "RULE-SET,china_ip,DIRECT"
+            "MATCH,SELECT"
+          ];
+
+          rule-providers = let
+            ruleSetClassical = {
+              type = "http";
+              behavior = "classical";
+              interval = 43200;
+              format = "text";
+              proxy = "SELECT";
+            };
+            ruleSetDomain = {
+              type = "http";
+              behavior = "domain";
+              interval = 43200;
+              format = "text";
+              proxy = "SELECT";
+            };
+            ruleSetIpcidr = {
+              type = "http";
+              behavior = "ipcidr";
+              interval = 43200;
+              format = "text";
+              proxy = "SELECT";
+            };
+          in {
+            tailscale_non_ip = {
+              type = "inline";
+              behavior = "classical";
+              payload = [
+                "PROCESS-NAME,tailscale"
+                "PROCESS-NAME,tailscaled"
+                "PROCESS-NAME,.tailscaled-wrapped"
+                "DOMAIN-SUFFIX,ts.net"
+                "DOMAIN-SUFFIX,net.trin.one"
+              ];
+            };
+            reject_non_ip_no_drop =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/reject-no-drop.txt";
+                path = "./rule_set/sukkaw_ruleset/reject_non_ip_no_drop.txt";
+              };
+            reject_non_ip_drop =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/reject-drop.txt";
+                path = "./rule_set/sukkaw_ruleset/reject_non_ip_drop.txt";
+              };
+            reject_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/reject.txt";
+                path = "./rule_set/sukkaw_ruleset/reject_non_ip.txt";
+              };
+            reject_domainset =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/domainset/reject.txt";
+                path = "./rule_set/sukkaw_ruleset/reject_domainset.txt";
+              };
+            reject_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/reject.txt";
+                path = "./rule_set/sukkaw_ruleset/reject_ip.txt";
+              };
+            cdn_domainset =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/domainset/cdn.txt";
+                path = "./rule_set/sukkaw_ruleset/cdn_domainset.txt";
+              };
+            cdn_non_ip =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/cdn.txt";
+                path = "./rule_set/sukkaw_ruleset/cdn_non_ip.txt";
+              };
+            stream_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/stream.txt";
+                path = "./rule_set/sukkaw_ruleset/stream_non_ip.txt";
+              };
+            stream_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/stream.txt";
+                path = "./rule_set/sukkaw_ruleset/stream_ip.txt";
+              };
+            ai_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/ai.txt";
+                path = "./rule_set/sukkaw_ruleset/ai_non_ip.txt";
+              };
+            telegram_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/telegram.txt";
+                path = "./rule_set/sukkaw_ruleset/telegram_non_ip.txt";
+              };
+            telegram_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/telegram.txt";
+                path = "./rule_set/sukkaw_ruleset/telegram_ip.txt";
+              };
+            apple_cdn =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/domainset/apple_cdn.txt";
+                path = "./rule_set/sukkaw_ruleset/apple_cdn.txt";
+              };
+            apple_services =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/apple_services.txt";
+                path = "./rule_set/sukkaw_ruleset/apple_services.txt";
+              };
+            apple_cn_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/apple_cn.txt";
+                path = "./rule_set/sukkaw_ruleset/apple_cn_non_ip.txt";
+              };
+            microsoft_cdn_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/microsoft_cdn.txt";
+                path = "./rule_set/sukkaw_ruleset/microsoft_cdn_non_ip.txt";
+              };
+            microsoft_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/microsoft.txt";
+                path = "./rule_set/sukkaw_ruleset/microsoft_non_ip.txt";
+              };
+            download_domainset =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/domainset/download.txt";
+                path = "./rule_set/sukkaw_ruleset/download_domainset.txt";
+              };
+            download_non_ip =
+              ruleSetDomain
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/download.txt";
+                path = "./rule_set/sukkaw_ruleset/download_non_ip.txt";
+              };
+            lan_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/lan.txt";
+                path = "./rule_set/sukkaw_ruleset/lan_non_ip.txt";
+              };
+            lan_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/lan.txt";
+                path = "./rule_set/sukkaw_ruleset/lan_ip.txt";
+              };
+            domestic_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/domestic.txt";
+                path = "./rule_set/sukkaw_ruleset/domestic_non_ip.txt";
+              };
+            direct_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/direct.txt";
+                path = "./rule_set/sukkaw_ruleset/direct_non_ip.txt";
+              };
+            global_non_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/non_ip/global.txt";
+                path = "./rule_set/sukkaw_ruleset/global_non_ip.txt";
+              };
+            domestic_ip =
+              ruleSetClassical
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/domestic.txt";
+                path = "./rule_set/sukkaw_ruleset/domestic_ip.txt";
+              };
+            china_ip =
+              ruleSetIpcidr
+              // {
+                url = "https://ruleset.skk.moe/Clash/ip/china_ip.txt";
+                path = "./rule_set/sukkaw_ruleset/china_ip.txt";
+              };
+          };
+        };
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/sniffer.nix
@@ -0,0 +1,30 @@
+{
+  den.aspects.services.proxy.mihomo.sniffer = {
+    nixos = {
+      services.mihomo = {
+        config = {
+          sniffer = {
+            enable = true;
+            force-dns-mapping = true;
+            sniff = {
+              HTTP = {
+                ports = [80 "8080-8880"];
+                override-destination = true;
+              };
+              TLS = {
+                ports = [443 8443];
+              };
+              QUIC = {
+                ports = [443 8443];
+              };
+            };
+            skip-domain = [
+              "Mijia Cloud"
+              "+.push.apple.com"
+            ];
+          };
+        };
+      };
+    };
+  };
+}
modules/services/proxy/mihomo/tun.nix
@@ -0,0 +1,35 @@
+{lib, ...}: {
+  den.aspects.services.proxy.mihomo.tun = {
+    nixos = {
+      host,
+      config,
+      ...
+    }: let
+      cfg = host.settings.services.proxy.mihomo;
+    in {
+      services.mihomo = {
+        tunMode = true;
+        config = {
+          tun = {
+            enable = true;
+            stack = "mixed";
+            device = "mihomo-tun0";
+            auto-route = true;
+            auto-redirect = true;
+            auto-detect-interface = false;
+            dns-hijack = [
+              "any:53"
+              "tcp://any:53"
+            ];
+            strict-route = true;
+            mtu = 1500;
+            include-interface = ["lo"] ++ [cfg.interfaces.wan] ++ cfg.interfaces.lan;
+            route-exclude-address = ["100.64.0.0/10" "fd7a:115c:a1e0::/48"]; # Tailscale
+          };
+        };
+      };
+
+      networking.firewall.trustedInterfaces = lib.mkIf config.services.mihomo.tunMode [config.services.mihomo.config.tun.device];
+    };
+  };
+}
modules/services/proxy/default.nix
@@ -1,8 +0,0 @@
-{den, ...}: {
-  den.aspects.services.proxy = {
-    includes = [
-      den.aspects.services.proxy.dae
-      den.aspects.services.proxy.sub-store
-    ];
-  };
-}
secrets/cache/kevin/8b8624022b6227c9c3e3d4a349dbb3554c2b2f31be2b4d79153003d2ef90f1db
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ Dh2zj3HzTwGeUkZvmzEzLYilt4zToGgmjunz88RY+n8
+BTd9Y5w3SRq9RU22vYuH024ZHTv3gPAkxf+rq0eU5kM
+-> ;eT.'|-grease 0RP-]7;%
+G4GbiIuUCZ55BInHZxMJdHJWiV38qQ
+--- ynkx++aAE8BCBKTGYeklIl2KlDRxFp+rFNU80Nvq3Bg
+����8��>���!ʒW�hj�$*��,U�������ǝ��8v��&��+�U�3�M���Ou�pA���\��U����5�B�^t�ߡ7	�B[��X��K���-J��R`����Vi��/�
\ No newline at end of file
secrets/cache/kevin/e62331160d2c9b2083dcff12923722e7ee52e91a2c7ac3519666d873ceef12b1
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ pkcqxdC6GuZYU1wahZP+djaV2IgP1EeKVn5eB/b0qCs
+53jrcl90fsjNpdZIYWpf0VL6DMSHgGh+K2poK2rlcdM
+-> cb%^-l>i-grease {82Q9^` 08uN
+STqWy7tq3yrOhwAYWuvRM8n5zyntCJEZMKXbNReJnLfbabUVBtXHDVMY1389BUJX
+HFOixiVMvPXnaL1UMMT9qvs
+--- bAUA/CLcPojoS1zCN0fD8RmHOzsFCs1e+CguCWPqn+U
+�CI8�
+�钲�1E��IӬ�;���%#���o���ZNM���&���F���)��G�?�:tiT�R�
�v�G�"+�iVܧ��/"z�D�Vp���P�D��ޮ�誅�cm�д��
\ No newline at end of file
secrets/cache/tribios/523f549ed96d70bac2b29f3d9dfa5caeb6ae6b131fe1ba5e49ffa2943d55f6b6
Binary file
secrets/cache/tribios/933dc774c4b9926ee79cc113303524f3872b2da03f5572ffb2dc6e2d900102fe
@@ -1,7 +0,0 @@
-age-encryption.org/v1
--> ssh-ed25519 1YGZAA TPMeCzIQkFN6nXjYD6v/7GMnK6q6HEIm9Kw5iq+10Xg
-C4RxyLuQ+MYTF7Qc9v243mkx1p12tfhnMvzy8eihAHk
--> *Z-grease SW Ea'*@~s $h:&KAsK xKq
-uu8hbA
---- DJkoXZ8Vrs/nOKODiGBhmnYZAwLKCUliir2imm+ou/A
-�Ǯq���y�1Z��D�Õ|�/˨�]3�1�z�_Dr��:�k�~�
\ No newline at end of file
secrets/cache/tribios/c06551522a2701a8586f7fc2d1f69b17510352b8bf5cd9be5b1b8537063f1772
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> ssh-ed25519 1YGZAA 5nNVFX5LQe136lAL70+64286JiQAzPcPY3VRfnUFxGk
+PQBIfIsdvOVhjo3wjpkaMDWrHWjx8wPpEEAgujvHiao
+-> xE`[,{C_-grease r1qm%9# JV 60.&x[x/ O)d&
+77w1lSfrOkR8ni0IN3a8F8ndF+C1u5BSgNPfk+KoZs1eakqVEB/vbg
+--- lNcYfKxzHz9bQC/lSIfzhMH6l80dGZaR3Mkly2lKNx8
+��Kt�d�'�i�V\A8�L�v�|[����*�+A�g6j��s����pꆦ]#��[`N��
+��N^w�ba~9�y��<.���{J�����7���Qce�]�*J����j&
+�a��
\ No newline at end of file
flake.lock
@@ -424,11 +424,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1783695157,
-        "narHash": "sha256-/Sr8poE9uC5NKP1zZ69A8vNQBRRSB+uWit3KFKLwe30=",
-        "rev": "1bd560f1e059fc2322d96d52d5b0c156c2d9c7cf",
+        "lastModified": 1783862180,
+        "narHash": "sha256-c3EFIQvUMMruRX0LORMe0TK8uSOF3Rkiq3PuoHdTJ4Y=",
+        "rev": "1f53073ac4efaf080a2dc2f0fc1397af1e2bcd6f",
         "type": "tarball",
-        "url": "https://codeberg.org/api/v1/repos/HPCesia/nur-packages/archive/1bd560f1e059fc2322d96d52d5b0c156c2d9c7cf.tar.gz?rev=1bd560f1e059fc2322d96d52d5b0c156c2d9c7cf"
+        "url": "https://codeberg.org/api/v1/repos/HPCesia/nur-packages/archive/1f53073ac4efaf080a2dc2f0fc1397af1e2bcd6f.tar.gz?rev=1f53073ac4efaf080a2dc2f0fc1397af1e2bcd6f"
       },
       "original": {
         "type": "tarball",