old
1{
2 den,
3 lib,
4 ...
5}: {
6 den.aspects.services.proxy.mihomo.rules = {
7 nixos = {
8 host,
9 config,
10 ...
11 }: let
12 allHosts = builtins.concatMap builtins.attrValues (builtins.attrValues den.hosts);
13 otherHosts = builtins.filter (h: h.name != host.name) allHosts;
14
15 hostsWithIpv4ClearText = builtins.filter (h: h.address.ipv4.clearText != null) otherHosts;
16 hostsWithIpv4Secret = builtins.filter (h: h.address.ipv4.secret.name != null && h.address.ipv4.secret.file != null) otherHosts;
17 hostsWithIpv6ClearText = builtins.filter (h: h.address.ipv6.clearText != null) otherHosts;
18 hostsWithIpv6Secret = builtins.filter (h: h.address.ipv6.secret.name != null && h.address.ipv6.secret.file != null) otherHosts;
19
20 mkMihomoIpRule = ip: "IP-CIDR,${ip}/32";
21
22 clearTextIps =
23 (map (h: mkMihomoIpRule h.address.ipv4.clearText) hostsWithIpv4ClearText)
24 ++ (map (h: mkMihomoIpRule h.address.ipv6.clearText) hostsWithIpv6ClearText);
25
26 secretIps =
27 (map (h: {_secret = config.vaultix.templates."mihomo-rules-${h.address.ipv4.secret.name}".path;}) hostsWithIpv4Secret)
28 ++ (map (h: {_secret = config.vaultix.templates."mihomo-rules-${h.address.ipv6.secret.name}".path;}) hostsWithIpv6Secret);
29
30 allHostIps = clearTextIps ++ secretIps;
31 in {
32 vaultix = {
33 secrets = lib.mkMerge (
34 (map (h: {${h.address.ipv4.secret.name}.file = h.address.ipv4.secret.file;}) hostsWithIpv4Secret)
35 ++ (map (h: {${h.address.ipv6.secret.name}.file = h.address.ipv6.secret.file;}) hostsWithIpv6Secret)
36 );
37 templates =
38 lib.mergeAttrsList
39 ((map (h: let
40 name = h.address.ipv4.secret.name;
41 in {
42 "mihomo-rules-${name}".content = mkMihomoIpRule config.vaultix.placeholder.${name};
43 })
44 hostsWithIpv4Secret)
45 ++ (map (h: let
46 name = h.address.ipv6.secret.name;
47 in {
48 "mihomo-rules-${name}".content = mkMihomoIpRule config.vaultix.placeholder.${name};
49 })
50 hostsWithIpv6Secret));
51 };
52
53 services.mihomo = {
54 config = {
55 rules = [
56 # === Non-IP ===
57 # Private
58 "RULE-SET,reject_non_ip,REJECT"
59 "RULE-SET,reject_domainset,REJECT"
60 "RULE-SET,reject_non_ip_drop,REJECT-DROP"
61 "RULE-SET,reject_non_ip_no_drop,REJECT"
62 "RULE-SET,tailscale_non_ip,DIRECT"
63 "RULE-SET,lan_non_ip,DIRECT"
64
65 # Game
66 "DOMAIN-SUFFIX,cm.steampowered.com,DIRECT"
67 "DOMAIN-SUFFIX,steamserver.net,DIRECT"
68 "GEOSITE,steam@cn,DIRECT"
69 "GEOSITE,category-game-platforms-download@cn,DIRECT"
70
71 # Should DIRECT
72 "DST-PORT,22,DIRECT" # For SSH
73 "DOMAIN-SUFFIX,kagi.com,DIRECT" # DIRECT is faster
74 "DOMAIN-SUFFIX,mxrouting.net,DIRECT"
75
76 # Common
77 "RULE-SET,cdn_domainset,SELECT"
78 "RULE-SET,cdn_non_ip,SELECT"
79 "RULE-SET,stream_non_ip,🇺🇸 - AUTO"
80 "RULE-SET,telegram_non_ip,🇺🇸 - AUTO"
81 "RULE-SET,apple_cdn,DIRECT"
82 "RULE-SET,download_domainset,SELECT"
83 "RULE-SET,download_non_ip,SELECT"
84 "RULE-SET,microsoft_cdn_non_ip,DIRECT"
85 "RULE-SET,apple_cn_non_ip,DIRECT"
86 "RULE-SET,apple_services,DIRECT"
87 "RULE-SET,microsoft_non_ip,DIRECT"
88 "RULE-SET,ai_non_ip,🇺🇸 - AUTO"
89 "RULE-SET,global_non_ip,SELECT"
90 "RULE-SET,domestic_non_ip,DIRECT"
91 "RULE-SET,direct_non_ip,DIRECT"
92
93 # === IP ===
94 "RULE-SET,reject_ip,REJECT"
95 "RULE-SET,my_hosts,DIRECT"
96 "RULE-SET,telegram_ip,🇺🇸 - AUTO"
97 "RULE-SET,stream_ip,🇺🇸 - AUTO"
98 "RULE-SET,lan_ip,DIRECT"
99 "RULE-SET,domestic_ip,DIRECT"
100 "RULE-SET,china_ip,DIRECT"
101 "MATCH,SELECT"
102 ];
103
104 rule-providers = let
105 ruleSetClassical = {
106 type = "http";
107 behavior = "classical";
108 interval = 43200;
109 format = "text";
110 proxy = "SELECT";
111 };
112 ruleSetDomain = {
113 type = "http";
114 behavior = "domain";
115 interval = 43200;
116 format = "text";
117 proxy = "SELECT";
118 };
119 ruleSetIpcidr = {
120 type = "http";
121 behavior = "ipcidr";
122 interval = 43200;
123 format = "text";
124 proxy = "SELECT";
125 };
126 in {
127 my_hosts = {
128 type = "inline";
129 behavior = "classical";
130 payload = allHostIps;
131 };
132 tailscale_non_ip = {
133 type = "inline";
134 behavior = "classical";
135 payload = [
136 "PROCESS-NAME,tailscale"
137 "PROCESS-NAME,tailscaled"
138 "PROCESS-NAME,.tailscaled-wrapped"
139 "DOMAIN-SUFFIX,ts.net"
140 "DOMAIN-SUFFIX,net.trin.one"
141 "DOMAIN,controlplane.tailscale.com"
142 "DOMAIN,gate.trin.one"
143 ];
144 };
145 reject_non_ip_no_drop =
146 ruleSetClassical
147 // {
148 url = "https://ruleset.skk.moe/Clash/non_ip/reject-no-drop.txt";
149 path = "./rule_set/sukkaw_ruleset/reject_non_ip_no_drop.txt";
150 };
151 reject_non_ip_drop =
152 ruleSetClassical
153 // {
154 url = "https://ruleset.skk.moe/Clash/non_ip/reject-drop.txt";
155 path = "./rule_set/sukkaw_ruleset/reject_non_ip_drop.txt";
156 };
157 reject_non_ip =
158 ruleSetClassical
159 // {
160 url = "https://ruleset.skk.moe/Clash/non_ip/reject.txt";
161 path = "./rule_set/sukkaw_ruleset/reject_non_ip.txt";
162 };
163 reject_domainset =
164 ruleSetDomain
165 // {
166 url = "https://ruleset.skk.moe/Clash/domainset/reject.txt";
167 path = "./rule_set/sukkaw_ruleset/reject_domainset.txt";
168 };
169 reject_ip =
170 ruleSetClassical
171 // {
172 url = "https://ruleset.skk.moe/Clash/ip/reject.txt";
173 path = "./rule_set/sukkaw_ruleset/reject_ip.txt";
174 };
175 cdn_domainset =
176 ruleSetDomain
177 // {
178 url = "https://ruleset.skk.moe/Clash/domainset/cdn.txt";
179 path = "./rule_set/sukkaw_ruleset/cdn_domainset.txt";
180 };
181 cdn_non_ip =
182 ruleSetDomain
183 // {
184 url = "https://ruleset.skk.moe/Clash/non_ip/cdn.txt";
185 path = "./rule_set/sukkaw_ruleset/cdn_non_ip.txt";
186 };
187 stream_non_ip =
188 ruleSetClassical
189 // {
190 url = "https://ruleset.skk.moe/Clash/non_ip/stream.txt";
191 path = "./rule_set/sukkaw_ruleset/stream_non_ip.txt";
192 };
193 stream_ip =
194 ruleSetClassical
195 // {
196 url = "https://ruleset.skk.moe/Clash/ip/stream.txt";
197 path = "./rule_set/sukkaw_ruleset/stream_ip.txt";
198 };
199 ai_non_ip =
200 ruleSetClassical
201 // {
202 url = "https://ruleset.skk.moe/Clash/non_ip/ai.txt";
203 path = "./rule_set/sukkaw_ruleset/ai_non_ip.txt";
204 };
205 telegram_non_ip =
206 ruleSetClassical
207 // {
208 url = "https://ruleset.skk.moe/Clash/non_ip/telegram.txt";
209 path = "./rule_set/sukkaw_ruleset/telegram_non_ip.txt";
210 };
211 telegram_ip =
212 ruleSetClassical
213 // {
214 url = "https://ruleset.skk.moe/Clash/ip/telegram.txt";
215 path = "./rule_set/sukkaw_ruleset/telegram_ip.txt";
216 };
217 apple_cdn =
218 ruleSetDomain
219 // {
220 url = "https://ruleset.skk.moe/Clash/domainset/apple_cdn.txt";
221 path = "./rule_set/sukkaw_ruleset/apple_cdn.txt";
222 };
223 apple_services =
224 ruleSetClassical
225 // {
226 url = "https://ruleset.skk.moe/Clash/non_ip/apple_services.txt";
227 path = "./rule_set/sukkaw_ruleset/apple_services.txt";
228 };
229 apple_cn_non_ip =
230 ruleSetClassical
231 // {
232 url = "https://ruleset.skk.moe/Clash/non_ip/apple_cn.txt";
233 path = "./rule_set/sukkaw_ruleset/apple_cn_non_ip.txt";
234 };
235 microsoft_cdn_non_ip =
236 ruleSetClassical
237 // {
238 url = "https://ruleset.skk.moe/Clash/non_ip/microsoft_cdn.txt";
239 path = "./rule_set/sukkaw_ruleset/microsoft_cdn_non_ip.txt";
240 };
241 microsoft_non_ip =
242 ruleSetClassical
243 // {
244 url = "https://ruleset.skk.moe/Clash/non_ip/microsoft.txt";
245 path = "./rule_set/sukkaw_ruleset/microsoft_non_ip.txt";
246 };
247 download_domainset =
248 ruleSetDomain
249 // {
250 url = "https://ruleset.skk.moe/Clash/domainset/download.txt";
251 path = "./rule_set/sukkaw_ruleset/download_domainset.txt";
252 };
253 download_non_ip =
254 ruleSetDomain
255 // {
256 url = "https://ruleset.skk.moe/Clash/non_ip/download.txt";
257 path = "./rule_set/sukkaw_ruleset/download_non_ip.txt";
258 };
259 lan_non_ip =
260 ruleSetClassical
261 // {
262 url = "https://ruleset.skk.moe/Clash/non_ip/lan.txt";
263 path = "./rule_set/sukkaw_ruleset/lan_non_ip.txt";
264 };
265 lan_ip =
266 ruleSetClassical
267 // {
268 url = "https://ruleset.skk.moe/Clash/ip/lan.txt";
269 path = "./rule_set/sukkaw_ruleset/lan_ip.txt";
270 };
271 domestic_non_ip =
272 ruleSetClassical
273 // {
274 url = "https://ruleset.skk.moe/Clash/non_ip/domestic.txt";
275 path = "./rule_set/sukkaw_ruleset/domestic_non_ip.txt";
276 };
277 direct_non_ip =
278 ruleSetClassical
279 // {
280 url = "https://ruleset.skk.moe/Clash/non_ip/direct.txt";
281 path = "./rule_set/sukkaw_ruleset/direct_non_ip.txt";
282 };
283 global_non_ip =
284 ruleSetClassical
285 // {
286 url = "https://ruleset.skk.moe/Clash/non_ip/global.txt";
287 path = "./rule_set/sukkaw_ruleset/global_non_ip.txt";
288 };
289 domestic_ip =
290 ruleSetClassical
291 // {
292 url = "https://ruleset.skk.moe/Clash/ip/domestic.txt";
293 path = "./rule_set/sukkaw_ruleset/domestic_ip.txt";
294 };
295 china_ip =
296 ruleSetIpcidr
297 // {
298 url = "https://ruleset.skk.moe/Clash/ip/china_ip.txt";
299 path = "./rule_set/sukkaw_ruleset/china_ip.txt";
300 };
301 };
302 };
303 };
304 };
305 };
306}