mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-20 01:50:58 +00:00
* feat: support latest Wireguard features from Xray-core Implements support for Xray-core PRs #5833, #5643, and #5850 for Wireguard Inbounds: - Adds 'domainStrategy' and 'workers' to Wireguard inbound configuration. - Enables the Stream Settings tab for Wireguard inbounds to configure 'sockopt' and 'finalmask', hiding the irrelevant 'network' transmission dropdown. - Adds the 'randRange' field to the 'noise' UDP Finalmask obfuscation settings. * fix --------- Co-authored-by: Rqzbeh <Rqzbeh@example.com> Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -96,8 +96,12 @@ function defaultUdpHop(): Record<string, unknown> {
|
|||||||
export default function FinalMaskForm({ name, network, protocol, form, showAll = false }: FinalMaskFormProps) {
|
export default function FinalMaskForm({ name, network, protocol, form, showAll = false }: FinalMaskFormProps) {
|
||||||
const base = asPath(name);
|
const base = asPath(name);
|
||||||
const isHysteria = protocol === OutboundProtocols.Hysteria || protocol === 'hysteria';
|
const isHysteria = protocol === OutboundProtocols.Hysteria || protocol === 'hysteria';
|
||||||
const showTcp = showAll || TCP_NETWORKS.includes(network);
|
// Wireguard carries no user-selectable transport (always a UDP listener/
|
||||||
const showUdp = showAll || isHysteria || network === 'kcp';
|
// dialer), so only the UDP mask section applies — TCP masks would never
|
||||||
|
// wrap anything even though the leftover network value may be 'tcp'.
|
||||||
|
const isWireguard = protocol === 'wireguard';
|
||||||
|
const showTcp = showAll || (!isWireguard && TCP_NETWORKS.includes(network));
|
||||||
|
const showUdp = showAll || isHysteria || isWireguard || network === 'kcp';
|
||||||
const showQuic = showAll || isHysteria || network === 'xhttp';
|
const showQuic = showAll || isHysteria || network === 'xhttp';
|
||||||
const quicParams = Form.useWatch([...base, 'quicParams'], { form, preserve: true });
|
const quicParams = Form.useWatch([...base, 'quicParams'], { form, preserve: true });
|
||||||
const hasQuicParams = quicParams != null;
|
const hasQuicParams = quicParams != null;
|
||||||
@@ -107,7 +111,7 @@ export default function FinalMaskForm({ name, network, protocol, form, showAll =
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{showTcp && <TcpMasksList base={base} form={form} />}
|
{showTcp && <TcpMasksList base={base} form={form} />}
|
||||||
{showUdp && <UdpMasksList base={base} form={form} isHysteria={isHysteria} network={network} />}
|
{showUdp && <UdpMasksList base={base} form={form} isHysteria={isHysteria} isWireguard={isWireguard} network={network} />}
|
||||||
{showQuic && (
|
{showQuic && (
|
||||||
<>
|
<>
|
||||||
<Form.Item label="QUIC Params">
|
<Form.Item label="QUIC Params">
|
||||||
@@ -275,6 +279,22 @@ function validateFragmentLength(_rule: unknown, value: unknown): Promise<void> {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// randRange bytes must sit in 0-255 — xray rejects the whole config with
|
||||||
|
// "invalid randRange" otherwise (reversed ranges like "200-100" are fine,
|
||||||
|
// xray reorders them).
|
||||||
|
function validateRandRange(_rule: unknown, value: unknown): Promise<void> {
|
||||||
|
const str = typeof value === 'string' ? value.trim() : String(value ?? '').trim();
|
||||||
|
if (str.length === 0) return Promise.resolve();
|
||||||
|
const m = /^(\d{1,3})(?:-(\d{1,3}))?$/.exec(str);
|
||||||
|
if (!m) return Promise.reject(new Error('Use a byte value or range like 0-255'));
|
||||||
|
const from = Number(m[1]);
|
||||||
|
const to = m[2] !== undefined ? Number(m[2]) : from;
|
||||||
|
if (from > 255 || to > 255) {
|
||||||
|
return Promise.reject(new Error('randRange bytes must be within 0-255'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
function getDeep(obj: unknown, path: (string | number)[]): unknown {
|
function getDeep(obj: unknown, path: (string | number)[]): unknown {
|
||||||
let cur: unknown = obj;
|
let cur: unknown = obj;
|
||||||
for (const key of path) {
|
for (const key of path) {
|
||||||
@@ -345,8 +365,8 @@ function HeaderCustomGroups({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UdpMasksList({
|
function UdpMasksList({
|
||||||
base, form, isHysteria, network,
|
base, form, isHysteria, isWireguard, network,
|
||||||
}: { base: (string | number)[]; form: FormInstance; isHysteria: boolean; network: string }) {
|
}: { base: (string | number)[]; form: FormInstance; isHysteria: boolean; isWireguard: boolean; network: string }) {
|
||||||
return (
|
return (
|
||||||
<Form.List name={[...base, 'udp']}>
|
<Form.List name={[...base, 'udp']}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
@@ -357,7 +377,7 @@ function UdpMasksList({
|
|||||||
size="small"
|
size="small"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const def = isHysteria ? 'salamander' : 'mkcp-legacy';
|
const def = isHysteria || isWireguard ? 'salamander' : 'mkcp-legacy';
|
||||||
add({ type: def, settings: defaultUdpMaskSettings(def) });
|
add({ type: def, settings: defaultUdpMaskSettings(def) });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -370,6 +390,7 @@ function UdpMasksList({
|
|||||||
form={form}
|
form={form}
|
||||||
listPath={[...base, 'udp']}
|
listPath={[...base, 'udp']}
|
||||||
isHysteria={isHysteria}
|
isHysteria={isHysteria}
|
||||||
|
isWireguard={isWireguard}
|
||||||
network={network}
|
network={network}
|
||||||
onRemove={() => remove(field.name)}
|
onRemove={() => remove(field.name)}
|
||||||
/>
|
/>
|
||||||
@@ -381,13 +402,14 @@ function UdpMasksList({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UdpMaskItem({
|
function UdpMaskItem({
|
||||||
fieldName, displayIndex, form, listPath, isHysteria, network, onRemove,
|
fieldName, displayIndex, form, listPath, isHysteria, isWireguard, network, onRemove,
|
||||||
}: {
|
}: {
|
||||||
fieldName: number;
|
fieldName: number;
|
||||||
displayIndex: number;
|
displayIndex: number;
|
||||||
form: FormInstance;
|
form: FormInstance;
|
||||||
listPath: (string | number)[];
|
listPath: (string | number)[];
|
||||||
isHysteria: boolean;
|
isHysteria: boolean;
|
||||||
|
isWireguard: boolean;
|
||||||
network: string;
|
network: string;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -404,6 +426,9 @@ function UdpMaskItem({
|
|||||||
const options = isHysteria
|
const options = isHysteria
|
||||||
? [{ value: 'salamander', label: 'Salamander (Hysteria2)' }]
|
? [{ value: 'salamander', label: 'Salamander (Hysteria2)' }]
|
||||||
: [
|
: [
|
||||||
|
// Salamander is the mask xray-core's own wireguard finalmask example
|
||||||
|
// uses; it stays hysteria-only elsewhere to keep legacy parity.
|
||||||
|
...(isWireguard ? [{ value: 'salamander', label: 'Salamander' }] : []),
|
||||||
{ value: 'mkcp-legacy', label: 'mKCP Legacy' },
|
{ value: 'mkcp-legacy', label: 'mKCP Legacy' },
|
||||||
{ value: 'xdns', label: 'xDNS' },
|
{ value: 'xdns', label: 'xDNS' },
|
||||||
{ value: 'xicmp', label: 'xICMP' },
|
{ value: 'xicmp', label: 'xICMP' },
|
||||||
@@ -674,7 +699,15 @@ function ItemEditor({
|
|||||||
<InputNumber min={0} />
|
<InputNumber min={0} />
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Rand Range" name={[fieldName, 'randRange']}>
|
{/* Cleared must become undefined, not '': xray parses an
|
||||||
|
explicit "" as the range 0-0 (all-zero fill bytes), while
|
||||||
|
an omitted randRange falls back to the 0-255 default. */}
|
||||||
|
<Form.Item
|
||||||
|
label="Rand Range"
|
||||||
|
name={[fieldName, 'randRange']}
|
||||||
|
normalize={(v) => (v === '' ? undefined : v)}
|
||||||
|
rules={[{ validator: validateRandRange }]}
|
||||||
|
>
|
||||||
<Input placeholder="0-255" />
|
<Input placeholder="0-255" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const TLS_ELIGIBLE_PROTOCOLS = ['vmess', 'vless', 'trojan', 'shadowsocks'];
|
|||||||
const TLS_NETWORKS = ['tcp', 'ws', 'http', 'grpc', 'httpupgrade', 'xhttp'];
|
const TLS_NETWORKS = ['tcp', 'ws', 'http', 'grpc', 'httpupgrade', 'xhttp'];
|
||||||
const REALITY_ELIGIBLE_PROTOCOLS = ['vless', 'trojan'];
|
const REALITY_ELIGIBLE_PROTOCOLS = ['vless', 'trojan'];
|
||||||
const REALITY_NETWORKS = ['tcp', 'http', 'grpc', 'xhttp'];
|
const REALITY_NETWORKS = ['tcp', 'http', 'grpc', 'xhttp'];
|
||||||
const STREAM_PROTOCOLS = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria'];
|
const STREAM_PROTOCOLS = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'wireguard'];
|
||||||
const VISION_FLOW = 'xtls-rprx-vision';
|
const VISION_FLOW = 'xtls-rprx-vision';
|
||||||
const SS_2022_PREFIX = '2022';
|
const SS_2022_PREFIX = '2022';
|
||||||
const SS_BLAKE3_CHACHA20 = '2022-blake3-chacha20-poly1305';
|
const SS_BLAKE3_CHACHA20 = '2022-blake3-chacha20-poly1305';
|
||||||
|
|||||||
@@ -372,9 +372,15 @@ export default function InboundFormModal({
|
|||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else if (next === Protocols.WIREGUARD) {
|
||||||
|
// Wireguard has no user-selectable transport: the listener is always
|
||||||
|
// UDP and only finalmask/sockopt from streamSettings apply. Drop the
|
||||||
|
// leftover network/transport slices so the stream tab doesn't render
|
||||||
|
// a TCP sub-form and the wire payload carries no dead tcpSettings.
|
||||||
|
form.setFieldValue('streamSettings', { security: 'none' });
|
||||||
} else {
|
} else {
|
||||||
const current = form.getFieldValue('streamSettings') as { network?: string } | undefined;
|
const current = form.getFieldValue('streamSettings') as { network?: string } | undefined;
|
||||||
if (current?.network === 'hysteria') {
|
if (current?.network === 'hysteria' || !current?.network) {
|
||||||
form.setFieldValue('streamSettings', { network: 'tcp', security: 'none', tcpSettings: {} });
|
form.setFieldValue('streamSettings', { network: 'tcp', security: 'none', tcpSettings: {} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,7 +651,7 @@ export default function InboundFormModal({
|
|||||||
|
|
||||||
const streamTab = (
|
const streamTab = (
|
||||||
<>
|
<>
|
||||||
{protocol !== Protocols.HYSTERIA && (
|
{protocol !== Protocols.HYSTERIA && protocol !== Protocols.WIREGUARD && (
|
||||||
<Form.Item label={t('transmission')} name={['streamSettings', 'network']}>
|
<Form.Item label={t('transmission')} name={['streamSettings', 'network']}>
|
||||||
<Select
|
<Select
|
||||||
style={{ width: '75%' }}
|
style={{ width: '75%' }}
|
||||||
@@ -683,7 +689,10 @@ export default function InboundFormModal({
|
|||||||
|
|
||||||
{network === 'kcp' && <KcpForm />}
|
{network === 'kcp' && <KcpForm />}
|
||||||
|
|
||||||
<ExternalProxyForm toggleExternalProxy={toggleExternalProxy} />
|
{/* externalProxy only feeds client share links, and wireguard's
|
||||||
|
per-peer .conf fanout resolves its host elsewhere — the section
|
||||||
|
would be dead weight on a wireguard inbound. */}
|
||||||
|
{protocol !== Protocols.WIREGUARD && <ExternalProxyForm toggleExternalProxy={toggleExternalProxy} />}
|
||||||
|
|
||||||
<SockoptForm toggleSockopt={toggleSockopt} />
|
<SockoptForm toggleSockopt={toggleSockopt} />
|
||||||
|
|
||||||
@@ -897,7 +906,11 @@ export default function InboundFormModal({
|
|||||||
...(streamEnabled
|
...(streamEnabled
|
||||||
? [
|
? [
|
||||||
{ key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab, forceRender: true },
|
{ key: 'stream', label: t('pages.inbounds.streamTab'), children: streamTab, forceRender: true },
|
||||||
{ key: 'security', label: t('pages.inbounds.securityTab'), children: securityTab, forceRender: true },
|
// Wireguard can't do TLS/Reality (canEnableTls is false), so
|
||||||
|
// the security tab would only show a fully disabled radio.
|
||||||
|
...(protocol !== Protocols.WIREGUARD
|
||||||
|
? [{ key: 'security', label: t('pages.inbounds.securityTab'), children: securityTab, forceRender: true }]
|
||||||
|
: []),
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(sniffingSupported
|
...(sniffingSupported
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button, Divider, Form, Input, InputNumber, Space, Switch } from 'antd';
|
import { Button, Divider, Form, Input, InputNumber, Select, Space, Switch } from 'antd';
|
||||||
import { MinusOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
import { MinusOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
import { Wireguard } from '@/utils';
|
import { Wireguard } from '@/utils';
|
||||||
@@ -62,6 +62,21 @@ export default function WireguardFields({ wgPubKey, regenInboundWg, regenWgPeerK
|
|||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item name={['settings', 'workers']} label='Workers'>
|
||||||
|
<InputNumber min={1} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name={['settings', 'domainStrategy']} label={t('pages.xray.wireguard.domainStrategy')}>
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
options={[
|
||||||
|
{ value: 'ForceIP', label: 'ForceIP' },
|
||||||
|
{ value: 'ForceIPv4', label: 'ForceIPv4' },
|
||||||
|
{ value: 'ForceIPv4v6', label: 'ForceIPv4v6' },
|
||||||
|
{ value: 'ForceIPv6', label: 'ForceIPv6' },
|
||||||
|
{ value: 'ForceIPv6v4', label: 'ForceIPv6v4' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
<Form.List name={['settings', 'peers']}>
|
<Form.List name={['settings', 'peers']}>
|
||||||
{(fields, { add, remove }) => (
|
{(fields, { add, remove }) => (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -156,10 +156,17 @@ export default function OutboundFormModal({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!streamAllowed) return;
|
if (!streamAllowed) return;
|
||||||
|
// Wireguard dials its own UDP — only finalmask/sockopt apply, never a
|
||||||
|
// transport. Don't seed network 'tcp'; clear a leftover one (from a
|
||||||
|
// protocol switch) so the transmission/security blocks stay hidden.
|
||||||
|
if (protocol === 'wireguard') {
|
||||||
|
if (network) form.setFieldValue('streamSettings', { security: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (network) return;
|
if (network) return;
|
||||||
form.setFieldValue('streamSettings', { ...newStreamSlice('tcp'), security: 'none' });
|
form.setFieldValue('streamSettings', { ...newStreamSlice('tcp'), security: 'none' });
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [streamAllowed, network]);
|
}, [streamAllowed, network, protocol]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (protocol !== 'hysteria') return;
|
if (protocol !== 'hysteria') return;
|
||||||
@@ -565,7 +572,7 @@ export default function OutboundFormModal({
|
|||||||
|
|
||||||
{security === 'reality' && realityAllowed && <RealityForm />}
|
{security === 'reality' && realityAllowed && <RealityForm />}
|
||||||
|
|
||||||
{((streamAllowed && network) || !streamAllowed) && (
|
{((streamAllowed && network) || !streamAllowed || protocol === 'wireguard') && (
|
||||||
<SockoptForm form={form} outboundTags={existingTags} />
|
<SockoptForm form={form} outboundTags={existingTags} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const WireguardDomainStrategySchema = z.enum([
|
||||||
|
'ForceIP',
|
||||||
|
'ForceIPv4',
|
||||||
|
'ForceIPv4v6',
|
||||||
|
'ForceIPv6',
|
||||||
|
'ForceIPv6v4',
|
||||||
|
]);
|
||||||
|
export type WireguardDomainStrategy = z.infer<typeof WireguardDomainStrategySchema>;
|
||||||
|
|
||||||
|
// AntD InputNumber emits null (not undefined) when the user clears it, and
|
||||||
|
// the form store hands that null straight to safeParse on submit — a bare
|
||||||
|
// .optional() would reject it and block the save.
|
||||||
|
const optionalClearedInt = (schema: z.ZodNumber) =>
|
||||||
|
z.preprocess((v) => (v == null ? undefined : v), schema.optional());
|
||||||
|
|
||||||
// Wireguard inbound is peer-based (no clients). Each peer is a client device
|
// Wireguard inbound is peer-based (no clients). Each peer is a client device
|
||||||
// the server accepts; secretKey is the server-side private key and pubKey is
|
// the server accepts; secretKey is the server-side private key and pubKey is
|
||||||
// derived from it at runtime (not persisted on the wire). Inbound peers
|
// derived from it at runtime (not persisted on the wire). Inbound peers
|
||||||
@@ -10,14 +25,16 @@ export const WireguardInboundPeerSchema = z.object({
|
|||||||
publicKey: z.string().min(1),
|
publicKey: z.string().min(1),
|
||||||
preSharedKey: z.string().optional(),
|
preSharedKey: z.string().optional(),
|
||||||
allowedIPs: z.array(z.string()).default([]),
|
allowedIPs: z.array(z.string()).default([]),
|
||||||
keepAlive: z.number().int().min(0).optional(),
|
keepAlive: optionalClearedInt(z.number().int().min(0)),
|
||||||
});
|
});
|
||||||
export type WireguardInboundPeer = z.infer<typeof WireguardInboundPeerSchema>;
|
export type WireguardInboundPeer = z.infer<typeof WireguardInboundPeerSchema>;
|
||||||
|
|
||||||
export const WireguardInboundSettingsSchema = z.object({
|
export const WireguardInboundSettingsSchema = z.object({
|
||||||
mtu: z.number().int().min(1).optional(),
|
mtu: optionalClearedInt(z.number().int().min(1)),
|
||||||
secretKey: z.string().min(1),
|
secretKey: z.string().min(1),
|
||||||
peers: z.array(WireguardInboundPeerSchema).default([]),
|
peers: z.array(WireguardInboundPeerSchema).default([]),
|
||||||
noKernelTun: z.boolean().default(false),
|
noKernelTun: z.boolean().default(false),
|
||||||
|
workers: optionalClearedInt(z.number().int().min(1)),
|
||||||
|
domainStrategy: WireguardDomainStrategySchema.optional(),
|
||||||
});
|
});
|
||||||
export type WireguardInboundSettings = z.infer<typeof WireguardInboundSettingsSchema>;
|
export type WireguardInboundSettings = z.infer<typeof WireguardInboundSettingsSchema>;
|
||||||
|
|||||||
@@ -1683,7 +1683,7 @@ exports[`protocol capability predicates > vmess-basic :: xhttp/tls 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: grpc/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: grpc/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1695,7 +1695,7 @@ exports[`protocol capability predicates > wireguard-basic :: grpc/none 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: grpc/reality 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: grpc/reality 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1707,7 +1707,7 @@ exports[`protocol capability predicates > wireguard-basic :: grpc/reality 1`] =
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: grpc/tls 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: grpc/tls 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1719,7 +1719,7 @@ exports[`protocol capability predicates > wireguard-basic :: grpc/tls 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: httpupgrade/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: httpupgrade/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1731,7 +1731,7 @@ exports[`protocol capability predicates > wireguard-basic :: httpupgrade/none 1`
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: httpupgrade/tls 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: httpupgrade/tls 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1743,7 +1743,7 @@ exports[`protocol capability predicates > wireguard-basic :: httpupgrade/tls 1`]
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: kcp/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: kcp/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1755,7 +1755,7 @@ exports[`protocol capability predicates > wireguard-basic :: kcp/none 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: tcp/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: tcp/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1767,7 +1767,7 @@ exports[`protocol capability predicates > wireguard-basic :: tcp/none 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: tcp/reality 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: tcp/reality 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1779,7 +1779,7 @@ exports[`protocol capability predicates > wireguard-basic :: tcp/reality 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: tcp/tls 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: tcp/tls 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1791,7 +1791,7 @@ exports[`protocol capability predicates > wireguard-basic :: tcp/tls 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: ws/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: ws/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1803,7 +1803,7 @@ exports[`protocol capability predicates > wireguard-basic :: ws/none 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: ws/tls 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: ws/tls 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1815,7 +1815,7 @@ exports[`protocol capability predicates > wireguard-basic :: ws/tls 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: xhttp/none 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: xhttp/none 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1827,7 +1827,7 @@ exports[`protocol capability predicates > wireguard-basic :: xhttp/none 1`] = `
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: xhttp/reality 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: xhttp/reality 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
@@ -1839,7 +1839,7 @@ exports[`protocol capability predicates > wireguard-basic :: xhttp/reality 1`] =
|
|||||||
exports[`protocol capability predicates > wireguard-basic :: xhttp/tls 1`] = `
|
exports[`protocol capability predicates > wireguard-basic :: xhttp/tls 1`] = `
|
||||||
{
|
{
|
||||||
"canEnableReality": false,
|
"canEnableReality": false,
|
||||||
"canEnableStream": false,
|
"canEnableStream": true,
|
||||||
"canEnableTls": false,
|
"canEnableTls": false,
|
||||||
"canEnableTlsFlow": false,
|
"canEnableTlsFlow": false,
|
||||||
"canEnableVisionSeed": false,
|
"canEnableVisionSeed": false,
|
||||||
|
|||||||
@@ -289,7 +289,8 @@ func (s *InboundService) getAllEmailSubIDs() (map[string]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// normalizeStreamSettings clears StreamSettings for protocols that don't use it.
|
// normalizeStreamSettings clears StreamSettings for protocols that don't use it.
|
||||||
// Only vmess, vless, trojan, shadowsocks, and hysteria protocols use streamSettings.
|
// Only vmess, vless, trojan, shadowsocks, hysteria, and wireguard protocols use
|
||||||
|
// streamSettings (wireguard for finalmask UDP masks and sockopt on its listener).
|
||||||
func (s *InboundService) normalizeStreamSettings(inbound *model.Inbound) {
|
func (s *InboundService) normalizeStreamSettings(inbound *model.Inbound) {
|
||||||
protocolsWithStream := map[model.Protocol]bool{
|
protocolsWithStream := map[model.Protocol]bool{
|
||||||
model.VMESS: true,
|
model.VMESS: true,
|
||||||
@@ -297,6 +298,7 @@ func (s *InboundService) normalizeStreamSettings(inbound *model.Inbound) {
|
|||||||
model.Trojan: true,
|
model.Trojan: true,
|
||||||
model.Shadowsocks: true,
|
model.Shadowsocks: true,
|
||||||
model.Hysteria: true,
|
model.Hysteria: true,
|
||||||
|
model.WireGuard: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !protocolsWithStream[inbound.Protocol] {
|
if !protocolsWithStream[inbound.Protocol] {
|
||||||
|
|||||||
Reference in New Issue
Block a user