fix(panel): use the hosting node address for WireGuard client configs (#5679)

* fix(panel): use the hosting node address for WireGuard client configs

The clients page rendered a node-managed WireGuard inbound's config with the
master panel's host in Endpoint instead of the hosting node's address, so the
copied/QR config pointed at the wrong server. The subscription path already
resolves this via resolveInboundAddress; the UI generator did not.

Expose the share-host resolution inputs (node address, listen, share-address
strategy/address) on InboundOption and route buildWireguardClientConfig through
the same canonical resolver the inbounds-page share links use, extracted as
resolveShareHost. This also brings local inbounds with a shareable listen or a
listen/custom share strategy into parity with the subscription Endpoint; the
common listen=0.0.0.0 case still falls back to the panel host.

* fix(frontend): keep a raw fallback host and refresh node-fed inbound options

Code review of the WireGuard node-endpoint change surfaced two gaps.
resolveShareHost normalized its last-resort fallbackHostname, so a panel
reached via a hostname the share-host grammar rejects (underscore label,
trailing-dot FQDN) emitted a broken 'Endpoint = :51820'; the fallback now
stays verbatim when normalization empties it. Node mutations only
invalidated the nodes query, leaving the staleTime-Infinity inbound
options cache serving an edited node address until the sync job
broadcast (never, for disabled/offline nodes); they now invalidate the
options key too.

Also folds the ShareHostFields projections into direct structural passes,
elides the default node shareAddrStrategy so omitempty drops it, and
replaces the nullable node-address scan with COALESCE.

---------

Co-authored-by: STRENCH0 <17428017+STRENCH0@users.noreply.github.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
Grigoriy
2026-07-03 02:12:32 +03:00
committed by GitHub
parent dbdecda03f
commit f90e4a6962
12 changed files with 267 additions and 46 deletions
+4
View File
@@ -400,10 +400,14 @@ export const EXAMPLES: Record<string, unknown> = {
},
"InboundOption": {
"id": 1,
"listen": "",
"nodeAddress": "",
"nodeId": null,
"port": 443,
"protocol": "vless",
"remark": "VLESS-443",
"shareAddr": "",
"shareAddrStrategy": "",
"ssMethod": "",
"tag": "in-443-tcp",
"tlsFlowCapable": true,
+13
View File
@@ -1802,6 +1802,13 @@ export const SCHEMAS: Record<string, unknown> = {
"example": 1,
"type": "integer"
},
"listen": {
"type": "string"
},
"nodeAddress": {
"description": "Share-host resolution inputs, mirroring the subscription's\nresolveInboundAddress so the clients page renders a node-managed WireGuard\nEndpoint that points at the node, not the master panel. NodeAddress is the\nhosting node's externally reachable address (empty for this panel's own\ninbounds); Listen and ShareAddrStrategy/ShareAddr feed the same\nnode→listen→custom fallback the share/QR links already use.",
"type": "string"
},
"nodeId": {
"description": "Hosting node; nil for this panel's own inbounds. Lets the clients\npage map a node filter onto inbound IDs (#4997).",
"nullable": true,
@@ -1819,6 +1826,12 @@ export const SCHEMAS: Record<string, unknown> = {
"example": "VLESS-443",
"type": "string"
},
"shareAddr": {
"type": "string"
},
"shareAddrStrategy": {
"type": "string"
},
"ssMethod": {
"type": "string"
},
+4
View File
@@ -394,10 +394,14 @@ export interface InboundFallback {
export interface InboundOption {
id: number;
listen?: string;
nodeAddress?: string;
nodeId?: number | null;
port: number;
protocol: string;
remark: string;
shareAddr?: string;
shareAddrStrategy?: string;
ssMethod: string;
tag: string;
tlsFlowCapable: boolean;
+4
View File
@@ -421,10 +421,14 @@ export type InboundFallback = z.infer<typeof InboundFallbackSchema>;
export const InboundOptionSchema = z.object({
id: z.number().int(),
listen: z.string().optional(),
nodeAddress: z.string().optional(),
nodeId: z.number().int().nullable().optional(),
port: z.number().int(),
protocol: z.string(),
remark: z.string(),
shareAddr: z.string().optional(),
shareAddrStrategy: z.string().optional(),
ssMethod: z.string(),
tag: z.string(),
tlsFlowCapable: z.boolean(),