Skip to content

Commit f296138

Browse files
committed
feat: 完善 WireGuard IP/IPv6 解析转换
1 parent 820c191 commit f296138

14 files changed

Lines changed: 342 additions & 39 deletions

File tree

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.21.99",
3+
"version": "2.22.0",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"scripts": {

backend/src/core/proxy-utils/index.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import { findByName } from '@/utils/database';
2323
import { produceArtifact } from '@/restful/sync';
2424
import { getFlag, removeFlag, getISO, MMDB } from '@/utils/geo';
2525
import Gist from '@/utils/gist';
26-
import { isPresent, isShadowsocksOverTls } from './producers/utils';
26+
import {
27+
isPresent,
28+
isShadowsocksOverTls,
29+
normalizeWireGuardInterface,
30+
} from './producers/utils';
2731
import { doh } from '@/utils/dns';
2832
import JSON5 from 'json5';
2933
import { hex_md5 } from '@/vendor/md5';
@@ -313,6 +317,9 @@ function produce(proxies, targetPlatform, type, opts = {}) {
313317
proxy.port = getRandomPort(proxy.ports);
314318
}
315319
}
320+
if (proxy.type === 'wireguard') {
321+
normalizeWireGuardInterface(proxy);
322+
}
316323

317324
return proxy;
318325
});
@@ -745,18 +752,7 @@ function lastParse(proxy) {
745752
}
746753
}
747754
}
748-
if (proxy.ip?.includes('/')) {
749-
const [ip] = proxy.ip.split('/');
750-
if (isIPv4(ip)) {
751-
proxy.ip = ip;
752-
}
753-
}
754-
if (proxy.ipv6?.includes('/')) {
755-
const [ip] = proxy.ipv6.split('/');
756-
if (isIPv6(ip)) {
757-
proxy.ipv6 = ip;
758-
}
759-
}
755+
normalizeWireGuardInterface(proxy);
760756
}
761757
return proxy;
762758
}

backend/src/core/proxy-utils/parsers/index.js

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,32 @@ function splitURIFragment(raw) {
4242
};
4343
}
4444

45+
function parseWireGuardURIAddressValue(value) {
46+
if (value == null) return null;
47+
const raw = `${value}`.trim();
48+
if (!raw) return null;
49+
const [, hostRaw = raw, cidrRaw] = /^(.*?)(?:\/(\d+))?$/.exec(raw) || [];
50+
const host = `${hostRaw}`.trim().replace(/^\[/, '').replace(/\]$/, '');
51+
const normalizeCIDR = (cidr, max) => {
52+
if (cidr == null) return undefined;
53+
if (!/^\d+$/.test(cidr)) return undefined;
54+
const parsed = parseInt(cidr, 10);
55+
if (parsed < 0 || parsed > max) return undefined;
56+
return parsed;
57+
};
58+
if (isIPv4(host)) {
59+
return { family: 'ipv4', address: host, cidr: normalizeCIDR(cidrRaw, 32) };
60+
}
61+
if (isIPv6(host)) {
62+
return {
63+
family: 'ipv6',
64+
address: host,
65+
cidr: normalizeCIDR(cidrRaw, 128),
66+
};
67+
}
68+
return null;
69+
}
70+
4571
function URI_PROXY() {
4672
// socks5+tls
4773
// socks5
@@ -1420,7 +1446,16 @@ function URI_WireGuard() {
14201446
};
14211447
for (const addon of addons.split('&')) {
14221448
if (addon) {
1423-
let [key, value] = addon.split('=');
1449+
const equalIndex = addon.indexOf('=');
1450+
let key;
1451+
let value;
1452+
if (equalIndex === -1) {
1453+
key = addon;
1454+
value = '';
1455+
} else {
1456+
key = addon.slice(0, equalIndex);
1457+
value = addon.slice(equalIndex + 1);
1458+
}
14241459
key = key.replace(/_/, '-');
14251460
value = decodeURIComponent(value);
14261461
if (['reserved'].includes(key)) {
@@ -1433,15 +1468,18 @@ function URI_WireGuard() {
14331468
}
14341469
} else if (['address', 'ip'].includes(key)) {
14351470
value.split(',').map((i) => {
1436-
const ip = i
1437-
.trim()
1438-
.replace(/\/\d+$/, '')
1439-
.replace(/^\[/, '')
1440-
.replace(/\]$/, '');
1441-
if (isIPv4(ip)) {
1442-
proxy.ip = ip;
1443-
} else if (isIPv6(ip)) {
1444-
proxy.ipv6 = ip;
1471+
const parsed = parseWireGuardURIAddressValue(i);
1472+
if (!parsed) return;
1473+
if (parsed.family === 'ipv4') {
1474+
proxy.ip = parsed.address;
1475+
if (typeof parsed.cidr !== 'undefined') {
1476+
proxy['ip-cidr'] = parsed.cidr;
1477+
}
1478+
} else if (parsed.family === 'ipv6') {
1479+
proxy.ipv6 = parsed.address;
1480+
if (typeof parsed.cidr !== 'undefined') {
1481+
proxy['ipv6-cidr'] = parsed.cidr;
1482+
}
14451483
}
14461484
});
14471485
} else if (['mtu'].includes(key)) {

backend/src/core/proxy-utils/producers/clash.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ export default function Clash_Producer() {
200200
delete proxy.id;
201201
delete proxy.resolved;
202202
delete proxy['no-resolve'];
203+
delete proxy['ip-cidr'];
204+
delete proxy['ipv6-cidr'];
203205
if (type !== 'internal') {
204206
for (const key in proxy) {
205207
if (proxy[key] == null || /^_/i.test(key)) {

backend/src/core/proxy-utils/producers/clashmeta.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
getWireGuardAddressWithCIDR,
23
isPresent,
34
produceProxyListOutput,
45
supportsShadowsocksV2rayPluginMode,
@@ -163,6 +164,8 @@ export default function ClashMeta_Producer() {
163164
proxy['preshared-key'] =
164165
proxy['preshared-key'] ?? proxy['pre-shared-key'];
165166
proxy['pre-shared-key'] = proxy['preshared-key'];
167+
proxy.ip = getWireGuardAddressWithCIDR(proxy, 'ipv4');
168+
proxy.ipv6 = getWireGuardAddressWithCIDR(proxy, 'ipv6');
166169
} else if (proxy.type === 'snell' && proxy.version < 3) {
167170
delete proxy.udp;
168171
} else if (proxy.type === 'vless') {
@@ -287,6 +290,8 @@ export default function ClashMeta_Producer() {
287290
delete proxy.id;
288291
delete proxy.resolved;
289292
delete proxy['no-resolve'];
293+
delete proxy['ip-cidr'];
294+
delete proxy['ipv6-cidr'];
290295
if (type !== 'internal' || opts['delete-underscore-fields']) {
291296
for (const key in proxy) {
292297
if (proxy[key] == null || /^_/i.test(key)) {

backend/src/core/proxy-utils/producers/shadowrocket.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
getWireGuardAddressWithCIDR,
23
isPresent,
34
isShadowsocksOverTls,
45
produceProxyListOutput,
@@ -146,6 +147,8 @@ export default function Shadowrocket_Producer() {
146147
proxy['preshared-key'] =
147148
proxy['preshared-key'] ?? proxy['pre-shared-key'];
148149
proxy['pre-shared-key'] = proxy['preshared-key'];
150+
proxy.ip = getWireGuardAddressWithCIDR(proxy, 'ipv4');
151+
proxy.ipv6 = getWireGuardAddressWithCIDR(proxy, 'ipv6');
149152
} else if (proxy.type === 'snell' && proxy.version < 3) {
150153
delete proxy.udp;
151154
} else if (proxy.type === 'vless') {
@@ -277,6 +280,8 @@ export default function Shadowrocket_Producer() {
277280
delete proxy.id;
278281
delete proxy.resolved;
279282
delete proxy['no-resolve'];
283+
delete proxy['ip-cidr'];
284+
delete proxy['ipv6-cidr'];
280285
if (type !== 'internal') {
281286
for (const key in proxy) {
282287
if (proxy[key] == null || /^_/i.test(key)) {

backend/src/core/proxy-utils/producers/sing-box.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import ClashMeta_Producer from './clashmeta';
22
import $ from '@/core/app';
3-
import { isIPv4, isIPv6, isPlainObject } from '@/utils';
4-
import { normalizePluginMuxValue } from './utils';
3+
import { isPlainObject } from '@/utils';
4+
import { getWireGuardAddressWithCIDR, normalizePluginMuxValue } from './utils';
55

66
const ipVersions = {
77
ipv4: 'ipv4_only',
@@ -951,12 +951,8 @@ const tailscaleParser = (proxy = {}) => {
951951
};
952952

953953
const wireguardParser = (proxy = {}) => {
954-
const address = ['ip', 'ipv6']
955-
.map((i) => proxy[i])
956-
.map((i) => {
957-
if (isIPv4(i)) return `${i}/32`;
958-
if (isIPv6(i)) return `${i}/128`;
959-
})
954+
const address = ['ipv4', 'ipv6']
955+
.map((family) => getWireGuardAddressWithCIDR(proxy, family))
960956
.filter((i) => i);
961957
const parsedProxy = {
962958
system: !!proxy.system,

backend/src/core/proxy-utils/producers/stash.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ export default function Stash_Producer() {
340340
delete proxy.id;
341341
delete proxy.resolved;
342342
delete proxy['no-resolve'];
343+
delete proxy['ip-cidr'];
344+
delete proxy['ipv6-cidr'];
343345
if (type !== 'internal') {
344346
for (const key in proxy) {
345347
if (proxy[key] == null || /^_/i.test(key)) {

backend/src/core/proxy-utils/producers/uri.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable no-case-declarations */
22
import { Base64 } from 'js-base64';
33
import { isIPv6 } from '@/utils';
4-
import { normalizePluginMuxValue } from './utils';
4+
import { getWireGuardAddressWithCIDR, normalizePluginMuxValue } from './utils';
55
import { normalizeXhttpScalarUpperBound } from '../xhttp-utils';
66

77
function isObject(value) {
@@ -1168,6 +1168,8 @@ export default function URI_Producer() {
11681168
'port',
11691169
'ip',
11701170
'ipv6',
1171+
'ip-cidr',
1172+
'ipv6-cidr',
11711173
'private-key',
11721174
].includes(key)
11731175
) {
@@ -1186,19 +1188,27 @@ export default function URI_Producer() {
11861188
}
11871189
}
11881190
});
1189-
if (proxy.ip && proxy.ipv6) {
1191+
const wireguardIPv4 = getWireGuardAddressWithCIDR(
1192+
proxy,
1193+
'ipv4',
1194+
);
1195+
const wireguardIPv6 = getWireGuardAddressWithCIDR(
1196+
proxy,
1197+
'ipv6',
1198+
);
1199+
if (wireguardIPv4 && wireguardIPv6) {
11901200
wireguardParams.push(
11911201
`address=${encodeURIComponent(
1192-
`${proxy.ip}/32,${proxy.ipv6}/128`,
1202+
`${wireguardIPv4},${wireguardIPv6}`,
11931203
)}`,
11941204
);
1195-
} else if (proxy.ip) {
1205+
} else if (wireguardIPv4) {
11961206
wireguardParams.push(
1197-
`address=${encodeURIComponent(`${proxy.ip}/32`)}`,
1207+
`address=${encodeURIComponent(wireguardIPv4)}`,
11981208
);
1199-
} else if (proxy.ipv6) {
1209+
} else if (wireguardIPv6) {
12001210
wireguardParams.push(
1201-
`address=${encodeURIComponent(`${proxy.ipv6}/128`)}`,
1211+
`address=${encodeURIComponent(wireguardIPv6)}`,
12021212
);
12031213
}
12041214
result = `wireguard://${encodeURIComponent(

backend/src/core/proxy-utils/producers/utils.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import _ from 'lodash';
22
import YAML from '@/utils/yaml';
3+
import { isIPv4, isIPv6 } from '@/utils';
34

45
export class Result {
56
constructor(proxy) {
@@ -65,6 +66,81 @@ export function supportsShadowsocksV2rayPluginMode(proxy, supportedModes) {
6566
return supportedModes.includes(normalizedMode);
6667
}
6768

69+
function parseWireGuardCIDR(cidr, max) {
70+
if (cidr == null) return undefined;
71+
const normalized = `${cidr}`.trim();
72+
if (!/^\d+$/.test(normalized)) return undefined;
73+
const parsed = parseInt(normalized, 10);
74+
if (parsed < 0 || parsed > max) return undefined;
75+
return parsed;
76+
}
77+
78+
function parseWireGuardInterfaceAddress(value, family) {
79+
if (value == null) return null;
80+
const raw = `${value}`.trim();
81+
if (!raw) return null;
82+
const [, hostRaw = raw, cidrRaw] = /^(.*?)(?:\/(\d+))?$/.exec(raw) || [];
83+
const host = `${hostRaw}`.trim().replace(/^\[/, '').replace(/\]$/, '');
84+
const isIPv4Family = family === 'ipv4';
85+
const isValid = isIPv4Family ? isIPv4(host) : isIPv6(host);
86+
if (!isValid) return null;
87+
const max = isIPv4Family ? 32 : 128;
88+
return {
89+
address: host,
90+
cidr: parseWireGuardCIDR(cidrRaw, max),
91+
};
92+
}
93+
94+
function normalizeWireGuardInterfaceAddress(proxy, config) {
95+
const { addressKey, cidrKey, family, defaultCIDR } = config;
96+
const parsed = parseWireGuardInterfaceAddress(proxy[addressKey], family);
97+
if (!parsed) {
98+
if (
99+
proxy[addressKey] == null ||
100+
`${proxy[addressKey]}`.trim().length === 0
101+
) {
102+
delete proxy[cidrKey];
103+
}
104+
return;
105+
}
106+
proxy[addressKey] = parsed.address;
107+
const normalizedCIDR = parseWireGuardCIDR(proxy[cidrKey], defaultCIDR);
108+
proxy[cidrKey] = normalizedCIDR ?? parsed.cidr ?? defaultCIDR;
109+
}
110+
111+
export function normalizeWireGuardInterface(proxy = {}) {
112+
normalizeWireGuardInterfaceAddress(proxy, {
113+
addressKey: 'ip',
114+
cidrKey: 'ip-cidr',
115+
family: 'ipv4',
116+
defaultCIDR: 32,
117+
});
118+
normalizeWireGuardInterfaceAddress(proxy, {
119+
addressKey: 'ipv6',
120+
cidrKey: 'ipv6-cidr',
121+
family: 'ipv6',
122+
defaultCIDR: 128,
123+
});
124+
return proxy;
125+
}
126+
127+
export function getWireGuardAddressWithCIDR(proxy = {}, family = 'ipv4') {
128+
const config =
129+
family === 'ipv6'
130+
? { addressKey: 'ipv6', cidrKey: 'ipv6-cidr', defaultCIDR: 128 }
131+
: { addressKey: 'ip', cidrKey: 'ip-cidr', defaultCIDR: 32 };
132+
const parsed = parseWireGuardInterfaceAddress(
133+
proxy[config.addressKey],
134+
family,
135+
);
136+
if (!parsed) return undefined;
137+
const normalizedCIDR = parseWireGuardCIDR(
138+
proxy[config.cidrKey],
139+
config.defaultCIDR,
140+
);
141+
return `${parsed.address}/${normalizedCIDR ?? parsed.cidr ?? config.defaultCIDR}`;
142+
}
143+
68144
export function produceProxyListOutput(list, type, opts = {}) {
69145
if (type === 'internal') return list;
70146

0 commit comments

Comments
 (0)