diff --git a/management/internals/network_map_db/pgsql/network_map_data.go b/management/internals/network_map_db/pgsql/network_map_data.go index e94444908..6d150ca30 100644 --- a/management/internals/network_map_db/pgsql/network_map_data.go +++ b/management/internals/network_map_db/pgsql/network_map_data.go @@ -81,6 +81,10 @@ func (pg *PgStore) GetNetworkMapData(ctx context.Context, accountId string) (*ne if err != nil { return rollbackAndReturnError(ctx, tx, err) } + proxyTargetedDomainResourceIDs, err := GetProxyTargetedDomainResourceIDsViaPgxConnection(ctx, tx.Conn(), accountId) + if err != nil { + return rollbackAndReturnError(ctx, tx, fmt.Errorf("failed to get proxy targeted domain resources: %w", err)) + } resourcePolicies := make(map[string][]*nmdata.Policy) for _, resource := range networkResources { @@ -131,6 +135,8 @@ func (pg *PgStore) GetNetworkMapData(ctx context.Context, accountId string) (*ne AppliedZoneCandidates: dnsZones, PrivateServiceCandidates: buildPrivateServiceCandidates(services, domains, proxyPeers), PostureCheckXIDToPublicID: postureCheckXIDToPublicID, + + ProxyTargetedDomainResourceIDs: proxyTargetedDomainResourceIDs, } return &toret, nil diff --git a/management/internals/network_map_db/pgsql/service.go b/management/internals/network_map_db/pgsql/service.go index d4ad31219..add69a208 100644 --- a/management/internals/network_map_db/pgsql/service.go +++ b/management/internals/network_map_db/pgsql/service.go @@ -13,6 +13,14 @@ const ( from services where account_id=$1 ` + + GetProxyTargetedDomainResourcesQuery = ` + select t.target_id + from targets as t + join services as s on s.id = t.service_id + where s.account_id=$1 and s.enabled and not coalesce(s.terminated, false) + and t.enabled and t.target_type='domain' and t.target_id is not null + ` ) func (pg *PgStore) GetPrivateServices(ctx context.Context, accountId string) ([]service, error) { @@ -32,6 +40,24 @@ func GetPrivateServicesViaPgxConnection(ctx context.Context, conn *pgx.Conn, acc return pgx.CollectRows(rows, pgx.RowToStructByName[service]) } +func GetProxyTargetedDomainResourceIDsViaPgxConnection(ctx context.Context, conn *pgx.Conn, accountId string) (map[string]struct{}, error) { + rows, err := conn.Query(ctx, GetProxyTargetedDomainResourcesQuery, accountId) + if err != nil { + return nil, err + } + + ids, err := pgx.CollectRows(rows, pgx.RowTo[string]) + if err != nil { + return nil, err + } + + toret := make(map[string]struct{}, len(ids)) + for _, id := range ids { + toret[id] = struct{}{} + } + return toret, nil +} + type service struct { Enabled sql.NullBool Private sql.NullBool diff --git a/management/server/types/account.go b/management/server/types/account.go index 54f1f21b0..4d726acbc 100644 --- a/management/server/types/account.go +++ b/management/server/types/account.go @@ -978,34 +978,6 @@ func (a *Account) GetPeerConnectionResources(ctx context.Context, peer *nbpeer.P return peers, fwRules, authorizedUsers, sshEnabled } -// forcesRoutingPeerDNSResolution reports whether the given peer must run -// routing-peer DNS resolution regardless of the account-global -// RoutingPeerDNSResolutionEnabled setting. It returns true when the peer is a -// router for a domain network resource that is targeted by an enabled -// reverse-proxy service, so the peer's DNS forwarder starts and can resolve -// the target for the embedded proxy peers. Embedded proxy peers themselves are -// handled at PeerConfig build time. -func (a *Account) forcesRoutingPeerDNSResolution(peerID string, routers map[string]map[string]*routerTypes.NetworkRouter) bool { - targeted := a.proxyTargetedDomainResourceIDs() - if len(targeted) == 0 { - return false - } - - for _, resource := range a.NetworkResources { - if resource == nil || !resource.Enabled || resource.Type != resourceTypes.Domain { - continue - } - if _, ok := targeted[resource.ID]; !ok { - continue - } - if _, isRouter := routers[resource.NetworkID][peerID]; isRouter { - return true - } - } - - return false -} - // proxyTargetedDomainResourceIDs returns the set of domain network resource IDs // targeted by an enabled, non-terminated reverse-proxy service. func (a *Account) proxyTargetedDomainResourceIDs() map[string]struct{} { diff --git a/management/server/types/account_components.go b/management/server/types/account_components.go index 1a4f87ef0..f95ad817d 100644 --- a/management/server/types/account_components.go +++ b/management/server/types/account_components.go @@ -104,9 +104,5 @@ func (a *Account) GetPeerNetworkMapComponents( groupIDToUserIDs map[string][]string, ) *NetworkMapComponents { nmd := a.toNetworkMapData(accountZones, validatedPeersMap, resourcePolicies, routers, groupIDToUserIDs) - components := nmd.GetPeerNetworkMapComponents(peerID, TwinCustomZone(peersCustomZone)) - if components != nil { - components.ForceRoutingPeerDNSResolution = a.forcesRoutingPeerDNSResolution(peerID, routers) - } - return components + return nmd.GetPeerNetworkMapComponents(peerID, TwinCustomZone(peersCustomZone)) } diff --git a/management/server/types/account_networkmapdata.go b/management/server/types/account_networkmapdata.go index 1613628da..5ec15aecd 100644 --- a/management/server/types/account_networkmapdata.go +++ b/management/server/types/account_networkmapdata.go @@ -108,6 +108,7 @@ func (a *Account) toNetworkMapData( nmd.Routers[networkID] = twinInner } + nmd.ProxyTargetedDomainResourceIDs = a.proxyTargetedDomainResourceIDs() nmd.AppliedZoneCandidates = buildAppliedZoneCandidates(accountZones) nmd.PrivateServiceCandidates = a.buildPrivateServiceCandidates() diff --git a/shared/management/networkmap/networkmapcompute.go b/shared/management/networkmap/networkmapcompute.go index c5f126228..0d4cf4b6f 100644 --- a/shared/management/networkmap/networkmapcompute.go +++ b/shared/management/networkmap/networkmapcompute.go @@ -17,37 +17,42 @@ type sshRequirements struct { // exactly, operating on nmdata twins throughout — no Account reference and no // twin↔real conversion, since the produced components hold twins. func (nmd *NetworkMapData) GetPeerNetworkMapComponents(peerID string, peersCustomZone nmdata.CustomZone) *types.NetworkMapComponents { + forceRoutingPeerDNS := nmd.forcesRoutingPeerDNSResolution(peerID) + peer := nmd.Peers[peerID] if peer == nil { return types.EmptyNetworkMapComponents(&types.NetworkMapComponents{ - PeerID: peerID, - Network: nmd.Network, - Peers: map[string]*nmdata.Peer{peerID: peer}, + PeerID: peerID, + Network: nmd.Network, + Peers: map[string]*nmdata.Peer{peerID: peer}, + ForceRoutingPeerDNSResolution: forceRoutingPeerDNS, }) } if _, ok := nmd.ValidatedPeers[peerID]; !ok { return types.EmptyNetworkMapComponents(&types.NetworkMapComponents{ - PeerID: peerID, - Network: nmd.Network, - Peers: map[string]*nmdata.Peer{peerID: peer}, + PeerID: peerID, + Network: nmd.Network, + Peers: map[string]*nmdata.Peer{peerID: peer}, + ForceRoutingPeerDNSResolution: forceRoutingPeerDNS, }) } components := &types.NetworkMapComponents{ - PeerID: peerID, - Network: nmd.Network, - AccountSettings: nmd.AccountSettings, - DNSSettings: nmd.DNSSettings, - CustomZoneDomain: peersCustomZone.Domain, - NameServerGroups: make([]*nmdata.NameServerGroup, 0), - ResourcePoliciesMap: make(map[string][]*nmdata.Policy), - RoutersMap: make(map[string]map[string]*nmdata.NetworkRouter), - NetworkResources: make([]*nmdata.NetworkResource, 0), - PostureFailedPeers: make(map[string]map[string]struct{}, len(nmd.PostureChecks)), - RouterPeers: make(map[string]*nmdata.Peer), - NetworkXIDToPublicID: nmd.NetworkXIDToPublicID, - PostureCheckXIDToPublicID: nmd.PostureCheckXIDToPublicID, + PeerID: peerID, + Network: nmd.Network, + AccountSettings: nmd.AccountSettings, + DNSSettings: nmd.DNSSettings, + CustomZoneDomain: peersCustomZone.Domain, + NameServerGroups: make([]*nmdata.NameServerGroup, 0), + ResourcePoliciesMap: make(map[string][]*nmdata.Policy), + RoutersMap: make(map[string]map[string]*nmdata.NetworkRouter), + NetworkResources: make([]*nmdata.NetworkResource, 0), + PostureFailedPeers: make(map[string]map[string]struct{}, len(nmd.PostureChecks)), + RouterPeers: make(map[string]*nmdata.Peer), + NetworkXIDToPublicID: nmd.NetworkXIDToPublicID, + PostureCheckXIDToPublicID: nmd.PostureCheckXIDToPublicID, + ForceRoutingPeerDNSResolution: forceRoutingPeerDNS, } relevantPeers, relevantGroups, relevantPolicies, relevantRoutes, sshReqs := nmd.getPeersGroupsPoliciesRoutes(peerID, peer.SSHEnabled, &components.PostureFailedPeers) @@ -473,6 +478,31 @@ func (nmd *NetworkMapData) getPostureValidPeersSaveFailed(inputPeers []string, p return dest } +// forcesRoutingPeerDNSResolution reports whether the given peer must run +// routing-peer DNS resolution regardless of the account-global +// RoutingPeerDNSResolutionEnabled setting: true when the peer routes a domain +// network resource targeted by an enabled reverse-proxy service, so the peer's +// DNS forwarder starts and can resolve the target for the embedded proxy peers. +func (nmd *NetworkMapData) forcesRoutingPeerDNSResolution(peerID string) bool { + if len(nmd.ProxyTargetedDomainResourceIDs) == 0 { + return false + } + + for _, resource := range nmd.NetworkResources { + if resource == nil || !resource.Enabled || resource.Type != string(types.ResourceTypeDomain) { + continue + } + if _, ok := nmd.ProxyTargetedDomainResourceIDs[resource.ID]; !ok { + continue + } + if _, isRouter := nmd.Routers[resource.NetworkID][peerID]; isRouter { + return true + } + } + + return false +} + func (nmd *NetworkMapData) GetPeerGroups(peerID string) map[string]struct{} { groups := make(map[string]struct{}) for groupID, group := range nmd.Groups { diff --git a/shared/management/networkmap/networkmapdata.go b/shared/management/networkmap/networkmapdata.go index 9193daa41..272f6152a 100644 --- a/shared/management/networkmap/networkmapdata.go +++ b/shared/management/networkmap/networkmapdata.go @@ -32,6 +32,11 @@ type NetworkMapData struct { GroupIDToUserIDs map[string][]string DNSDomain string + // ProxyTargetedDomainResourceIDs is the account-level half of + // forcesRoutingPeerDNSResolution: domain network resources targeted by an + // enabled reverse-proxy service. + ProxyTargetedDomainResourceIDs map[string]struct{} + AppliedZoneCandidates []AppliedZoneCandidate PrivateServiceCandidates []PrivateServiceCandidate }