mirror of
https://github.com/safing/portbase
synced 2025-09-02 02:29:59 +00:00
238 lines
6.5 KiB
Go
238 lines
6.5 KiB
Go
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
|
|
package configuration
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/Safing/safing-core/database"
|
|
"github.com/Safing/safing-core/log"
|
|
"github.com/Safing/safing-core/modules"
|
|
)
|
|
|
|
// think about:
|
|
// config changes validation (e.g. if on in secure mode, must be on in fortress mode)
|
|
// config switches
|
|
// small codebase
|
|
// nice api
|
|
// be static as much as possible
|
|
|
|
const (
|
|
SecurityLevelOff int8 = 0
|
|
SecurityLevelDynamic int8 = 1
|
|
SecurityLevelSecure int8 = 2
|
|
SecurityLevelFortress int8 = 3
|
|
|
|
CompetenceLevelNone int8 = 0
|
|
CompetenceLevelBasic int8 = 1
|
|
CompetenceLevelPowerUser int8 = 2
|
|
CompetenceLevelExpert int8 = 3
|
|
|
|
StatusOk int8 = 0
|
|
StatusWarning int8 = 1
|
|
StatusError int8 = 2
|
|
)
|
|
|
|
var (
|
|
configurationModule *modules.Module
|
|
|
|
lastChange *int64
|
|
securityLevel *int32
|
|
|
|
lock sync.RWMutex
|
|
status *SystemStatus
|
|
currentConfig *Configuration
|
|
)
|
|
|
|
func init() {
|
|
configurationModule = modules.Register("Configuration", 128)
|
|
|
|
initDefaultConfig()
|
|
initSystemStatusModel()
|
|
initConfigurationModel()
|
|
|
|
lastChangeValue := time.Now().Unix()
|
|
lastChange = &lastChangeValue
|
|
|
|
var securityLevelValue int32
|
|
securityLevel = &securityLevelValue
|
|
|
|
var err error
|
|
config, err := GetConfiguration(configurationInstanceName)
|
|
if err != nil {
|
|
log.Warningf("configuration: could not load configuration: %s", err)
|
|
loadedConfig := defaultConfig
|
|
config = &loadedConfig
|
|
err = config.Create(configurationInstanceName)
|
|
if err != nil {
|
|
log.Warningf("configuration: could not save new configuration: %s", err)
|
|
}
|
|
}
|
|
|
|
status, err = GetSystemStatus()
|
|
if err != nil {
|
|
log.Warningf("configuration: could not load status: %s", err)
|
|
status = &SystemStatus{
|
|
CurrentSecurityLevel: 1,
|
|
SelectedSecurityLevel: 1,
|
|
}
|
|
err = status.Create()
|
|
if err != nil {
|
|
log.Warningf("configuration: could not save new status: %s", err)
|
|
}
|
|
}
|
|
|
|
log.Infof("configuration: initial security level is [%s]", status.FmtSecurityLevel())
|
|
// atomic.StoreInt32(securityLevel, int32(status.CurrentSecurityLevel))
|
|
|
|
updateConfig(config)
|
|
|
|
go configChangeListener()
|
|
go statusChangeListener()
|
|
}
|
|
|
|
func configChangeListener() {
|
|
sub := database.NewSubscription()
|
|
sub.Subscribe(fmt.Sprintf("%s/Configuration:%s", database.Me.String(), configurationInstanceName))
|
|
for {
|
|
var receivedModel database.Model
|
|
|
|
select {
|
|
case <-configurationModule.Stop:
|
|
configurationModule.StopComplete()
|
|
return
|
|
case receivedModel = <-sub.Updated:
|
|
case receivedModel = <-sub.Created:
|
|
}
|
|
|
|
config, ok := database.SilentEnsureModel(receivedModel, configurationModel).(*Configuration)
|
|
if !ok {
|
|
log.Warning("configuration: received config update, but was not of type *Configuration")
|
|
continue
|
|
}
|
|
|
|
updateConfig(config)
|
|
|
|
}
|
|
}
|
|
|
|
func updateConfig(update *Configuration) {
|
|
new := &Configuration{}
|
|
|
|
if update.EnforceCT > 0 && update.EnforceCT < 4 {
|
|
new.EnforceCT = update.EnforceCT
|
|
} else {
|
|
new.EnforceCT = defaultConfig.EnforceCT
|
|
}
|
|
if update.EnforceRevocation > 0 && update.EnforceRevocation < 4 {
|
|
new.EnforceRevocation = update.EnforceRevocation
|
|
} else {
|
|
new.EnforceRevocation = defaultConfig.EnforceRevocation
|
|
}
|
|
if update.DenyInsecureTLS > 0 && update.DenyInsecureTLS < 4 {
|
|
new.DenyInsecureTLS = update.DenyInsecureTLS
|
|
} else {
|
|
new.DenyInsecureTLS = defaultConfig.DenyInsecureTLS
|
|
}
|
|
if update.DenyTLSWithoutSNI > 0 && update.DenyTLSWithoutSNI < 4 {
|
|
new.DenyTLSWithoutSNI = update.DenyTLSWithoutSNI
|
|
} else {
|
|
new.DenyTLSWithoutSNI = defaultConfig.DenyTLSWithoutSNI
|
|
}
|
|
if update.DoNotUseAssignedDNS > 0 && update.DoNotUseAssignedDNS < 4 {
|
|
new.DoNotUseAssignedDNS = update.DoNotUseAssignedDNS
|
|
} else {
|
|
new.DoNotUseAssignedDNS = defaultConfig.DoNotUseAssignedDNS
|
|
}
|
|
if update.DoNotUseMDNS > 0 && update.DoNotUseMDNS < 4 {
|
|
new.DoNotUseMDNS = update.DoNotUseMDNS
|
|
} else {
|
|
new.DoNotUseMDNS = defaultConfig.DoNotUseMDNS
|
|
}
|
|
if update.DoNotForwardSpecialDomains > 0 && update.DoNotForwardSpecialDomains < 4 {
|
|
new.DoNotForwardSpecialDomains = update.DoNotForwardSpecialDomains
|
|
} else {
|
|
new.DoNotForwardSpecialDomains = defaultConfig.DoNotForwardSpecialDomains
|
|
}
|
|
if update.AlwaysPromptAtNewProfile > 0 && update.AlwaysPromptAtNewProfile < 4 {
|
|
new.AlwaysPromptAtNewProfile = update.AlwaysPromptAtNewProfile
|
|
} else {
|
|
new.AlwaysPromptAtNewProfile = defaultConfig.AlwaysPromptAtNewProfile
|
|
}
|
|
if update.DenyNetworkUntilProfileApproved > 0 && update.DenyNetworkUntilProfileApproved < 4 {
|
|
new.DenyNetworkUntilProfileApproved = update.DenyNetworkUntilProfileApproved
|
|
} else {
|
|
new.DenyNetworkUntilProfileApproved = defaultConfig.DenyNetworkUntilProfileApproved
|
|
}
|
|
|
|
// generic configuration
|
|
if update.CompetenceLevel >= 0 && update.CompetenceLevel <= 3 {
|
|
new.CompetenceLevel = update.CompetenceLevel
|
|
} else {
|
|
new.CompetenceLevel = 3
|
|
// TODO: maybe notify user?
|
|
}
|
|
|
|
if len(update.DNSServers) != 0 {
|
|
new.DNSServers = update.DNSServers
|
|
} else {
|
|
new.DNSServers = defaultConfig.DNSServers
|
|
}
|
|
|
|
if update.DNSServerRetryRate != 0 {
|
|
new.DNSServerRetryRate = update.DNSServerRetryRate
|
|
} else {
|
|
new.DNSServerRetryRate = defaultConfig.DNSServerRetryRate
|
|
}
|
|
if len(update.CountryBlacklist) != 0 {
|
|
new.CountryBlacklist = update.CountryBlacklist
|
|
} else {
|
|
new.CountryBlacklist = defaultConfig.CountryBlacklist
|
|
}
|
|
if len(update.ASBlacklist) != 0 {
|
|
new.ASBlacklist = update.ASBlacklist
|
|
} else {
|
|
new.ASBlacklist = defaultConfig.ASBlacklist
|
|
}
|
|
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
|
|
// set new config and update timestamp
|
|
currentConfig = new
|
|
atomic.StoreInt64(lastChange, time.Now().UnixNano())
|
|
|
|
// update status with new values
|
|
// status.CurrentSecurityLevel = currentConfig.SecurityLevel
|
|
// status.Save()
|
|
|
|
// update atomic securityLevel
|
|
// atomic.StoreInt32(securityLevel, int32(currentConfig.SecurityLevel))
|
|
}
|
|
|
|
func statusChangeListener() {
|
|
sub := database.NewSubscription()
|
|
sub.Subscribe(fmt.Sprintf("%s/SystemStatus:%s", database.Me.String(), systemStatusInstanceName))
|
|
for {
|
|
var receivedModel database.Model
|
|
|
|
select {
|
|
case <-configurationModule.Stop:
|
|
configurationModule.StopComplete()
|
|
return
|
|
case receivedModel = <-sub.Updated:
|
|
case receivedModel = <-sub.Created:
|
|
}
|
|
|
|
status, ok := database.SilentEnsureModel(receivedModel, systemStatusModel).(*SystemStatus)
|
|
if !ok {
|
|
log.Warning("configuration: received system status update, but was not of type *SystemStatus")
|
|
continue
|
|
}
|
|
|
|
atomic.StoreInt32(securityLevel, int32(status.CurrentSecurityLevel))
|
|
}
|
|
}
|