build-sgmodule-always-realip.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import path from 'node:path';
  2. import { task } from './trace';
  3. import { compareAndWriteFile, DomainsetOutput } from './lib/create-file';
  4. import { DIRECTS } from '../Source/non_ip/direct';
  5. import type { DNSMapping } from '../Source/non_ip/direct';
  6. import { DOMESTICS } from '../Source/non_ip/domestic';
  7. import * as yaml from 'yaml';
  8. import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR } from './constants/dir';
  9. import { appendArrayInPlace } from './lib/append-array-in-place';
  10. import { SHARED_DESCRIPTION } from './lib/constants';
  11. import { createGetDnsMappingRule } from './build-domestic-direct-lan-ruleset-dns-mapping-module';
  12. const HOSTNAMES = [
  13. // Network Detection, Captive Portal
  14. 'dns.msftncsi.com',
  15. // '*.msftconnecttest.com',
  16. // 'network-test.debian.org',
  17. // 'detectportal.firefox.com',
  18. // Handle SNAT conversation properly
  19. '*.srv.nintendo.net',
  20. '*.stun.playstation.net',
  21. 'xbox.*.microsoft.com',
  22. '*.xboxlive.com',
  23. '*.turn.twilio.com',
  24. '*.stun.twilio.com',
  25. 'stun.syncthing.net',
  26. 'stun.*'
  27. // 'controlplane.tailscale.com',
  28. // NTP
  29. // 'time.*.com', 'time.*.gov', 'time.*.edu.cn', 'time.*.apple.com', 'time?.*.com', 'ntp.*.com', 'ntp?.*.com', '*.time.edu.cn', '*.ntp.org.cn', '*.pool.ntp.org'
  30. // 'time*.cloud.tencent.com', 'ntp?.aliyun.com',
  31. // QQ Login
  32. // 'localhost.*.qq.com'
  33. // 'localhost.ptlogin2.qq.com
  34. // 'localhost.sec.qq.com',
  35. // 'localhost.work.weixin.qq.com',
  36. ];
  37. export const buildAlwaysRealIPModule = task(require.main === module, __filename)(async (span) => {
  38. const surge: string[] = [];
  39. const clashFakeIpFilter = new DomainsetOutput(span, 'clash_fake_ip_filter')
  40. .withTitle('Sukka\'s Ruleset - Always Real IP Plus')
  41. .withDescription([
  42. ...SHARED_DESCRIPTION,
  43. '',
  44. 'Clash.Meta fake-ip-filter as ruleset'
  45. ]);
  46. // Intranet, Router Setup, and mant more
  47. const dataset = [DIRECTS, DOMESTICS].reduce<DNSMapping[]>((acc, item) => {
  48. Object.values(item).forEach((i: DNSMapping) => {
  49. if (i.realip) {
  50. acc.push(i);
  51. }
  52. });
  53. return acc;
  54. }, []);
  55. const getDnsMappingRuleWithoutWildcard = createGetDnsMappingRule(false);
  56. for (const { domains } of dataset) {
  57. clashFakeIpFilter.addFromRuleset(domains.flatMap(getDnsMappingRuleWithoutWildcard));
  58. }
  59. return Promise.all([
  60. compareAndWriteFile(
  61. span,
  62. [
  63. '#!name=[Sukka] Always Real IP Plus',
  64. `#!desc=Last Updated: ${new Date().toISOString()}`,
  65. '',
  66. '[General]',
  67. `always-real-ip = %APPEND% ${HOSTNAMES.concat(surge).join(', ')}`
  68. ],
  69. path.resolve(OUTPUT_MODULES_DIR, 'sukka_common_always_realip.sgmodule')
  70. ),
  71. clashFakeIpFilter.writeClash(),
  72. compareAndWriteFile(
  73. span,
  74. yaml.stringify(
  75. {
  76. dns: {
  77. 'fake-ip-filter': appendArrayInPlace(
  78. /** clash */
  79. dataset.flatMap(({ domains }) => domains.map((domain) => `+.${domain}`)),
  80. HOSTNAMES
  81. )
  82. }
  83. },
  84. { version: '1.1' }
  85. ).split('\n'),
  86. path.join(OUTPUT_INTERNAL_DIR, 'clash_fake_ip_filter.yaml')
  87. )
  88. ]);
  89. });