fix: Prevent unintended use of SPN nodes when intel data is not yet applied

Related Issue Details:
In some situations, SPN intel data was not fully applied.
This lead to Portmaster making connections that don’t align with the intended intel preferences.

https://github.com/safing/portmaster/issues/1999
https://github.com/safing/portmaster-shadow/issues/35
This commit is contained in:
Alexandr Stelnykovych
2025-09-02 18:26:34 +03:00
parent d67c8e9a04
commit 7a95b021a5
5 changed files with 28 additions and 5 deletions

View File

@@ -67,14 +67,18 @@ func (m *Map) GetIntel() *hub.Intel {
}
func (m *Map) updateIntelStatuses(pin *Pin, trustNodes []string) {
// Reset all related states.
pin.removeStates(StateTrusted | StateUsageDiscouraged | StateUsageAsHomeDiscouraged | StateUsageAsDestinationDiscouraged)
// Reset all related states (StateSummaryStatusesAppliedFromIntel).
pin.stateIntelApplied.UnSet()
pin.removeStates(StateTrusted | StateUsageDiscouraged | StateUsageAsHomeDiscouraged | StateUsageAsDestinationDiscouraged) // same as: StateSummaryStatusesAppliedFromIntel
// Check if Intel data is loaded.
if m.intel == nil {
return
}
// Indicate that intel statuses have been applied to the pin
defer pin.stateIntelApplied.Set()
// Check Hub Intel
hubIntel, ok := m.intel.Hubs[pin.Hub.ID]
if ok {

View File

@@ -246,6 +246,14 @@ func (o *HubOptions) Matcher(hubType HubType, hubIntel *hub.Intel) PinMatcher {
return false
}
// Check if all required states from intel were applied.
if regard.HasAnyOf(StateSummaryStatusesAppliedFromIntel) || disregard.HasAnyOf(StateSummaryStatusesAppliedFromIntel) {
if pin.stateIntelApplied.IsNotSet() {
log.Warningf("spn/navigator: pin %s skipped as intel statuses were not applied", pin.Hub.ID)
return false
}
}
// Check verified owners.
if len(o.RequireVerifiedOwners) > 0 {
// Check if Pin has a verified owner at all.

View File

@@ -26,6 +26,10 @@ type Pin struct { //nolint:maligned
// Hub Status
State PinState
// stateIntelApplied signifies that states from intel file were applied to the pin.
stateIntelApplied *abool.AtomicBool
// VerifiedOwner holds the name of the verified owner / operator of the Hub.
VerifiedOwner string
// HopDistance signifies the needed hops to reach this Hub.

View File

@@ -91,6 +91,12 @@ const (
StateOffline |
StateUsageDiscouraged |
StateIsHomeHub
// StateSummaryStatusesAppliedFromIntel summarizes all states that are applied from the intel file.
StateSummaryStatusesAppliedFromIntel = StateTrusted |
StateUsageDiscouraged |
StateUsageAsHomeDiscouraged |
StateUsageAsDestinationDiscouraged
)
var allStates = []PinState{

View File

@@ -168,9 +168,10 @@ func (m *Map) updateHub(h *hub.Hub, lockMap, lockHub bool) {
pin.Hub = h
} else {
pin = &Pin{
Hub: h,
ConnectedTo: make(map[string]*Lane),
pushChanges: abool.New(),
Hub: h,
ConnectedTo: make(map[string]*Lane),
stateIntelApplied: abool.New(),
pushChanges: abool.New(),
}
m.all[h.ID] = pin
}