clash.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import picocolors from 'picocolors';
  2. import { domainWildCardToRegex } from './misc';
  3. import { isProbablyIpv4, isProbablyIpv6 } from './is-fast-ip';
  4. const identity = <T>(x: T): T => x;
  5. const unsupported = Symbol('unsupported');
  6. // https://dreamacro.github.io/clash/configuration/rules.html
  7. const PROCESSOR: Record<string, ((raw: string, type: string, value: string) => string) | typeof unsupported> = {
  8. DOMAIN: identity,
  9. 'DOMAIN-SUFFIX': identity,
  10. 'DOMAIN-KEYWORD': identity,
  11. 'DOMAIN-WILDCARD': (_raw, _type, value) => `DOMAIN-REGEX,${domainWildCardToRegex(value)}`,
  12. GEOIP: identity,
  13. 'IP-CIDR': identity,
  14. 'IP-CIDR6': identity,
  15. 'IP-ASN': identity,
  16. 'SRC-IP': (_raw, _type, value) => {
  17. if (value.includes('/')) {
  18. return `SRC-IP-CIDR,${value}`;
  19. }
  20. if (isProbablyIpv4(value)) {
  21. return `SRC-IP-CIDR,${value}/32`;
  22. }
  23. if (isProbablyIpv6(value)) {
  24. return `SRC-IP-CIDR6,${value}/128`;
  25. }
  26. return '';
  27. },
  28. 'SRC-IP-CIDR': identity,
  29. 'SRC-PORT': identity,
  30. 'DST-PORT': identity,
  31. 'PROCESS-NAME': (_raw, _type, value) => ((value.includes('/') || value.includes('\\')) ? `PROCESS-PATH,${value}` : `PROCESS-NAME,${value}`),
  32. 'DEST-PORT': (_raw, _type, value) => `DST-PORT,${value}`,
  33. 'IN-PORT': (_raw, _type, value) => `SRC-PORT,${value}`,
  34. 'URL-REGEX': unsupported,
  35. 'USER-AGENT': unsupported
  36. };
  37. export const surgeRulesetToClashClassicalTextRuleset = (rules: string[] | Set<string>) => {
  38. return Array.from(rules).reduce<string[]>((acc, cur) => {
  39. let buf = '';
  40. let type = '';
  41. let i = 0;
  42. for (const len = cur.length; i < len; i++) {
  43. if (cur[i] === ',') {
  44. type = buf;
  45. break;
  46. }
  47. buf += cur[i];
  48. }
  49. if (type === '') {
  50. return acc;
  51. }
  52. const value = cur.slice(i + 1);
  53. if (type in PROCESSOR) {
  54. const proc = PROCESSOR[type];
  55. if (proc !== unsupported) {
  56. acc.push(proc(cur, type, value));
  57. }
  58. } else {
  59. console.log(picocolors.yellow(`[clash] unknown rule type: ${type}`), cur);
  60. }
  61. return acc;
  62. }, []);
  63. };
  64. export const surgeDomainsetToClashDomainset = (domainset: string[]) => {
  65. return domainset.map(i => (i[0] === '.' ? `+${i}` : i));
  66. };
  67. export const surgeDomainsetToClashRuleset = (domainset: string[]) => {
  68. return domainset.map(i => (i[0] === '.' ? `DOMAIN-SUFFIX,${i.slice(1)}` : `DOMAIN,${i}`));
  69. };