mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-02-13 13:57:59 +00:00
Add UDP mask support for Hysteria outbound
Introduces a 'congestion' option to Hysteria stream settings and updates the form to allow selection between BBR (Auto) and Brutal. Adds support for UDP masks, including model, serialization, and UI for adding/removing masks with type and password fields.
This commit is contained in:
parent
2a76cec804
commit
93b7ce199f
2 changed files with 83 additions and 10 deletions
|
|
@ -430,6 +430,7 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
version = 2,
|
version = 2,
|
||||||
auth = '',
|
auth = '',
|
||||||
|
congestion = '',
|
||||||
up = '0',
|
up = '0',
|
||||||
down = '0',
|
down = '0',
|
||||||
udphopPort = '',
|
udphopPort = '',
|
||||||
|
|
@ -445,6 +446,7 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
super();
|
super();
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
|
this.congestion = congestion;
|
||||||
this.up = up;
|
this.up = up;
|
||||||
this.down = down;
|
this.down = down;
|
||||||
this.udphopPort = udphopPort;
|
this.udphopPort = udphopPort;
|
||||||
|
|
@ -468,6 +470,7 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
return new HysteriaStreamSettings(
|
return new HysteriaStreamSettings(
|
||||||
json.version,
|
json.version,
|
||||||
json.auth,
|
json.auth,
|
||||||
|
json.congestion,
|
||||||
json.up,
|
json.up,
|
||||||
json.down,
|
json.down,
|
||||||
udphopPort,
|
udphopPort,
|
||||||
|
|
@ -486,6 +489,7 @@ class HysteriaStreamSettings extends CommonClass {
|
||||||
const result = {
|
const result = {
|
||||||
version: this.version,
|
version: this.version,
|
||||||
auth: this.auth,
|
auth: this.auth,
|
||||||
|
congestion: this.congestion,
|
||||||
up: this.up,
|
up: this.up,
|
||||||
down: this.down,
|
down: this.down,
|
||||||
initStreamReceiveWindow: this.initStreamReceiveWindow,
|
initStreamReceiveWindow: this.initStreamReceiveWindow,
|
||||||
|
|
@ -554,6 +558,30 @@ class SockoptStreamSettings extends CommonClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UdpMask extends CommonClass {
|
||||||
|
constructor(type = 'salamander', password = '') {
|
||||||
|
super();
|
||||||
|
this.type = type;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json = {}) {
|
||||||
|
return new UdpMask(
|
||||||
|
json.type,
|
||||||
|
json.settings?.password || ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
toJson() {
|
||||||
|
return {
|
||||||
|
type: this.type,
|
||||||
|
settings: {
|
||||||
|
password: this.password
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class StreamSettings extends CommonClass {
|
class StreamSettings extends CommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
network = 'tcp',
|
network = 'tcp',
|
||||||
|
|
@ -567,6 +595,7 @@ class StreamSettings extends CommonClass {
|
||||||
httpupgradeSettings = new HttpUpgradeStreamSettings(),
|
httpupgradeSettings = new HttpUpgradeStreamSettings(),
|
||||||
xhttpSettings = new xHTTPStreamSettings(),
|
xhttpSettings = new xHTTPStreamSettings(),
|
||||||
hysteriaSettings = new HysteriaStreamSettings(),
|
hysteriaSettings = new HysteriaStreamSettings(),
|
||||||
|
udpmasks = [],
|
||||||
sockopt = undefined,
|
sockopt = undefined,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -581,9 +610,18 @@ class StreamSettings extends CommonClass {
|
||||||
this.httpupgrade = httpupgradeSettings;
|
this.httpupgrade = httpupgradeSettings;
|
||||||
this.xhttp = xhttpSettings;
|
this.xhttp = xhttpSettings;
|
||||||
this.hysteria = hysteriaSettings;
|
this.hysteria = hysteriaSettings;
|
||||||
|
this.udpmasks = udpmasks;
|
||||||
this.sockopt = sockopt;
|
this.sockopt = sockopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addUdpMask() {
|
||||||
|
this.udpmasks.push(new UdpMask());
|
||||||
|
}
|
||||||
|
|
||||||
|
delUdpMask(index) {
|
||||||
|
this.udpmasks.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
get isTls() {
|
get isTls() {
|
||||||
return this.security === 'tls';
|
return this.security === 'tls';
|
||||||
}
|
}
|
||||||
|
|
@ -601,6 +639,7 @@ class StreamSettings extends CommonClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
static fromJson(json = {}) {
|
||||||
|
const udpmasks = json.udpmasks ? json.udpmasks.map(mask => UdpMask.fromJson(mask)) : [];
|
||||||
return new StreamSettings(
|
return new StreamSettings(
|
||||||
json.network,
|
json.network,
|
||||||
json.security,
|
json.security,
|
||||||
|
|
@ -613,6 +652,7 @@ class StreamSettings extends CommonClass {
|
||||||
HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings),
|
||||||
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
xHTTPStreamSettings.fromJson(json.xhttpSettings),
|
||||||
HysteriaStreamSettings.fromJson(json.hysteriaSettings),
|
HysteriaStreamSettings.fromJson(json.hysteriaSettings),
|
||||||
|
udpmasks,
|
||||||
SockoptStreamSettings.fromJson(json.sockopt),
|
SockoptStreamSettings.fromJson(json.sockopt),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -631,6 +671,7 @@ class StreamSettings extends CommonClass {
|
||||||
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined,
|
||||||
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
xhttpSettings: network === 'xhttp' ? this.xhttp.toJson() : undefined,
|
||||||
hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
|
hysteriaSettings: network === 'hysteria' ? this.hysteria.toJson() : undefined,
|
||||||
|
udpmasks: this.udpmasks.length > 0 ? this.udpmasks.map(mask => mask.toJson()) : undefined,
|
||||||
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -694,7 +735,8 @@ class Outbound extends CommonClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
canEnableTls() {
|
canEnableTls() {
|
||||||
if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol)) return false;
|
if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, Protocols.Hysteria].includes(this.protocol)) return false;
|
||||||
|
if (this.protocol === Protocols.Hysteria) return this.stream.network === 'hysteria';
|
||||||
return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.stream.network);
|
return ["tcp", "ws", "http", "grpc", "httpupgrade", "xhttp"].includes(this.stream.network);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -950,6 +992,7 @@ class Outbound extends CommonClass {
|
||||||
|
|
||||||
// Set hysteria stream settings
|
// Set hysteria stream settings
|
||||||
stream.hysteria.auth = password;
|
stream.hysteria.auth = password;
|
||||||
|
stream.hysteria.congestion = urlParams.get('congestion') ?? '';
|
||||||
stream.hysteria.up = urlParams.get('up') ?? '0';
|
stream.hysteria.up = urlParams.get('up') ?? '0';
|
||||||
stream.hysteria.down = urlParams.get('down') ?? '0';
|
stream.hysteria.down = urlParams.get('down') ?? '0';
|
||||||
stream.hysteria.udphopPort = urlParams.get('udphopPort') ?? '';
|
stream.hysteria.udphopPort = urlParams.get('udphopPort') ?? '';
|
||||||
|
|
|
||||||
|
|
@ -545,6 +545,12 @@
|
||||||
<a-form-item label='Auth Password'>
|
<a-form-item label='Auth Password'>
|
||||||
<a-input v-model.trim="outbound.stream.hysteria.auth"></a-input>
|
<a-input v-model.trim="outbound.stream.hysteria.auth"></a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label='Congestion'>
|
||||||
|
<a-select v-model="outbound.stream.hysteria.congestion" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value="">BBR (Auto)</a-select-option>
|
||||||
|
<a-select-option value="brutal">Brutal</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label='Upload Speed'>
|
<a-form-item label='Upload Speed'>
|
||||||
<a-input v-model.trim="outbound.stream.hysteria.up"
|
<a-input v-model.trim="outbound.stream.hysteria.up"
|
||||||
placeholder="0 (BBR mode), e.g., 100 mbps"></a-input>
|
placeholder="0 (BBR mode), e.g., 100 mbps"></a-input>
|
||||||
|
|
@ -596,6 +602,30 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- udpmasks settings -->
|
||||||
|
<template v-if="outbound.canEnableStream()">
|
||||||
|
<a-form-item label="UDP Masks">
|
||||||
|
<a-button icon="plus" type="primary" size="small" @click="outbound.stream.addUdpMask()"></a-button>
|
||||||
|
</a-form-item>
|
||||||
|
<template v-if="outbound.stream.udpmasks.length > 0">
|
||||||
|
<a-form v-for="(mask, index) in outbound.stream.udpmasks" :key="index" :colon="false"
|
||||||
|
:label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
||||||
|
<a-divider :style="{ margin: '0' }"> UDP Mask [[ index + 1 ]]
|
||||||
|
<a-icon type="delete" @click="() => outbound.stream.delUdpMask(index)"
|
||||||
|
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
|
||||||
|
</a-divider>
|
||||||
|
<a-form-item label='Type'>
|
||||||
|
<a-select v-model="mask.type" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||||
|
<a-select-option value="salamander">Salamander</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label='Password'>
|
||||||
|
<a-input v-model.trim="mask.password" placeholder="Obfuscation password"></a-input>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- tls settings -->
|
<!-- tls settings -->
|
||||||
<template v-if="outbound.canEnableTls()">
|
<template v-if="outbound.canEnableTls()">
|
||||||
<a-form-item label='{{ i18n "security" }}'>
|
<a-form-item label='{{ i18n "security" }}'>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue