mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 15:17:14 +00:00
feat(sub): let the panel set the JSON subscription DNS servers (#6485)
* feat(sub): let the panel set the JSON subscription DNS servers A baked routing profile (#6402) carries only the DNS its preset defines, so an operator who wants their own resolvers has to override the whole profile or patch the subscription behind a proxy. Add the subJsonDns setting: either a full xray dns block or a bare array of servers. It wins over the profile's DNS while leaving the profile's routing rules intact, and reaches per-inbound, balancer and info-node documents alike. The value is validated with xray's own schema (internal/xray/dnsconf): a block the client could not load is rejected when the settings are saved and ignored with a warning at request time, instead of being baked into every document. Both the sub server and the settings API share that validator, so a stored value can never be silently dropped. xray's Build() is deliberately not used for validation: it resolves geosite tokens from the geodata files and would reject valid configs whenever those are absent from the panel's working directory. * style(dnsconf): drop the ineffectual initial map assignment golangci's ineffassign flagged the zero-value map whose value both paths overwrite: the object branch now assigns the decoded map directly. * docs(sub): scope the DNS setting to the documents it rewrites The Routing header mirrored to Happ/INCY keeps the routing profile's own resolvers, so the setting description and the header-source comment now say so instead of claiming the profile's DNS is replaced everywhere. Also trims two comments in the new dnsconf package to the repo's two-line cap.
This commit is contained in:
@@ -88,6 +88,7 @@ export const EXAMPLES: Record<string, unknown> = {
|
||||
"subInfoNodeEnable": false,
|
||||
"subJsonAlwaysArray": false,
|
||||
"subJsonAutoDetect": false,
|
||||
"subJsonDns": "",
|
||||
"subJsonEnable": false,
|
||||
"subJsonFinalMask": "",
|
||||
"subJsonMux": "",
|
||||
@@ -229,6 +230,7 @@ export const EXAMPLES: Record<string, unknown> = {
|
||||
"subInfoNodeEnable": false,
|
||||
"subJsonAlwaysArray": false,
|
||||
"subJsonAutoDetect": false,
|
||||
"subJsonDns": "",
|
||||
"subJsonEnable": false,
|
||||
"subJsonFinalMask": "",
|
||||
"subJsonMux": "",
|
||||
|
||||
@@ -282,6 +282,9 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"subJsonAutoDetect": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"subJsonDns": {
|
||||
"type": "string"
|
||||
},
|
||||
"subJsonEnable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -519,6 +522,7 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"subInfoNodeEnable",
|
||||
"subJsonAlwaysArray",
|
||||
"subJsonAutoDetect",
|
||||
"subJsonDns",
|
||||
"subJsonEnable",
|
||||
"subJsonFinalMask",
|
||||
"subJsonMux",
|
||||
@@ -870,6 +874,9 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"subJsonAutoDetect": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"subJsonDns": {
|
||||
"type": "string"
|
||||
},
|
||||
"subJsonEnable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -1114,6 +1121,7 @@ export const SCHEMAS: Record<string, unknown> = {
|
||||
"subInfoNodeEnable",
|
||||
"subJsonAlwaysArray",
|
||||
"subJsonAutoDetect",
|
||||
"subJsonDns",
|
||||
"subJsonEnable",
|
||||
"subJsonFinalMask",
|
||||
"subJsonMux",
|
||||
|
||||
@@ -96,6 +96,7 @@ export interface AllSetting {
|
||||
subInfoNodeEnable: boolean;
|
||||
subJsonAlwaysArray: boolean;
|
||||
subJsonAutoDetect: boolean;
|
||||
subJsonDns: string;
|
||||
subJsonEnable: boolean;
|
||||
subJsonFinalMask: string;
|
||||
subJsonMux: string;
|
||||
@@ -238,6 +239,7 @@ export interface AllSettingView {
|
||||
subInfoNodeEnable: boolean;
|
||||
subJsonAlwaysArray: boolean;
|
||||
subJsonAutoDetect: boolean;
|
||||
subJsonDns: string;
|
||||
subJsonEnable: boolean;
|
||||
subJsonFinalMask: string;
|
||||
subJsonMux: string;
|
||||
|
||||
@@ -112,6 +112,7 @@ export const AllSettingSchema = z.object({
|
||||
subInfoNodeEnable: z.boolean(),
|
||||
subJsonAlwaysArray: z.boolean(),
|
||||
subJsonAutoDetect: z.boolean(),
|
||||
subJsonDns: z.string(),
|
||||
subJsonEnable: z.boolean(),
|
||||
subJsonFinalMask: z.string(),
|
||||
subJsonMux: z.string(),
|
||||
@@ -255,6 +256,7 @@ export const AllSettingViewSchema = z.object({
|
||||
subInfoNodeEnable: z.boolean(),
|
||||
subJsonAlwaysArray: z.boolean(),
|
||||
subJsonAutoDetect: z.boolean(),
|
||||
subJsonDns: z.string(),
|
||||
subJsonEnable: z.boolean(),
|
||||
subJsonFinalMask: z.string(),
|
||||
subJsonMux: z.string(),
|
||||
|
||||
@@ -70,6 +70,7 @@ export class AllSetting {
|
||||
subJsonMux = '';
|
||||
subJsonRules = '';
|
||||
subJsonRoutingRules = '';
|
||||
subJsonDns = '';
|
||||
subJsonFinalMask = '';
|
||||
subJsonObservatory = '';
|
||||
subThemeDir = '';
|
||||
|
||||
@@ -241,6 +241,18 @@ export default function SubscriptionFormatsTab({
|
||||
autoSize={{ minRows: 2, maxRows: 6 }}
|
||||
/>
|
||||
</SettingListItem>
|
||||
<SettingListItem
|
||||
paddings="small"
|
||||
title={t('pages.settings.subJsonDns')}
|
||||
description={t('pages.settings.subJsonDnsDesc')}
|
||||
>
|
||||
<Input.TextArea
|
||||
value={allSetting.subJsonDns}
|
||||
placeholder='{"servers": ["https://dns.google/dns-query", "tls://1.1.1.1"]}'
|
||||
onChange={(e) => updateSetting({ subJsonDns: e.target.value })}
|
||||
autoSize={{ minRows: 2, maxRows: 6 }}
|
||||
/>
|
||||
</SettingListItem>
|
||||
</Card>
|
||||
)}
|
||||
{allSetting.subClashEnable && (
|
||||
|
||||
@@ -75,6 +75,7 @@ export const AllSettingSchema = z
|
||||
subJsonMux: z.string().optional(),
|
||||
subJsonRules: z.string().optional(),
|
||||
subJsonRoutingRules: z.string().optional(),
|
||||
subJsonDns: z.string().optional(),
|
||||
subJsonFinalMask: z.string().optional(),
|
||||
subJsonObservatory: z.string().optional(),
|
||||
subHideSettings: z.boolean().optional(),
|
||||
|
||||
Reference in New Issue
Block a user