build-chn-cidr.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { fetchRemoteTextByLine } from './lib/fetch-text-by-line';
  2. import { task } from './trace';
  3. import { contains as containsCidr, exclude as excludeCidr } from 'fast-cidr-tools';
  4. import { createMemoizedPromise } from './lib/memo-promise';
  5. import { CN_CIDR_MISSING_IN_CHNROUTE, NON_CN_CIDR_INCLUDED_IN_CHNROUTE } from './constants/cidr';
  6. import { appendArrayInPlace } from './lib/append-array-in-place';
  7. import { IPListOutput } from './lib/rules/ip';
  8. import { cachedOnlyFail } from './lib/fs-memo';
  9. import { createFileDescription } from './constants/description';
  10. const PROBE_CHN_CIDR_V4 = [
  11. // NetEase Hangzhou
  12. '223.252.196.38',
  13. // Aliyun ShenZhen
  14. '120.78.92.171'
  15. ];
  16. export const getChnCidrPromise = createMemoizedPromise(cachedOnlyFail<[], [string[], string[]]>(
  17. async function getChnCidr() {
  18. const [_cidr4, cidr6] = await Promise.all([
  19. fetchRemoteTextByLine('https://raw.githubusercontent.com/misakaio/chnroutes2/master/chnroutes.txt', true).then(Array.fromAsync<string>),
  20. fetchRemoteTextByLine('https://gaoyifan.github.io/china-operator-ip/china6.txt', true).then(Array.fromAsync<string>)
  21. ]);
  22. const cidr4 = excludeCidr(
  23. appendArrayInPlace(_cidr4, CN_CIDR_MISSING_IN_CHNROUTE),
  24. NON_CN_CIDR_INCLUDED_IN_CHNROUTE,
  25. true
  26. );
  27. for (const probeIp of PROBE_CHN_CIDR_V4) {
  28. if (!containsCidr(cidr4, PROBE_CHN_CIDR_V4)) {
  29. const err = new TypeError('chnroutes missing probe IP');
  30. err.cause = probeIp;
  31. throw err;
  32. }
  33. }
  34. return [cidr4, cidr6] as const;
  35. },
  36. {
  37. serializer: JSON.stringify,
  38. deserializer: JSON.parse
  39. }
  40. ));
  41. export const buildChnCidr = task(require.main === module, __filename)(async (span) => {
  42. const [filteredCidr4, cidr6] = await span.traceChildAsync('download chnroutes2', getChnCidrPromise);
  43. // Can not use SHARED_DESCRIPTION here as different license
  44. const description = createFileDescription('CC BY-SA 2.0');
  45. return Promise.all([
  46. new IPListOutput(span, 'china_ip', false)
  47. .withTitle('Sukka\'s Ruleset - Mainland China IPv4 CIDR')
  48. .withDescription([
  49. ...description,
  50. 'Data from https://misaka.io (misakaio @ GitHub)'
  51. ])
  52. .bulkAddCIDR4(filteredCidr4)
  53. .write(),
  54. new IPListOutput(span, 'china_ip_ipv6', false)
  55. .withTitle('Sukka\'s Ruleset - Mainland China IPv6 CIDR')
  56. .withDescription([
  57. ...description,
  58. 'Data from https://github.com/gaoyifan/china-operator-ip'
  59. ])
  60. .bulkAddCIDR6(cidr6)
  61. .write()
  62. ]);
  63. });