safing-portmaster/service/firewall/module.go
Vladimir Stoilov 1a1bc14804
Feature/systemd query events ()
* [service] Subscribe to systemd-resolver events

* [service] Add disabled state to the resolver

* [service] Add ETW DNS event listener

* [service] DNS listener refactoring

* [service] Add windows core dll project

* [service] DNSListener refactoring, small bugfixes

* [service] Change dns bypass rule

* [service] Update gitignore

* [service] Remove shim from integration module

* [service] Add DNS packet analyzer

* [service] Add self-check in dns monitor

* [service] Fix go linter errors

* [CI] Add github workflow for the windows core dll

* [service] Minor fixes to the dns monitor
2024-11-27 17:10:47 +02:00

169 lines
4.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package firewall
import (
"errors"
"flag"
"fmt"
"path/filepath"
"strings"
"sync/atomic"
"time"
"github.com/safing/portmaster/base/config"
"github.com/safing/portmaster/base/log"
_ "github.com/safing/portmaster/service/core"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/service/netquery"
"github.com/safing/portmaster/service/network"
"github.com/safing/portmaster/service/profile"
"github.com/safing/portmaster/service/resolver"
"github.com/safing/portmaster/spn/access"
"github.com/safing/portmaster/spn/captain"
)
type stringSliceFlag []string
func (ss *stringSliceFlag) String() string {
return strings.Join(*ss, ":")
}
func (ss *stringSliceFlag) Set(value string) error {
*ss = append(*ss, filepath.Clean(value))
return nil
}
var allowedClients stringSliceFlag
type Firewall struct {
mgr *mgr.Manager
instance instance
}
func init() {
flag.Var(&allowedClients, "allowed-clients", "A list of binaries that are allowed to connect to the Portmaster API")
}
func (f *Firewall) Manager() *mgr.Manager {
return f.mgr
}
func (f *Firewall) Start() error {
if err := prep(); err != nil {
log.Errorf("Failed to prepare firewall module %q", err)
return err
}
return start()
}
func (f *Firewall) Stop() error {
// Cancel all workers and give them a little time.
// The bandwidth updater can crash the sqlite DB for some reason.
// TODO: Investigate.
f.mgr.Cancel()
time.Sleep(100 * time.Millisecond)
return stop()
}
func prep() error {
network.SetDefaultFirewallHandler(defaultFirewallHandler)
// Reset connections every time configuration changes
// this will be triggered on spn enable/disable
module.instance.Config().EventConfigChange.AddCallback("reset connection verdicts after global config change", func(w *mgr.WorkerCtx, _ struct{}) (bool, error) {
resetAllConnectionVerdicts()
return false, nil
})
module.instance.Profile().EventConfigChange.AddCallback("reset connection verdicts after profile config change",
func(m *mgr.WorkerCtx, profileID string) (bool, error) {
// Expected event data: scoped profile ID.
profileSource, profileID, ok := strings.Cut(profileID, "/")
if !ok {
return false, fmt.Errorf("event data does not seem to be a scoped profile ID: %v", profileID)
}
resetProfileConnectionVerdict(profileSource, profileID)
return false, nil
},
)
// Reset connections when spn is connected
// connect and disconnecting is triggered on config change event but connecting takеs more time
module.instance.Captain().EventSPNConnected.AddCallback("reset connection verdicts on SPN connect", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {
resetAllConnectionVerdicts()
return false, err
})
// Reset connections when account is updated.
// This will not change verdicts, but will update the feature flags on connections.
module.instance.Access().EventAccountUpdate.AddCallback("update connection feature flags after account update", func(wc *mgr.WorkerCtx, s struct{}) (cancel bool, err error) {
resetAllConnectionVerdicts()
return false, err
})
module.instance.Network().EventConnectionReattributed.AddCallback("reset connection verdicts after connection re-attribution", func(wc *mgr.WorkerCtx, connID string) (cancel bool, err error) {
// Expected event data: connection ID.
resetSingleConnectionVerdict(connID)
return false, err
})
return nil
}
func start() error {
getConfig()
startAPIAuth()
module.mgr.Go("packet handler", packetHandler)
module.mgr.Go("bandwidth update handler", bandwidthUpdateHandler)
// Start stat logger if logging is set to trace.
if log.GetLogLevel() == log.TraceLevel {
module.mgr.Go("stat logger", statLogger)
}
return nil
}
func stop() error {
return nil
}
var (
module *Firewall
shimLoaded atomic.Bool
)
func New(instance instance) (*Firewall, error) {
if !shimLoaded.CompareAndSwap(false, true) {
return nil, errors.New("only one instance allowed")
}
m := mgr.New("Firewall")
module = &Firewall{
mgr: m,
instance: instance,
}
if err := prepAPIAuth(); err != nil {
return nil, err
}
if err := registerConfig(); err != nil {
return nil, err
}
return module, nil
}
type instance interface {
Config() *config.Config
Profile() *profile.ProfileModule
Captain() *captain.Captain
Access() *access.Access
Network() *network.Network
NetQuery() *netquery.NetQuery
Resolver() *resolver.ResolverModule
}