feat: 添加 WireGuard 设备管理并完善客户端分流
实现独立加密设备身份、网关 agent、持久生命周期任务和 Surge/FlClash 专属订阅凭证。 完善 Shadowrocket 规则转换与 Clash AI DNS,增加 Surge FFSB 适配、规则快照、运维工具及验收文档。
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import YAML from 'yaml';
|
||||
import { clientSupports, normalizeSsCipher, splitRuleExpression, type ExcludedNode, type NodeDto } from '@proxy-station/shared';
|
||||
import type { ProfileIR } from '../ir.js';
|
||||
import { clashAiDns } from './clash-ai-dns.js';
|
||||
import { WG_POLICY } from './wireguard.js';
|
||||
|
||||
export function clashProxy(n: NodeDto): Record<string, unknown> {
|
||||
const base: Record<string, unknown> = {
|
||||
@@ -119,6 +121,9 @@ export interface ClashOutput {
|
||||
}
|
||||
|
||||
export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }): ClashOutput {
|
||||
if (ir.wireguard && [...ir.nodes, ...ir.groups].some(n => n.name === WG_POLICY)) {
|
||||
throw new Error('WireGuard 组网策略名称与现有节点或组冲突');
|
||||
}
|
||||
const excluded: ExcludedNode[] = [];
|
||||
const usable = ir.nodes.filter((n) => {
|
||||
const verdict = clientSupports('clash', n);
|
||||
@@ -128,6 +133,13 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
const usableNames = new Set(usable.map((n) => n.name));
|
||||
|
||||
const proxies = usable.map(clashProxy);
|
||||
if (ir.wireguard) {
|
||||
const wg = ir.wireguard;
|
||||
proxies.push({ name: WG_POLICY, type: 'wireguard', ip: wg.address, 'private-key': wg.privateKey,
|
||||
mtu: wg.mtu, udp: true, 'persistent-keepalive': wg.keepalive,
|
||||
peers: [{ server: wg.server, port: wg.port, 'public-key': wg.serverPublicKey,
|
||||
...(wg.presharedKey ? { 'pre-shared-key': wg.presharedKey } : {}), 'allowed-ips': [wg.subnet] }] });
|
||||
}
|
||||
|
||||
const proxyGroups = ir.groups.map((g) => {
|
||||
const group: Record<string, unknown> = { name: g.name, type: g.type };
|
||||
@@ -136,10 +148,12 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
.map((m) => m.name);
|
||||
if (g.filterRegex) {
|
||||
group['include-all-proxies'] = true;
|
||||
if (ir.wireguard) group['exclude-filter'] = `^${WG_POLICY}$`;
|
||||
group.filter = g.filterRegex;
|
||||
if (members.length) group.proxies = [...new Set(members)];
|
||||
} else if (g.includeAllNodes) {
|
||||
group['include-all-proxies'] = true;
|
||||
if (ir.wireguard) group['exclude-filter'] = `^${WG_POLICY}$`;
|
||||
if (members.length) group.proxies = [...new Set(members)];
|
||||
} else {
|
||||
group.proxies = members.length ? members : ['DIRECT'];
|
||||
@@ -154,7 +168,7 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
|
||||
// rule-providers:从启用规则引用的规则集生成,名称唯一化
|
||||
const providerNameByRulesetId = new Map<string, string>();
|
||||
const providers: Record<string, unknown> = {};
|
||||
const providers: Record<string, Record<string, unknown>> = {};
|
||||
const takenNames = new Set<string>();
|
||||
const usedRulesets = ir.rules.flatMap((r) => (r.ruleset ? [r.ruleset] : []));
|
||||
for (const rs of usedRulesets) {
|
||||
@@ -175,6 +189,7 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
|
||||
const skippedRules: string[] = [];
|
||||
const ruleLines: string[] = [];
|
||||
if (ir.wireguard) ruleLines.push(`IP-CIDR,${ir.wireguard.subnet},${WG_POLICY},no-resolve`);
|
||||
for (const r of ir.rules) {
|
||||
if (r.type === 'FINAL') {
|
||||
ruleLines.push(`MATCH,${mapPolicy(r.policy)}`);
|
||||
@@ -217,6 +232,8 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
ruleLines.push([r.type, r.value, policy, ...params].join(','));
|
||||
}
|
||||
|
||||
const defaultNameservers = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'];
|
||||
const aiDns = clashAiDns(ir, providers, providerNameByRulesetId, defaultNameservers);
|
||||
const doc = {
|
||||
'mixed-port': 7890,
|
||||
'allow-lan': false,
|
||||
@@ -228,7 +245,8 @@ export function generateClash(ir: ProfileIR, opts: { convertBaseUrl: string }):
|
||||
enable: true,
|
||||
listen: '0.0.0.0:1053',
|
||||
'enhanced-mode': 'fake-ip',
|
||||
nameserver: ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'],
|
||||
nameserver: defaultNameservers,
|
||||
...aiDns,
|
||||
},
|
||||
proxies,
|
||||
'proxy-groups': proxyGroups,
|
||||
|
||||
Reference in New Issue
Block a user