XDNS finalmask: Support resolvers (client) and domains (server)

Treat the xdns mask type as a multi-value setting and update forms accordingly. Inbound/outbound UdpMask models now return arrays for xdns (inbound: settings.domains, outbound: settings.resolvers) using Array.isArray checks. UI templates were split so 'header-dns' still uses a single domain string, while 'xdns' renders a tags-style <a-select> for multiple entries (domains/resolvers). Conditionals were made explicit (mask.type === ...) instead of using includes(). Changed files: web/assets/js/model/inbound.js, web/assets/js/model/outbound.js, web/html/form/outbound.html, web/html/form/stream/stream_finalmask.html.
This commit is contained in:
MHSanaei 2026-04-20 19:09:45 +02:00
parent 2b3b2770b4
commit 88dafa6cdf
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
4 changed files with 28 additions and 10 deletions

View file

@ -1073,8 +1073,9 @@ class UdpMask extends XrayCommonClass {
case 'mkcp-aes128gcm': case 'mkcp-aes128gcm':
return { password: settings.password || '' }; return { password: settings.password || '' };
case 'header-dns': case 'header-dns':
case 'xdns':
return { domain: settings.domain || '' }; return { domain: settings.domain || '' };
case 'xdns':
return { domains: Array.isArray(settings.domains) ? settings.domains : [] };
case 'xicmp': case 'xicmp':
return { ip: settings.ip || '', id: settings.id ?? 0 }; return { ip: settings.ip || '', id: settings.id ?? 0 };
case 'mkcp-original': case 'mkcp-original':

View file

@ -573,8 +573,9 @@ class UdpMask extends CommonClass {
case 'mkcp-aes128gcm': case 'mkcp-aes128gcm':
return { password: settings.password || '' }; return { password: settings.password || '' };
case 'header-dns': case 'header-dns':
case 'xdns':
return { domain: settings.domain || '' }; return { domain: settings.domain || '' };
case 'xdns':
return { resolvers: Array.isArray(settings.resolvers) ? settings.resolvers : [] };
case 'xicmp': case 'xicmp':
return { ip: settings.ip || '', id: settings.id ?? 0 }; return { ip: settings.ip || '', id: settings.id ?? 0 };
case 'mkcp-original': case 'mkcp-original':

View file

@ -886,15 +886,23 @@
placeholder="Obfuscation password" placeholder="Obfuscation password"
></a-input> ></a-input>
</a-form-item> </a-form-item>
<a-form-item <a-form-item label="Domain" v-if="mask.type === 'header-dns'">
label="Domain"
v-if="['header-dns', 'xdns'].includes(mask.type)"
>
<a-input <a-input
v-model.trim="mask.settings.domain" v-model.trim="mask.settings.domain"
placeholder="e.g., www.example.com" placeholder="e.g., www.example.com"
></a-input> ></a-input>
</a-form-item> </a-form-item>
<template v-if="mask.type === 'xdns'">
<a-form-item label="Resolvers">
<a-select
mode="tags"
v-model="mask.settings.resolvers"
:style="{ width: '100%' }"
:token-separators="[',']"
placeholder="e.g., xxx+udp://8.8.8.8:53"
></a-select>
</a-form-item>
</template>
<template v-if="mask.type === 'header-custom'"> <template v-if="mask.type === 'header-custom'">
<a-form-item label="Client"> <a-form-item label="Client">
<a-icon <a-icon

View file

@ -81,15 +81,23 @@
placeholder="Obfuscation password" placeholder="Obfuscation password"
></a-input> ></a-input>
</a-form-item> </a-form-item>
<a-form-item <a-form-item label="Domain" v-if="mask.type === 'header-dns'">
label="Domain"
v-if="['header-dns', 'xdns'].includes(mask.type)"
>
<a-input <a-input
v-model.trim="mask.settings.domain" v-model.trim="mask.settings.domain"
placeholder="e.g., www.example.com" placeholder="e.g., www.example.com"
></a-input> ></a-input>
</a-form-item> </a-form-item>
<template v-if="mask.type === 'xdns'">
<a-form-item label="Domains">
<a-select
mode="tags"
v-model="mask.settings.domains"
:style="{ width: '100%' }"
:token-separators="[',']"
placeholder="e.g., www.example.com"
></a-select>
</a-form-item>
</template>
<template v-if="mask.type === 'header-custom'"> <template v-if="mask.type === 'header-custom'">
<a-form-item label="Client"> <a-form-item label="Client">
<a-icon <a-icon