Merge pull request #44 from safing/feature/pre-alpha-finalizing
Pre alpha finalizing
This commit is contained in:
@@ -11,6 +11,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
CfgDevModeKey = "core/devMode"
|
CfgDevModeKey = "core/devMode"
|
||||||
defaultDevMode bool
|
defaultDevMode bool
|
||||||
|
|
||||||
|
CfgUseSystemNotificationsKey = "core/useSystemNotifications"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -28,6 +30,7 @@ func registerConfig() error {
|
|||||||
Name: "Development Mode",
|
Name: "Development Mode",
|
||||||
Key: CfgDevModeKey,
|
Key: CfgDevModeKey,
|
||||||
Description: "In Development Mode security restrictions are lifted/softened to enable easier access to Portmaster for debugging and testing purposes.",
|
Description: "In Development Mode security restrictions are lifted/softened to enable easier access to Portmaster for debugging and testing purposes.",
|
||||||
|
Order: 127,
|
||||||
OptType: config.OptTypeBool,
|
OptType: config.OptTypeBool,
|
||||||
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
||||||
ReleaseLevel: config.ReleaseLevelStable,
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
@@ -37,5 +40,19 @@ func registerConfig() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = config.Register(&config.Option{
|
||||||
|
Name: "Use System Notifications",
|
||||||
|
Key: CfgUseSystemNotificationsKey,
|
||||||
|
Description: "Send notifications to your operating system's notification system. When this setting is turned off, notifications will only be visible in the Portmaster App. This affects both alerts from the Portmaster and questions from the Privacy Filter.",
|
||||||
|
Order: 32,
|
||||||
|
OptType: config.OptTypeBool,
|
||||||
|
ExpertiseLevel: config.ExpertiseLevelUser,
|
||||||
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
|
DefaultValue: true, // TODO: turn off by default on unsupported systems
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
100
core/control.go
Normal file
100
core/control.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/database"
|
||||||
|
"github.com/safing/portbase/database/record"
|
||||||
|
"github.com/safing/portbase/database/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StorageInterface provices a storage.Interface to the storage manager.
|
||||||
|
type StorageInterface struct {
|
||||||
|
storage.InjectBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a database record.
|
||||||
|
func (s *StorageInterface) Get(key string) (record.Record, error) {
|
||||||
|
msg := newMessage(key)
|
||||||
|
splittedKey := strings.Split(key, "/")
|
||||||
|
|
||||||
|
switch splittedKey[0] {
|
||||||
|
case "module":
|
||||||
|
return controlModule(msg, splittedKey)
|
||||||
|
default:
|
||||||
|
return nil, storage.ErrNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func controlModule(msg *MessageRecord, splittedKey []string) (record.Record, error) {
|
||||||
|
// format: module/moduleName/action/param
|
||||||
|
var moduleName string
|
||||||
|
var action string
|
||||||
|
var param string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// parse elements
|
||||||
|
switch len(splittedKey) {
|
||||||
|
case 4:
|
||||||
|
param = splittedKey[3]
|
||||||
|
fallthrough
|
||||||
|
case 3:
|
||||||
|
moduleName = splittedKey[1]
|
||||||
|
action = splittedKey[2]
|
||||||
|
default:
|
||||||
|
return nil, storage.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute
|
||||||
|
switch action {
|
||||||
|
case "trigger":
|
||||||
|
err = module.InjectEvent(fmt.Sprintf("user triggered the '%s/%s' event", moduleName, param), moduleName, param, nil)
|
||||||
|
default:
|
||||||
|
return nil, storage.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
msg.Message = err.Error()
|
||||||
|
} else {
|
||||||
|
msg.Success = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerControlDatabase() error {
|
||||||
|
_, err := database.Register(&database.Database{
|
||||||
|
Name: "control",
|
||||||
|
Description: "Control Interface for the Portmaster",
|
||||||
|
StorageType: "injected",
|
||||||
|
PrimaryAPI: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = database.InjectDatabase("control", &StorageInterface{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageRecord is a simple record used for control database feedback
|
||||||
|
type MessageRecord struct {
|
||||||
|
record.Base
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
Success bool
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMessage(key string) *MessageRecord {
|
||||||
|
m := &MessageRecord{}
|
||||||
|
m.SetKey("control:" + key)
|
||||||
|
m.UpdateMeta()
|
||||||
|
return m
|
||||||
|
}
|
||||||
23
core/core.go
23
core/core.go
@@ -20,7 +20,19 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
modules.Register("base", nil, registerDatabases, nil, "database", "config", "rng")
|
modules.Register("base", nil, registerDatabases, nil, "database", "config", "rng")
|
||||||
|
|
||||||
module = modules.Register("core", nil, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui")
|
// For prettier subsystem graph, printed with --print-subsystem-graph
|
||||||
|
/*
|
||||||
|
subsystems.Register(
|
||||||
|
"base",
|
||||||
|
"Base",
|
||||||
|
"THE GROUND.",
|
||||||
|
baseModule,
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
module = modules.Register("core", prep, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui", "netenv", "network", "interception")
|
||||||
subsystems.Register(
|
subsystems.Register(
|
||||||
"core",
|
"core",
|
||||||
"Core",
|
"Core",
|
||||||
@@ -31,10 +43,19 @@ func init() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prep() error {
|
||||||
|
registerEvents()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func start() error {
|
func start() error {
|
||||||
if err := startPlatformSpecific(); err != nil {
|
if err := startPlatformSpecific(); err != nil {
|
||||||
return fmt.Errorf("failed to start plattform-specific components: %s", err)
|
return fmt.Errorf("failed to start plattform-specific components: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := registerEventHooks(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,5 +46,5 @@ func registerDatabases() error {
|
|||||||
// return err
|
// return err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return nil
|
return registerControlDatabase()
|
||||||
}
|
}
|
||||||
|
|||||||
46
core/events.go
Normal file
46
core/events.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portbase/modules"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventShutdown = "shutdown"
|
||||||
|
eventRestart = "restart"
|
||||||
|
restartCode = 23
|
||||||
|
)
|
||||||
|
|
||||||
|
func registerEvents() {
|
||||||
|
module.RegisterEvent(eventShutdown)
|
||||||
|
module.RegisterEvent(eventRestart)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerEventHooks() error {
|
||||||
|
err := module.RegisterEventHook("core", eventShutdown, "execute shutdown", shutdown)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = module.RegisterEventHook("core", eventRestart, "execute shutdown", restart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shutdown(ctx context.Context, _ interface{}) error {
|
||||||
|
log.Warning("core: user requested shutdown")
|
||||||
|
go modules.Shutdown() //nolint:errcheck
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func restart(ctx context.Context, data interface{}) error {
|
||||||
|
log.Info("core: user requested restart")
|
||||||
|
modules.SetExitStatusCode(restartCode)
|
||||||
|
go modules.Shutdown() //nolint:errcheck
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
package firewall
|
package firewall
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/safing/portbase/api"
|
||||||
"github.com/safing/portbase/config"
|
"github.com/safing/portbase/config"
|
||||||
|
"github.com/safing/portmaster/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration Keys
|
// Configuration Keys
|
||||||
var (
|
var (
|
||||||
CfgOptionEnableFilterKey = "filter/enable"
|
CfgOptionEnableFilterKey = "filter/enable"
|
||||||
|
|
||||||
CfgOptionPromptTimeoutKey = "filter/promptTimeout"
|
CfgOptionAskWithSystemNotificationsKey = "filter/askWithSystemNotifications"
|
||||||
CfgOptionPromptTimeoutOrder = 2
|
CfgOptionAskWithSystemNotificationsOrder = 2
|
||||||
promptTimeout config.IntOption
|
askWithSystemNotifications config.BoolOption
|
||||||
|
useSystemNotifications config.BoolOption
|
||||||
|
|
||||||
|
CfgOptionAskTimeoutKey = "filter/askTimeout"
|
||||||
|
CfgOptionAskTimeoutOrder = 3
|
||||||
|
askTimeout config.IntOption
|
||||||
|
|
||||||
CfgOptionPermanentVerdictsKey = "filter/permanentVerdicts"
|
CfgOptionPermanentVerdictsKey = "filter/permanentVerdicts"
|
||||||
CfgOptionPermanentVerdictsOrder = 128
|
CfgOptionPermanentVerdictsOrder = 128
|
||||||
@@ -37,22 +44,38 @@ func registerConfig() error {
|
|||||||
permanentVerdicts = config.Concurrent.GetAsBool(CfgOptionPermanentVerdictsKey, true)
|
permanentVerdicts = config.Concurrent.GetAsBool(CfgOptionPermanentVerdictsKey, true)
|
||||||
|
|
||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Timeout for prompt notifications",
|
Name: "Ask with System Notifications",
|
||||||
Key: CfgOptionPromptTimeoutKey,
|
Key: CfgOptionAskWithSystemNotificationsKey,
|
||||||
Description: "Amount of time how long Portmaster will wait for a response when prompting about a connection via a notification. In seconds.",
|
Description: `Ask about connections using your operating system's notification system. For this to be enabled, the setting "Use System Notifications" must enabled too. This only affects questions from the Privacy Filter, and does not affect alerts from the Portmaster.`,
|
||||||
Order: CfgOptionPromptTimeoutOrder,
|
Order: CfgOptionAskWithSystemNotificationsOrder,
|
||||||
|
OptType: config.OptTypeBool,
|
||||||
|
ExpertiseLevel: config.ExpertiseLevelUser,
|
||||||
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
|
DefaultValue: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
askWithSystemNotifications = config.Concurrent.GetAsBool(CfgOptionAskWithSystemNotificationsKey, true)
|
||||||
|
useSystemNotifications = config.Concurrent.GetAsBool(core.CfgUseSystemNotificationsKey, true)
|
||||||
|
|
||||||
|
err = config.Register(&config.Option{
|
||||||
|
Name: "Timeout for Ask Notifications",
|
||||||
|
Key: CfgOptionAskTimeoutKey,
|
||||||
|
Description: "Amount of time (in seconds) how long the Portmaster will wait for a response when prompting about a connection via a notification. Please note that system notifications might not respect this or have it's own limits.",
|
||||||
|
Order: CfgOptionAskTimeoutOrder,
|
||||||
OptType: config.OptTypeInt,
|
OptType: config.OptTypeInt,
|
||||||
ExpertiseLevel: config.ExpertiseLevelUser,
|
ExpertiseLevel: config.ExpertiseLevelUser,
|
||||||
ReleaseLevel: config.ReleaseLevelBeta,
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
DefaultValue: 60,
|
DefaultValue: 60,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
promptTimeout = config.Concurrent.GetAsInt(CfgOptionPromptTimeoutKey, 60)
|
askTimeout = config.Concurrent.GetAsInt(CfgOptionAskTimeoutKey, 60)
|
||||||
|
|
||||||
devMode = config.Concurrent.GetAsBool("core/devMode", false)
|
devMode = config.Concurrent.GetAsBool(core.CfgDevModeKey, false)
|
||||||
apiListenAddress = config.GetAsString("api/listenAddress", "")
|
apiListenAddress = config.GetAsString(api.CfgDefaultListenAddressKey, "")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
47
firewall/filter.go
Normal file
47
firewall/filter.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package firewall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/safing/portbase/config"
|
||||||
|
"github.com/safing/portbase/modules/subsystems"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/modules"
|
||||||
|
|
||||||
|
// module dependencies
|
||||||
|
_ "github.com/safing/portmaster/core"
|
||||||
|
_ "github.com/safing/portmaster/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
filterModule *modules.Module
|
||||||
|
filterEnabled config.BoolOption
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
filterModule = modules.Register("filter", filterPrep, nil, nil, "core", "intel")
|
||||||
|
subsystems.Register(
|
||||||
|
"filter",
|
||||||
|
"Privacy Filter",
|
||||||
|
"DNS and Network Filter",
|
||||||
|
filterModule,
|
||||||
|
"config:filter/",
|
||||||
|
&config.Option{
|
||||||
|
Name: "Enable Privacy Filter",
|
||||||
|
Key: CfgOptionEnableFilterKey,
|
||||||
|
Description: "Enable the Privacy Filter Subsystem to filter DNS queries and network requests.",
|
||||||
|
OptType: config.OptTypeBool,
|
||||||
|
ExpertiseLevel: config.ExpertiseLevelUser,
|
||||||
|
ReleaseLevel: config.ReleaseLevelBeta,
|
||||||
|
DefaultValue: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterPrep() (err error) {
|
||||||
|
err = registerConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filterEnabled = config.GetAsBool(CfgOptionEnableFilterKey, true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -7,9 +7,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portbase/config"
|
|
||||||
"github.com/safing/portbase/modules/subsystems"
|
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portbase/modules"
|
"github.com/safing/portbase/modules"
|
||||||
"github.com/safing/portmaster/firewall/inspection"
|
"github.com/safing/portmaster/firewall/inspection"
|
||||||
@@ -23,7 +20,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
module *modules.Module
|
interceptionModule *modules.Module
|
||||||
|
|
||||||
// localNet net.IPNet
|
// localNet net.IPNet
|
||||||
// localhost net.IP
|
// localhost net.IP
|
||||||
@@ -45,33 +42,12 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
module = modules.Register("filter", prep, start, stop, "core", "network", "nameserver", "intel")
|
interceptionModule = modules.Register("interception", interceptionPrep, interceptionStart, interceptionStop, "base")
|
||||||
subsystems.Register(
|
|
||||||
"filter",
|
|
||||||
"Privacy Filter",
|
|
||||||
"DNS and Network Filter",
|
|
||||||
module,
|
|
||||||
"config:filter/",
|
|
||||||
&config.Option{
|
|
||||||
Name: "Enable Privacy Filter",
|
|
||||||
Key: CfgOptionEnableFilterKey,
|
|
||||||
Description: "Enable the Privacy Filter Subsystem to filter DNS queries and network requests.",
|
|
||||||
OptType: config.OptTypeBool,
|
|
||||||
ExpertiseLevel: config.ExpertiseLevelUser,
|
|
||||||
ReleaseLevel: config.ReleaseLevelBeta,
|
|
||||||
DefaultValue: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
network.SetDefaultFirewallHandler(defaultHandler)
|
network.SetDefaultFirewallHandler(defaultHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() (err error) {
|
func interceptionPrep() (err error) {
|
||||||
err = registerConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = prepAPIAuth()
|
err = prepAPIAuth()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -101,20 +77,20 @@ func prep() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() error {
|
func interceptionStart() error {
|
||||||
startAPIAuth()
|
startAPIAuth()
|
||||||
|
|
||||||
module.StartWorker("stat logger", func(ctx context.Context) error {
|
interceptionModule.StartWorker("stat logger", func(ctx context.Context) error {
|
||||||
statLogger()
|
statLogger()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
module.StartWorker("packet handler", func(ctx context.Context) error {
|
interceptionModule.StartWorker("packet handler", func(ctx context.Context) error {
|
||||||
run()
|
run()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
module.StartWorker("ports state cleaner", func(ctx context.Context) error {
|
interceptionModule.StartWorker("ports state cleaner", func(ctx context.Context) error {
|
||||||
portsInUseCleaner()
|
portsInUseCleaner()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -122,7 +98,7 @@ func start() error {
|
|||||||
return interception.Start()
|
return interception.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() error {
|
func interceptionStop() error {
|
||||||
return interception.Stop()
|
return interception.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,6 +224,15 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if filtering is enabled
|
||||||
|
if !filterEnabled() {
|
||||||
|
conn.Inspecting = false
|
||||||
|
conn.SetVerdict(network.VerdictAccept, "privacy filter disabled", nil)
|
||||||
|
conn.StopFirewallHandler()
|
||||||
|
issueVerdict(conn, pkt, 0, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Tracer(pkt.Ctx()).Trace("filter: starting decision process")
|
log.Tracer(pkt.Ctx()).Trace("filter: starting decision process")
|
||||||
DecideOnConnection(conn, pkt)
|
DecideOnConnection(conn, pkt)
|
||||||
conn.Inspecting = false // TODO: enable inspecting again
|
conn.Inspecting = false // TODO: enable inspecting again
|
||||||
@@ -350,7 +335,7 @@ func issueVerdict(conn *network.Connection, pkt packet.Packet, verdict network.V
|
|||||||
func run() {
|
func run() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-module.Stopping():
|
case <-interceptionModule.Stopping():
|
||||||
return
|
return
|
||||||
case pkt := <-interception.Packets:
|
case pkt := <-interception.Packets:
|
||||||
handlePacket(pkt)
|
handlePacket(pkt)
|
||||||
@@ -361,7 +346,7 @@ func run() {
|
|||||||
func statLogger() {
|
func statLogger() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-module.Stopping():
|
case <-interceptionModule.Stopping():
|
||||||
return
|
return
|
||||||
case <-time.After(10 * time.Second):
|
case <-time.After(10 * time.Second):
|
||||||
log.Tracef(
|
log.Tracef(
|
||||||
@@ -45,14 +45,14 @@ func init() {
|
|||||||
"mangle C171 -m mark --mark 0 -j NFQUEUE --queue-num 17140 --queue-bypass",
|
"mangle C171 -m mark --mark 0 -j NFQUEUE --queue-num 17140 --queue-bypass",
|
||||||
|
|
||||||
"filter C17 -m mark --mark 0 -j DROP",
|
"filter C17 -m mark --mark 0 -j DROP",
|
||||||
"filter C17 -m mark --mark 1700 -j ACCEPT",
|
"filter C17 -m mark --mark 1700 -j RETURN",
|
||||||
"filter C17 -m mark --mark 1701 -j REJECT --reject-with icmp-host-prohibited",
|
"filter C17 -m mark --mark 1701 -j REJECT --reject-with icmp-host-prohibited",
|
||||||
"filter C17 -m mark --mark 1702 -j DROP",
|
"filter C17 -m mark --mark 1702 -j DROP",
|
||||||
"filter C17 -j CONNMARK --save-mark",
|
"filter C17 -j CONNMARK --save-mark",
|
||||||
"filter C17 -m mark --mark 1710 -j ACCEPT",
|
"filter C17 -m mark --mark 1710 -j RETURN",
|
||||||
"filter C17 -m mark --mark 1711 -j REJECT --reject-with icmp-host-prohibited",
|
"filter C17 -m mark --mark 1711 -j REJECT --reject-with icmp-host-prohibited",
|
||||||
"filter C17 -m mark --mark 1712 -j DROP",
|
"filter C17 -m mark --mark 1712 -j DROP",
|
||||||
"filter C17 -m mark --mark 1717 -j ACCEPT",
|
"filter C17 -m mark --mark 1717 -j RETURN",
|
||||||
}
|
}
|
||||||
|
|
||||||
v4once = []string{
|
v4once = []string{
|
||||||
@@ -80,14 +80,14 @@ func init() {
|
|||||||
"mangle C171 -m mark --mark 0 -j NFQUEUE --queue-num 17160 --queue-bypass",
|
"mangle C171 -m mark --mark 0 -j NFQUEUE --queue-num 17160 --queue-bypass",
|
||||||
|
|
||||||
"filter C17 -m mark --mark 0 -j DROP",
|
"filter C17 -m mark --mark 0 -j DROP",
|
||||||
"filter C17 -m mark --mark 1700 -j ACCEPT",
|
"filter C17 -m mark --mark 1700 -j RETURN",
|
||||||
"filter C17 -m mark --mark 1701 -j REJECT --reject-with icmp6-adm-prohibited",
|
"filter C17 -m mark --mark 1701 -j REJECT --reject-with icmp6-adm-prohibited",
|
||||||
"filter C17 -m mark --mark 1702 -j DROP",
|
"filter C17 -m mark --mark 1702 -j DROP",
|
||||||
"filter C17 -j CONNMARK --save-mark",
|
"filter C17 -j CONNMARK --save-mark",
|
||||||
"filter C17 -m mark --mark 1710 -j ACCEPT",
|
"filter C17 -m mark --mark 1710 -j RETURN",
|
||||||
"filter C17 -m mark --mark 1711 -j REJECT --reject-with icmp6-adm-prohibited",
|
"filter C17 -m mark --mark 1711 -j REJECT --reject-with icmp6-adm-prohibited",
|
||||||
"filter C17 -m mark --mark 1712 -j DROP",
|
"filter C17 -m mark --mark 1712 -j DROP",
|
||||||
"filter C17 -m mark --mark 1717 -j ACCEPT",
|
"filter C17 -m mark --mark 1717 -j RETURN",
|
||||||
}
|
}
|
||||||
|
|
||||||
v6once = []string{
|
v6once = []string{
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ func checkConnectionType(conn *network.Connection, _ packet.Packet) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case network.PeerLAN, network.PeerInternet, network.PeerInvalid:
|
case network.PeerInternet:
|
||||||
// Important: PeerHost is and should be missing!
|
// BlockP2P only applies to connections to the Internet
|
||||||
if p.BlockP2P() {
|
if p.BlockP2P() {
|
||||||
conn.Block("direct connections (P2P) blocked")
|
conn.Block("direct connections (P2P) blocked")
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func GetPermittedPort() uint16 {
|
|||||||
func portsInUseCleaner() {
|
func portsInUseCleaner() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-module.Stopping():
|
case <-interceptionModule.Stopping():
|
||||||
return
|
return
|
||||||
case <-time.After(cleanerTickDuration):
|
case <-time.After(cleanerTickDuration):
|
||||||
cleanPortsInUse()
|
cleanPortsInUse()
|
||||||
|
|||||||
@@ -26,16 +26,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func prompt(conn *network.Connection, pkt packet.Packet) { //nolint:gocognit // TODO
|
func prompt(conn *network.Connection, pkt packet.Packet) { //nolint:gocognit // TODO
|
||||||
nTTL := time.Duration(promptTimeout()) * time.Second
|
nTTL := time.Duration(askTimeout()) * time.Second
|
||||||
|
|
||||||
// first check if there is an existing notification for this.
|
// first check if there is an existing notification for this.
|
||||||
// build notification ID
|
// build notification ID
|
||||||
var nID string
|
var nID string
|
||||||
switch {
|
switch {
|
||||||
case conn.Inbound, conn.Entity.Domain == "": // connection to/from IP
|
case conn.Inbound, conn.Entity.Domain == "": // connection to/from IP
|
||||||
nID = fmt.Sprintf("firewall-prompt-%d-%s-%s", conn.Process().Pid, conn.Scope, pkt.Info().RemoteIP())
|
nID = fmt.Sprintf("filter:prompt-%d-%s-%s", conn.Process().Pid, conn.Scope, pkt.Info().RemoteIP())
|
||||||
default: // connection to domain
|
default: // connection to domain
|
||||||
nID = fmt.Sprintf("firewall-prompt-%d-%s", conn.Process().Pid, conn.Scope)
|
nID = fmt.Sprintf("filter:prompt-%d-%s", conn.Process().Pid, conn.Scope)
|
||||||
}
|
}
|
||||||
n := notifications.Get(nID)
|
n := notifications.Get(nID)
|
||||||
saveResponse := true
|
saveResponse := true
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
ignoreNetEnvEvents.Set()
|
ignoreNetEnvEvents.Set()
|
||||||
|
|
||||||
module = modules.Register("filterlists", prep, start, nil, "core", "netenv")
|
module = modules.Register("filterlists", prep, start, stop, "core")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func prep() error {
|
||||||
@@ -98,3 +98,8 @@ func start() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stop() error {
|
||||||
|
filterListsLoaded = make(chan struct{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
module = modules.Register("nameserver", prep, start, stop, "core", "resolver", "network", "netenv")
|
module = modules.Register("nameserver", prep, start, stop, "core", "resolver")
|
||||||
subsystems.Register(
|
subsystems.Register(
|
||||||
"dns",
|
"dns",
|
||||||
"Secure DNS",
|
"Secure DNS",
|
||||||
|
|||||||
@@ -41,8 +41,14 @@ func cleanConnections() (activePIDs map[int]struct{}) {
|
|||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
deleteOlderThan := time.Now().Add(-deleteConnsAfterEndedThreshold).Unix()
|
deleteOlderThan := time.Now().Add(-deleteConnsAfterEndedThreshold).Unix()
|
||||||
|
|
||||||
// network connections
|
// lock both together because we cannot fully guarantee in which map a connection lands
|
||||||
|
// of course every connection should land in the correct map, but this increases resilience
|
||||||
connsLock.Lock()
|
connsLock.Lock()
|
||||||
|
defer connsLock.Unlock()
|
||||||
|
dnsConnsLock.Lock()
|
||||||
|
defer dnsConnsLock.Unlock()
|
||||||
|
|
||||||
|
// network connections
|
||||||
for key, conn := range conns {
|
for key, conn := range conns {
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
|
|
||||||
@@ -67,10 +73,8 @@ func cleanConnections() (activePIDs map[int]struct{}) {
|
|||||||
|
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
}
|
}
|
||||||
connsLock.Unlock()
|
|
||||||
|
|
||||||
// dns requests
|
// dns requests
|
||||||
dnsConnsLock.Lock()
|
|
||||||
for _, conn := range dnsConns {
|
for _, conn := range dnsConns {
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
|
|
||||||
@@ -82,7 +86,6 @@ func cleanConnections() (activePIDs map[int]struct{}) {
|
|||||||
|
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
}
|
}
|
||||||
dnsConnsLock.Unlock()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -146,13 +146,13 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp := time.Now().Unix()
|
|
||||||
return &Connection{
|
return &Connection{
|
||||||
ID: pkt.GetConnectionID(),
|
ID: pkt.GetConnectionID(),
|
||||||
Scope: scope,
|
Scope: scope,
|
||||||
|
Inbound: inbound,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
process: proc,
|
process: proc,
|
||||||
Started: timestamp,
|
Started: time.Now().Unix(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,11 +236,11 @@ func (conn *Connection) Failed(reason string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetVerdict sets a new verdict for the connection, making sure it does not interfere with previous verdicts.
|
// SetVerdict sets a new verdict for the connection, making sure it does not interfere with previous verdicts.
|
||||||
func (conn *Connection) SetVerdict(newVerdict Verdict, reason string, ctx interface{}) (ok bool) {
|
func (conn *Connection) SetVerdict(newVerdict Verdict, reason string, reasonCtx interface{}) (ok bool) {
|
||||||
if newVerdict >= conn.Verdict {
|
if newVerdict >= conn.Verdict {
|
||||||
conn.Verdict = newVerdict
|
conn.Verdict = newVerdict
|
||||||
conn.Reason = reason
|
conn.Reason = reason
|
||||||
conn.ReasonContext = ctx
|
conn.ReasonContext = reasonCtx
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -77,9 +77,11 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
|||||||
if slashes <= 1 {
|
if slashes <= 1 {
|
||||||
// processes
|
// processes
|
||||||
for _, proc := range process.All() {
|
for _, proc := range process.All() {
|
||||||
|
proc.Lock()
|
||||||
if q.Matches(proc) {
|
if q.Matches(proc) {
|
||||||
it.Next <- proc
|
it.Next <- proc
|
||||||
}
|
}
|
||||||
|
proc.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,9 +89,11 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
|||||||
// dns scopes only
|
// dns scopes only
|
||||||
dnsConnsLock.RLock()
|
dnsConnsLock.RLock()
|
||||||
for _, dnsConn := range dnsConns {
|
for _, dnsConn := range dnsConns {
|
||||||
|
dnsConn.Lock()
|
||||||
if q.Matches(dnsConn) {
|
if q.Matches(dnsConn) {
|
||||||
it.Next <- dnsConn
|
it.Next <- dnsConn
|
||||||
}
|
}
|
||||||
|
dnsConn.Unlock()
|
||||||
}
|
}
|
||||||
dnsConnsLock.RUnlock()
|
dnsConnsLock.RUnlock()
|
||||||
}
|
}
|
||||||
@@ -98,9 +102,11 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) {
|
|||||||
// connections
|
// connections
|
||||||
connsLock.RLock()
|
connsLock.RLock()
|
||||||
for _, conn := range conns {
|
for _, conn := range conns {
|
||||||
|
conn.Lock()
|
||||||
if q.Matches(conn) {
|
if q.Matches(conn) {
|
||||||
it.Next <- conn
|
it.Next <- conn
|
||||||
}
|
}
|
||||||
|
conn.Unlock()
|
||||||
}
|
}
|
||||||
connsLock.RUnlock()
|
connsLock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
module = modules.Register("network", nil, start, nil, "core", "processes")
|
module = modules.Register("network", nil, start, nil, "base", "processes")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaultFirewallHandler sets the default firewall handler.
|
// SetDefaultFirewallHandler sets the default firewall handler.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ClassifyIP returns the classification for the given IP address.
|
// ClassifyIP returns the classification for the given IP address.
|
||||||
func ClassifyIP(ip net.IP) int8 {
|
func ClassifyIP(ip net.IP) int8 { //nolint:gocognit
|
||||||
if ip4 := ip.To4(); ip4 != nil {
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
// IPv4
|
// IPv4
|
||||||
switch {
|
switch {
|
||||||
@@ -36,11 +36,18 @@ func ClassifyIP(ip net.IP) int8 {
|
|||||||
case ip4[0] == 224:
|
case ip4[0] == 224:
|
||||||
// 224.0.0.0/8
|
// 224.0.0.0/8
|
||||||
return LocalMulticast
|
return LocalMulticast
|
||||||
case ip4[0] >= 225 && ip4[0] <= 239:
|
case ip4[0] >= 225 && ip4[0] <= 238:
|
||||||
// 225.0.0.0/8 - 239.0.0.0/8
|
// 225.0.0.0/8 - 238.0.0.0/8
|
||||||
return GlobalMulticast
|
return GlobalMulticast
|
||||||
|
case ip4[0] == 239:
|
||||||
|
// 239.0.0.0/8
|
||||||
|
// RFC2365 - https://tools.ietf.org/html/rfc2365
|
||||||
|
return LocalMulticast
|
||||||
|
case ip4[0] == 255 && ip4[1] == 255 && ip4[2] == 255 && ip4[3] == 255:
|
||||||
|
// 255.255.255.255/32
|
||||||
|
return LocalMulticast
|
||||||
case ip4[0] >= 240:
|
case ip4[0] >= 240:
|
||||||
// 240.0.0.0/8 - 255.0.0.0/8
|
// 240.0.0.0/8 - 255.0.0.0/8 (minus 255.255.255.255/32)
|
||||||
return Invalid
|
return Invalid
|
||||||
default:
|
default:
|
||||||
return Global
|
return Global
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import (
|
|||||||
"github.com/tevino/abool"
|
"github.com/tevino/abool"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
restartCode = 23
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
runningInConsole bool
|
runningInConsole bool
|
||||||
onWindows = runtime.GOOS == "windows"
|
onWindows = runtime.GOOS == "windows"
|
||||||
@@ -375,7 +379,7 @@ func execute(opts *Options, args []string) (cont bool, err error) {
|
|||||||
case 1:
|
case 1:
|
||||||
// error exit
|
// error exit
|
||||||
return true, fmt.Errorf("error during execution: %s", err)
|
return true, fmt.Errorf("error during execution: %s", err)
|
||||||
case 2357427: // Leet Speak for "restart"
|
case restartCode:
|
||||||
// restart request
|
// restart request
|
||||||
log.Printf("restarting %s\n", opts.Identifier)
|
log.Printf("restarting %s\n", opts.Identifier)
|
||||||
return true, nil
|
return true, nil
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ func registerConfiguration() error {
|
|||||||
Name: "Enable Process Detection",
|
Name: "Enable Process Detection",
|
||||||
Key: CfgOptionEnableProcessDetectionKey,
|
Key: CfgOptionEnableProcessDetectionKey,
|
||||||
Description: "This option enables the attribution of network traffic to processes. This should be always enabled, and effectively disables app profiles if disabled.",
|
Description: "This option enables the attribution of network traffic to processes. This should be always enabled, and effectively disables app profiles if disabled.",
|
||||||
|
Order: 144,
|
||||||
OptType: config.OptTypeBool,
|
OptType: config.OptTypeBool,
|
||||||
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
ExpertiseLevel: config.ExpertiseLevelDeveloper,
|
||||||
DefaultValue: true,
|
DefaultValue: true,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/config"
|
||||||
|
|
||||||
"github.com/safing/portmaster/intel/filterlists"
|
"github.com/safing/portmaster/intel/filterlists"
|
||||||
"github.com/safing/portmaster/profile/endpoints"
|
"github.com/safing/portmaster/profile/endpoints"
|
||||||
)
|
)
|
||||||
@@ -77,20 +79,24 @@ func updateGlobalConfigProfile(ctx context.Context, data interface{}) error {
|
|||||||
internalSave: true,
|
internalSave: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newConfig := make(map[string]interface{})
|
||||||
// fill profile config options
|
// fill profile config options
|
||||||
for key, value := range cfgStringOptions {
|
for key, value := range cfgStringOptions {
|
||||||
profile.Config[key] = value()
|
newConfig[key] = value()
|
||||||
}
|
}
|
||||||
for key, value := range cfgStringArrayOptions {
|
for key, value := range cfgStringArrayOptions {
|
||||||
profile.Config[key] = value()
|
newConfig[key] = value()
|
||||||
}
|
}
|
||||||
for key, value := range cfgIntOptions {
|
for key, value := range cfgIntOptions {
|
||||||
profile.Config[key] = value()
|
newConfig[key] = value()
|
||||||
}
|
}
|
||||||
for key, value := range cfgBoolOptions {
|
for key, value := range cfgBoolOptions {
|
||||||
profile.Config[key] = value()
|
newConfig[key] = value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expand and assign
|
||||||
|
profile.Config = config.Expand(newConfig)
|
||||||
|
|
||||||
// save profile
|
// save profile
|
||||||
err = profile.Save()
|
err = profile.Save()
|
||||||
if err != nil && lastErr == nil {
|
if err != nil && lastErr == nil {
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ func registerConfiguration() error {
|
|||||||
"+": permit
|
"+": permit
|
||||||
"-": block
|
"-": block
|
||||||
Host Matching:
|
Host Matching:
|
||||||
IP, CIDR, Country Code, ASN, "*" for any
|
IP, CIDR, Country Code, ASN, Filterlist, "*" for any
|
||||||
Domains:
|
Domains:
|
||||||
"example.com": exact match
|
"example.com": exact match
|
||||||
".example.com": exact match + subdomains
|
".example.com": exact match + subdomains
|
||||||
@@ -144,7 +144,11 @@ func registerConfiguration() error {
|
|||||||
Examples:
|
Examples:
|
||||||
+ .example.com */HTTP
|
+ .example.com */HTTP
|
||||||
- .example.com
|
- .example.com
|
||||||
+ 192.168.0.1/24`,
|
+ 192.168.0.1/24
|
||||||
|
- L:MAL
|
||||||
|
- AS0
|
||||||
|
+ AT
|
||||||
|
- *`,
|
||||||
Order: cfgOptionEndpointsOrder,
|
Order: cfgOptionEndpointsOrder,
|
||||||
OptType: config.OptTypeStringArray,
|
OptType: config.OptTypeStringArray,
|
||||||
DefaultValue: []string{},
|
DefaultValue: []string{},
|
||||||
@@ -167,7 +171,7 @@ Examples:
|
|||||||
"+": permit
|
"+": permit
|
||||||
"-": block
|
"-": block
|
||||||
Host Matching:
|
Host Matching:
|
||||||
IP, CIDR, Country Code, ASN, "*" for any
|
IP, CIDR, Country Code, ASN, Filterlist, "*" for any
|
||||||
Domains:
|
Domains:
|
||||||
"example.com": exact match
|
"example.com": exact match
|
||||||
".example.com": exact match + subdomains
|
".example.com": exact match + subdomains
|
||||||
@@ -180,7 +184,11 @@ Examples:
|
|||||||
Examples:
|
Examples:
|
||||||
+ .example.com */HTTP
|
+ .example.com */HTTP
|
||||||
- .example.com
|
- .example.com
|
||||||
+ 192.168.0.1/24`,
|
+ 192.168.0.1/24
|
||||||
|
- L:MAL
|
||||||
|
- AS0
|
||||||
|
+ AT
|
||||||
|
- *`,
|
||||||
Order: cfgOptionServiceEndpointsOrder,
|
Order: cfgOptionServiceEndpointsOrder,
|
||||||
OptType: config.OptTypeStringArray,
|
OptType: config.OptTypeStringArray,
|
||||||
DefaultValue: []string{},
|
DefaultValue: []string{},
|
||||||
@@ -249,9 +257,10 @@ Examples:
|
|||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Block Scope Local",
|
Name: "Block Scope Local",
|
||||||
Key: CfgOptionBlockScopeLocalKey,
|
Key: CfgOptionBlockScopeLocalKey,
|
||||||
Description: "Block connections to your own device, ie. localhost.",
|
Description: "Block internal connections on your own device, ie. localhost.",
|
||||||
Order: cfgOptionBlockScopeLocalOrder,
|
Order: cfgOptionBlockScopeLocalOrder,
|
||||||
OptType: config.OptTypeInt,
|
OptType: config.OptTypeInt,
|
||||||
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
ExternalOptType: "security level",
|
ExternalOptType: "security level",
|
||||||
DefaultValue: status.SecurityLevelOff,
|
DefaultValue: status.SecurityLevelOff,
|
||||||
ValidationRegex: "^(0|4|6|7)$",
|
ValidationRegex: "^(0|4|6|7)$",
|
||||||
@@ -270,7 +279,7 @@ Examples:
|
|||||||
Order: cfgOptionBlockScopeLANOrder,
|
Order: cfgOptionBlockScopeLANOrder,
|
||||||
OptType: config.OptTypeInt,
|
OptType: config.OptTypeInt,
|
||||||
ExternalOptType: "security level",
|
ExternalOptType: "security level",
|
||||||
DefaultValue: status.SecurityLevelOff,
|
DefaultValue: status.SecurityLevelsHighAndExtreme,
|
||||||
ValidationRegex: "^(0|4|6|7)$",
|
ValidationRegex: "^(0|4|6|7)$",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -300,7 +309,7 @@ Examples:
|
|||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Block Peer to Peer Connections",
|
Name: "Block Peer to Peer Connections",
|
||||||
Key: CfgOptionBlockP2PKey,
|
Key: CfgOptionBlockP2PKey,
|
||||||
Description: "Block peer to peer connections. These are connections that are established directly to an IP address on the Internet without resolving a domain name via DNS first.",
|
Description: "These are connections that are established directly to an IP address on the Internet without resolving a domain name via DNS first.",
|
||||||
Order: cfgOptionBlockP2POrder,
|
Order: cfgOptionBlockP2POrder,
|
||||||
OptType: config.OptTypeInt,
|
OptType: config.OptTypeInt,
|
||||||
ExternalOptType: "security level",
|
ExternalOptType: "security level",
|
||||||
@@ -317,7 +326,7 @@ Examples:
|
|||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Block Inbound Connections",
|
Name: "Block Inbound Connections",
|
||||||
Key: CfgOptionBlockInboundKey,
|
Key: CfgOptionBlockInboundKey,
|
||||||
Description: "Block inbound connections to your device. This will usually only be the case if you are running a network service or are using peer to peer software.",
|
Description: "Connections initiated towards your device. This will usually only be the case if you are running a network service or are using peer to peer software.",
|
||||||
Order: cfgOptionBlockInboundOrder,
|
Order: cfgOptionBlockInboundOrder,
|
||||||
OptType: config.OptTypeInt,
|
OptType: config.OptTypeInt,
|
||||||
ExternalOptType: "security level",
|
ExternalOptType: "security level",
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/config"
|
||||||
|
|
||||||
"github.com/safing/portbase/database"
|
"github.com/safing/portbase/database"
|
||||||
"github.com/safing/portbase/database/query"
|
"github.com/safing/portbase/database/query"
|
||||||
"github.com/safing/portbase/database/record"
|
"github.com/safing/portbase/database/record"
|
||||||
@@ -87,6 +89,9 @@ func (h *databaseHook) PrePut(r record.Record) (record.Record, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean config
|
||||||
|
config.CleanHierarchicalConfig(profile.Config)
|
||||||
|
|
||||||
// prepare config
|
// prepare config
|
||||||
err = profile.prepConfig()
|
err = profile.prepConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
module = modules.Register("profiles", prep, start, nil, "core")
|
module = modules.Register("profiles", prep, start, nil, "base")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func prep() error {
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ func (profile *Profile) addEndpointyEntry(cfgKey, newEntry string) {
|
|||||||
endpointList = make([]string, 0, 1)
|
endpointList = make([]string, 0, 1)
|
||||||
}
|
}
|
||||||
endpointList = append(endpointList, newEntry)
|
endpointList = append(endpointList, newEntry)
|
||||||
profile.Config[cfgKey] = endpointList
|
config.PutValueIntoHierarchicalConfig(profile.Config, cfgKey, endpointList)
|
||||||
|
|
||||||
profile.Unlock()
|
profile.Unlock()
|
||||||
err := profile.Save()
|
err := profile.Save()
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ func start() error {
|
|||||||
|
|
||||||
// load status into atomic getters
|
// load status into atomic getters
|
||||||
atomicUpdateSelectedSecurityLevel(status.SelectedSecurityLevel)
|
atomicUpdateSelectedSecurityLevel(status.SelectedSecurityLevel)
|
||||||
atomicUpdatePortmasterStatus(status.PortmasterStatus)
|
|
||||||
atomicUpdateGate17Status(status.Gate17Status)
|
|
||||||
|
|
||||||
// update status
|
// update status
|
||||||
status.updateThreatMitigationLevel()
|
status.updateThreatMitigationLevel()
|
||||||
|
|||||||
@@ -45,40 +45,6 @@ func setSelectedSecurityLevel(level uint8) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPortmasterStatus sets the current Portmaster status.
|
|
||||||
func SetPortmasterStatus(pmStatus uint8, msg string) {
|
|
||||||
switch pmStatus {
|
|
||||||
case StatusOff, StatusError, StatusWarning, StatusOk:
|
|
||||||
status.Lock()
|
|
||||||
defer status.Unlock()
|
|
||||||
|
|
||||||
status.PortmasterStatus = pmStatus
|
|
||||||
status.PortmasterStatusMsg = msg
|
|
||||||
atomicUpdatePortmasterStatus(pmStatus)
|
|
||||||
|
|
||||||
go status.Save()
|
|
||||||
default:
|
|
||||||
log.Errorf("status: tried to set portmaster to invalid status: %d", pmStatus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetGate17Status sets the current Gate17 status.
|
|
||||||
func SetGate17Status(g17Status uint8, msg string) {
|
|
||||||
switch g17Status {
|
|
||||||
case StatusOff, StatusError, StatusWarning, StatusOk:
|
|
||||||
status.Lock()
|
|
||||||
defer status.Unlock()
|
|
||||||
|
|
||||||
status.Gate17Status = g17Status
|
|
||||||
status.Gate17StatusMsg = msg
|
|
||||||
atomicUpdateGate17Status(g17Status)
|
|
||||||
|
|
||||||
go status.Save()
|
|
||||||
default:
|
|
||||||
log.Errorf("status: tried to set gate17 to invalid status: %d", g17Status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update functions for atomic stuff
|
// update functions for atomic stuff
|
||||||
func atomicUpdateActiveSecurityLevel(level uint8) {
|
func atomicUpdateActiveSecurityLevel(level uint8) {
|
||||||
atomic.StoreUint32(activeSecurityLevel, uint32(level))
|
atomic.StoreUint32(activeSecurityLevel, uint32(level))
|
||||||
@@ -87,11 +53,3 @@ func atomicUpdateActiveSecurityLevel(level uint8) {
|
|||||||
func atomicUpdateSelectedSecurityLevel(level uint8) {
|
func atomicUpdateSelectedSecurityLevel(level uint8) {
|
||||||
atomic.StoreUint32(selectedSecurityLevel, uint32(level))
|
atomic.StoreUint32(selectedSecurityLevel, uint32(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
func atomicUpdatePortmasterStatus(status uint8) {
|
|
||||||
atomic.StoreUint32(portmasterStatus, uint32(status))
|
|
||||||
}
|
|
||||||
|
|
||||||
func atomicUpdateGate17Status(status uint8) {
|
|
||||||
atomic.StoreUint32(gate17Status, uint32(status))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,7 +7,5 @@ func TestSet(t *testing.T) {
|
|||||||
// only test for panics
|
// only test for panics
|
||||||
// TODO: write real tests
|
// TODO: write real tests
|
||||||
setSelectedSecurityLevel(0)
|
setSelectedSecurityLevel(0)
|
||||||
SetPortmasterStatus(0, "")
|
|
||||||
SetGate17Status(0, "")
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,16 +28,8 @@ type SystemStatus struct {
|
|||||||
ActiveSecurityLevel uint8
|
ActiveSecurityLevel uint8
|
||||||
SelectedSecurityLevel uint8
|
SelectedSecurityLevel uint8
|
||||||
|
|
||||||
PortmasterStatus uint8
|
|
||||||
PortmasterStatusMsg string
|
|
||||||
|
|
||||||
Gate17Status uint8
|
|
||||||
Gate17StatusMsg string
|
|
||||||
|
|
||||||
ThreatMitigationLevel uint8
|
ThreatMitigationLevel uint8
|
||||||
Threats map[string]*Threat
|
Threats map[string]*Threat
|
||||||
|
|
||||||
UpdateStatus string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save saves the SystemStatus to the database
|
// Save saves the SystemStatus to the database
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package status
|
|
||||||
|
|
||||||
// Update status options
|
|
||||||
const (
|
|
||||||
UpdateStatusCurrentStable = "stable"
|
|
||||||
UpdateStatusCurrentBeta = "beta"
|
|
||||||
UpdateStatusAvailable = "available" // restart or reboot required
|
|
||||||
UpdateStatusFailed = "failed" // check logs
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetUpdateStatus updates the system status with a new update status.
|
|
||||||
func SetUpdateStatus(newStatus string) {
|
|
||||||
status.Lock()
|
|
||||||
status.UpdateStatus = newStatus
|
|
||||||
status.Unlock()
|
|
||||||
|
|
||||||
go status.Save()
|
|
||||||
}
|
|
||||||
40
ui/module.go
40
ui/module.go
@@ -1,13 +1,51 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
resources "github.com/cookieo9/resources-go"
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portbase/modules"
|
"github.com/safing/portbase/modules"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eventReload = "reload"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
module *modules.Module
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
modules.Register("ui", prep, nil, nil, "api", "updates")
|
module = modules.Register("ui", prep, start, nil, "api", "updates")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func prep() error {
|
||||||
|
module.RegisterEvent(eventReload)
|
||||||
|
|
||||||
return registerRoutes()
|
return registerRoutes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func start() error {
|
||||||
|
return module.RegisterEventHook("ui", eventReload, "reload assets", reloadUI)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reloadUI(ctx context.Context, _ interface{}) error {
|
||||||
|
log.Info("core: user/UI requested UI reload")
|
||||||
|
|
||||||
|
appsLock.Lock()
|
||||||
|
defer appsLock.Unlock()
|
||||||
|
|
||||||
|
// close all bundles
|
||||||
|
for id, bundle := range apps {
|
||||||
|
err := bundle.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("ui: failed to close bundle %s: %s", id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset index
|
||||||
|
apps = make(map[string]*resources.BundleSequence)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ import (
|
|||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cfgDevModeKey = "core/devMode"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
releaseChannel config.StringOption
|
releaseChannel config.StringOption
|
||||||
devMode config.BoolOption
|
devMode config.BoolOption
|
||||||
@@ -23,6 +27,7 @@ func registerConfig() error {
|
|||||||
Name: "Release Channel",
|
Name: "Release Channel",
|
||||||
Key: releaseChannelKey,
|
Key: releaseChannelKey,
|
||||||
Description: "The Release Channel changes which updates are applied. When using beta, you will receive new features earlier and Portmaster will update more frequently. Some beta or experimental features are also available in the stable release channel.",
|
Description: "The Release Channel changes which updates are applied. When using beta, you will receive new features earlier and Portmaster will update more frequently. Some beta or experimental features are also available in the stable release channel.",
|
||||||
|
Order: 1,
|
||||||
OptType: config.OptTypeString,
|
OptType: config.OptTypeString,
|
||||||
ExpertiseLevel: config.ExpertiseLevelExpert,
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
ReleaseLevel: config.ReleaseLevelBeta,
|
ReleaseLevel: config.ReleaseLevelBeta,
|
||||||
@@ -39,6 +44,7 @@ func registerConfig() error {
|
|||||||
Name: "Disable Updates",
|
Name: "Disable Updates",
|
||||||
Key: disableUpdatesKey,
|
Key: disableUpdatesKey,
|
||||||
Description: "Disable automatic updates.",
|
Description: "Disable automatic updates.",
|
||||||
|
Order: 64,
|
||||||
OptType: config.OptTypeBool,
|
OptType: config.OptTypeBool,
|
||||||
ExpertiseLevel: config.ExpertiseLevelExpert,
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
ReleaseLevel: config.ReleaseLevelStable,
|
ReleaseLevel: config.ReleaseLevelStable,
|
||||||
@@ -55,9 +61,13 @@ func registerConfig() error {
|
|||||||
|
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
releaseChannel = config.GetAsString(releaseChannelKey, releaseChannelStable)
|
releaseChannel = config.GetAsString(releaseChannelKey, releaseChannelStable)
|
||||||
disableUpdates = config.GetAsBool(disableUpdatesKey, false)
|
previousReleaseChannel = releaseChannel()
|
||||||
|
|
||||||
devMode = config.GetAsBool("core/devMode", false)
|
disableUpdates = config.GetAsBool(disableUpdatesKey, false)
|
||||||
|
updatesCurrentlyDisabled = disableUpdates()
|
||||||
|
|
||||||
|
devMode = config.GetAsBool(cfgDevModeKey, false)
|
||||||
|
previousDevMode = devMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRegistryConfig(_ context.Context, _ interface{}) error {
|
func updateRegistryConfig(_ context.Context, _ interface{}) error {
|
||||||
@@ -90,8 +100,8 @@ func updateRegistryConfig(_ context.Context, _ interface{}) error {
|
|||||||
module.Resolve(updateFailed)
|
module.Resolve(updateFailed)
|
||||||
_ = TriggerUpdate()
|
_ = TriggerUpdate()
|
||||||
log.Infof("updates: automatic updates enabled again.")
|
log.Infof("updates: automatic updates enabled again.")
|
||||||
} else {
|
} else if updatesCurrentlyDisabled {
|
||||||
module.Warning(updateFailed, "Updates are disabled!")
|
module.Warning(updateFailed, "Automatic updates are disabled! This also affects security updates and threat intelligence.")
|
||||||
log.Warningf("updates: automatic updates are now disabled.")
|
log.Warningf("updates: automatic updates are now disabled.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user