mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-31 07:27:13 +00:00
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:
@@ -305,24 +305,39 @@ type InboundOption struct {
|
||||
// Hosting node; nil for this panel's own inbounds. Lets the clients
|
||||
// page map a node filter onto inbound IDs (#4997).
|
||||
NodeId *int `json:"nodeId,omitempty"`
|
||||
// Share-host resolution inputs, mirroring the subscription's
|
||||
// resolveInboundAddress so the clients page renders a node-managed WireGuard
|
||||
// Endpoint that points at the node, not the master panel. NodeAddress is the
|
||||
// hosting node's externally reachable address (empty for this panel's own
|
||||
// inbounds); Listen and ShareAddrStrategy/ShareAddr feed the same
|
||||
// node→listen→custom fallback the share/QR links already use.
|
||||
NodeAddress string `json:"nodeAddress,omitempty"`
|
||||
Listen string `json:"listen,omitempty"`
|
||||
ShareAddr string `json:"shareAddr,omitempty"`
|
||||
ShareAddrStrategy string `json:"shareAddrStrategy,omitempty"`
|
||||
}
|
||||
|
||||
func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error) {
|
||||
db := database.GetDB()
|
||||
var rows []struct {
|
||||
Id int `gorm:"column:id"`
|
||||
Remark string `gorm:"column:remark"`
|
||||
Tag string `gorm:"column:tag"`
|
||||
Protocol string `gorm:"column:protocol"`
|
||||
Port int `gorm:"column:port"`
|
||||
StreamSettings string `gorm:"column:stream_settings"`
|
||||
Settings string `gorm:"column:settings"`
|
||||
NodeId *int `gorm:"column:node_id"`
|
||||
Id int `gorm:"column:id"`
|
||||
Remark string `gorm:"column:remark"`
|
||||
Tag string `gorm:"column:tag"`
|
||||
Protocol string `gorm:"column:protocol"`
|
||||
Port int `gorm:"column:port"`
|
||||
StreamSettings string `gorm:"column:stream_settings"`
|
||||
Settings string `gorm:"column:settings"`
|
||||
Listen string `gorm:"column:listen"`
|
||||
ShareAddr string `gorm:"column:share_addr"`
|
||||
ShareAddrStrategy string `gorm:"column:share_addr_strategy"`
|
||||
NodeId *int `gorm:"column:node_id"`
|
||||
NodeAddress string `gorm:"column:node_address"`
|
||||
}
|
||||
err := db.Table("inbounds").
|
||||
Select("id, remark, tag, protocol, port, stream_settings, settings, node_id").
|
||||
Where("user_id = ?", userId).
|
||||
Order("id ASC").
|
||||
Select("inbounds.id, inbounds.remark, inbounds.tag, inbounds.protocol, inbounds.port, inbounds.stream_settings, inbounds.settings, inbounds.listen, inbounds.share_addr, inbounds.share_addr_strategy, inbounds.node_id, COALESCE(nodes.address, '') AS node_address").
|
||||
Joins("LEFT JOIN nodes ON nodes.id = inbounds.node_id").
|
||||
Where("inbounds.user_id = ?", userId).
|
||||
Order("inbounds.id ASC").
|
||||
Scan(&rows).Error
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, err
|
||||
@@ -330,18 +345,26 @@ func (s *InboundService) GetInboundOptions(userId int) ([]InboundOption, error)
|
||||
out := make([]InboundOption, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
wgPublicKey, wgMtu, wgDns := inboundWireguardHints(r.Protocol, r.Settings)
|
||||
shareAddrStrategy := r.ShareAddrStrategy
|
||||
if shareAddrStrategy == "node" {
|
||||
shareAddrStrategy = ""
|
||||
}
|
||||
out = append(out, InboundOption{
|
||||
Id: r.Id,
|
||||
Remark: r.Remark,
|
||||
Tag: r.Tag,
|
||||
Protocol: r.Protocol,
|
||||
Port: r.Port,
|
||||
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings, r.Settings),
|
||||
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
|
||||
WgPublicKey: wgPublicKey,
|
||||
WgMtu: wgMtu,
|
||||
WgDns: wgDns,
|
||||
NodeId: r.NodeId,
|
||||
Id: r.Id,
|
||||
Remark: r.Remark,
|
||||
Tag: r.Tag,
|
||||
Protocol: r.Protocol,
|
||||
Port: r.Port,
|
||||
TlsFlowCapable: inboundCanEnableTlsFlow(r.Protocol, r.StreamSettings, r.Settings),
|
||||
SsMethod: inboundShadowsocksMethod(r.Protocol, r.Settings),
|
||||
WgPublicKey: wgPublicKey,
|
||||
WgMtu: wgMtu,
|
||||
WgDns: wgDns,
|
||||
NodeId: r.NodeId,
|
||||
NodeAddress: r.NodeAddress,
|
||||
Listen: r.Listen,
|
||||
ShareAddr: r.ShareAddr,
|
||||
ShareAddrStrategy: shareAddrStrategy,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
|
||||
Reference in New Issue
Block a user