From 60d8664e7bb4c9e930667f2b013d899e3cae44df Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 2 Feb 2022 12:48:42 +0100 Subject: [PATCH] Fix tests and linters --- cmds/portmaster-core/main.go | 6 +- cmds/portmaster-start/console_default.go | 5 +- cmds/portmaster-start/lock.go | 2 +- cmds/portmaster-start/logs.go | 9 +- cmds/portmaster-start/main.go | 17 +- cmds/portmaster-start/recover_linux.go | 14 +- cmds/portmaster-start/run.go | 13 +- cmds/portmaster-start/show.go | 5 +- cmds/portmaster-start/shutdown.go | 14 +- cmds/portmaster-start/update.go | 3 +- cmds/portmaster-start/version.go | 7 +- cmds/trafficgen/main.go | 8 +- cmds/updatemgr/main.go | 5 +- cmds/updatemgr/release.go | 12 +- compat/callbacks.go | 4 + compat/module.go | 8 +- compat/notify.go | 11 +- compat/selfcheck.go | 14 +- core/base/databases.go | 6 +- core/base/global.go | 4 +- core/base/module.go | 9 +- core/base/profiling.go | 10 +- core/core.go | 6 +- core/os_default.go | 2 +- core/pmtesting/testing.go | 10 +- detection/dga/lms_test.go | 4 + firewall/api.go | 13 +- firewall/bypassing.go | 7 +- firewall/dns.go | 7 +- firewall/filter.go | 7 +- firewall/interception.go | 29 ++- firewall/interception/interception.go | 2 +- firewall/interception/introspection.go | 4 +- firewall/interception/nfq/nfq.go | 18 +- firewall/interception/nfq/packet.go | 6 +- firewall/interception/nfqueue_linux.go | 6 +- firewall/master.go | 24 ++- firewall/preauth.go | 8 +- firewall/prompt.go | 2 +- intel/block_reason.go | 1 + intel/entity.go | 7 +- intel/filterlists/bloom.go | 3 +- intel/filterlists/cache_version.go | 4 +- intel/filterlists/database.go | 19 +- intel/filterlists/decoder.go | 5 +- intel/filterlists/index.go | 5 +- intel/filterlists/lookup.go | 3 +- intel/filterlists/module.go | 8 +- intel/filterlists/record.go | 10 +- intel/filterlists/updater.go | 17 +- intel/geoip/database.go | 4 +- intel/geoip/location.go | 6 +- intel/geoip/location_test.go | 2 + intel/geoip/lookup_test.go | 10 +- intel/module.go | 6 +- intel/resolver.go | 4 +- nameserver/config.go | 6 +- nameserver/failing.go | 6 +- nameserver/module.go | 47 ++--- nameserver/nameserver.go | 14 +- nameserver/nsutil/nsutil.go | 7 +- nameserver/response.go | 1 + nameserver/takeover.go | 21 +- netenv/addresses.go | 8 +- netenv/addresses_test.go | 4 + netenv/dbus_linux.go | 28 +-- netenv/dbus_linux_test.go | 2 + netenv/dialing.go | 4 +- netenv/environment_linux.go | 13 +- netenv/environment_linux_test.go | 2 + netenv/environment_test.go | 2 + netenv/location.go | 47 +++-- netenv/location_default.go | 4 +- netenv/location_test.go | 6 +- netenv/main.go | 6 +- netenv/network-change.go | 3 +- netenv/online-status.go | 27 ++- netenv/online-status_test.go | 2 + network/api.go | 15 +- network/api_test.go | 4 + network/clean.go | 7 +- network/connection.go | 28 ++- network/connection_store.go | 2 +- network/database.go | 20 +- network/dns.go | 17 +- network/metrics.go | 2 +- network/netutils/address.go | 2 +- network/netutils/dns.go | 24 +-- network/netutils/dns_test.go | 4 + network/netutils/ip.go | 4 +- network/netutils/ip_test.go | 4 + network/netutils/tcpassembly.go | 4 +- network/packet/const.go | 19 +- network/packet/packet.go | 31 +-- network/packet/packetinfo.go | 2 +- network/packet/parse.go | 2 +- network/proc/findpid.go | 10 +- network/proc/pids_by_user.go | 2 +- network/proc/tables.go | 10 +- network/proc/tables_test.go | 4 +- network/socket/socket.go | 2 +- network/state/exists.go | 1 - network/state/info.go | 1 - network/state/udp.go | 1 - network/status.go | 4 +- process/database.go | 6 +- process/find.go | 1 + process/process.go | 53 +++-- process/process_linux.go | 4 +- process/profile.go | 4 +- process/special.go | 5 +- profile/active.go | 11 - profile/config.go | 22 +- profile/database.go | 17 +- profile/endpoints/endpoint-asn.go | 4 +- profile/endpoints/endpoint-country.go | 4 +- profile/endpoints/endpoint-domain.go | 4 +- profile/endpoints/endpoint-scopes.go | 5 +- profile/endpoints/endpoint.go | 6 +- profile/endpoints/endpoint_test.go | 8 +- profile/endpoints/endpoints.go | 6 +- profile/endpoints/endpoints_test.go | 46 ++-- profile/fingerprint/const.go | 2 +- profile/fingerprint/const_darwin.go | 2 +- profile/fingerprint/const_linux.go | 2 +- profile/fingerprint/const_openbsd.go | 2 +- profile/fingerprint/const_windows.go | 2 +- profile/fingerprint/fingerprint.go | 16 +- profile/fingerprint/identifier_linux.go | 2 +- profile/fingerprint/identifier_linux_test.go | 4 + profile/get.go | 1 - profile/migrations.go | 11 +- profile/module.go | 4 +- profile/profile-layered-provider.go | 1 - profile/profile-layered.go | 54 +++-- profile/profile.go | 20 +- resolver/block-detection.go | 2 +- resolver/config.go | 2 +- resolver/ipinfo.go | 40 ++-- resolver/ipinfo_test.go | 2 + resolver/main.go | 15 +- resolver/main_test.go | 208 +++++++++---------- resolver/namerecord.go | 42 ++-- resolver/namerecord_test.go | 2 + resolver/resolve.go | 34 +-- resolver/resolver-env.go | 5 +- resolver/resolver-mdns.go | 35 ++-- resolver/resolver-plain.go | 5 +- resolver/resolver-tcp.go | 4 +- resolver/resolver.go | 12 +- resolver/resolver_test.go | 18 +- resolver/resolvers.go | 6 +- resolver/resolvers_test.go | 3 + resolver/reverse.go | 1 + resolver/reverse_test.go | 4 + resolver/rrcache.go | 14 +- resolver/rrcache_test.go | 2 + resolver/scopes.go | 14 +- status/config.go | 5 +- status/mitigation.go | 2 +- status/module.go | 4 +- status/provider.go | 4 +- ui/api.go | 1 + ui/module.go | 11 +- ui/serve.go | 7 +- updates/config.go | 4 +- updates/helper/electron.go | 6 +- updates/helper/indexes.go | 7 +- updates/main.go | 4 +- updates/restart.go | 3 +- updates/upgrader.go | 20 +- 171 files changed, 944 insertions(+), 874 deletions(-) diff --git a/cmds/portmaster-core/main.go b/cmds/portmaster-core/main.go index 4e918df1..ea220a87 100644 --- a/cmds/portmaster-core/main.go +++ b/cmds/portmaster-core/main.go @@ -1,6 +1,6 @@ package main -import ( +import ( //nolint:gci,nolintlint "os" "github.com/safing/portbase/info" @@ -8,7 +8,7 @@ import ( "github.com/safing/portbase/run" "github.com/safing/spn/conf" - // include packages here + // Include packages here. _ "github.com/safing/portbase/modules/subsystems" _ "github.com/safing/portmaster/core" _ "github.com/safing/portmaster/firewall" @@ -22,7 +22,7 @@ func main() { info.Set("Portmaster", "0.7.21", "AGPLv3", true) // Configure metrics. - metrics.SetNamespace("portmaster") + _ = metrics.SetNamespace("portmaster") // enable SPN client mode conf.EnableClient(true) diff --git a/cmds/portmaster-start/console_default.go b/cmds/portmaster-start/console_default.go index 7f2fc446..8a29fbb6 100644 --- a/cmds/portmaster-start/console_default.go +++ b/cmds/portmaster-start/console_default.go @@ -1,4 +1,4 @@ -// +build !windows +// go:build !windows package main @@ -8,5 +8,4 @@ func attachToParentConsole() (attached bool, err error) { return true, nil } -func hideWindow(cmd *exec.Cmd) { -} +func hideWindow(cmd *exec.Cmd) {} diff --git a/cmds/portmaster-start/lock.go b/cmds/portmaster-start/lock.go index 9635744d..e121c1f5 100644 --- a/cmds/portmaster-start/lock.go +++ b/cmds/portmaster-start/lock.go @@ -86,7 +86,7 @@ func createInstanceLock(lockFilePath string) error { // create lock file // TODO: Investigate required permissions. - err = ioutil.WriteFile(lockFilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0666) //nolint:gosec + err = ioutil.WriteFile(lockFilePath, []byte(fmt.Sprintf("%d", os.Getpid())), 0o0666) //nolint:gosec if err != nil { return err } diff --git a/cmds/portmaster-start/logs.go b/cmds/portmaster-start/logs.go index 34f00867..d14f1250 100644 --- a/cmds/portmaster-start/logs.go +++ b/cmds/portmaster-start/logs.go @@ -8,15 +8,16 @@ import ( "runtime" "time" + "github.com/spf13/cobra" + "github.com/safing/portbase/container" "github.com/safing/portbase/database/record" "github.com/safing/portbase/formats/dsd" "github.com/safing/portbase/info" - "github.com/spf13/cobra" ) func initializeLogFile(logFilePath string, identifier string, version string) *os.File { - logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0444) + logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0o0444) if err != nil { log.Printf("failed to create log file %s: %s\n", logFilePath, err) return nil @@ -107,7 +108,9 @@ func logControlError(cErr error) { if errorFile == nil { return } - defer errorFile.Close() + defer func() { + _ = errorFile.Close() + }() fmt.Fprintln(errorFile, cErr.Error()) } diff --git a/cmds/portmaster-start/main.go b/cmds/portmaster-start/main.go index 19bb1117..8e010ed5 100644 --- a/cmds/portmaster-start/main.go +++ b/cmds/portmaster-start/main.go @@ -11,15 +11,14 @@ import ( "strings" "syscall" - "github.com/safing/portmaster/updates/helper" + "github.com/spf13/cobra" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/info" portlog "github.com/safing/portbase/log" "github.com/safing/portbase/updater" "github.com/safing/portbase/utils" - - "github.com/spf13/cobra" + "github.com/safing/portmaster/updates/helper" ) var ( @@ -29,7 +28,7 @@ var ( dataRoot *utils.DirStructure logsRoot *utils.DirStructure - // create registry + // Create registry. registry = &updater.ResourceRegistry{ Name: "updates", UpdateURLs: []string{ @@ -153,14 +152,14 @@ func configureRegistry(mustLoadIndex bool) error { // Remove left over quotes. dataDir = strings.Trim(dataDir, `\"`) // Initialize data root. - err := dataroot.Initialize(dataDir, 0755) + err := dataroot.Initialize(dataDir, 0o0755) if err != nil { - return fmt.Errorf("failed to initialize data root: %s", err) + return fmt.Errorf("failed to initialize data root: %w", err) } dataRoot = dataroot.Root() // Initialize registry. - err = registry.Initialize(dataRoot.ChildDir("updates", 0755)) + err = registry.Initialize(dataRoot.ChildDir("updates", 0o0755)) if err != nil { return err } @@ -170,10 +169,10 @@ func configureRegistry(mustLoadIndex bool) error { func ensureLoggingDir() error { // set up logs root - logsRoot = dataRoot.ChildDir("logs", 0777) + logsRoot = dataRoot.ChildDir("logs", 0o0777) err := logsRoot.Ensure() if err != nil { - return fmt.Errorf("failed to initialize logs root (%q): %s", logsRoot.Path, err) + return fmt.Errorf("failed to initialize logs root (%q): %w", logsRoot.Path, err) } // warn about CTRL-C on windows diff --git a/cmds/portmaster-start/recover_linux.go b/cmds/portmaster-start/recover_linux.go index 06529431..ecb9a219 100644 --- a/cmds/portmaster-start/recover_linux.go +++ b/cmds/portmaster-start/recover_linux.go @@ -1,13 +1,15 @@ package main import ( + "errors" "fmt" "os" "strings" "github.com/hashicorp/go-multierror" - "github.com/safing/portmaster/firewall/interception" "github.com/spf13/cobra" + + "github.com/safing/portmaster/firewall/interception" ) var recoverIPTablesCmd = &cobra.Command{ @@ -19,8 +21,10 @@ var recoverIPTablesCmd = &cobra.Command{ // we don't get the errno of the actual error and need to parse the // output instead. Make sure it's always english by setting LC_ALL=C currentLocale := os.Getenv("LC_ALL") - os.Setenv("LC_ALL", "C") - defer os.Setenv("LC_ALL", currentLocale) + _ = os.Setenv("LC_ALL", "C") + defer func() { + _ = os.Setenv("LC_ALL", currentLocale) + }() err := interception.DeactivateNfqueueFirewall() if err == nil { @@ -29,8 +33,8 @@ var recoverIPTablesCmd = &cobra.Command{ // we don't want to show ErrNotExists to the user // as that only means portmaster did the cleanup itself. - mr, ok := err.(*multierror.Error) - if !ok { + var mr *multierror.Error + if !errors.As(err, &mr) { return err } diff --git a/cmds/portmaster-start/run.go b/cmds/portmaster-start/run.go index 9564f7fa..8881b2d6 100644 --- a/cmds/portmaster-start/run.go +++ b/cmds/portmaster-start/run.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "io" "log" @@ -12,9 +13,10 @@ import ( "strings" "time" - "github.com/safing/portmaster/updates/helper" "github.com/spf13/cobra" "github.com/tevino/abool" + + "github.com/safing/portmaster/updates/helper" ) const ( @@ -223,11 +225,11 @@ func fixExecPerm(path string) error { return fmt.Errorf("failed to stat %s: %w", path, err) } - if info.Mode() == 0755 { + if info.Mode() == 0o0755 { return nil } - if err := os.Chmod(path, 0755); err != nil { + if err := os.Chmod(path, 0o0755); err != nil { //nolint:gosec // Set execution rights. return fmt.Errorf("failed to chmod %s: %w", path, err) } @@ -367,7 +369,7 @@ func execute(opts *Options, args []string) (cont bool, err error) { case <-time.After(3 * time.Minute): // portmaster core prints stack if not able to shutdown in 3 minutes, give it one more ... err = exc.Process.Kill() if err != nil { - return false, fmt.Errorf("failed to kill %s: %s", opts.Identifier, err) + return false, fmt.Errorf("failed to kill %s: %w", opts.Identifier, err) } return false, fmt.Errorf("killed %s", opts.Identifier) } @@ -402,7 +404,8 @@ func parseExitError(err error) (restart bool, errWithCtx error) { return false, nil } - if exErr, ok := err.(*exec.ExitError); ok { + var exErr *exec.ExitError + if errors.As(err, &exErr) { switch exErr.ProcessState.ExitCode() { case 0: return false, fmt.Errorf("clean exit with error: %w", err) diff --git a/cmds/portmaster-start/show.go b/cmds/portmaster-start/show.go index 8406b0b0..207b7183 100644 --- a/cmds/portmaster-start/show.go +++ b/cmds/portmaster-start/show.go @@ -4,8 +4,9 @@ import ( "fmt" "strings" - "github.com/safing/portmaster/updates/helper" "github.com/spf13/cobra" + + "github.com/safing/portmaster/updates/helper" ) func init() { @@ -35,7 +36,7 @@ func show(opts *Options, cmdArgs []string) error { helper.PlatformIdentifier(opts.Identifier), ) if err != nil { - return fmt.Errorf("could not get component: %s", err) + return fmt.Errorf("could not get component: %w", err) } fmt.Printf("%s %s\n", file.Path(), strings.Join(args, " ")) diff --git a/cmds/portmaster-start/shutdown.go b/cmds/portmaster-start/shutdown.go index f136f344..31d34f96 100644 --- a/cmds/portmaster-start/shutdown.go +++ b/cmds/portmaster-start/shutdown.go @@ -5,10 +5,16 @@ import ( ) var ( - startupComplete = make(chan struct{}) // signal that the start procedure completed (is never closed, just signaled once) - shuttingDown = make(chan struct{}) // signal that we are shutting down (will be closed, may not be closed directly, use initiateShutdown) - //nolint:unused // false positive on linux, currently used by windows only - shutdownError error // protected by shutdownLock + // startupComplete signals that the start procedure completed. + // The channel is not closed, just signaled once. + startupComplete = make(chan struct{}) + + // shuttingDown signals that we are shutting down. + // The channel will be closed, but may not be closed directly - only via initiateShutdown. + shuttingDown = make(chan struct{}) + + // shutdownError is protected by shutdownLock. + shutdownError error //nolint:unused,errname // Not what the linter thinks it is. Currently used on windows only. shutdownLock sync.Mutex ) diff --git a/cmds/portmaster-start/update.go b/cmds/portmaster-start/update.go index 69c26e2c..45b7df8e 100644 --- a/cmds/portmaster-start/update.go +++ b/cmds/portmaster-start/update.go @@ -5,9 +5,10 @@ import ( "fmt" "os" + "github.com/spf13/cobra" + "github.com/safing/portbase/log" "github.com/safing/portmaster/updates/helper" - "github.com/spf13/cobra" ) var reset bool diff --git a/cmds/portmaster-start/version.go b/cmds/portmaster-start/version.go index 88af21e6..fa82884b 100644 --- a/cmds/portmaster-start/version.go +++ b/cmds/portmaster-start/version.go @@ -8,8 +8,9 @@ import ( "strings" "text/tabwriter" - "github.com/safing/portbase/info" "github.com/spf13/cobra" + + "github.com/safing/portbase/info" ) var ( @@ -64,9 +65,7 @@ var ( fmt.Fprintf(tw, " %s\t%s\n", identifier, res.SelectedVersion.VersionNumber) } - tw.Flush() - - return nil + return tw.Flush() }, } ) diff --git a/cmds/trafficgen/main.go b/cmds/trafficgen/main.go index d3af1b37..e57b6d1d 100644 --- a/cmds/trafficgen/main.go +++ b/cmds/trafficgen/main.go @@ -12,9 +12,7 @@ import ( "github.com/safing/portbase/log" ) -const ( - dnsResolver = "1.1.1.1:53" -) +const dnsResolver = "1.1.1.1:53" var ( url string @@ -72,7 +70,9 @@ func makeHTTPRequest(i int) { log.Errorf("http request #%d failed after %s: %s", i, time.Since(start).Round(time.Millisecond), err) return } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() log.Infof("http response #%d after %s: %d", i, time.Since(start).Round(time.Millisecond), resp.StatusCode) } diff --git a/cmds/updatemgr/main.go b/cmds/updatemgr/main.go index 267aade0..ffd66b28 100644 --- a/cmds/updatemgr/main.go +++ b/cmds/updatemgr/main.go @@ -5,9 +5,10 @@ import ( "os" "path/filepath" + "github.com/spf13/cobra" + "github.com/safing/portbase/updater" "github.com/safing/portbase/utils" - "github.com/spf13/cobra" ) var ( @@ -30,7 +31,7 @@ var rootCmd = &cobra.Command{ } registry = &updater.ResourceRegistry{} - err = registry.Initialize(utils.NewDirStructure(absDistPath, 0755)) + err = registry.Initialize(utils.NewDirStructure(absDistPath, 0o0755)) if err != nil { return err } diff --git a/cmds/updatemgr/release.go b/cmds/updatemgr/release.go index 4dbd296b..194fadaf 100644 --- a/cmds/updatemgr/release.go +++ b/cmds/updatemgr/release.go @@ -8,9 +8,9 @@ import ( "os" "path/filepath" - "github.com/safing/portbase/updater" - "github.com/spf13/cobra" + + "github.com/safing/portbase/updater" ) var ( @@ -44,13 +44,13 @@ func release(cmd *cobra.Command, args []string) error { // Check if we want to reset instead. if resetPreReleases { - return removeFilesFromIndex(getChannelVersions(channel, preReleaseFrom, true)) + return removeFilesFromIndex(getChannelVersions(preReleaseFrom, true)) } // Write new index. err := writeIndex( channel, - getChannelVersions(channel, preReleaseFrom, false), + getChannelVersions(preReleaseFrom, false), ) if err != nil { return err @@ -95,7 +95,7 @@ func writeIndex(channel string, versions map[string]string) error { } // Write new index to disk. - err = ioutil.WriteFile(indexFilePath, versionData, 0644) //nolint:gosec // 0644 is intended + err = ioutil.WriteFile(indexFilePath, versionData, 0o0644) //nolint:gosec // 0644 is intended if err != nil { return err } @@ -129,7 +129,7 @@ func removeFilesFromIndex(versions map[string]string) error { return nil } -func getChannelVersions(channel string, prereleaseFrom string, storagePath bool) map[string]string { +func getChannelVersions(prereleaseFrom string, storagePath bool) map[string]string { if prereleaseFrom != "" { registry.AddIndex(updater.Index{ Path: prereleaseFrom + ".json", diff --git a/compat/callbacks.go b/compat/callbacks.go index 87f85078..e997ff8f 100644 --- a/compat/callbacks.go +++ b/compat/callbacks.go @@ -7,6 +7,7 @@ import ( "github.com/safing/portmaster/process" ) +// SubmitSystemIntegrationCheckPacket submit a packet for the system integrity check. func SubmitSystemIntegrationCheckPacket(p packet.Packet) { select { case systemIntegrationCheckPackets <- p: @@ -14,6 +15,7 @@ func SubmitSystemIntegrationCheckPacket(p packet.Packet) { } } +// SubmitDNSCheckDomain submits a subdomain for the dns check. func SubmitDNSCheckDomain(subdomain string) (respondWith net.IP) { // Submit queried domain. select { @@ -27,10 +29,12 @@ func SubmitDNSCheckDomain(subdomain string) (respondWith net.IP) { return dnsCheckAnswer } +// ReportSecureDNSBypassIssue reports a DNS bypassing issue for the given process. func ReportSecureDNSBypassIssue(p *process.Process) { secureDNSBypassIssue.notify(p) } +// ReportMultiPeerUDPTunnelIssue reports a multi-peer UDP tunnel for the given process. func ReportMultiPeerUDPTunnelIssue(p *process.Process) { multiPeerUDPTunnelIssue.notify(p) } diff --git a/compat/module.go b/compat/module.go index fb1b7d1f..2cc6eca7 100644 --- a/compat/module.go +++ b/compat/module.go @@ -4,11 +4,12 @@ import ( "context" "time" + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/resolver" - "github.com/tevino/abool" ) var ( @@ -43,7 +44,7 @@ func prep() error { func start() error { selfcheckTask = module.NewTask("compatibility self-check", selfcheckTaskFunc). - Repeat(1 * time.Minute). + Repeat(5 * time.Minute). MaxDelay(selfcheckTaskRetryAfter). Schedule(time.Now().Add(selfcheckTaskRetryAfter)) @@ -98,6 +99,9 @@ func selfcheckTaskFunc(ctx context.Context, task *modules.Task) error { return nil } +// SelfCheckIsFailing returns whether the self check is currently failing. +// This returns true after the first check fails, and does not wait for the +// failing threshold to be met. func SelfCheckIsFailing() bool { return selfCheckIsFailing.IsSet() } diff --git a/compat/notify.go b/compat/notify.go index a64b81d6..718e4846 100644 --- a/compat/notify.go +++ b/compat/notify.go @@ -7,18 +7,17 @@ import ( "sync" "time" - "github.com/safing/portmaster/profile" - "github.com/safing/portbase/log" "github.com/safing/portbase/notifications" "github.com/safing/portmaster/process" + "github.com/safing/portmaster/profile" ) type baseIssue struct { - id string - title string - message string - level notifications.Type + id string //nolint:structcheck // Inherited. + title string //nolint:structcheck // Inherited. + message string //nolint:structcheck // Inherited. + level notifications.Type //nolint:structcheck // Inherited. } type systemIssue baseIssue diff --git a/compat/selfcheck.go b/compat/selfcheck.go index 407ccdb2..4aee02a7 100644 --- a/compat/selfcheck.go +++ b/compat/selfcheck.go @@ -18,22 +18,24 @@ import ( var ( selfcheckLock sync.Mutex - SystemIntegrationCheckDstIP = net.IPv4(127, 65, 67, 75) + // SystemIntegrationCheckDstIP is the IP address to send a packet to for the + // system integration test. + SystemIntegrationCheckDstIP = net.IPv4(127, 65, 67, 75) + // SystemIntegrationCheckProtocol is the IP protocol to use for the system + // integration test. SystemIntegrationCheckProtocol = packet.AnyHostInternalProtocol61 systemIntegrationCheckDialNet = fmt.Sprintf("ip4:%d", uint8(SystemIntegrationCheckProtocol)) systemIntegrationCheckDialIP = SystemIntegrationCheckDstIP.String() systemIntegrationCheckPackets = make(chan packet.Packet, 1) - systemIntegrationCheckWaitDuration = 3 * time.Second + systemIntegrationCheckWaitDuration = 10 * time.Second + // DNSCheckInternalDomainScope is the domain scope to use for dns checks. DNSCheckInternalDomainScope = ".self-check." + resolver.InternalSpecialUseDomain dnsCheckReceivedDomain = make(chan string, 1) - dnsCheckWaitDuration = 3 * time.Second + dnsCheckWaitDuration = 10 * time.Second dnsCheckAnswerLock sync.Mutex dnsCheckAnswer net.IP - - DNSTestDomain = "one.one.one.one." - DNSTestExpectedIP = net.IPv4(1, 1, 1, 1) ) func selfcheck(ctx context.Context) (issue *systemIssue, err error) { diff --git a/core/base/databases.go b/core/base/databases.go index e9ae8f74..d2ba2552 100644 --- a/core/base/databases.go +++ b/core/base/databases.go @@ -3,14 +3,12 @@ package base import ( "github.com/safing/portbase/database" - // database module + // Dependencies. _ "github.com/safing/portbase/database/dbmodule" - - // module dependencies _ "github.com/safing/portbase/database/storage/bbolt" ) -// Default Values (changeable for testing) +// Default Values (changeable for testing). var ( DefaultDatabaseStorageType = "bbolt" ) diff --git a/core/base/global.go b/core/base/global.go index b314797c..2de07ad2 100644 --- a/core/base/global.go +++ b/core/base/global.go @@ -11,7 +11,7 @@ import ( "github.com/safing/portbase/modules" ) -// Default Values (changeable for testing) +// Default Values (changeable for testing). var ( DefaultAPIListenAddress = "127.0.0.1:817" @@ -56,7 +56,7 @@ func globalPrep() error { } // initialize structure - err := dataroot.Initialize(dataDir, 0755) + err := dataroot.Initialize(dataDir, 0o0755) if err != nil { return err } diff --git a/core/base/module.go b/core/base/module.go index 759d5d8e..3b31eb46 100644 --- a/core/base/module.go +++ b/core/base/module.go @@ -1,19 +1,14 @@ package base import ( + _ "github.com/safing/portbase/config" "github.com/safing/portbase/log" "github.com/safing/portbase/metrics" "github.com/safing/portbase/modules" - - // module dependencies - _ "github.com/safing/portbase/config" - _ "github.com/safing/portbase/metrics" _ "github.com/safing/portbase/rng" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register("base", nil, start, nil, "database", "config", "rng", "metrics") diff --git a/core/base/profiling.go b/core/base/profiling.go index bf96e9f5..bae54645 100644 --- a/core/base/profiling.go +++ b/core/base/profiling.go @@ -8,9 +8,7 @@ import ( "runtime/pprof" ) -var ( - cpuProfile string -) +var cpuProfile string func init() { flag.StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to `file`") @@ -25,10 +23,10 @@ func startProfiling() { func cpuProfiler(ctx context.Context) error { f, err := os.Create(cpuProfile) if err != nil { - return fmt.Errorf("could not create CPU profile: %s", err) + return fmt.Errorf("could not create CPU profile: %w", err) } if err := pprof.StartCPUProfile(f); err != nil { - return fmt.Errorf("could not start CPU profile: %s", err) + return fmt.Errorf("could not start CPU profile: %w", err) } // wait for shutdown @@ -37,7 +35,7 @@ func cpuProfiler(ctx context.Context) error { pprof.StopCPUProfile() err = f.Close() if err != nil { - return fmt.Errorf("failed to close CPU profile file: %s", err) + return fmt.Errorf("failed to close CPU profile file: %w", err) } return nil } diff --git a/core/core.go b/core/core.go index 07ff9ec1..80bd6343 100644 --- a/core/core.go +++ b/core/core.go @@ -7,12 +7,10 @@ import ( "github.com/safing/portbase/modules" "github.com/safing/portbase/modules/subsystems" - "github.com/safing/portmaster/updates" - - // module dependencies _ "github.com/safing/portmaster/netenv" _ "github.com/safing/portmaster/status" _ "github.com/safing/portmaster/ui" + "github.com/safing/portmaster/updates" ) const ( @@ -65,7 +63,7 @@ func prep() error { func start() error { 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: %w", err) } registerLogCleaner() diff --git a/core/os_default.go b/core/os_default.go index 459e41a2..f00ffa01 100644 --- a/core/os_default.go +++ b/core/os_default.go @@ -1,4 +1,4 @@ -// +build !windows +// go:build !windows package core diff --git a/core/pmtesting/testing.go b/core/pmtesting/testing.go index 086ae2da..1f4324fa 100644 --- a/core/pmtesting/testing.go +++ b/core/pmtesting/testing.go @@ -24,18 +24,14 @@ import ( "runtime/pprof" "testing" + _ "github.com/safing/portbase/database/storage/hashmap" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portmaster/core/base" - - // module dependencies - _ "github.com/safing/portbase/database/storage/hashmap" ) -var ( - printStackOnExit bool -) +var printStackOnExit bool func init() { flag.BoolVar(&printStackOnExit, "print-stack-on-exit", false, "prints the stack before of shutting down") @@ -73,7 +69,7 @@ func TestMainWithHooks(m *testing.M, module *modules.Module, afterStartFn, befor // tmp dir for data root (db & config) tmpDir := filepath.Join(os.TempDir(), "portmaster-testing") // initialize data dir - err := dataroot.Initialize(tmpDir, 0755) + err := dataroot.Initialize(tmpDir, 0o0755) if err != nil { fmt.Fprintf(os.Stderr, "failed to initialize data root: %s\n", err) os.Exit(1) diff --git a/detection/dga/lms_test.go b/detection/dga/lms_test.go index 9421550b..ce5697c8 100644 --- a/detection/dga/lms_test.go +++ b/detection/dga/lms_test.go @@ -3,6 +3,8 @@ package dga import "testing" func TestLmsScoreOfDomain(t *testing.T) { + t.Parallel() + testDomain(t, "g.symcd.com.", 100, 100) testDomain(t, "www.google.com.", 100, 100) testDomain(t, "55ttt5.12abc3.test.com.", 68, 69) @@ -10,6 +12,8 @@ func TestLmsScoreOfDomain(t *testing.T) { } func testDomain(t *testing.T, domain string, min, max float64) { + t.Helper() + score := LmsScoreOfDomain(domain) if score < min || score > max { t.Errorf("domain %s has scored %.2f, but should be between %.0f and %.0f", domain, score, min, max) diff --git a/firewall/api.go b/firewall/api.go index 168d25bc..18c675e9 100644 --- a/firewall/api.go +++ b/firewall/api.go @@ -11,16 +11,14 @@ import ( "strings" "time" - "github.com/safing/portmaster/netenv" - - "github.com/safing/portmaster/updates" - "github.com/safing/portbase/api" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/log" "github.com/safing/portbase/utils" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/packet" "github.com/safing/portmaster/process" + "github.com/safing/portmaster/updates" ) const ( @@ -79,13 +77,13 @@ func apiAuthenticator(r *http.Request, s *http.Server) (token *api.AuthToken, er // get local IP/Port localIP, localPort, err := parseHostPort(s.Addr) if err != nil { - return nil, fmt.Errorf("failed to get local IP/Port: %s", err) + return nil, fmt.Errorf("failed to get local IP/Port: %w", err) } // get remote IP/Port remoteIP, remotePort, err := parseHostPort(r.RemoteAddr) if err != nil { - return nil, fmt.Errorf("failed to get remote IP/Port: %s", err) + return nil, fmt.Errorf("failed to get remote IP/Port: %w", err) } // Check if the request is even local. @@ -151,11 +149,12 @@ func authenticateAPIRequest(ctx context.Context, pktInfo *packet.Info) (retry bo // Go up up to two levels, if we don't match the path. checkLevels := 2 + checkLevelsLoop: for i := 0; i < checkLevels+1; i++ { // Check for eligible path. switch proc.Pid { case process.UnidentifiedProcessID, process.SystemProcessID: - break + break checkLevelsLoop default: // normal process // Check if the requesting process is in database root / updates dir. if strings.HasPrefix(proc.Path, authenticatedPath) { diff --git a/firewall/bypassing.go b/firewall/bypassing.go index 016c1cc7..62d324c3 100644 --- a/firewall/bypassing.go +++ b/firewall/bypassing.go @@ -5,16 +5,13 @@ import ( "strings" "github.com/safing/portmaster/compat" - "github.com/safing/portmaster/nameserver/nsutil" "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/packet" "github.com/safing/portmaster/profile/endpoints" ) -var ( - resolverFilterLists = []string{"17-DNS"} -) +var resolverFilterLists = []string{"17-DNS"} // PreventBypassing checks if the connection should be denied or permitted // based on some bypass protection checks. @@ -27,7 +24,7 @@ func PreventBypassing(ctx context.Context, conn *network.Connection) (endpoints. } // Block direct connections to known DNS resolvers. - switch packet.IPProtocol(conn.Entity.Protocol) { + switch packet.IPProtocol(conn.Entity.Protocol) { //nolint:exhaustive // Checking for specific values only. case packet.ICMP, packet.ICMPv6: // Make an exception for ICMP, as these IPs are also often used for debugging. default: diff --git a/firewall/dns.go b/firewall/dns.go index 72fb398f..cb78e5c4 100644 --- a/firewall/dns.go +++ b/firewall/dns.go @@ -2,10 +2,12 @@ package firewall import ( "context" + "errors" "net" "strings" "github.com/miekg/dns" + "github.com/safing/portbase/database" "github.com/safing/portbase/log" "github.com/safing/portmaster/network" @@ -22,7 +24,6 @@ func filterDNSSection( resolverScope netutils.IPScope, sysResolver bool, ) ([]dns.RR, []string, int, string) { - // Will be filled 1:1 most of the time. goodEntries := make([]dns.RR, 0, len(entries)) @@ -275,7 +276,7 @@ func UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *netw } // Resolve all CNAMEs in the correct order and add the to the record. - var domain = q.FQDN + domain := q.FQDN for { nextDomain, isCNAME := cnames[domain] if !isCNAME { @@ -294,7 +295,7 @@ func UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *netw ipString := ip.String() info, err := resolver.GetIPInfo(profileID, ipString) if err != nil { - if err != database.ErrNotFound { + if !errors.Is(err, database.ErrNotFound) { log.Errorf("nameserver: failed to search for IP info record: %s", err) } diff --git a/firewall/filter.go b/firewall/filter.go index 9c0efdeb..cb7dc3aa 100644 --- a/firewall/filter.go +++ b/firewall/filter.go @@ -2,13 +2,12 @@ package firewall import ( "github.com/safing/portbase/config" - "github.com/safing/portbase/modules/subsystems" - "github.com/safing/spn/captain" - "github.com/safing/portbase/modules" + "github.com/safing/portbase/modules/subsystems" - // module dependencies + // Dependency. _ "github.com/safing/portmaster/core" + "github.com/safing/spn/captain" ) var ( diff --git a/firewall/interception.go b/firewall/interception.go index 4691d447..393dee9f 100644 --- a/firewall/interception.go +++ b/firewall/interception.go @@ -9,28 +9,25 @@ import ( "sync/atomic" "time" - "github.com/safing/portmaster/compat" - - "github.com/safing/spn/captain" - "github.com/google/gopacket/layers" - "github.com/safing/portmaster/netenv" - "golang.org/x/sync/singleflight" - "github.com/tevino/abool" + "golang.org/x/sync/singleflight" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" + "github.com/safing/portmaster/compat" + + // Dependency. + _ "github.com/safing/portmaster/core/base" "github.com/safing/portmaster/firewall/inspection" "github.com/safing/portmaster/firewall/interception" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/network/packet" + "github.com/safing/spn/captain" "github.com/safing/spn/crew" "github.com/safing/spn/sluice" - - // module dependencies - _ "github.com/safing/portmaster/core/base" ) var ( @@ -141,14 +138,14 @@ func getConnection(pkt packet.Packet) (*network.Connection, error) { return conn, nil }) if err != nil { - return nil, fmt.Errorf("failed to get connection: %s", err) + return nil, fmt.Errorf("failed to get connection: %w", err) } if newConn == nil { return nil, errors.New("connection getter returned nil") } // Transform and log result. - conn := newConn.(*network.Connection) + conn := newConn.(*network.Connection) //nolint:forcetypeassert // Can only be a *network.Connection. sharedIndicator := "" if shared { sharedIndicator = " (shared)" @@ -188,7 +185,7 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) { return true } - switch meta.Protocol { + switch meta.Protocol { //nolint:exhaustive // Checking for specific values only. case packet.ICMP, packet.ICMPv6: // Load packet data. err := pkt.LoadPacketData() @@ -243,7 +240,7 @@ func fastTrackedPermit(pkt packet.Packet) (handled bool) { } // DHCP is only valid in local network scopes. - switch netutils.ClassifyIP(meta.Dst) { + switch netutils.ClassifyIP(meta.Dst) { //nolint:exhaustive // Checking for specific values only. case netutils.HostLocal, netutils.LinkLocal, netutils.SiteLocal, netutils.LocalMulticast: default: return false @@ -430,7 +427,6 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) { conn.StopFirewallHandler() issueVerdict(conn, pkt, 0, true) } - } func defaultHandler(conn *network.Connection, pkt packet.Packet) { @@ -494,6 +490,9 @@ func issueVerdict(conn *network.Connection, pkt packet.Packet, verdict network.V case network.VerdictFailed: atomic.AddUint64(packetsFailed, 1) err = pkt.Drop() + case network.VerdictUndecided, network.VerdictUndeterminable: + log.Warningf("filter: tried to apply verdict %s to pkt %s: dropping instead", verdict, pkt) + fallthrough default: atomic.AddUint64(packetsDropped, 1) err = pkt.Drop() diff --git a/firewall/interception/interception.go b/firewall/interception/interception.go index 4846f943..f3cbd5c5 100644 --- a/firewall/interception/interception.go +++ b/firewall/interception/interception.go @@ -25,7 +25,7 @@ func Start() error { return nil } - var inputPackets = Packets + inputPackets := Packets if packetMetricsDestination != "" { go metrics.writeMetrics() inputPackets = make(chan packet.Packet) diff --git a/firewall/interception/introspection.go b/firewall/interception/introspection.go index 6bb0019e..c8361e1c 100644 --- a/firewall/interception/introspection.go +++ b/firewall/interception/introspection.go @@ -58,7 +58,9 @@ func (pm *packetMetrics) writeMetrics() { log.Errorf("Failed to create packet metrics file: %s", err) return } - defer f.Close() + defer func() { + _ = f.Close() + }() for { select { diff --git a/firewall/interception/nfq/nfq.go b/firewall/interception/nfq/nfq.go index a32c89bc..3bd59307 100644 --- a/firewall/interception/nfq/nfq.go +++ b/firewall/interception/nfq/nfq.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux // Package nfq contains a nfqueue library experiment. package nfq @@ -10,15 +10,15 @@ import ( "sync/atomic" "time" - "github.com/safing/portbase/log" - pmpacket "github.com/safing/portmaster/network/packet" + "github.com/florianl/go-nfqueue" "github.com/tevino/abool" "golang.org/x/sys/unix" - "github.com/florianl/go-nfqueue" + "github.com/safing/portbase/log" + pmpacket "github.com/safing/portmaster/network/packet" ) -// Queue wraps a nfqueue +// Queue wraps a nfqueue. type Queue struct { id uint16 afFamily uint8 @@ -32,7 +32,7 @@ type Queue struct { } func (q *Queue) getNfq() *nfqueue.Nfqueue { - return q.nf.Load().(*nfqueue.Nfqueue) + return q.nf.Load().(*nfqueue.Nfqueue) //nolint:forcetypeassert // TODO: Check. } // New opens a new nfQueue. @@ -112,7 +112,7 @@ func (q *Queue) open(ctx context.Context) error { } if err := nf.RegisterWithErrorFunc(ctx, q.packetHandler(ctx), q.handleError); err != nil { - defer nf.Close() + _ = nf.Close() return err } @@ -124,7 +124,7 @@ func (q *Queue) open(ctx context.Context) error { func (q *Queue) handleError(e error) int { // embedded interface is required to work-around some // dep-vendoring weirdness - if opError, ok := e.(interface { + if opError, ok := e.(interface { //nolint:errorlint // TODO: Check if we can remove workaround. Timeout() bool Temporary() bool }); ok { @@ -153,7 +153,7 @@ func (q *Queue) handleError(e error) int { // Close the existing socket if nf := q.getNfq(); nf != nil { - nf.Close() + _ = nf.Close() } // Trigger a restart of the queue diff --git a/firewall/interception/nfq/packet.go b/firewall/interception/nfq/packet.go index 766af8c1..ff5d7a27 100644 --- a/firewall/interception/nfq/packet.go +++ b/firewall/interception/nfq/packet.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package nfq @@ -8,9 +8,9 @@ import ( "sync/atomic" "time" + "github.com/florianl/go-nfqueue" "github.com/tevino/abool" - "github.com/florianl/go-nfqueue" "github.com/safing/portbase/log" pmpacket "github.com/safing/portmaster/network/packet" ) @@ -104,7 +104,7 @@ func (pkt *packet) setMark(mark int) error { if err := pkt.queue.getNfq().SetVerdictWithMark(pkt.pktID, nfqueue.NfAccept, mark); err != nil { // embedded interface is required to work-around some // dep-vendoring weirdness - if opErr, ok := err.(interface { + if opErr, ok := err.(interface { //nolint:errorlint // TODO: Check if we can remove workaround. Timeout() bool Temporary() bool }); ok { diff --git a/firewall/interception/nfqueue_linux.go b/firewall/interception/nfqueue_linux.go index 31a7f66b..6a6caf7b 100644 --- a/firewall/interception/nfqueue_linux.go +++ b/firewall/interception/nfqueue_linux.go @@ -44,7 +44,6 @@ type nfQueue interface { } func init() { - v4chains = []string{ "mangle C170", "mangle C171", @@ -128,7 +127,6 @@ func init() { // Reverse because we'd like to insert in a loop _ = sort.Reverse(sort.StringSlice(v4once)) // silence vet (sort is used just like in the docs) _ = sort.Reverse(sort.StringSlice(v6once)) // silence vet (sort is used just like in the docs) - } func activateNfqueueFirewall() error { @@ -241,7 +239,7 @@ func StartNfqueueInterception(packets chan<- packet.Packet) (err error) { err = activateNfqueueFirewall() if err != nil { _ = Stop() - return fmt.Errorf("could not initialize nfqueue: %s", err) + return fmt.Errorf("could not initialize nfqueue: %w", err) } out4Queue, err = nfq.New(17040, false) @@ -288,7 +286,7 @@ func StopNfqueueInterception() error { err := DeactivateNfqueueFirewall() if err != nil { - return fmt.Errorf("interception: error while deactivating nfqueue: %s", err) + return fmt.Errorf("interception: error while deactivating nfqueue: %w", err) } return nil diff --git a/firewall/master.go b/firewall/master.go index 724c0046..69a5bd0f 100644 --- a/firewall/master.go +++ b/firewall/master.go @@ -6,11 +6,12 @@ import ( "path/filepath" "strings" - "github.com/safing/portmaster/detection/dga" - "github.com/safing/portmaster/netenv" + "github.com/agext/levenshtein" "golang.org/x/net/publicsuffix" "github.com/safing/portbase/log" + "github.com/safing/portmaster/detection/dga" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/network/packet" @@ -18,8 +19,6 @@ import ( "github.com/safing/portmaster/process" "github.com/safing/portmaster/profile" "github.com/safing/portmaster/profile/endpoints" - - "github.com/agext/levenshtein" ) // Call order: @@ -215,6 +214,8 @@ func checkEndpointLists(ctx context.Context, conn *network.Connection, p *profil case endpoints.Permitted: conn.AcceptWithContext(reason.String(), optionKey, reason.Context()) return true + case endpoints.NoMatch: + return false } return false @@ -236,6 +237,8 @@ func checkEndpointListsForSystemResolverDNSRequests(ctx context.Context, conn *n case endpoints.Permitted: conn.AcceptWithContext(reason.String(), profile.CfgOptionEndpointsKey, reason.Context()) return true + case endpoints.NoMatch: + return false } } } @@ -345,7 +348,9 @@ func checkConnectionScope(_ context.Context, conn *network.Connection, p *profil conn.Block("Localhost access blocked", profile.CfgOptionBlockScopeLocalKey) // Block Outbound / Drop Inbound return true } - default: // netutils.Unknown and netutils.Invalid + case netutils.Undefined, netutils.Invalid: + fallthrough + default: conn.Deny("invalid IP", noReasonOptionKey) // Block Outbound / Drop Inbound return true } @@ -358,14 +363,19 @@ func checkBypassPrevention(ctx context.Context, conn *network.Connection, p *pro // check for bypass protection result, reason, reasonCtx := PreventBypassing(ctx, conn) switch result { - case endpoints.Denied: + case endpoints.Denied, endpoints.MatchError: + // Also block on MatchError to be on the safe side. + // PreventBypassing does not use any data that needs to be loaded, so it should not fail anyway. conn.BlockWithContext("bypass prevention: "+reason, profile.CfgOptionPreventBypassingKey, reasonCtx) return true case endpoints.Permitted: conn.AcceptWithContext("bypass prevention: "+reason, profile.CfgOptionPreventBypassingKey, reasonCtx) return true + case endpoints.NoMatch: + return false } } + return false } @@ -378,6 +388,8 @@ func checkFilterLists(ctx context.Context, conn *network.Connection, p *profile. return true case endpoints.NoMatch: // nothing to do + case endpoints.Permitted, endpoints.MatchError: + fallthrough default: log.Tracer(ctx).Debugf("filter: filter lists returned unsupported verdict: %s", result) } diff --git a/firewall/preauth.go b/firewall/preauth.go index a2ab7322..3ee749a6 100644 --- a/firewall/preauth.go +++ b/firewall/preauth.go @@ -1,16 +1,14 @@ package firewall import ( + "fmt" + "net" "strconv" "sync" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/packet" - - "fmt" - "net" - - "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/resolver" ) diff --git a/firewall/prompt.go b/firewall/prompt.go index f2036fc9..5b3b07a4 100644 --- a/firewall/prompt.go +++ b/firewall/prompt.go @@ -16,7 +16,7 @@ import ( ) const ( - // notification action IDs + // notification action IDs. allowDomainAll = "allow-domain-all" allowDomainDistinct = "allow-domain-distinct" blockDomainAll = "block-domain-all" diff --git a/intel/block_reason.go b/intel/block_reason.go index 6ec51cb0..b29ef279 100644 --- a/intel/block_reason.go +++ b/intel/block_reason.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/nameserver/nsutil" ) diff --git a/intel/entity.go b/intel/entity.go index 3c01bf46..53f803fc 100644 --- a/intel/entity.go +++ b/intel/entity.go @@ -8,12 +8,13 @@ import ( "strings" "sync" + "golang.org/x/net/publicsuffix" + "github.com/safing/portbase/log" "github.com/safing/portmaster/intel/filterlists" "github.com/safing/portmaster/intel/geoip" "github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/status" - "golang.org/x/net/publicsuffix" ) // Entity describes a remote endpoint in many different ways. @@ -21,7 +22,7 @@ import ( // functions performs locking. The caller MUST ENSURE // proper locking and synchronization when accessing // any properties of Entity. -type Entity struct { +type Entity struct { //nolint:maligned sync.Mutex // lists exist for most entity information and @@ -319,7 +320,7 @@ func (e *Entity) getDomainLists(ctx context.Context) { log.Tracer(ctx).Tracef("intel: loading domain list for %s", domain) e.loadDomainListOnce.Do(func() { - var domainsToInspect = []string{domain} + domainsToInspect := []string{domain} if e.checkCNAMEs && len(e.CNAME) > 0 { log.Tracer(ctx).Tracef("intel: CNAME filtering enabled, checking %v too", e.CNAME) diff --git a/intel/filterlists/bloom.go b/intel/filterlists/bloom.go index 35fa1b7b..1b0fd99f 100644 --- a/intel/filterlists/bloom.go +++ b/intel/filterlists/bloom.go @@ -6,9 +6,10 @@ import ( "strings" "sync" + "github.com/tannerryan/ring" + "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" - "github.com/tannerryan/ring" ) var defaultFilter = newScopedBloom() diff --git a/intel/filterlists/cache_version.go b/intel/filterlists/cache_version.go index 6b6dec9e..b1f40dfc 100644 --- a/intel/filterlists/cache_version.go +++ b/intel/filterlists/cache_version.go @@ -4,9 +4,9 @@ import ( "fmt" "sync" - "github.com/safing/portbase/database" - "github.com/hashicorp/go-version" + + "github.com/safing/portbase/database" "github.com/safing/portbase/database/record" ) diff --git a/intel/filterlists/database.go b/intel/filterlists/database.go index eb48e43c..73330440 100644 --- a/intel/filterlists/database.go +++ b/intel/filterlists/database.go @@ -9,12 +9,13 @@ import ( "sync" "time" + "golang.org/x/sync/errgroup" + "github.com/safing/portbase/database" "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" "github.com/safing/portbase/updater" "github.com/safing/portmaster/updates" - "golang.org/x/sync/errgroup" ) const ( @@ -46,13 +47,11 @@ var ( filterListsLoaded chan struct{} ) -var ( - cache = database.NewInterface(&database.Options{ - Local: true, - Internal: true, - CacheSize: 2 ^ 8, - }) -) +var cache = database.NewInterface(&database.Options{ + Local: true, + Internal: true, + CacheSize: 2 ^ 8, +}) // getFileFunc is the function used to get a file from // the updater. It's basically updates.GetFile and used @@ -85,7 +84,9 @@ func processListFile(ctx context.Context, filter *scopedBloom, file *updater.Fil if err != nil { return err } - defer f.Close() + defer func() { + _ = f.Close() + }() values := make(chan *listEntry, 100) records := make(chan record.Record, 100) diff --git a/intel/filterlists/decoder.go b/intel/filterlists/decoder.go index c2be0f7e..b8837aca 100644 --- a/intel/filterlists/decoder.go +++ b/intel/filterlists/decoder.go @@ -4,6 +4,7 @@ import ( "compress/gzip" "context" "encoding/binary" + "errors" "fmt" "io" @@ -57,7 +58,7 @@ func decodeFile(ctx context.Context, r io.Reader, ch chan<- *listEntry) error { entryCount++ length, readErr := binary.ReadUvarint(reader) if readErr != nil { - if readErr == io.EOF { + if errors.Is(readErr, io.EOF) { return nil } return fmt.Errorf("failed to load varint entity length: %w", readErr) @@ -66,7 +67,7 @@ func decodeFile(ctx context.Context, r io.Reader, ch chan<- *listEntry) error { blob := make([]byte, length) _, readErr = io.ReadFull(reader, blob) if readErr != nil { - if readErr == io.EOF { + if errors.Is(readErr, io.EOF) { // there shouldn't be an EOF here because // we actually got a length above. Return // ErrUnexpectedEOF instead of just EOF. diff --git a/intel/filterlists/index.go b/intel/filterlists/index.go index 888f233b..f0c511e7 100644 --- a/intel/filterlists/index.go +++ b/intel/filterlists/index.go @@ -163,7 +163,7 @@ func getListIndexFromCache() (*ListIndexFile, error) { } var ( - // listIndexUpdate must only be used by updateListIndex + // listIndexUpdate must only be used by updateListIndex. listIndexUpdate *updater.File listIndexUpdateLock sync.Mutex ) @@ -232,9 +232,8 @@ func updateListIndex() error { // a slice of distinct source IDs. func ResolveListIDs(ids []string) ([]string, error) { index, err := getListIndexFromCache() - if err != nil { - if err == database.ErrNotFound { + if errors.Is(err, database.ErrNotFound) { if err := updateListIndex(); err != nil { return nil, err } diff --git a/intel/filterlists/lookup.go b/intel/filterlists/lookup.go index 94f4e129..8b4e0bd7 100644 --- a/intel/filterlists/lookup.go +++ b/intel/filterlists/lookup.go @@ -33,7 +33,7 @@ func lookupBlockLists(entity, value string) ([]string, error) { // log.Debugf("intel/filterlists: searching for entries with %s", key) entry, err := getEntityRecordByKey(key) if err != nil { - if err == database.ErrNotFound { + if errors.Is(err, database.ErrNotFound) { return nil, nil } log.Errorf("intel/filterlists: failed to get entries for key %s: %s", key, err) @@ -103,7 +103,6 @@ func LookupIPv4String(ipv4 string) ([]string, error) { // LookupIPv4 is like LookupIPv4String but accepts a net.IP. func LookupIPv4(ipv4 net.IP) ([]string, error) { - ip := ipv4.To4() if ip == nil { return nil, errors.New("invalid IPv4") diff --git a/intel/filterlists/module.go b/intel/filterlists/module.go index d2af5742..6f5568aa 100644 --- a/intel/filterlists/module.go +++ b/intel/filterlists/module.go @@ -4,22 +4,20 @@ import ( "context" "fmt" + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/updates" - "github.com/tevino/abool" ) -var ( - module *modules.Module -) +var module *modules.Module const ( filterlistsDisabled = "filterlists:disabled" filterlistsUpdateFailed = "filterlists:update-failed" filterlistsStaleDataSurvived = "filterlists:staledata" - filterlistsUpdateInProgress = "filterlists:update-in-progress" ) // booleans mainly used to decouple the module diff --git a/intel/filterlists/record.go b/intel/filterlists/record.go index 8865ce9d..418790d6 100644 --- a/intel/filterlists/record.go +++ b/intel/filterlists/record.go @@ -24,17 +24,17 @@ func getEntityRecordByKey(key string) (*entityRecord, error) { } if r.IsWrapped() { - new := &entityRecord{} - if err := record.Unwrap(r, new); err != nil { + newER := &entityRecord{} + if err := record.Unwrap(r, newER); err != nil { return nil, err } - return new, nil + return newER, nil } - e, ok := r.(*entityRecord) + newER, ok := r.(*entityRecord) if !ok { return nil, fmt.Errorf("record not of type *entityRecord, but %T", r) } - return e, nil + return newER, nil } diff --git a/intel/filterlists/updater.go b/intel/filterlists/updater.go index e3553a0b..ff5ce3e9 100644 --- a/intel/filterlists/updater.go +++ b/intel/filterlists/updater.go @@ -2,17 +2,19 @@ package filterlists import ( "context" + "errors" "fmt" "sort" "time" "github.com/hashicorp/go-version" + "github.com/tevino/abool" + "github.com/safing/portbase/database" "github.com/safing/portbase/database/query" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portbase/updater" - "github.com/tevino/abool" ) var updateInProgress = abool.New() @@ -21,7 +23,6 @@ var updateInProgress = abool.New() // error state is correctly set or resolved. func tryListUpdate(ctx context.Context) error { err := performUpdate(ctx) - if err != nil { // Check if the module already has a failure status set. If not, set a // generic one with the returned error. @@ -123,7 +124,7 @@ func performUpdate(ctx context.Context) error { module.Warning( filterlistsStaleDataSurvived, "Filter Lists May Overblock", - fmt.Sprintf("The Portmaster failed to delete outdated filter list data. Filtering capabilities are fully available, but overblocking may occur. Error: %s", err.Error()), + fmt.Sprintf("The Portmaster failed to delete outdated filter list data. Filtering capabilities are fully available, but overblocking may occur. Error: %s", err.Error()), //nolint:misspell // overblocking != overclocking ) return fmt.Errorf("failed to cleanup stale cache records: %w", err) } @@ -137,7 +138,7 @@ func performUpdate(ctx context.Context) error { log.Infof("intel/filterlists: successfully migrated cache database to %s", highestVersion.Version()) } - // The list update suceeded, resolve any states. + // The list update succeeded, resolve any states. module.Resolve("") return nil } @@ -178,7 +179,7 @@ func getUpgradableFiles() ([]*updater.File, error) { if intermediateFile == nil || intermediateFile.UpgradeAvailable() || !cacheDBInUse { var err error intermediateFile, err = getFile(intermediateListFilePath) - if err != nil && err != updater.ErrNotFound { + if err != nil && !errors.Is(err, updater.ErrNotFound) { return nil, err } @@ -191,7 +192,7 @@ func getUpgradableFiles() ([]*updater.File, error) { if urgentFile == nil || urgentFile.UpgradeAvailable() || !cacheDBInUse { var err error urgentFile, err = getFile(urgentListFilePath) - if err != nil && err != updater.ErrNotFound { + if err != nil && !errors.Is(err, updater.ErrNotFound) { return nil, err } @@ -216,7 +217,7 @@ func resolveUpdateOrder(updateOrder []*updater.File) ([]*updater.File, error) { var err error cacheDBVersion, err = getCacheDatabaseVersion() if err != nil { - if err != database.ErrNotFound { + if !errors.Is(err, database.ErrNotFound) { log.Errorf("intel/filterlists: failed to get cache database version: %s", err) } cacheDBVersion, _ = version.NewSemver("v0.0.0") @@ -247,12 +248,14 @@ func resolveUpdateOrder(updateOrder []*updater.File) ([]*updater.File, error) { type byAscVersion []*updater.File func (fs byAscVersion) Len() int { return len(fs) } + func (fs byAscVersion) Less(i, j int) bool { vi, _ := version.NewSemver(fs[i].Version()) vj, _ := version.NewSemver(fs[j].Version()) return vi.LessThan(vj) } + func (fs byAscVersion) Swap(i, j int) { fi := fs[i] fj := fs[j] diff --git a/intel/geoip/database.go b/intel/geoip/database.go index e851670c..61bde277 100644 --- a/intel/geoip/database.go +++ b/intel/geoip/database.go @@ -58,7 +58,7 @@ func (ub *updateBroadcaster) ReplaceDatabase(db *geoIPDB) { defer ub.rw.Unlock() if ub.db != nil { - ub.db.Close() + _ = ub.db.Close() } ub.db = db ub.notifyWaiters() @@ -101,7 +101,7 @@ type updateWorker struct { // waiting nil is returned. func (upd *updateWorker) GetReader(v6 bool, wait bool) *maxminddb.Reader { // check which updateBroadcaster we need to use - var ub *updateBroadcaster = &upd.v4 + ub := &upd.v4 if v6 { ub = &upd.v6 } diff --git a/intel/geoip/location.go b/intel/geoip/location.go index 823aa05e..91fb5164 100644 --- a/intel/geoip/location.go +++ b/intel/geoip/location.go @@ -5,8 +5,9 @@ import ( "net" "strings" - "github.com/safing/portbase/utils" "github.com/umahmood/haversine" + + "github.com/safing/portbase/utils" ) const ( @@ -27,6 +28,7 @@ type Location struct { AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"` } +// Coordinates holds geographic coordinates and their estimated accuracy. type Coordinates struct { AccuracyRadius uint16 `maxminddb:"accuracy_radius"` Latitude float64 `maxminddb:"latitude"` @@ -199,6 +201,8 @@ var unknownASOrgNames = []string{ "undefined", // Programmatic unknown value. } +// ASOrgUnknown return whether the given AS Org string actually is meant to +// mean that the AS Org is unknown. func ASOrgUnknown(asOrg string) bool { return utils.StringInSlice( unknownASOrgNames, diff --git a/intel/geoip/location_test.go b/intel/geoip/location_test.go index c403d91b..21c74037 100644 --- a/intel/geoip/location_test.go +++ b/intel/geoip/location_test.go @@ -6,6 +6,8 @@ import ( ) func TestPrimitiveNetworkProximity(t *testing.T) { + t.Parallel() + ip4_1 := net.ParseIP("1.1.1.1") ip4_2 := net.ParseIP("1.1.1.2") ip4_3 := net.ParseIP("255.255.255.0") diff --git a/intel/geoip/lookup_test.go b/intel/geoip/lookup_test.go index 583fa1a7..42fba517 100644 --- a/intel/geoip/lookup_test.go +++ b/intel/geoip/lookup_test.go @@ -6,6 +6,8 @@ import ( ) func TestLocationLookup(t *testing.T) { + t.Parallel() + ip1 := net.ParseIP("81.2.69.142") loc1, err := GetLocation(ip1) if err != nil { @@ -53,8 +55,8 @@ func TestLocationLookup(t *testing.T) { dist3 := loc1.EstimateNetworkProximity(loc3) dist4 := loc1.EstimateNetworkProximity(loc4) - t.Logf("proximity %s <> %s: %d", ip1, ip2, dist1) - t.Logf("proximity %s <> %s: %d", ip2, ip3, dist2) - t.Logf("proximity %s <> %s: %d", ip1, ip3, dist3) - t.Logf("proximity %s <> %s: %d", ip1, ip4, dist4) + t.Logf("proximity %s <> %s: %.2f", ip1, ip2, dist1) + t.Logf("proximity %s <> %s: %.2f", ip2, ip3, dist2) + t.Logf("proximity %s <> %s: %.2f", ip1, ip3, dist3) + t.Logf("proximity %s <> %s: %.2f", ip1, ip4, dist4) } diff --git a/intel/module.go b/intel/module.go index 8c30985e..65fcc65d 100644 --- a/intel/module.go +++ b/intel/module.go @@ -4,10 +4,8 @@ import ( "github.com/safing/portbase/modules" ) -var ( - // Module of this package. Export needed for testing of the endpoints package. - Module *modules.Module -) +// Module of this package. Export needed for testing of the endpoints package. +var Module *modules.Module func init() { Module = modules.Register("intel", nil, nil, nil, "geoip", "filterlists") diff --git a/intel/resolver.go b/intel/resolver.go index ec9ca8a4..359db36a 100644 --- a/intel/resolver.go +++ b/intel/resolver.go @@ -4,9 +4,7 @@ import ( "context" ) -var ( - reverseResolver func(ctx context.Context, ip string, securityLevel uint8) (domain string, err error) -) +var reverseResolver func(ctx context.Context, ip string, securityLevel uint8) (domain string, err error) // SetReverseResolver allows the resolver module to register a function to allow reverse resolving IPs to domains. func SetReverseResolver(fn func(ctx context.Context, ip string, securityLevel uint8) (domain string, err error)) { diff --git a/nameserver/config.go b/nameserver/config.go index 9d73f5b4..c466a154 100644 --- a/nameserver/config.go +++ b/nameserver/config.go @@ -8,10 +8,8 @@ import ( "github.com/safing/portmaster/core" ) -// Config Keys -const ( - CfgDefaultNameserverAddressKey = "dns/listenAddress" -) +// CfgDefaultNameserverAddressKey is the config key for the listen address.. +const CfgDefaultNameserverAddressKey = "dns/listenAddress" var ( defaultNameserverAddress = "localhost:53" diff --git a/nameserver/failing.go b/nameserver/failing.go index 033af308..1880dc96 100644 --- a/nameserver/failing.go +++ b/nameserver/failing.go @@ -36,7 +36,7 @@ var ( failingQueriesNetworkChangedFlag = netenv.GetNetworkChangedFlag() ) -func checkIfQueryIsFailing(q *resolver.Query) (failingErr error, failingUntil *time.Time) { +func checkIfQueryIsFailing(q *resolver.Query) (failingUntil *time.Time, failingErr error) { // If the network changed, reset the failed queries. if failingQueriesNetworkChangedFlag.IsSet() { failingQueriesNetworkChangedFlag.Refresh() @@ -45,7 +45,7 @@ func checkIfQueryIsFailing(q *resolver.Query) (failingErr error, failingUntil *t defer failingQueriesLock.Unlock() // Compiler optimized map reset. - for key, _ := range failingQueries { + for key := range failingQueries { delete(failingQueries, key) } @@ -72,7 +72,7 @@ func checkIfQueryIsFailing(q *resolver.Query) (failingErr error, failingUntil *t } // Return failing error and until when it's valid. - return failing.Err, &failing.Until + return &failing.Until, failing.Err } func addFailingQuery(q *resolver.Query, err error) { diff --git a/nameserver/module.go b/nameserver/module.go index 6ef47d71..f136fac7 100644 --- a/nameserver/module.go +++ b/nameserver/module.go @@ -7,13 +7,13 @@ import ( "os" "strconv" + "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portbase/modules/subsystems" "github.com/safing/portmaster/firewall" "github.com/safing/portmaster/netenv" - - "github.com/miekg/dns" ) var ( @@ -69,32 +69,31 @@ func start() error { } return dstIsMe }) - } else { - return firewall.SetNameserverIPMatcher(func(ip net.IP) bool { - return ip.Equal(ip1) - }) } - - } else { - // Dual listener. - dnsServer1 := startListener(ip1, port) - dnsServer2 := startListener(ip2, port) - stopListener = func() error { - // Shutdown both listeners. - err1 := dnsServer1.Shutdown() - err2 := dnsServer2.Shutdown() - // Return first error. - if err1 != nil { - return err1 - } - return err2 - } - - // Fast track dns queries destined for one of the listener IPs. return firewall.SetNameserverIPMatcher(func(ip net.IP) bool { - return ip.Equal(ip1) || ip.Equal(ip2) + return ip.Equal(ip1) }) + } + + // Dual listener. + dnsServer1 := startListener(ip1, port) + dnsServer2 := startListener(ip2, port) + stopListener = func() error { + // Shutdown both listeners. + err1 := dnsServer1.Shutdown() + err2 := dnsServer2.Shutdown() + // Return first error. + if err1 != nil { + return err1 + } + return err2 + } + + // Fast track dns queries destined for one of the listener IPs. + return firewall.SetNameserverIPMatcher(func(ip net.IP) bool { + return ip.Equal(ip1) || ip.Equal(ip2) + }) } func startListener(ip net.IP, port uint16) *dns.Server { diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index d9c12c63..f2aea112 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/firewall" "github.com/safing/portmaster/nameserver/nsutil" @@ -15,8 +17,6 @@ import ( "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/resolver" - - "github.com/miekg/dns" ) var hostname string @@ -30,7 +30,7 @@ func handleRequestAsWorker(w dns.ResponseWriter, query *dns.Msg) { } } -func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) error { //nolint:gocognit // TODO +func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) error { //nolint:maintidx // TODO // Record metrics. startTime := time.Now() defer requestsHistogram.UpdateDuration(startTime) @@ -113,7 +113,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) // will fail with a very high probability, it is beneficial to just kill the // query for some time before doing any expensive work. defer cleanFailingQueries(10, 3) - failingErr, failingUntil := checkIfQueryIsFailing(q) + failingUntil, failingErr := checkIfQueryIsFailing(q) if failingErr != nil { remainingFailingDuration := time.Until(*failingUntil) tracer.Debugf("nameserver: returning previous error for %s: %s", q.ID(), failingErr) @@ -205,6 +205,8 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) network.SaveOpenDNSRequest(q, rrCache, conn) firewall.UpdateIPsAndCNAMEs(q, rrCache, conn) + case network.VerdictUndeterminable: + fallthrough default: tracer.Warningf("nameserver: unexpected verdict %s for connection %s, not saving", conn.Verdict, conn) } @@ -224,7 +226,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) } // Check if there is a Verdict to act upon. - switch conn.Verdict { + switch conn.Verdict { //nolint:exhaustive // Only checking for specific values. case network.VerdictBlock, network.VerdictDrop, network.VerdictFailed: tracer.Infof( "nameserver: returning %s response for %s to %s", @@ -289,7 +291,7 @@ func handleRequest(ctx context.Context, w dns.ResponseWriter, request *dns.Msg) } // Check if there is a Verdict to act upon. - switch conn.Verdict { + switch conn.Verdict { //nolint:exhaustive // Only checking for specific values. case network.VerdictBlock, network.VerdictDrop, network.VerdictFailed: tracer.Infof( "nameserver: returning %s response for %s to %s", diff --git a/nameserver/nsutil/nsutil.go b/nameserver/nsutil/nsutil.go index 65674672..7c440c11 100644 --- a/nameserver/nsutil/nsutil.go +++ b/nameserver/nsutil/nsutil.go @@ -9,13 +9,12 @@ import ( "time" "github.com/miekg/dns" + "github.com/safing/portbase/log" ) -var ( - // ErrNilRR is returned when a parsed RR is nil. - ErrNilRR = errors.New("is nil") -) +// ErrNilRR is returned when a parsed RR is nil. +var ErrNilRR = errors.New("is nil") // Responder defines the interface that any block/deny reason interface // may implement to support sending custom DNS responses for a given reason. diff --git a/nameserver/response.go b/nameserver/response.go index 18e9f75d..2a0e992e 100644 --- a/nameserver/response.go +++ b/nameserver/response.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/nameserver/nsutil" ) diff --git a/nameserver/takeover.go b/nameserver/takeover.go index 2365463e..5446e8ef 100644 --- a/nameserver/takeover.go +++ b/nameserver/takeover.go @@ -13,15 +13,13 @@ import ( "github.com/safing/portmaster/network/state" ) -var ( - commonResolverIPs = []net.IP{ - net.IPv4zero, - net.IPv4(127, 0, 0, 1), // default - net.IPv4(127, 0, 0, 53), // some resolvers on Linux - net.IPv6zero, - net.IPv6loopback, - } -) +var commonResolverIPs = []net.IP{ + net.IPv4zero, + net.IPv4(127, 0, 0, 1), // default + net.IPv4(127, 0, 0, 53), // some resolvers on Linux + net.IPv6zero, + net.IPv6loopback, +} func checkForConflictingService(ip net.IP, port uint16) error { // Evaluate which IPs to check. @@ -34,6 +32,7 @@ func checkForConflictingService(ip net.IP, port uint16) error { // Check if there is another resolver when need to take over. var killed int +ipsToCheckLoop: for _, resolverIP := range ipsToCheck { pid, err := takeover(resolverIP, port) switch { @@ -44,7 +43,7 @@ func checkForConflictingService(ip net.IP, port uint16) error { case pid != 0: // Conflicting service identified and killed! killed = pid - break + break ipsToCheckLoop } } @@ -92,7 +91,7 @@ func takeover(resolverIP net.IP, resolverPort uint16) (int, error) { }, true) if err != nil { // there may be nothing listening on :53 - return 0, nil + return 0, nil //nolint:nilerr // Treat lookup error as "not found". } // Just don't, uh, kill ourselves... diff --git a/netenv/addresses.go b/netenv/addresses.go index 053b5cd0..70712239 100644 --- a/netenv/addresses.go +++ b/netenv/addresses.go @@ -55,7 +55,7 @@ var ( myNetworks []*net.IPNet myNetworksLock sync.Mutex myNetworksNetworkChangedFlag = GetNetworkChangedFlag() - myNetworksRefreshError error + myNetworksRefreshError error //nolint:errname // Not what the linter thinks this is for. myNetworksRefreshFailingUntil time.Time ) @@ -63,7 +63,7 @@ var ( // Broadcast or multicast addresses will never match, even if valid in in use. func IsMyIP(ip net.IP) (yes bool, err error) { // Check for IPs that don't need extra checks. - switch netutils.GetIPScope(ip) { + switch netutils.GetIPScope(ip) { //nolint:exhaustive // Only looking for specific values. case netutils.HostLocal: return true, nil case netutils.LocalMulticast, netutils.GlobalMulticast: @@ -90,7 +90,7 @@ func IsMyIP(ip net.IP) (yes bool, err error) { // Check if there was a recent error on the previous refresh. if myNetworksRefreshError != nil && time.Now().Before(myNetworksRefreshFailingUntil) { - return false, fmt.Errorf("failed to previously refresh interface addresses: %s", myNetworksRefreshError) + return false, fmt.Errorf("failed to previously refresh interface addresses: %w", myNetworksRefreshError) } // Refresh assigned networks. @@ -101,7 +101,7 @@ func IsMyIP(ip net.IP) (yes bool, err error) { // literally over thousand goroutines wanting to try this again. myNetworksRefreshError = err myNetworksRefreshFailingUntil = time.Now().Add(1 * time.Second) - return false, fmt.Errorf("failed to refresh interface addresses: %s", err) + return false, fmt.Errorf("failed to refresh interface addresses: %w", err) } myNetworks = make([]*net.IPNet, 0, len(interfaceNetworks)) for _, ifNet := range interfaceNetworks { diff --git a/netenv/addresses_test.go b/netenv/addresses_test.go index 65bd7e84..7711ddc8 100644 --- a/netenv/addresses_test.go +++ b/netenv/addresses_test.go @@ -5,6 +5,8 @@ import ( ) func TestGetAssignedAddresses(t *testing.T) { + t.Parallel() + ipv4, ipv6, err := GetAssignedAddresses() t.Logf("all v4: %v", ipv4) t.Logf("all v6: %v", ipv6) @@ -17,6 +19,8 @@ func TestGetAssignedAddresses(t *testing.T) { } func TestGetAssignedGlobalAddresses(t *testing.T) { + t.Parallel() + ipv4, ipv6, err := GetAssignedGlobalAddresses() t.Logf("all global v4: %v", ipv4) t.Logf("all global v6: %v", ipv6) diff --git a/netenv/dbus_linux.go b/netenv/dbus_linux.go index 1fefeb9b..9cc63c28 100644 --- a/netenv/dbus_linux.go +++ b/netenv/dbus_linux.go @@ -1,4 +1,4 @@ -// +build !server +// go:build !server package netenv @@ -8,9 +8,9 @@ import ( "net" "sync" - "github.com/safing/portbase/log" - "github.com/godbus/dbus/v5" + + "github.com/safing/portbase/log" ) var ( @@ -36,7 +36,7 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO primaryConnectionVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.PrimaryConnection") if err != nil { - return nil, fmt.Errorf("dbus: failed to access NetworkManager.PrimaryConnection: %s", err) + return nil, fmt.Errorf("dbus: failed to access NetworkManager.PrimaryConnection: %w", err) } primaryConnection, ok := primaryConnectionVariant.Value().(dbus.ObjectPath) if !ok { @@ -45,7 +45,7 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO activeConnectionsVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.ActiveConnections") if err != nil { - return nil, fmt.Errorf("dbus: failed to access NetworkManager.ActiveConnections: %s", err) + return nil, fmt.Errorf("dbus: failed to access NetworkManager.ActiveConnections: %w", err) } activeConnections, ok := activeConnectionsVariant.Value().([]dbus.ObjectPath) if !ok { @@ -60,18 +60,18 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO } for _, activeConnection := range sortedConnections { - new, err := dbusGetInterfaceNameservers(dbusConn, activeConnection, 4) + newNameservers, err := dbusGetInterfaceNameservers(dbusConn, activeConnection, 4) if err != nil { log.Warningf("failed to get nameserver: %s", err) } else { - ns = append(ns, new...) + ns = append(ns, newNameservers...) } - new, err = dbusGetInterfaceNameservers(dbusConn, activeConnection, 6) + newNameservers, err = dbusGetInterfaceNameservers(dbusConn, activeConnection, 6) if err != nil { log.Warningf("failed to get nameserver: %s", err) } else { - ns = append(ns, new...) + ns = append(ns, newNameservers...) } } @@ -87,7 +87,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec // Get Interface Configuration. ipConfigVariant, err := getNetworkManagerProperty(dbusConn, interfaceObject, ipConfigPropertyKey) if err != nil { - return nil, fmt.Errorf("failed to access %s:%s: %s", interfaceObject, ipConfigPropertyKey, err) + return nil, fmt.Errorf("failed to access %s:%s: %w", interfaceObject, ipConfigPropertyKey, err) } ipConfig, ok := ipConfigVariant.Value().(dbus.ObjectPath) if !ok { @@ -102,7 +102,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec // Get Nameserver IPs nameserverIPsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversIPsPropertyKey) if err != nil { - return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversIPsPropertyKey, err) + return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversIPsPropertyKey, err) } var nameserverIPs []net.IP switch ipVersion { @@ -134,7 +134,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec // Get Nameserver Domains nameserverDomainsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversDomainsPropertyKey) if err != nil { - return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversDomainsPropertyKey, err) + return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversDomainsPropertyKey, err) } nameserverDomains, ok := nameserverDomainsVariant.Value().([]string) if !ok { @@ -144,7 +144,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec // Get Nameserver Searches nameserverSearchesVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversSearchesPropertyKey) if err != nil { - return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversSearchesPropertyKey, err) + return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversSearchesPropertyKey, err) } nameserverSearches, ok := nameserverSearchesVariant.Value().([]string) if !ok { @@ -152,7 +152,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec } ns := make([]Nameserver, 0, len(nameserverIPs)) - searchDomains := append(nameserverDomains, nameserverSearches...) + searchDomains := append(nameserverDomains, nameserverSearches...) //nolint:gocritic for _, nameserverIP := range nameserverIPs { ns = append(ns, Nameserver{ IP: nameserverIP, diff --git a/netenv/dbus_linux_test.go b/netenv/dbus_linux_test.go index f69bcd2c..160d4c06 100644 --- a/netenv/dbus_linux_test.go +++ b/netenv/dbus_linux_test.go @@ -6,6 +6,8 @@ import ( ) func TestDbus(t *testing.T) { + t.Parallel() + if testing.Short() { t.Skip("skipping test in short mode because it fails in the CI") } diff --git a/netenv/dialing.go b/netenv/dialing.go index dc1023d7..262e1c2b 100644 --- a/netenv/dialing.go +++ b/netenv/dialing.go @@ -2,9 +2,7 @@ package netenv import "net" -var ( - localAddrFactory func(network string) net.Addr -) +var localAddrFactory func(network string) net.Addr // SetLocalAddrFactory supplies the environment package with a function to get permitted local addresses for connections. func SetLocalAddrFactory(laf func(network string) net.Addr) { diff --git a/netenv/environment_linux.go b/netenv/environment_linux.go index 42f02750..d6b57b91 100644 --- a/netenv/environment_linux.go +++ b/netenv/environment_linux.go @@ -43,7 +43,9 @@ func Gateways() []net.IP { log.Warningf("environment: could not read /proc/net/route: %s", err) return gateways } - defer route.Close() + defer func() { + _ = route.Close() + }() // file scanner scanner := bufio.NewScanner(route) @@ -76,7 +78,9 @@ func Gateways() []net.IP { log.Warningf("environment: could not read /proc/net/ipv6_route: %s", err) return gateways } - defer v6route.Close() + defer func() { + _ = v6route.Close() + }() // file scanner scanner = bufio.NewScanner(v6route) @@ -149,7 +153,9 @@ func getNameserversFromResolvconf() ([]Nameserver, error) { log.Warningf("environment: could not read /etc/resolv.conf: %s", err) return nil, err } - defer resolvconf.Close() + defer func() { + _ = resolvconf.Close() + }() // file scanner scanner := bufio.NewScanner(resolvconf) @@ -186,7 +192,6 @@ func getNameserversFromResolvconf() ([]Nameserver, error) { }) } return nameservers, nil - } func addNameservers(nameservers, newNameservers []Nameserver) []Nameserver { diff --git a/netenv/environment_linux_test.go b/netenv/environment_linux_test.go index d8af6948..e2fa648d 100644 --- a/netenv/environment_linux_test.go +++ b/netenv/environment_linux_test.go @@ -3,6 +3,8 @@ package netenv import "testing" func TestLinuxEnvironment(t *testing.T) { + t.Parallel() + nameserversTest, err := getNameserversFromResolvconf() if err != nil { t.Errorf("failed to get namerservers from resolvconf: %s", err) diff --git a/netenv/environment_test.go b/netenv/environment_test.go index f5c6e995..26dd79fe 100644 --- a/netenv/environment_test.go +++ b/netenv/environment_test.go @@ -3,6 +3,8 @@ package netenv import "testing" func TestEnvironment(t *testing.T) { + t.Parallel() + nameserversTest := Nameservers() t.Logf("nameservers: %+v", nameserversTest) diff --git a/netenv/location.go b/netenv/location.go index dc089820..75da8c87 100644 --- a/netenv/location.go +++ b/netenv/location.go @@ -9,10 +9,10 @@ import ( "syscall" "time" + "github.com/google/gopacket/layers" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" - "github.com/google/gopacket/layers" "github.com/safing/portbase/log" "github.com/safing/portbase/rng" "github.com/safing/portmaster/intel/geoip" @@ -41,10 +41,12 @@ func prepLocation() (err error) { return err } +// DeviceLocations holds multiple device locations. type DeviceLocations struct { All []*DeviceLocation } +// Best returns the best (most accurate) device location. func (dl *DeviceLocations) Best() *DeviceLocation { if len(dl.All) > 0 { return dl.All[0] @@ -52,6 +54,7 @@ func (dl *DeviceLocations) Best() *DeviceLocation { return nil } +// BestV4 returns the best (most accurate) IPv4 device location. func (dl *DeviceLocations) BestV4() *DeviceLocation { for _, loc := range dl.All { if loc.IPVersion == packet.IPv4 { @@ -61,6 +64,7 @@ func (dl *DeviceLocations) BestV4() *DeviceLocation { return nil } +// BestV6 returns the best (most accurate) IPv6 device location. func (dl *DeviceLocations) BestV6() *DeviceLocation { for _, loc := range dl.All { if loc.IPVersion == packet.IPv6 { @@ -129,6 +133,7 @@ func (dl *DeviceLocation) IsMoreAccurateThan(other *DeviceLocation) bool { return false } +// LocationOrNil or returns the geoip location, or nil if not present. func (dl *DeviceLocation) LocationOrNil() *geoip.Location { if dl == nil { return nil @@ -147,8 +152,10 @@ func (dl *DeviceLocation) String() string { } } +// DeviceLocationSource is a location source. type DeviceLocationSource string +// Location Sources. const ( SourceInterface DeviceLocationSource = "interface" SourcePeer DeviceLocationSource = "peer" @@ -158,6 +165,7 @@ const ( SourceOther DeviceLocationSource = "other" ) +// Accuracy returns the location accuracy of the source. func (dls DeviceLocationSource) Accuracy() int { switch dls { case SourceInterface: @@ -183,6 +191,7 @@ func (a sortLocationsByAccuracy) Len() int { return len(a) } func (a sortLocationsByAccuracy) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a sortLocationsByAccuracy) Less(i, j int) bool { return !a[j].IsMoreAccurateThan(a[i]) } +// SetInternetLocation provides the location management system with a possible Internet location. func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) { // Check if IP is global. if netutils.GetIPScope(ip) != netutils.Global { @@ -206,9 +215,8 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLoca if err != nil { log.Warningf("netenv: failed to get geolocation data of %s (from %s): %s", ip, source, err) return nil, false - } else { - loc.Location = geoLoc } + loc.Location = geoLoc addLocation(loc) return loc, true @@ -242,7 +250,8 @@ func addLocation(dl *DeviceLocation) { sort.Sort(sortLocationsByAccuracy(locations.All)) } -// DEPRECATED: Please use GetInternetLocation instead. +// GetApproximateInternetLocation returns the approximate Internet location. +// Deprecated: Please use GetInternetLocation instead. func GetApproximateInternetLocation() (net.IP, error) { loc, ok := GetInternetLocation() if !ok || loc.Best() == nil { @@ -251,6 +260,7 @@ func GetApproximateInternetLocation() (net.IP, error) { return loc.Best().IP, nil } +// GetInternetLocation returns the possible device locations. func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) { gettingLocationsLock.Lock() defer gettingLocationsLock.Unlock() @@ -323,7 +333,7 @@ func getLocationFromInterfaces() (v4ok, v6ok bool) { func getLocationFromUPnP() (ok bool) { // Endoint: urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress // A first test showed that a router did offer that endpoint, but did not - // return an IP addres. + // return an IP address. return false } */ @@ -332,14 +342,14 @@ func getLocationFromTraceroute() (dl *DeviceLocation, err error) { // Create connection. conn, err := net.ListenPacket("ip4:icmp", "") if err != nil { - return nil, fmt.Errorf("failed to open icmp conn: %s", err) + return nil, fmt.Errorf("failed to open icmp conn: %w", err) } v4Conn := ipv4.NewPacketConn(conn) // Generate a random ID for the ICMP packets. generatedID, err := rng.Number(0xFFFF) // uint16 if err != nil { - return nil, fmt.Errorf("failed to generate icmp msg ID: %s", err) + return nil, fmt.Errorf("failed to generate icmp msg ID: %w", err) } msgID := int(generatedID) var msgSeq int @@ -368,28 +378,27 @@ nextHop: for j := 1; j <= 2; j++ { // Try every hop twice. // Increase sequence number. msgSeq++ - pingMessage.Body.(*icmp.Echo).Seq = msgSeq + pingMessage.Body.(*icmp.Echo).Seq = msgSeq //nolint:forcetypeassert // Can only be *icmp.Echo. // Make packet data. pingPacket, err := pingMessage.Marshal(nil) if err != nil { - return nil, fmt.Errorf("failed to build icmp packet: %s", err) + return nil, fmt.Errorf("failed to build icmp packet: %w", err) } // Set TTL on IP packet. err = v4Conn.SetTTL(i) if err != nil { - return nil, fmt.Errorf("failed to set icmp packet TTL: %s", err) + return nil, fmt.Errorf("failed to set icmp packet TTL: %w", err) } // Send ICMP packet. if _, err := conn.WriteTo(pingPacket, locationTestingIPv4Addr); err != nil { - if neterr, ok := err.(*net.OpError); ok { - if neterr.Err == syscall.ENOBUFS { - continue - } + var opErr *net.OpError + if errors.As(err, &opErr) && errors.Is(opErr.Err, syscall.ENOBUFS) { + continue } - return nil, fmt.Errorf("failed to send icmp packet: %s", err) + return nil, fmt.Errorf("failed to send icmp packet: %w", err) } // Listen for replies of the ICMP packet. @@ -433,7 +442,7 @@ nextHop: continue listen } // Check if the ID and sequence match. - if originalEcho.ID != int(msgID) { + if originalEcho.ID != msgID { continue listen } if originalEcho.Seq < minSeq { @@ -469,8 +478,8 @@ nextHop: } func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) ( - remoteIP net.IP, imcpPacket *layers.ICMPv4, ok bool) { - + remoteIP net.IP, imcpPacket *layers.ICMPv4, ok bool, +) { for { select { case pkt := <-icmpPacketsViaFirewall: @@ -496,7 +505,7 @@ func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) ( } } -func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { +func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { //nolint:unparam // This is documentation. // Create base struct. tzLoc := &DeviceLocation{ IPVersion: ipVersion, diff --git a/netenv/location_default.go b/netenv/location_default.go index 2d45d744..1581c6a9 100644 --- a/netenv/location_default.go +++ b/netenv/location_default.go @@ -1,9 +1,9 @@ -//+build !windows +// go:build !windows package netenv import "net" -func newICMPListener(_ string) (net.PacketConn, error) { +func newICMPListener(_ string) (net.PacketConn, error) { //nolint:unused,deadcode // TODO: clean with Windows code later. return net.ListenPacket("ip4:icmp", "0.0.0.0") } diff --git a/netenv/location_test.go b/netenv/location_test.go index c243ace0..b8f8c37a 100644 --- a/netenv/location_test.go +++ b/netenv/location_test.go @@ -5,15 +5,15 @@ import ( "testing" ) -var ( - privileged bool -) +var privileged bool func init() { flag.BoolVar(&privileged, "privileged", false, "run tests that require root/admin privileges") } func TestGetInternetLocation(t *testing.T) { + t.Parallel() + if testing.Short() { t.Skip() } diff --git a/netenv/main.go b/netenv/main.go index baeaa7d5..0d831e76 100644 --- a/netenv/main.go +++ b/netenv/main.go @@ -4,16 +4,14 @@ import ( "github.com/safing/portbase/modules" ) -// Event Names +// Event Names. const ( ModuleName = "netenv" NetworkChangedEvent = "network changed" OnlineStatusChangedEvent = "online status changed" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register(ModuleName, prep, start, nil) diff --git a/netenv/network-change.go b/netenv/network-change.go index 721ffd36..6a591cc8 100644 --- a/netenv/network-change.go +++ b/netenv/network-change.go @@ -3,7 +3,7 @@ package netenv import ( "bytes" "context" - "crypto/sha1" //nolint:gosec // not used for security + "crypto/sha1" "io" "net" "time" @@ -17,6 +17,7 @@ var ( networkChangedBroadcastFlag = utils.NewBroadcastFlag() ) +// GetNetworkChangedFlag returns a flag to be notified about a network change. func GetNetworkChangedFlag() *utils.Flag { return networkChangedBroadcastFlag.NewFlag() } diff --git a/netenv/online-status.go b/netenv/online-status.go index 10dbbd04..a7589a13 100644 --- a/netenv/online-status.go +++ b/netenv/online-status.go @@ -2,6 +2,7 @@ package netenv import ( "context" + "errors" "fmt" "net" "net/http" @@ -21,7 +22,7 @@ import ( // OnlineStatus represent a state of connectivity to the Internet. type OnlineStatus uint8 -// Online Status Values +// Online Status Values. const ( StatusUnknown OnlineStatus = 0 StatusOffline OnlineStatus = 1 @@ -31,7 +32,7 @@ const ( StatusOnline OnlineStatus = 5 ) -// Online Status and Resolver +// Online Status and Resolver. var ( PortalTestIP = net.IPv4(192, 0, 2, 1) PortalTestURL = fmt.Sprintf("http://%s/", PortalTestIP) @@ -124,8 +125,6 @@ func IsConnectivityDomain(domain string) bool { func (os OnlineStatus) String() string { switch os { - default: - return "Unknown" case StatusOffline: return "Offline" case StatusLimited: @@ -136,6 +135,10 @@ func (os OnlineStatus) String() string { return "SemiOnline" case StatusOnline: return "Online" + case StatusUnknown: + fallthrough + default: + return "Unknown" } } @@ -175,7 +178,7 @@ func GetOnlineStatus() OnlineStatus { return OnlineStatus(atomic.LoadInt32(onlineStatus)) } -// CheckAndGetOnlineStatus triggers a new online status check and returns the result +// CheckAndGetOnlineStatus triggers a new online status check and returns the result. func CheckAndGetOnlineStatus() OnlineStatus { // trigger new investigation triggerOnlineStatusInvestigation() @@ -225,7 +228,7 @@ func notifyOnlineStatus(status OnlineStatus) { var eventID, title, message string // Check if status is worth notifying. - switch status { + switch status { //nolint:exhaustive // Checking for selection only. case StatusOffline: eventID = "netenv:online-status:offline" title = "Device is Offline" @@ -419,7 +422,7 @@ func checkOnlineStatus(ctx context.Context) { } else { var lan bool for _, ip := range ipv4 { - switch netutils.GetIPScope(ip) { + switch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only. case netutils.SiteLocal: lan = true case netutils.Global: @@ -429,7 +432,7 @@ func checkOnlineStatus(ctx context.Context) { } } for _, ip := range ipv6 { - switch netutils.GetIPScope(ip) { + switch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only. case netutils.SiteLocal, netutils.Global: // IPv6 global addresses are also used in local networks lan = true @@ -470,14 +473,16 @@ func checkOnlineStatus(ctx context.Context) { response, err := client.Do(request) if err != nil { - nErr, ok := err.(net.Error) - if !ok || !nErr.Timeout() { + var netErr net.Error + if !errors.As(err, &netErr) || !netErr.Timeout() { // Timeout is the expected error when there is no portal log.Debugf("netenv: http portal test failed: %s", err) // TODO: discern between errors to detect StatusLimited } } else { - defer response.Body.Close() + defer func() { + _ = response.Body.Close() + }() // Got a response, something is messing with the request // check location diff --git a/netenv/online-status_test.go b/netenv/online-status_test.go index 7c61d9ab..7ffe3ec4 100644 --- a/netenv/online-status_test.go +++ b/netenv/online-status_test.go @@ -6,6 +6,8 @@ import ( ) func TestCheckOnlineStatus(t *testing.T) { + t.Parallel() + checkOnlineStatus(context.Background()) t.Logf("online status: %s", GetOnlineStatus()) t.Logf("captive portal: %+v", GetCaptivePortal()) diff --git a/network/api.go b/network/api.go index f73698d9..21fda11e 100644 --- a/network/api.go +++ b/network/api.go @@ -89,6 +89,7 @@ func debugInfo(ar *api.Request) (data []byte, err error) { return di.Bytes(), nil } +// AddNetworkDebugData adds the network debug data of the given profile to the debug data. func AddNetworkDebugData(di *debug.Info, profile, where string) { // Prepend where prefix to query if necessary. if where != "" && !strings.HasPrefix(where, "where ") { @@ -99,7 +100,7 @@ func AddNetworkDebugData(di *debug.Info, profile, where string) { q, err := query.ParseQuery("query network: " + where) if err != nil { di.AddSection( - fmt.Sprintf("Network: Debug Failed"), + "Network: Debug Failed", debug.NoFlags, fmt.Sprintf("Failed to build query: %s", err), ) @@ -110,7 +111,7 @@ func AddNetworkDebugData(di *debug.Info, profile, where string) { it, err := dbController.Query(q, true, true) if err != nil { di.AddSection( - fmt.Sprintf("Network: Debug Failed"), + "Network: Debug Failed", debug.NoFlags, fmt.Sprintf("Failed to run query: %s", err), ) @@ -118,9 +119,11 @@ func AddNetworkDebugData(di *debug.Info, profile, where string) { } // Collect matching connections. - var debugConns []*Connection - var accepted int - var total int + var ( //nolint:prealloc // We don't know the size. + debugConns []*Connection + accepted int + total int + ) for maybeConn := range it.Next { // Switch to correct type. conn, ok := maybeConn.(*Connection) @@ -149,7 +152,7 @@ func AddNetworkDebugData(di *debug.Info, profile, where string) { // Count. total++ - switch conn.Verdict { + switch conn.Verdict { //nolint:exhaustive case VerdictAccept, VerdictRerouteToNameserver, VerdictRerouteToTunnel: diff --git a/network/api_test.go b/network/api_test.go index ae3a1825..a595e854 100644 --- a/network/api_test.go +++ b/network/api_test.go @@ -9,12 +9,16 @@ import ( ) func TestDebugInfoLineFormatting(t *testing.T) { + t.Parallel() + for _, conn := range connectionTestData { fmt.Println(conn.debugInfoLine()) } } func TestDebugInfoFormatting(t *testing.T) { + t.Parallel() + fmt.Println(buildNetworkDebugInfoData(connectionTestData)) } diff --git a/network/clean.go b/network/clean.go index 9b354c00..608e2c88 100644 --- a/network/clean.go +++ b/network/clean.go @@ -4,11 +4,9 @@ import ( "context" "time" - "github.com/safing/portmaster/network/packet" - - "github.com/safing/portmaster/network/state" - "github.com/safing/portbase/log" + "github.com/safing/portmaster/network/packet" + "github.com/safing/portmaster/network/state" "github.com/safing/portmaster/process" ) @@ -41,7 +39,6 @@ func cleanConnections() (activePIDs map[int]struct{}) { name := "clean connections" // TODO: change to new fn _ = module.RunMediumPriorityMicroTask(&name, func(ctx context.Context) error { - now := time.Now().UTC() nowUnix := now.Unix() deleteOlderThan := now.Add(-deleteConnsAfterEndedThreshold).Unix() diff --git a/network/connection.go b/network/connection.go index 37005665..6e8def4e 100644 --- a/network/connection.go +++ b/network/connection.go @@ -44,13 +44,14 @@ type ProcessContext struct { Source string } +// ConnectionType is a type of connection. type ConnectionType int8 +// Connection Types. const ( Undefined ConnectionType = iota IPConnection DNSRequest - // ProxyRequest ) // Connection describes a distinct physical network connection @@ -280,6 +281,7 @@ func NewConnectionFromDNSRequest(ctx context.Context, fqdn string, cnames []stri return dnsConn } +// NewConnectionFromExternalDNSRequest returns a connection for an external DNS request. func NewConnectionFromExternalDNSRequest(ctx context.Context, fqdn string, cnames []string, connID string, remoteIP net.IP) (*Connection, error) { remoteHost, err := process.GetNetworkHost(ctx, remoteIP) if err != nil { @@ -336,7 +338,6 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection { var dnsContext *resolver.DNSRequestContext if inbound { - switch entity.IPScope { case netutils.HostLocal: scope = IncomingHost @@ -345,12 +346,11 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection { case netutils.Global, netutils.GlobalMulticast: scope = IncomingInternet - case netutils.Invalid: + case netutils.Undefined, netutils.Invalid: fallthrough default: scope = IncomingInvalid } - } else { // check if we can find a domain for that IP @@ -379,7 +379,6 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection { } if scope == "" { - // outbound direct (possibly P2P) connection switch entity.IPScope { case netutils.HostLocal: @@ -389,12 +388,11 @@ func NewConnectionFromFirstPacket(pkt packet.Packet) *Connection { case netutils.Global, netutils.GlobalMulticast: scope = PeerInternet - case netutils.Invalid: + case netutils.Undefined, netutils.Invalid: fallthrough default: scope = PeerInvalid } - } } @@ -547,10 +545,10 @@ func (conn *Connection) Save() { if !conn.KeyIsSet() { if conn.Type == DNSRequest { - conn.SetKey(makeKey(conn.process.Pid, "dns", conn.ID)) + conn.SetKey(makeKey(conn.process.Pid, dbScopeDNS, conn.ID)) dnsConns.add(conn) } else { - conn.SetKey(makeKey(conn.process.Pid, "ip", conn.ID)) + conn.SetKey(makeKey(conn.process.Pid, dbScopeIP, conn.ID)) conns.add(conn) } } @@ -597,7 +595,7 @@ func (conn *Connection) StopFirewallHandler() { conn.pktQueue <- nil } -// HandlePacket queues packet of Link for handling +// HandlePacket queues packet of Link for handling. func (conn *Connection) HandlePacket(pkt packet.Packet) { conn.Lock() defer conn.Unlock() @@ -611,7 +609,7 @@ func (conn *Connection) HandlePacket(pkt packet.Packet) { } } -// packetHandler sequentially handles queued packets +// packetHandler sequentially handles queued packets. func (conn *Connection) packetHandler() { for pkt := range conn.pktQueue { if pkt == nil { @@ -649,8 +647,8 @@ func (conn *Connection) GetActiveInspectors() []bool { } // SetActiveInspectors sets the list of active inspectors. -func (conn *Connection) SetActiveInspectors(new []bool) { - conn.activeInspectors = new +func (conn *Connection) SetActiveInspectors(newInspectors []bool) { + conn.activeInspectors = newInspectors } // GetInspectorData returns the list of inspector data. @@ -659,8 +657,8 @@ func (conn *Connection) GetInspectorData() map[uint8]interface{} { } // SetInspectorData set the list of inspector data. -func (conn *Connection) SetInspectorData(new map[uint8]interface{}) { - conn.inspectorData = new +func (conn *Connection) SetInspectorData(newInspectorData map[uint8]interface{}) { + conn.inspectorData = newInspectorData } // String returns a string representation of conn. diff --git a/network/connection_store.go b/network/connection_store.go index a3c633cb..828bd9f6 100644 --- a/network/connection_store.go +++ b/network/connection_store.go @@ -48,7 +48,7 @@ func (cs *connectionStore) clone() map[string]*Connection { return m } -func (cs *connectionStore) len() int { +func (cs *connectionStore) len() int { //nolint:unused // TODO: Clean up if still unused. cs.rw.RLock() defer cs.rw.RUnlock() diff --git a/network/database.go b/network/database.go index 0937e3fb..f67d52d5 100644 --- a/network/database.go +++ b/network/database.go @@ -14,6 +14,12 @@ import ( "github.com/safing/portmaster/process" ) +const ( + dbScopeNone = "" + dbScopeDNS = "dns" + dbScopeIP = "ip" +) + var ( dbController *database.Controller @@ -43,7 +49,7 @@ func parseDBKey(key string) (pid int, scope, id string, ok bool) { // Split into segments. segments := strings.Split(key, "/") // Check for valid prefix. - if !strings.HasPrefix("tree", segments[0]) { + if segments[0] != "tree" { return 0, "", "", false } @@ -57,7 +63,7 @@ func parseDBKey(key string) (pid int, scope, id string, ok bool) { scope = segments[2] // Sanity check. switch scope { - case "dns", "ip", "": + case dbScopeNone, dbScopeDNS, dbScopeIP: // Parsed id matches possible values. // The empty string is for matching a trailing slash for in query prefix. // TODO: For queries, also prefixes of these values are valid. @@ -96,15 +102,15 @@ func (s *StorageInterface) Get(key string) (record.Record, error) { } switch scope { - case "dns": + case dbScopeDNS: if r, ok := dnsConns.get(id); ok { return r, nil } - case "ip": + case dbScopeIP: if r, ok := conns.get(id); ok { return r, nil } - case "": + case dbScopeNone: if proc, ok := process.GetProcessFromStorage(pid); ok { return proc, nil } @@ -147,7 +153,7 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) { } } - if scope == "" || scope == "dns" { + if scope == dbScopeNone || scope == dbScopeDNS { // dns scopes only for _, dnsConn := range dnsConns.clone() { func() { @@ -161,7 +167,7 @@ func (s *StorageInterface) processQuery(q *query.Query, it *iterator.Iterator) { } } - if scope == "" || scope == "ip" { + if scope == dbScopeNone || scope == dbScopeIP { // connections for _, conn := range conns.clone() { func() { diff --git a/network/dns.go b/network/dns.go index e7c88e77..6a4958c8 100644 --- a/network/dns.go +++ b/network/dns.go @@ -8,6 +8,7 @@ import ( "time" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/nameserver/nsutil" "github.com/safing/portmaster/process" @@ -17,16 +18,15 @@ import ( var ( openDNSRequests = make(map[string]*Connection) // key: /fqdn openDNSRequestsLock sync.Mutex - - // scope prefix - unidentifiedProcessScopePrefix = strconv.Itoa(process.UnidentifiedProcessID) + "/" ) const ( - // write open dns requests every + // writeOpenDNSRequestsTickDuration defines the interval in which open dns + // requests are written. writeOpenDNSRequestsTickDuration = 5 * time.Second - // duration after which DNS requests without a following connection are logged + // openDNSRequestLimit defines the duration after which DNS requests without + // a following connection are logged. openDNSRequestLimit = 3 * time.Second ) @@ -122,6 +122,9 @@ func (conn *Connection) ReplyWithDNS(ctx context.Context, request *dns.Msg) *dns return nil // Do not respond to request. case VerdictFailed: return nsutil.BlockIP().ReplyWithDNS(ctx, request) + case VerdictUndecided, VerdictUndeterminable, + VerdictAccept, VerdictRerouteToNameserver, VerdictRerouteToTunnel: + fallthrough default: reply := nsutil.ServerFailure().ReplyWithDNS(ctx, request) nsutil.AddMessagesToReply(ctx, reply, log.ErrorLevel, "INTERNAL ERROR: incorrect use of Connection DNS Responder") @@ -136,6 +139,10 @@ func (conn *Connection) GetExtraRRs(ctx context.Context, request *dns.Msg) []dns switch conn.Verdict { case VerdictFailed: level = log.ErrorLevel + case VerdictUndecided, VerdictUndeterminable, + VerdictAccept, VerdictBlock, VerdictDrop, + VerdictRerouteToNameserver, VerdictRerouteToTunnel: + fallthrough default: level = log.InfoLevel } diff --git a/network/metrics.go b/network/metrics.go index 047ad19c..720856ae 100644 --- a/network/metrics.go +++ b/network/metrics.go @@ -119,7 +119,7 @@ func (conn *Connection) addToMetrics() { } // Check the verdict. - switch conn.Verdict { + switch conn.Verdict { //nolint:exhaustive // Not critical. case VerdictBlock, VerdictDrop: blockedOutConnCounter.Inc() conn.addedToMetrics = true diff --git a/network/netutils/address.go b/network/netutils/address.go index 86a94995..b7ef1165 100644 --- a/network/netutils/address.go +++ b/network/netutils/address.go @@ -19,7 +19,7 @@ func IPFromAddr(addr net.Addr) (net.IP, error) { // Parse via string. host, _, err := net.SplitHostPort(addr.String()) if err != nil { - return nil, fmt.Errorf("failed to split host and port of %q: %s", addr, err) + return nil, fmt.Errorf("failed to split host and port of %q: %w", addr, err) } ip := net.ParseIP(host) if ip == nil { diff --git a/network/netutils/dns.go b/network/netutils/dns.go index 68bb5d54..7a7bd6e5 100644 --- a/network/netutils/dns.go +++ b/network/netutils/dns.go @@ -8,19 +8,17 @@ import ( "github.com/miekg/dns" ) -var ( - cleanDomainRegex = regexp.MustCompile( - `^` + // match beginning - `(` + // start subdomain group - `(xn--)?` + // idn prefix - `[a-z0-9_-]{1,63}` + // main chunk - `\.` + // ending with a dot - `)*` + // end subdomain group, allow any number of subdomains - `(xn--)?` + // TLD idn prefix - `[a-z0-9_-]{2,63}` + // TLD main chunk with at least two characters - `\.` + // ending with a dot - `$`, // match end - ) +var cleanDomainRegex = regexp.MustCompile( + `^` + // match beginning + `(` + // start subdomain group + `(xn--)?` + // idn prefix + `[a-z0-9_-]{1,63}` + // main chunk + `\.` + // ending with a dot + `)*` + // end subdomain group, allow any number of subdomains + `(xn--)?` + // TLD idn prefix + `[a-z0-9_-]{2,63}` + // TLD main chunk with at least two characters + `\.` + // ending with a dot + `$`, // match end ) // IsValidFqdn returns whether the given string is a valid fqdn. diff --git a/network/netutils/dns_test.go b/network/netutils/dns_test.go index 4f0dacb0..ca13adf9 100644 --- a/network/netutils/dns_test.go +++ b/network/netutils/dns_test.go @@ -3,12 +3,16 @@ package netutils import "testing" func testDomainValidity(t *testing.T, domain string, isValid bool) { + t.Helper() + if IsValidFqdn(domain) != isValid { t.Errorf("domain %s failed check: was valid=%v, expected valid=%v", domain, IsValidFqdn(domain), isValid) } } func TestDNSValidation(t *testing.T) { + t.Parallel() + // valid testDomainValidity(t, ".", true) testDomainValidity(t, "at.", true) diff --git a/network/netutils/ip.go b/network/netutils/ip.go index 0b058087..0cb8f59f 100644 --- a/network/netutils/ip.go +++ b/network/netutils/ip.go @@ -93,7 +93,7 @@ func (scope IPScope) IsLocalhost() bool { // IsLAN returns true if the scope is site-local or link-local. func (scope IPScope) IsLAN() bool { - switch scope { + switch scope { //nolint:exhaustive // Looking for something specific. case SiteLocal, LinkLocal, LocalMulticast: return true default: @@ -103,7 +103,7 @@ func (scope IPScope) IsLAN() bool { // IsGlobal returns true if the scope is global. func (scope IPScope) IsGlobal() bool { - switch scope { + switch scope { //nolint:exhaustive // Looking for something specific. case Global, GlobalMulticast: return true default: diff --git a/network/netutils/ip_test.go b/network/netutils/ip_test.go index 02ef2051..5dddd5d4 100644 --- a/network/netutils/ip_test.go +++ b/network/netutils/ip_test.go @@ -6,6 +6,8 @@ import ( ) func TestIPScope(t *testing.T) { + t.Parallel() + testScope(t, net.IPv4(71, 87, 113, 211), Global) testScope(t, net.IPv4(127, 0, 0, 1), HostLocal) testScope(t, net.IPv4(127, 255, 255, 1), HostLocal) @@ -17,6 +19,8 @@ func TestIPScope(t *testing.T) { } func testScope(t *testing.T, ip net.IP, expectedScope IPScope) { + t.Helper() + c := GetIPScope(ip) if c != expectedScope { t.Errorf("%s is %s, expected %s", ip, scopeName(c), scopeName(expectedScope)) diff --git a/network/netutils/tcpassembly.go b/network/netutils/tcpassembly.go index 43fa8bc9..62449e7d 100644 --- a/network/netutils/tcpassembly.go +++ b/network/netutils/tcpassembly.go @@ -7,7 +7,7 @@ import ( "github.com/google/gopacket/tcpassembly" ) -// SimpleStreamAssemblerManager is a simple manager for github.com/google/gopacket/tcpassembly +// SimpleStreamAssemblerManager is a simple manager for github.com/google/gopacket/tcpassembly. type SimpleStreamAssemblerManager struct { InitLock sync.Mutex lastAssembler *SimpleStreamAssembler @@ -25,7 +25,7 @@ func (m *SimpleStreamAssemblerManager) GetLastAssembler() *SimpleStreamAssembler return m.lastAssembler } -// SimpleStreamAssembler is a simple assembler for github.com/google/gopacket/tcpassembly +// SimpleStreamAssembler is a simple assembler for github.com/google/gopacket/tcpassembly. type SimpleStreamAssembler struct { Cumulated []byte CumulatedLen int diff --git a/network/packet/const.go b/network/packet/const.go index 69abd09c..2707350a 100644 --- a/network/packet/const.go +++ b/network/packet/const.go @@ -5,7 +5,7 @@ import ( "fmt" ) -// Basic Types +// Basic Types. type ( // IPVersion represents an IP version. IPVersion uint8 @@ -15,7 +15,7 @@ type ( Verdict uint8 ) -// Basic Constants +// Basic Constants. const ( IPv4 = IPVersion(4) IPv6 = IPVersion(6) @@ -34,7 +34,7 @@ const ( AnyHostInternalProtocol61 = IPProtocol(61) ) -// Verdicts +// Verdicts. const ( DROP Verdict = iota BLOCK @@ -45,12 +45,10 @@ const ( STOP ) -var ( - // ErrFailedToLoadPayload is returned by GetPayload if it failed for an unspecified reason, or is not implemented on the current system. - ErrFailedToLoadPayload = errors.New("could not load packet payload") -) +// ErrFailedToLoadPayload is returned by GetPayload if it failed for an unspecified reason, or is not implemented on the current system. +var ErrFailedToLoadPayload = errors.New("could not load packet payload") -// ByteSize returns the byte size of the ip, IPv4 = 4 bytes, IPv6 = 16 +// ByteSize returns the byte size of the ip (IPv4 = 4 bytes, IPv6 = 16). func (v IPVersion) ByteSize() int { switch v { case IPv4: @@ -89,8 +87,11 @@ func (p IPProtocol) String() string { return "ICMPv6" case IGMP: return "IGMP" + case AnyHostInternalProtocol61: + fallthrough + default: + return fmt.Sprintf("", uint8(p)) } - return fmt.Sprintf("", uint8(p)) } // String returns the string representation of the verdict. diff --git a/network/packet/packet.go b/network/packet/packet.go index c735e38f..b35c9f0b 100644 --- a/network/packet/packet.go +++ b/network/packet/packet.go @@ -71,8 +71,11 @@ func (pkt *Base) HasPorts() bool { return true case UDP, UDPLite: return true + case ICMP, ICMPv6, IGMP, RAW, AnyHostInternalProtocol61: + fallthrough + default: + return false } - return false } // LoadPacketData loads packet data from the integration, if not yet done. @@ -125,7 +128,7 @@ func (pkt *Base) createConnectionID() { // IN OUT // Local Dst Src // Remote Src Dst -// +//. func (pkt *Base) MatchesAddress(remote bool, protocol IPProtocol, network *net.IPNet, port uint16) bool { if pkt.info.Protocol != protocol { return false @@ -154,7 +157,7 @@ func (pkt *Base) MatchesAddress(remote bool, protocol IPProtocol, network *net.I // IN OUT // Local Dst Src // Remote Src Dst -// +//. func (pkt *Base) MatchesIP(endpoint bool, network *net.IPNet) bool { if pkt.info.Inbound != endpoint { if network.Contains(pkt.info.Src) { @@ -174,7 +177,7 @@ func (pkt *Base) String() string { return pkt.FmtPacket() } -// FmtPacket returns the most important information about the packet as a string +// FmtPacket returns the most important information about the packet as a string. func (pkt *Base) FmtPacket() string { if pkt.info.Protocol == TCP || pkt.info.Protocol == UDP { if pkt.info.Inbound { @@ -188,12 +191,12 @@ func (pkt *Base) FmtPacket() string { return fmt.Sprintf("OUT %s %s <-> %s", pkt.info.Protocol, pkt.info.Src, pkt.info.Dst) } -// FmtProtocol returns the protocol as a string +// FmtProtocol returns the protocol as a string. func (pkt *Base) FmtProtocol() string { return pkt.info.Protocol.String() } -// FmtRemoteIP returns the remote IP address as a string +// FmtRemoteIP returns the remote IP address as a string. func (pkt *Base) FmtRemoteIP() string { if pkt.info.Inbound { return pkt.info.Src.String() @@ -201,7 +204,7 @@ func (pkt *Base) FmtRemoteIP() string { return pkt.info.Dst.String() } -// FmtRemotePort returns the remote port as a string +// FmtRemotePort returns the remote port as a string. func (pkt *Base) FmtRemotePort() string { if pkt.info.SrcPort != 0 { if pkt.info.Inbound { @@ -212,14 +215,14 @@ func (pkt *Base) FmtRemotePort() string { return "-" } -// FmtRemoteAddress returns the full remote address (protocol, IP, port) as a string +// FmtRemoteAddress returns the full remote address (protocol, IP, port) as a string. func (pkt *Base) FmtRemoteAddress() string { return fmt.Sprintf("%s:%s:%s", pkt.info.Protocol.String(), pkt.FmtRemoteIP(), pkt.FmtRemotePort()) } -// Packet is an interface to a network packet to provide object behaviour the same across all systems +// Packet is an interface to a network packet to provide object behaviour the same across all systems. type Packet interface { - // VERDICTS + // Verdicts. Accept() error Block() error Drop() error @@ -230,7 +233,7 @@ type Packet interface { RerouteToTunnel() error FastTrackedByIntegration() bool - // INFO + // Info. SetCtx(context.Context) Ctx() context.Context Info() *Info @@ -242,17 +245,17 @@ type Packet interface { HasPorts() bool GetConnectionID() string - // PAYLOAD + // Payload. LoadPacketData() error Layers() gopacket.Packet Raw() []byte Payload() []byte - // MATCHING + // Matching. MatchesAddress(bool, IPProtocol, *net.IPNet, uint16) bool MatchesIP(bool, *net.IPNet) bool - // FORMATTING + // Formatting. String() string FmtPacket() string FmtProtocol() string diff --git a/network/packet/packetinfo.go b/network/packet/packetinfo.go index 3e68e8af..7158a6ca 100644 --- a/network/packet/packetinfo.go +++ b/network/packet/packetinfo.go @@ -4,7 +4,7 @@ import ( "net" ) -// Info holds IP and TCP/UDP header information +// Info holds IP and TCP/UDP header information. type Info struct { Inbound bool InTunnel bool diff --git a/network/packet/parse.go b/network/packet/parse.go index ed5a7817..562546af 100644 --- a/network/packet/parse.go +++ b/network/packet/parse.go @@ -135,7 +135,7 @@ func Parse(packetData []byte, pktBase *Base) (err error) { parseIPv6, parseTCP, parseUDP, - //parseUDPLite, // we don't yet support udplite + // parseUDPLite, // We don't yet support udplite. parseICMPv4, parseICMPv6, parseIGMP, diff --git a/network/proc/findpid.go b/network/proc/findpid.go index 37e9b0ef..1178eae8 100644 --- a/network/proc/findpid.go +++ b/network/proc/findpid.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package proc @@ -7,9 +7,8 @@ import ( "os" "time" - "github.com/safing/portmaster/network/socket" - "github.com/safing/portbase/log" + "github.com/safing/portmaster/network/socket" ) var ( @@ -128,7 +127,10 @@ func readDirNames(dir string) (names []string) { } return } - defer file.Close() + defer func() { + _ = file.Close() + }() + names, err = file.Readdirnames(0) if err != nil { log.Warningf("proc: could not get entries from directory %s: %s", dir, err) diff --git a/network/proc/pids_by_user.go b/network/proc/pids_by_user.go index 944786ff..4d32a481 100644 --- a/network/proc/pids_by_user.go +++ b/network/proc/pids_by_user.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package proc diff --git a/network/proc/tables.go b/network/proc/tables.go index 8ea303d1..36c9b844 100644 --- a/network/proc/tables.go +++ b/network/proc/tables.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package proc @@ -12,9 +12,8 @@ import ( "strings" "unicode" - "github.com/safing/portmaster/network/socket" - "github.com/safing/portbase/log" + "github.com/safing/portmaster/network/socket" ) /* @@ -85,7 +84,6 @@ const ( ) func getTableFromSource(stack uint8, procFile string) (connections []*socket.ConnectionInfo, binds []*socket.BindInfo, err error) { - var ipConverter func(string) net.IP switch stack { case TCP4, UDP4: @@ -101,7 +99,9 @@ func getTableFromSource(stack uint8, procFile string) (connections []*socket.Con if err != nil { return nil, nil, err } - defer socketData.Close() + defer func() { + _ = socketData.Close() + }() // file scanner scanner := bufio.NewScanner(socketData) diff --git a/network/proc/tables_test.go b/network/proc/tables_test.go index d5b1959f..5f4c4758 100644 --- a/network/proc/tables_test.go +++ b/network/proc/tables_test.go @@ -1,4 +1,4 @@ -// +build linux +// go:build linux package proc @@ -8,6 +8,8 @@ import ( ) func TestSockets(t *testing.T) { + t.Parallel() + connections, listeners, err := GetTCP4Table() if err != nil { t.Fatal(err) diff --git a/network/socket/socket.go b/network/socket/socket.go index 7ecfddf7..266176dd 100644 --- a/network/socket/socket.go +++ b/network/socket/socket.go @@ -111,6 +111,6 @@ func (i *BindInfo) GetUIDandInode() (int, int) { return i.UID, i.Inode } -// compile time checks +// Compile time checks. var _ Info = new(ConnectionInfo) var _ Info = new(BindInfo) diff --git a/network/state/exists.go b/network/state/exists.go index d401058a..967b8f95 100644 --- a/network/state/exists.go +++ b/network/state/exists.go @@ -14,7 +14,6 @@ const ( // Exists checks if the given connection is present in the system state tables. func Exists(pktInfo *packet.Info, now time.Time) (exists bool) { - // TODO: create lookup maps before running a flurry of Exists() checks. switch { diff --git a/network/state/info.go b/network/state/info.go index 7d4c11fc..6f97a74e 100644 --- a/network/state/info.go +++ b/network/state/info.go @@ -4,7 +4,6 @@ import ( "sync" "github.com/safing/portbase/database/record" - "github.com/safing/portmaster/network/socket" ) diff --git a/network/state/udp.go b/network/state/udp.go index 31474f5b..0302be14 100644 --- a/network/state/udp.go +++ b/network/state/udp.go @@ -117,7 +117,6 @@ func (table *udpTable) getDirection( } func (table *udpTable) cleanStates(now time.Time) { - // compute thresholds threshold := now.Add(-UDPConnStateTTL) shortThreshhold := now.Add(-UDPConnStateShortenedTTL) diff --git a/network/status.go b/network/status.go index 75c7f5a8..ce68aace 100644 --- a/network/status.go +++ b/network/status.go @@ -64,13 +64,13 @@ func (v Verdict) Verb() string { } } -// Packet Directions +// Packet Directions. const ( Inbound = true Outbound = false ) -// Non-Domain Scopes +// Non-Domain Scopes. const ( IncomingHost = "IH" IncomingLAN = "IL" diff --git a/process/database.go b/process/database.go index 226804d6..62df8f09 100644 --- a/process/database.go +++ b/process/database.go @@ -6,15 +6,13 @@ import ( "time" processInfo "github.com/shirou/gopsutil/process" + "github.com/tevino/abool" "github.com/safing/portbase/database" "github.com/safing/portbase/log" - "github.com/tevino/abool" ) -const ( - processDatabaseNamespace = "network:tree" -) +const processDatabaseNamespace = "network:tree" var ( processes = make(map[int]*Process) diff --git a/process/find.go b/process/find.go index e97779c0..5ce75574 100644 --- a/process/find.go +++ b/process/find.go @@ -49,6 +49,7 @@ func GetProcessByConnection(ctx context.Context, pktInfo *packet.Info) (process return process, connInbound, nil } +// GetNetworkHost returns a *Process that represents a host on the network. func GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err error) { //nolint:interfacer now := time.Now().Unix() networkHost := &Process{ diff --git a/process/process.go b/process/process.go index 72b2c2b3..61a9f4fe 100644 --- a/process/process.go +++ b/process/process.go @@ -19,9 +19,7 @@ import ( "github.com/safing/portmaster/profile" ) -const ( - onLinux = runtime.GOOS == "linux" -) +const onLinux = runtime.GOOS == "linux" var getProcessSingleInflight singleflight.Group @@ -103,7 +101,7 @@ func (p *Process) SetLastSeen(lastSeen int64) { p.LastSeen = lastSeen } -// Strings returns a string representation of process. +// String returns a string representation of process. func (p *Process) String() string { if p == nil { return "?" @@ -126,11 +124,10 @@ func GetOrFindProcess(ctx context.Context, pid int) (*Process, error) { return nil, errors.New("process getter returned nil") } - return p.(*Process), nil + return p.(*Process), nil // nolint:forcetypeassert // Can only be a *Process. } func loadProcess(ctx context.Context, pid int) (*Process, error) { - switch pid { case UnidentifiedProcessID: return GetUnidentifiedProcess(ctx), nil @@ -144,7 +141,7 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) { } // Create new a process object. - new := &Process{ + process = &Process{ Pid: pid, FirstSeen: time.Now().Unix(), } @@ -157,19 +154,19 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) { // UID // net yet implemented for windows - if runtime.GOOS == "linux" { + if onLinux { var uids []int32 uids, err = pInfo.Uids() if err != nil { - return nil, fmt.Errorf("failed to get UID for p%d: %s", pid, err) + return nil, fmt.Errorf("failed to get UID for p%d: %w", pid, err) } - new.UserID = int(uids[0]) + process.UserID = int(uids[0]) } // Username - new.UserName, err = pInfo.Username() + process.UserName, err = pInfo.Username() if err != nil { - return nil, fmt.Errorf("process: failed to get Username for p%d: %s", pid, err) + return nil, fmt.Errorf("process: failed to get Username for p%d: %w", pid, err) } // TODO: User Home @@ -178,47 +175,47 @@ func loadProcess(ctx context.Context, pid int) (*Process, error) { // PPID ppid, err := pInfo.Ppid() if err != nil { - return nil, fmt.Errorf("failed to get PPID for p%d: %s", pid, err) + return nil, fmt.Errorf("failed to get PPID for p%d: %w", pid, err) } - new.ParentPid = int(ppid) + process.ParentPid = int(ppid) // Path - new.Path, err = pInfo.Exe() + process.Path, err = pInfo.Exe() if err != nil { - return nil, fmt.Errorf("failed to get Path for p%d: %s", pid, err) + return nil, fmt.Errorf("failed to get Path for p%d: %w", pid, err) } // remove linux " (deleted)" suffix for deleted files if onLinux { - new.Path = strings.TrimSuffix(new.Path, " (deleted)") + process.Path = strings.TrimSuffix(process.Path, " (deleted)") } // Executable Name - _, new.ExecName = filepath.Split(new.Path) + _, process.ExecName = filepath.Split(process.Path) // Current working directory // net yet implemented for windows // new.Cwd, err = pInfo.Cwd() // if err != nil { - // log.Warningf("process: failed to get Cwd: %s", err) + // log.Warningf("process: failed to get Cwd: %w", err) // } // Command line arguments - new.CmdLine, err = pInfo.Cmdline() + process.CmdLine, err = pInfo.Cmdline() if err != nil { - return nil, fmt.Errorf("failed to get Cmdline for p%d: %s", pid, err) + return nil, fmt.Errorf("failed to get Cmdline for p%d: %w", pid, err) } // Name - new.Name, err = pInfo.Name() + process.Name, err = pInfo.Name() if err != nil { - return nil, fmt.Errorf("failed to get Name for p%d: %s", pid, err) + return nil, fmt.Errorf("failed to get Name for p%d: %w", pid, err) } - if new.Name == "" { - new.Name = new.ExecName + if process.Name == "" { + process.Name = process.ExecName } // OS specifics - new.specialOSInit() + process.specialOSInit() - new.Save() - return new, nil + process.Save() + return process, nil } diff --git a/process/process_linux.go b/process/process_linux.go index bd6a1fb6..64268a66 100644 --- a/process/process_linux.go +++ b/process/process_linux.go @@ -4,6 +4,4 @@ package process const SystemProcessID = 0 // specialOSInit does special OS specific Process initialization. -func (p *Process) specialOSInit() { - -} +func (p *Process) specialOSInit() {} diff --git a/process/profile.go b/process/profile.go index 0068d73a..381411fd 100644 --- a/process/profile.go +++ b/process/profile.go @@ -10,9 +10,7 @@ import ( "github.com/safing/portmaster/profile" ) -var ( - ownPID = os.Getpid() -) +var ownPID = os.Getpid() // GetProfile finds and assigns a profile set to the process. func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) { diff --git a/process/special.go b/process/special.go index 8ec47b4c..c22d5100 100644 --- a/process/special.go +++ b/process/special.go @@ -5,8 +5,9 @@ import ( "strconv" "time" - "github.com/safing/portbase/log" "golang.org/x/sync/singleflight" + + "github.com/safing/portbase/log" ) const ( @@ -76,5 +77,5 @@ func getSpecialProcess(ctx context.Context, template *Process) *Process { process.Save() return process, nil }) - return p.(*Process) + return p.(*Process) // nolint:forcetypeassert // Can only be a *Process. } diff --git a/profile/active.go b/profile/active.go index 08b6deab..94c86603 100644 --- a/profile/active.go +++ b/profile/active.go @@ -68,17 +68,6 @@ func addActiveProfile(profile *Profile) { activeProfiles[profile.ScopedID()] = profile } -// markActiveProfileAsOutdated marks an active profile as outdated. -func markActiveProfileAsOutdated(scopedID string) { - activeProfilesLock.RLock() - defer activeProfilesLock.RUnlock() - - profile, ok := activeProfiles[scopedID] - if ok { - profile.outdated.Set() - } -} - func cleanActiveProfiles(ctx context.Context) error { for { select { diff --git a/profile/config.go b/profile/config.go index f067cb12..84edc368 100644 --- a/profile/config.go +++ b/profile/config.go @@ -15,18 +15,18 @@ var ( cfgIntOptions = make(map[string]config.IntOption) cfgBoolOptions = make(map[string]config.BoolOption) - // General + // General. - // Enable Filter Order = 0 + // Setting "Enable Filter" at order 0. CfgOptionDefaultActionKey = "filter/defaultAction" cfgOptionDefaultAction config.StringOption cfgOptionDefaultActionOrder = 1 - // Prompt Desktop Notifications Order = 2 - // Prompt Timeout Order = 3 + // Setting "Prompt Desktop Notifications" at order 2. + // Setting "Prompt Timeout" at order 3. - // Network Scopes + // Network Scopes. CfgOptionBlockScopeInternetKey = "filter/blockInternet" cfgOptionBlockScopeInternet config.IntOption // security level option @@ -40,7 +40,7 @@ var ( cfgOptionBlockScopeLocal config.IntOption // security level option cfgOptionBlockScopeLocalOrder = 18 - // Connection Types + // Connection Types. CfgOptionBlockP2PKey = "filter/blockP2P" cfgOptionBlockP2P config.IntOption // security level option @@ -50,7 +50,7 @@ var ( cfgOptionBlockInbound config.IntOption // security level option cfgOptionBlockInboundOrder = 20 - // Rules + // Rules. CfgOptionEndpointsKey = "filter/endpoints" cfgOptionEndpoints config.StringArrayOption @@ -68,7 +68,7 @@ var ( cfgOptionFilterSubDomains config.IntOption // security level option cfgOptionFilterSubDomainsOrder = 35 - // DNS Filtering + // DNS Filtering. CfgOptionFilterCNAMEKey = "filter/includeCNAMEs" cfgOptionFilterCNAME config.IntOption // security level option @@ -86,7 +86,7 @@ var ( cfgOptionDomainHeuristics config.IntOption // security level option cfgOptionDomainHeuristicsOrder = 51 - // Advanced + // Advanced. CfgOptionPreventBypassingKey = "filter/preventBypassing" cfgOptionPreventBypassing config.IntOption // security level option @@ -96,7 +96,7 @@ var ( cfgOptionDisableAutoPermit config.IntOption // security level option cfgOptionDisableAutoPermitOrder = 65 - // Permanent Verdicts Order = 96 + // Setting "Permanent Verdicts" at order 96. CfgOptionUseSPNKey = "spn/use" cfgOptionUseSPN config.BoolOption @@ -119,7 +119,7 @@ var securityLevelSettings = []string{ CfgOptionDisableAutoPermitKey, } -func registerConfiguration() error { +func registerConfiguration() error { //nolint:maintidx // Default Filter Action // permit - blocklist mode: everything is allowed unless blocked // ask - ask mode: if not verdict is found, the user is consulted diff --git a/profile/database.go b/profile/database.go index 1ce873d3..3ddd9aea 100644 --- a/profile/database.go +++ b/profile/database.go @@ -6,27 +6,22 @@ import ( "strings" "github.com/safing/portbase/config" - "github.com/safing/portbase/log" - "github.com/safing/portbase/database" "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" + "github.com/safing/portbase/log" ) // Database paths: // core:profiles// // cache:profiles/index// -const ( - profilesDBPath = "core:profiles/" -) +const profilesDBPath = "core:profiles/" -var ( - profileDB = database.NewInterface(&database.Options{ - Local: true, - Internal: true, - }) -) +var profileDB = database.NewInterface(&database.Options{ + Local: true, + Internal: true, +}) func makeScopedID(source profileSource, id string) string { return string(source) + "/" + id diff --git a/profile/endpoints/endpoint-asn.go b/profile/endpoints/endpoint-asn.go index f5ababb5..fd5b11dc 100644 --- a/profile/endpoints/endpoint-asn.go +++ b/profile/endpoints/endpoint-asn.go @@ -9,9 +9,7 @@ import ( "github.com/safing/portmaster/intel" ) -var ( - asnRegex = regexp.MustCompile("^(AS)?[0-9]+$") -) +var asnRegex = regexp.MustCompile("^(AS)?[0-9]+$") // EndpointASN matches ASNs. type EndpointASN struct { diff --git a/profile/endpoints/endpoint-country.go b/profile/endpoints/endpoint-country.go index b38fe42d..ce1b0660 100644 --- a/profile/endpoints/endpoint-country.go +++ b/profile/endpoints/endpoint-country.go @@ -8,9 +8,7 @@ import ( "github.com/safing/portmaster/intel" ) -var ( - countryRegex = regexp.MustCompile(`^[A-Z]{2}$`) -) +var countryRegex = regexp.MustCompile(`^[A-Z]{2}$`) // EndpointCountry matches countries. type EndpointCountry struct { diff --git a/profile/endpoints/endpoint-domain.go b/profile/endpoints/endpoint-domain.go index 491b038d..0a8b00b6 100644 --- a/profile/endpoints/endpoint-domain.go +++ b/profile/endpoints/endpoint-domain.go @@ -17,9 +17,7 @@ const ( domainMatchTypeContains ) -var ( - allowedDomainChars = regexp.MustCompile(`^[a-z0-9\.-]+$`) -) +var allowedDomainChars = regexp.MustCompile(`^[a-z0-9\.-]+$`) // EndpointDomain matches domains. type EndpointDomain struct { diff --git a/profile/endpoints/endpoint-scopes.go b/profile/endpoints/endpoint-scopes.go index 2753c115..c969b408 100644 --- a/profile/endpoints/endpoint-scopes.go +++ b/profile/endpoints/endpoint-scopes.go @@ -4,9 +4,8 @@ import ( "context" "strings" - "github.com/safing/portmaster/network/netutils" - "github.com/safing/portmaster/intel" + "github.com/safing/portmaster/network/netutils" ) const ( @@ -50,6 +49,8 @@ func (ep *EndpointScope) Matches(_ context.Context, entity *intel.Entity) (EPRes scope = scopeLAN case netutils.GlobalMulticast: scope = scopeInternet + case netutils.Undefined, netutils.Invalid: + return NoMatch, nil } if ep.scopes&scope > 0 { diff --git a/profile/endpoints/endpoint.go b/profile/endpoints/endpoint.go index 345ac808..39f9700a 100644 --- a/profile/endpoints/endpoint.go +++ b/profile/endpoints/endpoint.go @@ -10,7 +10,7 @@ import ( "github.com/safing/portmaster/network/reference" ) -// Endpoint describes an Endpoint Matcher +// Endpoint describes an Endpoint Matcher. type Endpoint interface { Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) String() string @@ -48,7 +48,9 @@ func (ep *EndpointBase) makeReason(s fmt.Stringer, value, desc string, keyval .. key := keyval[idx] val := keyval[idx+1] - r.Extra[key.(string)] = val + if keyName, ok := key.(string); ok { + r.Extra[keyName] = val + } } return r diff --git a/profile/endpoints/endpoint_test.go b/profile/endpoints/endpoint_test.go index 21ef057e..e4dbe4ff 100644 --- a/profile/endpoints/endpoint_test.go +++ b/profile/endpoints/endpoint_test.go @@ -6,6 +6,8 @@ import ( ) func TestEndpointParsing(t *testing.T) { + t.Parallel() + // any (basics) testParsing(t, "- *") testParsing(t, "+ *") @@ -60,6 +62,8 @@ func TestEndpointParsing(t *testing.T) { } func testParsing(t *testing.T, value string) { + t.Helper() + ep, err := parseEndpoint(value) if err != nil { t.Error(err) @@ -71,6 +75,8 @@ func testParsing(t *testing.T, value string) { } func testDomainParsing(t *testing.T, value string, matchType uint8, matchValue string) { + t.Helper() + testParsing(t, value) epGeneric, err := parseTypeDomain(strings.Fields(value)) @@ -78,7 +84,7 @@ func testDomainParsing(t *testing.T, value string, matchType uint8, matchValue s t.Error(err) return } - ep := epGeneric.(*EndpointDomain) + ep := epGeneric.(*EndpointDomain) //nolint:forcetypeassert if ep.MatchType != matchType { t.Errorf(`error parsing domain endpoint "%s": match type should be %d, was %d`, value, matchType, ep.MatchType) diff --git a/profile/endpoints/endpoints.go b/profile/endpoints/endpoints.go index d4eada23..1f158017 100644 --- a/profile/endpoints/endpoints.go +++ b/profile/endpoints/endpoints.go @@ -11,10 +11,10 @@ import ( // Endpoints is a list of permitted or denied endpoints. type Endpoints []Endpoint -// EPResult represents the result of a check against an EndpointPermission +// EPResult represents the result of a check against an EndpointPermission. type EPResult uint8 -// Endpoint matching return values +// Endpoint matching return values. const ( NoMatch EPResult = iota MatchError @@ -50,7 +50,7 @@ entriesLoop: if firstErr != nil { if errCnt > 0 { - return endpoints, fmt.Errorf("encountered %d errors, first was: %s", errCnt, firstErr) + return endpoints, fmt.Errorf("encountered %d errors, first was: %w", errCnt, firstErr) } return endpoints, firstErr } diff --git a/profile/endpoints/endpoints_test.go b/profile/endpoints/endpoints_test.go index 437efc1b..d4093dc0 100644 --- a/profile/endpoints/endpoints_test.go +++ b/profile/endpoints/endpoints_test.go @@ -17,6 +17,8 @@ func TestMain(m *testing.M) { } func testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expectedResult EPResult) { + t.Helper() + entity.SetDstPort(entity.Port) result, _ := ep.Matches(context.TODO(), entity) @@ -33,6 +35,8 @@ func testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expected } func testFormat(t *testing.T, endpoint string, shouldSucceed bool) { + t.Helper() + _, err := parseEndpoint(endpoint) if shouldSucceed { assert.NoError(t, err) @@ -42,6 +46,8 @@ func testFormat(t *testing.T, endpoint string, shouldSucceed bool) { } func TestEndpointFormat(t *testing.T) { + t.Parallel() + testFormat(t, "+ .", false) testFormat(t, "+ .at", true) testFormat(t, "+ .at.", true) @@ -57,7 +63,9 @@ func TestEndpointFormat(t *testing.T) { testFormat(t, "+ *.sub..and.prefix.*", false) } -func TestEndpointMatching(t *testing.T) { +func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO + t.Parallel() + // ANY ep, err := parseEndpoint("+ *") @@ -258,7 +266,7 @@ func TestEndpointMatching(t *testing.T) { }).Init(), Permitted) testEndpointMatch(t, ep, (&intel.Entity{ Domain: "example.com.", - }).Init(), Undeterminable) + }).Init(), NoMatch) // ports @@ -289,7 +297,7 @@ func TestEndpointMatching(t *testing.T) { testEndpointMatch(t, ep, (&intel.Entity{ Domain: "example.com.", - }).Init(), Undeterminable) + }).Init(), NoMatch) // IP @@ -326,7 +334,7 @@ func TestEndpointMatching(t *testing.T) { testEndpointMatch(t, ep, (&intel.Entity{ Domain: "example.com.", - }).Init(), Undeterminable) + }).Init(), NoMatch) // IP Range @@ -346,17 +354,18 @@ func TestEndpointMatching(t *testing.T) { // ASN - ep, err = parseEndpoint("+ AS13335") + ep, err = parseEndpoint("+ AS15169") if err != nil { t.Fatal(err) } - testEndpointMatch(t, ep, (&intel.Entity{ - IP: net.ParseIP("1.1.1.2"), - }).Init(), Permitted) - testEndpointMatch(t, ep, (&intel.Entity{ - IP: net.ParseIP("8.8.8.8"), - }).Init(), NoMatch) + entity = &intel.Entity{} + entity.SetIP(net.ParseIP("8.8.8.8")) + testEndpointMatch(t, ep, entity, Permitted) + + entity = &intel.Entity{} + entity.SetIP(net.ParseIP("1.1.1.1")) + testEndpointMatch(t, ep, entity, NoMatch) // Country @@ -365,12 +374,13 @@ func TestEndpointMatching(t *testing.T) { t.Fatal(err) } - testEndpointMatch(t, ep, (&intel.Entity{ - IP: net.ParseIP("194.232.104.1"), // orf.at - }).Init(), Permitted) - testEndpointMatch(t, ep, (&intel.Entity{ - IP: net.ParseIP("151.101.1.164"), // nytimes.com - }).Init(), NoMatch) + entity = &intel.Entity{} + entity.SetIP(net.ParseIP("194.232.104.1")) // orf.at + testEndpointMatch(t, ep, entity, Permitted) + + entity = &intel.Entity{} + entity.SetIP(net.ParseIP("151.101.1.164")) // nytimes.com + testEndpointMatch(t, ep, entity, NoMatch) // Scope @@ -391,8 +401,8 @@ func TestEndpointMatching(t *testing.T) { if err != nil { t.Fatal(err) } - // TODO: write test for lists matcher + // TODO: write test for lists matcher } func getLineNumberOfCaller(levels int) int { diff --git a/profile/fingerprint/const.go b/profile/fingerprint/const.go index 72edcce3..02a0877a 100644 --- a/profile/fingerprint/const.go +++ b/profile/fingerprint/const.go @@ -1,6 +1,6 @@ package profile -// Platform identifiers +// Platform identifiers. const ( PlatformLinux = "linux" PlatformWindows = "windows" diff --git a/profile/fingerprint/const_darwin.go b/profile/fingerprint/const_darwin.go index 5654364a..7ce48800 100644 --- a/profile/fingerprint/const_darwin.go +++ b/profile/fingerprint/const_darwin.go @@ -1,6 +1,6 @@ package profile -// OS Identifier +// OS Identifier. const ( osIdentifier = PlatformMac ) diff --git a/profile/fingerprint/const_linux.go b/profile/fingerprint/const_linux.go index 0b8f8874..795b2ce5 100644 --- a/profile/fingerprint/const_linux.go +++ b/profile/fingerprint/const_linux.go @@ -1,6 +1,6 @@ package profile -// OS Identifier +// OS Identifier. const ( osIdentifier = PlatformLinux ) diff --git a/profile/fingerprint/const_openbsd.go b/profile/fingerprint/const_openbsd.go index 54ed4186..cfe2947c 100644 --- a/profile/fingerprint/const_openbsd.go +++ b/profile/fingerprint/const_openbsd.go @@ -1,6 +1,6 @@ package profile -// OS Identifier +// OS Identifier. const ( osIdentifier = PlatformOpenBSD ) diff --git a/profile/fingerprint/const_windows.go b/profile/fingerprint/const_windows.go index e4479c63..d5d33966 100644 --- a/profile/fingerprint/const_windows.go +++ b/profile/fingerprint/const_windows.go @@ -1,6 +1,6 @@ package profile -// OS Identifier +// OS Identifier. const ( osIdentifier = PlatformWindows ) diff --git a/profile/fingerprint/fingerprint.go b/profile/fingerprint/fingerprint.go index 7d7d4bde..0ee38f72 100644 --- a/profile/fingerprint/fingerprint.go +++ b/profile/fingerprint/fingerprint.go @@ -1,14 +1,12 @@ package profile -var ( - fingerprintWeights = map[string]int{ - "full_path": 2, - "partial_path": 1, - "md5_sum": 4, - "sha1_sum": 5, - "sha256_sum": 6, - } -) +var fingerprintWeights = map[string]int{ + "full_path": 2, + "partial_path": 1, + "md5_sum": 4, + "sha1_sum": 5, + "sha256_sum": 6, +} // Fingerprint links processes to profiles. type Fingerprint struct { diff --git a/profile/fingerprint/identifier_linux.go b/profile/fingerprint/identifier_linux.go index 3e6ffc96..dfa28eb1 100644 --- a/profile/fingerprint/identifier_linux.go +++ b/profile/fingerprint/identifier_linux.go @@ -7,7 +7,7 @@ import ( "github.com/safing/portbase/utils" ) -// GetPathIdentifier returns the identifier from the given path +// GetPathIdentifier returns the identifier from the given path. func GetPathIdentifier(path string) string { // clean path // TODO: is this necessary? diff --git a/profile/fingerprint/identifier_linux_test.go b/profile/fingerprint/identifier_linux_test.go index 65c2c1e0..a9ae09d4 100644 --- a/profile/fingerprint/identifier_linux_test.go +++ b/profile/fingerprint/identifier_linux_test.go @@ -3,6 +3,8 @@ package profile import "testing" func testPathID(t *testing.T, execPath, identifierPath string) { + t.Helper() + result := GetPathIdentifier(execPath) if result != identifierPath { t.Errorf("unexpected identifier path for %s: got %s, expected %s", execPath, result, identifierPath) @@ -10,6 +12,8 @@ func testPathID(t *testing.T, execPath, identifierPath string) { } func TestGetPathIdentifier(t *testing.T) { + t.Parallel() + testPathID(t, "/bin/bash", "bin/bash") testPathID(t, "/home/user/bin/bash", "bin/bash") testPathID(t, "/home/user/project/main", "project/main") diff --git a/profile/get.go b/profile/get.go index f5634be9..de4c25e8 100644 --- a/profile/get.go +++ b/profile/get.go @@ -5,7 +5,6 @@ import ( "sync" "github.com/safing/portbase/database" - "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" diff --git a/profile/migrations.go b/profile/migrations.go index 9024766a..a28baf7e 100644 --- a/profile/migrations.go +++ b/profile/migrations.go @@ -4,6 +4,7 @@ import ( "context" "github.com/hashicorp/go-version" + "github.com/safing/portbase/config" "github.com/safing/portbase/database" "github.com/safing/portbase/database/migration" @@ -21,7 +22,7 @@ func registerMigrations() error { ) } -func migrateNetworkRatingSystem(ctx context.Context, _, _ *version.Version, db *database.Interface) error { +func migrateNetworkRatingSystem(ctx context.Context, _, to *version.Version, db *database.Interface) error { // determine the default value for the network rating system by searching for // a global security level setting that is not set to the default. networkRatingEnabled := false @@ -32,7 +33,8 @@ func migrateNetworkRatingSystem(ctx context.Context, _, _ *version.Version, db * } intValue := config.Concurrent.GetAsInt(cfgkey, 0)() - if def.DefaultValue.(uint8) != uint8(intValue) { + defaultValue, ok := def.DefaultValue.(uint8) + if ok && defaultValue != uint8(intValue) { log.Tracer(ctx).Infof("found global security level setting with changed value. 0x%2x (default) != 0x%2x (current)", def.DefaultValue, intValue) networkRatingEnabled = true break @@ -40,7 +42,10 @@ func migrateNetworkRatingSystem(ctx context.Context, _, _ *version.Version, db * } if networkRatingEnabled { - status.SetNetworkRating(networkRatingEnabled) + err := status.SetNetworkRating(networkRatingEnabled) + if err != nil { + log.Warningf("profile: migration to %s failed to set network rating level to %v", to, networkRatingEnabled) + } } return nil diff --git a/profile/module.go b/profile/module.go index 668903f2..da479663 100644 --- a/profile/module.go +++ b/profile/module.go @@ -6,10 +6,10 @@ import ( "github.com/safing/portbase/database/migration" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" - "github.com/safing/portmaster/updates" - // module dependencies + // Dependency. _ "github.com/safing/portmaster/core/base" + "github.com/safing/portmaster/updates" ) var ( diff --git a/profile/profile-layered-provider.go b/profile/profile-layered-provider.go index 625a2d31..91378a40 100644 --- a/profile/profile-layered-provider.go +++ b/profile/profile-layered-provider.go @@ -24,7 +24,6 @@ func registerRevisionProvider() error { revisionProviderPrefix, runtime.SimpleValueGetterFunc(getRevisions), ) - if err != nil { return err } diff --git a/profile/profile-layered.go b/profile/profile-layered.go index ef40c7fc..e3747245 100644 --- a/profile/profile-layered.go +++ b/profile/profile-layered.go @@ -5,15 +5,13 @@ import ( "sync" "sync/atomic" + "github.com/safing/portbase/config" "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" "github.com/safing/portbase/runtime" - - "github.com/safing/portmaster/status" - - "github.com/safing/portbase/config" "github.com/safing/portmaster/intel" "github.com/safing/portmaster/profile/endpoints" + "github.com/safing/portmaster/status" ) // LayeredProfile combines multiple Profiles. @@ -56,7 +54,7 @@ type LayeredProfile struct { func NewLayeredProfile(localProfile *Profile) *LayeredProfile { var securityLevelVal uint32 - new := &LayeredProfile{ + lp := &LayeredProfile{ localProfile: localProfile, layers: make([]*Profile, 0, len(localProfile.LinkedProfiles)+1), LayerIDs: make([]string, 0, len(localProfile.LinkedProfiles)+1), @@ -65,76 +63,76 @@ func NewLayeredProfile(localProfile *Profile) *LayeredProfile { securityLevel: &securityLevelVal, } - new.DisableAutoPermit = new.wrapSecurityLevelOption( + lp.DisableAutoPermit = lp.wrapSecurityLevelOption( CfgOptionDisableAutoPermitKey, cfgOptionDisableAutoPermit, ) - new.BlockScopeLocal = new.wrapSecurityLevelOption( + lp.BlockScopeLocal = lp.wrapSecurityLevelOption( CfgOptionBlockScopeLocalKey, cfgOptionBlockScopeLocal, ) - new.BlockScopeLAN = new.wrapSecurityLevelOption( + lp.BlockScopeLAN = lp.wrapSecurityLevelOption( CfgOptionBlockScopeLANKey, cfgOptionBlockScopeLAN, ) - new.BlockScopeInternet = new.wrapSecurityLevelOption( + lp.BlockScopeInternet = lp.wrapSecurityLevelOption( CfgOptionBlockScopeInternetKey, cfgOptionBlockScopeInternet, ) - new.BlockP2P = new.wrapSecurityLevelOption( + lp.BlockP2P = lp.wrapSecurityLevelOption( CfgOptionBlockP2PKey, cfgOptionBlockP2P, ) - new.BlockInbound = new.wrapSecurityLevelOption( + lp.BlockInbound = lp.wrapSecurityLevelOption( CfgOptionBlockInboundKey, cfgOptionBlockInbound, ) - new.RemoveOutOfScopeDNS = new.wrapSecurityLevelOption( + lp.RemoveOutOfScopeDNS = lp.wrapSecurityLevelOption( CfgOptionRemoveOutOfScopeDNSKey, cfgOptionRemoveOutOfScopeDNS, ) - new.RemoveBlockedDNS = new.wrapSecurityLevelOption( + lp.RemoveBlockedDNS = lp.wrapSecurityLevelOption( CfgOptionRemoveBlockedDNSKey, cfgOptionRemoveBlockedDNS, ) - new.FilterSubDomains = new.wrapSecurityLevelOption( + lp.FilterSubDomains = lp.wrapSecurityLevelOption( CfgOptionFilterSubDomainsKey, cfgOptionFilterSubDomains, ) - new.FilterCNAMEs = new.wrapSecurityLevelOption( + lp.FilterCNAMEs = lp.wrapSecurityLevelOption( CfgOptionFilterCNAMEKey, cfgOptionFilterCNAME, ) - new.PreventBypassing = new.wrapSecurityLevelOption( + lp.PreventBypassing = lp.wrapSecurityLevelOption( CfgOptionPreventBypassingKey, cfgOptionPreventBypassing, ) - new.DomainHeuristics = new.wrapSecurityLevelOption( + lp.DomainHeuristics = lp.wrapSecurityLevelOption( CfgOptionDomainHeuristicsKey, cfgOptionDomainHeuristics, ) - new.UseSPN = new.wrapBoolOption( + lp.UseSPN = lp.wrapBoolOption( CfgOptionUseSPNKey, cfgOptionUseSPN, ) - new.LayerIDs = append(new.LayerIDs, localProfile.ScopedID()) - new.layers = append(new.layers, localProfile) + lp.LayerIDs = append(lp.LayerIDs, localProfile.ScopedID()) + lp.layers = append(lp.layers, localProfile) // TODO: Load additional profiles. - new.updateCaches() + lp.updateCaches() - new.CreateMeta() - new.SetKey(runtime.DefaultRegistry.DatabaseName() + ":" + revisionProviderPrefix + localProfile.ScopedID()) + lp.CreateMeta() + lp.SetKey(runtime.DefaultRegistry.DatabaseName() + ":" + revisionProviderPrefix + localProfile.ScopedID()) // Inform database subscribers about the new layered profile. - new.Lock() - defer new.Unlock() + lp.Lock() + defer lp.Unlock() - pushLayeredProfile(new) + pushLayeredProfile(lp) - return new + return lp } // LockForUsage locks the layered profile, including all layers individually. @@ -167,7 +165,7 @@ func (lp *LayeredProfile) LocalProfile() *Profile { // increaseRevisionCounter increases the revision counter and pushes the // layered profile to listeners. -func (lp *LayeredProfile) increaseRevisionCounter(lock bool) (revisionCounter uint64) { +func (lp *LayeredProfile) increaseRevisionCounter(lock bool) (revisionCounter uint64) { //nolint:unparam // This is documentation. if lp == nil { return 0 } diff --git a/profile/profile.go b/profile/profile.go index d96d1610..cb8af6b3 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -21,14 +21,10 @@ import ( "github.com/safing/portmaster/profile/endpoints" ) -var ( - lastUsedUpdateThreshold = 24 * time.Hour -) - // profileSource is the source of the profile. type profileSource string -// Profile Sources +// Profile Sources. const ( SourceLocal profileSource = "local" // local, editable SourceSpecial profileSource = "special" // specials (read-only) @@ -37,7 +33,7 @@ const ( SourceEnterprise profileSource = "enterprise" ) -// Default Action IDs +// Default Action IDs. const ( DefaultActionNotSet uint8 = 0 DefaultActionBlock uint8 = 1 @@ -266,7 +262,7 @@ func (profile *Profile) makeKey() { profile.SetKey(makeProfileKey(profile.Source, profile.ID)) } -// Save saves the profile to the database +// Save saves the profile to the database. func (profile *Profile) Save() error { if profile.ID == "" { return errors.New("profile: tried to save profile without ID") @@ -414,20 +410,20 @@ func EnsureProfile(r record.Record) (*Profile, error) { // unwrap if r.IsWrapped() { // only allocate a new struct, if we need it - new := &Profile{} - err := record.Unwrap(r, new) + newProfile := &Profile{} + err := record.Unwrap(r, newProfile) if err != nil { return nil, err } - return new, nil + return newProfile, nil } // or adjust type - new, ok := r.(*Profile) + newProfile, ok := r.(*Profile) if !ok { return nil, fmt.Errorf("record not of type *Profile, but %T", r) } - return new, nil + return newProfile, nil } // UpdateMetadata updates meta data fields on the profile and returns whether diff --git a/resolver/block-detection.go b/resolver/block-detection.go index 8a4005cd..24cef29d 100644 --- a/resolver/block-detection.go +++ b/resolver/block-detection.go @@ -6,7 +6,7 @@ import ( "github.com/miekg/dns" ) -// Supported upstream block detections +// Supported upstream block detections. const ( BlockDetectionRefused = "refused" BlockDetectionZeroIP = "zeroip" diff --git a/resolver/config.go b/resolver/config.go index f8d24cdf..069ce0dd 100644 --- a/resolver/config.go +++ b/resolver/config.go @@ -9,7 +9,7 @@ import ( "github.com/safing/portmaster/status" ) -// Configuration Keys +// Configuration Keys. var ( defaultNameServers = []string{ // Collection of default DNS Servers diff --git a/resolver/ipinfo.go b/resolver/ipinfo.go index ff48dbde..58bfc98a 100644 --- a/resolver/ipinfo.go +++ b/resolver/ipinfo.go @@ -14,21 +14,19 @@ const ( IPInfoProfileScopeGlobal = "global" ) -var ( - ipInfoDatabase = database.NewInterface(&database.Options{ - Local: true, - Internal: true, +var ipInfoDatabase = database.NewInterface(&database.Options{ + Local: true, + Internal: true, - // Cache entries because new/updated entries will often be queries soon - // after inserted. - CacheSize: 256, + // Cache entries because new/updated entries will often be queries soon + // after inserted. + CacheSize: 256, - // We only use the cache database here, so we can delay and batch all our - // writes. Also, no one else accesses these records, so we are fine using - // this. - DelayCachedWrites: "cache", - }) -) + // We only use the cache database here, so we can delay and batch all our + // writes. Also, no one else accesses these records, so we are fine using + // this. + DelayCachedWrites: "cache", +}) // ResolvedDomain holds a Domain name and a list of // CNAMES that have been resolved. @@ -54,7 +52,7 @@ type ResolvedDomain struct { } // String returns a string representation of ResolvedDomain including -// the CNAME chain. It implements fmt.Stringer +// the CNAME chain. It implements fmt.Stringer. func (resolved *ResolvedDomain) String() string { ret := resolved.Domain cnames := "" @@ -67,7 +65,7 @@ func (resolved *ResolvedDomain) String() string { } // ResolvedDomains is a helper type for operating on a slice -// of ResolvedDomain +// of ResolvedDomain. type ResolvedDomains []ResolvedDomain // String returns a string representation of all domains joined @@ -141,21 +139,21 @@ func GetIPInfo(profileID, ip string) (*IPInfo, error) { // unwrap if r.IsWrapped() { // only allocate a new struct, if we need it - new := &IPInfo{} - err = record.Unwrap(r, new) + newInfo := &IPInfo{} + err = record.Unwrap(r, newInfo) if err != nil { return nil, err } - return new, nil + return newInfo, nil } // or adjust type - new, ok := r.(*IPInfo) + newInfo, ok := r.(*IPInfo) if !ok { return nil, fmt.Errorf("record not of type *IPInfo, but %T", r) } - return new, nil + return newInfo, nil } // Save saves the IPInfo record to the database. @@ -187,7 +185,7 @@ func (info *IPInfo) Save() error { return ipInfoDatabase.Put(info) } -// FmtDomains returns a string consisting of the domains that have seen to use this IP, joined by " or " +// String returns a string consisting of the domains that have seen to use this IP. func (info *IPInfo) String() string { info.Lock() defer info.Unlock() diff --git a/resolver/ipinfo_test.go b/resolver/ipinfo_test.go index 759d0fed..61740c4d 100644 --- a/resolver/ipinfo_test.go +++ b/resolver/ipinfo_test.go @@ -7,6 +7,8 @@ import ( ) func TestIPInfo(t *testing.T) { + t.Parallel() + example := ResolvedDomain{ Domain: "example.com.", } diff --git a/resolver/main.go b/resolver/main.go index fa4d93be..8692397e 100644 --- a/resolver/main.go +++ b/resolver/main.go @@ -8,20 +8,19 @@ import ( "sync" "time" + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portbase/notifications" "github.com/safing/portbase/utils/debug" - "github.com/safing/portmaster/intel" - "github.com/tevino/abool" - // module dependencies + // Dependency. _ "github.com/safing/portmaster/core/base" + "github.com/safing/portmaster/intel" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register("resolver", prep, start, nil, "base", "netenv") @@ -93,9 +92,7 @@ func start() error { return nil } -var ( - localAddrFactory func(network string) net.Addr -) +var localAddrFactory func(network string) net.Addr // SetLocalAddrFactory supplies the intel package with a function to get permitted local addresses for connections. func SetLocalAddrFactory(laf func(network string) net.Addr) { diff --git a/resolver/main_test.go b/resolver/main_test.go index 5d4862f8..57168227 100644 --- a/resolver/main_test.go +++ b/resolver/main_test.go @@ -6,9 +6,7 @@ import ( "github.com/safing/portmaster/core/pmtesting" ) -var ( - domainFeed = make(chan string) -) +var domainFeed = make(chan string) func TestMain(m *testing.M) { pmtesting.TestMain(m, module) @@ -28,106 +26,104 @@ func feedDomains() { // Data -var ( - testDomains = []string{ - "facebook.com.", - "google.com.", - "youtube.com.", - "twitter.com.", - "instagram.com.", - "linkedin.com.", - "microsoft.com.", - "apple.com.", - "wikipedia.org.", - "plus.google.com.", - "en.wikipedia.org.", - "googletagmanager.com.", - "youtu.be.", - "adobe.com.", - "vimeo.com.", - "pinterest.com.", - "itunes.apple.com.", - "play.google.com.", - "maps.google.com.", - "goo.gl.", - "wordpress.com.", - "blogspot.com.", - "bit.ly.", - "github.com.", - "player.vimeo.com.", - "amazon.com.", - "wordpress.org.", - "docs.google.com.", - "yahoo.com.", - "mozilla.org.", - "tumblr.com.", - "godaddy.com.", - "flickr.com.", - "parked-content.godaddy.com.", - "drive.google.com.", - "support.google.com.", - "apache.org.", - "gravatar.com.", - "europa.eu.", - "qq.com.", - "w3.org.", - "nytimes.com.", - "reddit.com.", - "macromedia.com.", - "get.adobe.com.", - "soundcloud.com.", - "sourceforge.net.", - "sites.google.com.", - "nih.gov.", - "amazonaws.com.", - "t.co.", - "support.microsoft.com.", - "forbes.com.", - "theguardian.com.", - "cnn.com.", - "github.io.", - "bbc.co.uk.", - "dropbox.com.", - "whatsapp.com.", - "medium.com.", - "creativecommons.org.", - "www.ncbi.nlm.nih.gov.", - "httpd.apache.org.", - "archive.org.", - "ec.europa.eu.", - "php.net.", - "apps.apple.com.", - "weebly.com.", - "support.apple.com.", - "weibo.com.", - "wixsite.com.", - "issuu.com.", - "who.int.", - "paypal.com.", - "m.facebook.com.", - "oracle.com.", - "msn.com.", - "gnu.org.", - "tinyurl.com.", - "reuters.com.", - "l.facebook.com.", - "cloudflare.com.", - "wsj.com.", - "washingtonpost.com.", - "domainmarket.com.", - "imdb.com.", - "bbc.com.", - "bing.com.", - "accounts.google.com.", - "vk.com.", - "api.whatsapp.com.", - "opera.com.", - "cdc.gov.", - "slideshare.net.", - "wpa.qq.com.", - "harvard.edu.", - "mit.edu.", - "code.google.com.", - "wikimedia.org.", - } -) +var testDomains = []string{ + "facebook.com.", + "google.com.", + "youtube.com.", + "twitter.com.", + "instagram.com.", + "linkedin.com.", + "microsoft.com.", + "apple.com.", + "wikipedia.org.", + "plus.google.com.", + "en.wikipedia.org.", + "googletagmanager.com.", + "youtu.be.", + "adobe.com.", + "vimeo.com.", + "pinterest.com.", + "itunes.apple.com.", + "play.google.com.", + "maps.google.com.", + "goo.gl.", + "wordpress.com.", + "blogspot.com.", + "bit.ly.", + "github.com.", + "player.vimeo.com.", + "amazon.com.", + "wordpress.org.", + "docs.google.com.", + "yahoo.com.", + "mozilla.org.", + "tumblr.com.", + "godaddy.com.", + "flickr.com.", + "parked-content.godaddy.com.", + "drive.google.com.", + "support.google.com.", + "apache.org.", + "gravatar.com.", + "europa.eu.", + "qq.com.", + "w3.org.", + "nytimes.com.", + "reddit.com.", + "macromedia.com.", + "get.adobe.com.", + "soundcloud.com.", + "sourceforge.net.", + "sites.google.com.", + "nih.gov.", + "amazonaws.com.", + "t.co.", + "support.microsoft.com.", + "forbes.com.", + "theguardian.com.", + "cnn.com.", + "github.io.", + "bbc.co.uk.", + "dropbox.com.", + "whatsapp.com.", + "medium.com.", + "creativecommons.org.", + "www.ncbi.nlm.nih.gov.", + "httpd.apache.org.", + "archive.org.", + "ec.europa.eu.", + "php.net.", + "apps.apple.com.", + "weebly.com.", + "support.apple.com.", + "weibo.com.", + "wixsite.com.", + "issuu.com.", + "who.int.", + "paypal.com.", + "m.facebook.com.", + "oracle.com.", + "msn.com.", + "gnu.org.", + "tinyurl.com.", + "reuters.com.", + "l.facebook.com.", + "cloudflare.com.", + "wsj.com.", + "washingtonpost.com.", + "domainmarket.com.", + "imdb.com.", + "bbc.com.", + "bing.com.", + "accounts.google.com.", + "vk.com.", + "api.whatsapp.com.", + "opera.com.", + "cdc.gov.", + "slideshare.net.", + "wpa.qq.com.", + "harvard.edu.", + "mit.edu.", + "code.google.com.", + "wikimedia.org.", +} diff --git a/resolver/namerecord.go b/resolver/namerecord.go index 68d6055f..8e4841f2 100644 --- a/resolver/namerecord.go +++ b/resolver/namerecord.go @@ -1,7 +1,6 @@ package resolver import ( - "context" "errors" "fmt" "sync" @@ -81,30 +80,30 @@ func GetNameRecord(domain, question string) (*NameRecord, error) { // Unwrap record if it's wrapped. if r.IsWrapped() { // only allocate a new struct, if we need it - new := &NameRecord{} - err = record.Unwrap(r, new) + newNR := &NameRecord{} + err = record.Unwrap(r, newNR) if err != nil { return nil, err } // Check if the record is valid. - if !new.IsValid() { + if !newNR.IsValid() { return nil, errors.New("record is invalid (outdated format)") } - return new, nil + return newNR, nil } // Or just adjust the type. - new, ok := r.(*NameRecord) + newNR, ok := r.(*NameRecord) if !ok { return nil, fmt.Errorf("record not of type *NameRecord, but %T", r) } // Check if the record is valid. - if !new.IsValid() { + if !newNR.IsValid() { return nil, errors.New("record is invalid (outdated format)") } - return new, nil + return newNR, nil } // ResetCachedRecord deletes a NameRecord from the cache database. @@ -118,16 +117,16 @@ func ResetCachedRecord(domain, question string) error { } // Save saves the NameRecord to the database. -func (rec *NameRecord) Save() error { - if rec.Domain == "" || rec.Question == "" { +func (nameRecord *NameRecord) Save() error { + if nameRecord.Domain == "" || nameRecord.Question == "" { return errors.New("could not save NameRecord, missing Domain and/or Question") } - rec.SetKey(makeNameRecordKey(rec.Domain, rec.Question)) - rec.UpdateMeta() - rec.Meta().SetAbsoluteExpiry(rec.Expires + databaseOvertime) + nameRecord.SetKey(makeNameRecordKey(nameRecord.Domain, nameRecord.Question)) + nameRecord.UpdateMeta() + nameRecord.Meta().SetAbsoluteExpiry(nameRecord.Expires + databaseOvertime) - return recordDatabase.PutNew(rec) + return recordDatabase.PutNew(nameRecord) } // clearNameCache clears all dns caches from the database. @@ -144,18 +143,3 @@ func clearNameCache(ar *api.Request) (msg string, err error) { log.Debugf("resolver: cleared %d entries from dns cache", n) return fmt.Sprintf("cleared %d dns cache entries", n), nil } - -// DEPRECATED: remove in v0.7 -func clearNameCacheEventHandler(ctx context.Context, _ interface{}) error { - log.Debugf("resolver: dns cache clearing started...") - - recordDatabase.FlushCache() - recordDatabase.ClearCache() - n, err := recordDatabase.Purge(ctx, query.New(nameRecordsKeyPrefix)) - if err != nil { - return err - } - - log.Debugf("resolver: cleared %d entries from dns cache", n) - return nil -} diff --git a/resolver/namerecord_test.go b/resolver/namerecord_test.go index 8149fa64..15bc5ff7 100644 --- a/resolver/namerecord_test.go +++ b/resolver/namerecord_test.go @@ -3,6 +3,8 @@ package resolver import "testing" func TestNameRecordStorage(t *testing.T) { + t.Parallel() + testDomain := "Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com." testQuestion := "A" diff --git a/resolver/resolve.go b/resolver/resolve.go index 0206e09d..8663a32e 100644 --- a/resolver/resolve.go +++ b/resolver/resolve.go @@ -14,35 +14,36 @@ import ( "github.com/safing/portmaster/netenv" ) +// Errors. var ( - // basic errors + // Basic Errors. - // ErrNotFound is a basic error that will match all "not found" errors + // ErrNotFound is a basic error that will match all "not found" errors. ErrNotFound = errors.New("record could not be found") - // ErrBlocked is basic error that will match all "blocked" errors + // ErrBlocked is basic error that will match all "blocked" errors. ErrBlocked = errors.New("query was blocked") - // ErrLocalhost is returned to *.localhost queries + // ErrLocalhost is returned to *.localhost queries. ErrLocalhost = errors.New("query for localhost") - // ErrTimeout is returned when a query times out + // ErrTimeout is returned when a query times out. ErrTimeout = errors.New("query timed out") - // ErrOffline is returned when no network connection is detected + // ErrOffline is returned when no network connection is detected. ErrOffline = errors.New("device is offine") - // ErrFailure is returned when the type of failure is unclear + // ErrFailure is returned when the type of failure is unclear. ErrFailure = errors.New("query failed") - // ErrContinue is returned when the resolver has no answer, and the next resolver should be asked + // ErrContinue is returned when the resolver has no answer, and the next resolver should be asked. ErrContinue = errors.New("resolver has no answer") // ErrShuttingDown is returned when the resolver is shutting down. ErrShuttingDown = errors.New("resolver is shutting down") - // detailed errors + // Detailed Errors. - // ErrTestDomainsDisabled wraps ErrBlocked + // ErrTestDomainsDisabled wraps ErrBlocked. ErrTestDomainsDisabled = fmt.Errorf("%w: test domains disabled", ErrBlocked) - // ErrSpecialDomainsDisabled wraps ErrBlocked + // ErrSpecialDomainsDisabled wraps ErrBlocked. ErrSpecialDomainsDisabled = fmt.Errorf("%w: special domains disabled", ErrBlocked) - // ErrInvalid wraps ErrNotFound + // ErrInvalid wraps ErrNotFound. ErrInvalid = fmt.Errorf("%w: invalid request", ErrNotFound) - // ErrNoCompliance wraps ErrBlocked and is returned when no resolvers were able to comply with the current settings + // ErrNoCompliance wraps ErrBlocked and is returned when no resolvers were able to comply with the current settings. ErrNoCompliance = fmt.Errorf("%w: no compliant resolvers for this query", ErrBlocked) ) @@ -74,7 +75,7 @@ func (blocked *BlockedUpstreamError) Error() string { return fmt.Sprintf("%s by upstream DNS resolver %s", ErrBlocked, blocked.ResolverName) } -// Unwrap implements errors.Unwrapper +// Unwrap implements errors.Unwrapper. func (blocked *BlockedUpstreamError) Unwrap() error { return ErrBlocked } @@ -166,10 +167,9 @@ func checkCache(ctx context.Context, q *Query) *RRCache { // Get data from cache. rrCache, err := GetRRCache(q.FQDN, q.QType) - // Return if entry is not in cache. if err != nil { - if err != database.ErrNotFound { + if !errors.Is(err, database.ErrNotFound) { log.Tracer(ctx).Warningf("resolver: getting RRCache %s%s from database failed: %s", q.FQDN, q.QType.String(), err) } return nil @@ -403,7 +403,7 @@ resolveLoop: if err != nil { // tried all resolvers, possibly twice if i > 1 { - err = fmt.Errorf("all %d query-compliant resolvers failed, last error: %s", len(resolvers), err) + err = fmt.Errorf("all %d query-compliant resolvers failed, last error: %w", len(resolvers), err) if primarySource == ServerSourceConfigured && netenv.Online() && CompatSelfCheckIsFailing() { diff --git a/resolver/resolver-env.go b/resolver/resolver-env.go index 79142de2..18acfba4 100644 --- a/resolver/resolver-env.go +++ b/resolver/resolver-env.go @@ -7,12 +7,14 @@ import ( "strings" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/netutils" ) const ( + // InternalSpecialUseDomain is the domain scope used for internal services. InternalSpecialUseDomain = "portmaster.home.arpa." routerDomain = "router.local." + InternalSpecialUseDomain @@ -91,8 +93,7 @@ func (er *envResolverConn) Query(ctx context.Context, q *Query) (*RRCache, error } // Check for suffix matches. - switch { - case strings.HasSuffix(q.FQDN, CompatDNSCheckInternalDomainScope): + if strings.HasSuffix(q.FQDN, CompatDNSCheckInternalDomainScope) { subdomain := strings.TrimSuffix(q.FQDN, CompatDNSCheckInternalDomainScope) respondWith := CompatSubmitDNSCheckDomain(subdomain) diff --git a/resolver/resolver-mdns.go b/resolver/resolver-mdns.go index 48601386..ce0eab6d 100644 --- a/resolver/resolver-mdns.go +++ b/resolver/resolver-mdns.go @@ -10,11 +10,12 @@ import ( "time" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/network/netutils" ) -// DNS Classes +// DNS Classes. const ( DNSClassMulticast = dns.ClassINET | 1<<15 ) @@ -85,7 +86,9 @@ func listenToMDNS(ctx context.Context) error { module.StartServiceWorker("mdns udp4 multicast listener", 0, func(ctx context.Context) error { return listenForDNSPackets(ctx, multicast4Conn, messages) }) - defer multicast4Conn.Close() + defer func() { + _ = multicast4Conn.Close() + }() } multicast6Conn, err = net.ListenMulticastUDP("udp6", nil, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353}) @@ -96,7 +99,9 @@ func listenToMDNS(ctx context.Context) error { module.StartServiceWorker("mdns udp6 multicast listener", 0, func(ctx context.Context) error { return listenForDNSPackets(ctx, multicast6Conn, messages) }) - defer multicast6Conn.Close() + defer func() { + _ = multicast6Conn.Close() + }() } unicast4Conn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) @@ -107,7 +112,9 @@ func listenToMDNS(ctx context.Context) error { module.StartServiceWorker("mdns udp4 unicast listener", 0, func(ctx context.Context) error { return listenForDNSPackets(ctx, unicast4Conn, messages) }) - defer unicast4Conn.Close() + defer func() { + _ = unicast4Conn.Close() + }() } unicast6Conn, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0}) @@ -118,7 +125,9 @@ func listenToMDNS(ctx context.Context) error { module.StartServiceWorker("mdns udp6 unicast listener", 0, func(ctx context.Context) error { return listenForDNSPackets(ctx, unicast6Conn, messages) }) - defer unicast6Conn.Close() + defer func() { + _ = unicast6Conn.Close() + }() } // start message handler @@ -131,8 +140,7 @@ func listenToMDNS(ctx context.Context) error { return nil } -//nolint:gocyclo,gocognit // TODO -func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { +func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { //nolint:maintidx // TODO: Improve. for { select { case <-ctx.Done(): @@ -319,7 +327,6 @@ func handleMDNSMessages(ctx context.Context, messages chan *dns.Msg) error { cleanSavedQuestions() } - } func listenForDNSPackets(ctx context.Context, conn *net.UDPConn, messages chan *dns.Msg) error { @@ -377,30 +384,30 @@ func queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) { // pack qeury buf, err := dnsQuery.Pack() if err != nil { - return nil, fmt.Errorf("failed to pack query: %s", err) + return nil, fmt.Errorf("failed to pack query: %w", err) } // send queries if unicast4Conn != nil && uint16(q.QType) != dns.TypeAAAA { err = unicast4Conn.SetWriteDeadline(time.Now().Add(1 * time.Second)) if err != nil { - return nil, fmt.Errorf("failed to configure query (set timout): %s", err) + return nil, fmt.Errorf("failed to configure query (set timout): %w", err) } _, err = unicast4Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 251), Port: 5353}) if err != nil { - return nil, fmt.Errorf("failed to send query: %s", err) + return nil, fmt.Errorf("failed to send query: %w", err) } } if unicast6Conn != nil && uint16(q.QType) != dns.TypeA { err = unicast6Conn.SetWriteDeadline(time.Now().Add(1 * time.Second)) if err != nil { - return nil, fmt.Errorf("failed to configure query (set timout): %s", err) + return nil, fmt.Errorf("failed to configure query (set timout): %w", err) } _, err = unicast6Conn.WriteToUDP(buf, &net.UDPAddr{IP: net.IP([]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}), Port: 5353}) if err != nil { - return nil, fmt.Errorf("failed to send query: %s", err) + return nil, fmt.Errorf("failed to send query: %w", err) } } @@ -413,7 +420,7 @@ func queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) { case <-time.After(1 * time.Second): // check cache again rrCache, err := GetRRCache(q.FQDN, q.QType) - if err != nil { + if err == nil { return rrCache, nil } case <-ctx.Done(): diff --git a/resolver/resolver-plain.go b/resolver/resolver-plain.go index 024c079b..2ddcff90 100644 --- a/resolver/resolver-plain.go +++ b/resolver/resolver-plain.go @@ -2,10 +2,12 @@ package resolver import ( "context" + "errors" "net" "time" "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/netenv" ) @@ -65,7 +67,8 @@ func (pr *PlainResolver) Query(ctx context.Context, q *Query) (*RRCache, error) // error handling if err != nil { // Hint network environment at failed connection if err is not a timeout. - if nErr, ok := err.(net.Error); ok && !nErr.Timeout() { + var nErr net.Error + if errors.As(err, &nErr) && !nErr.Timeout() { netenv.ReportFailedConnection() } diff --git a/resolver/resolver-tcp.go b/resolver/resolver-tcp.go index 78968da8..cb37ec94 100644 --- a/resolver/resolver-tcp.go +++ b/resolver/resolver-tcp.go @@ -10,16 +10,16 @@ import ( "time" "github.com/miekg/dns" + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portmaster/netenv" - "github.com/tevino/abool" ) const ( tcpConnectionEstablishmentTimeout = 3 * time.Second tcpWriteTimeout = 2 * time.Second heartbeatTimeout = 5 * time.Second - ignoreQueriesAfter = 5 * time.Minute ) // TCPResolver is a resolver using just a single tcp connection with pipelining. diff --git a/resolver/resolver.go b/resolver/resolver.go index ba274550..0aaab91b 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -15,7 +15,7 @@ import ( "github.com/safing/portmaster/network/netutils" ) -// DNS Resolver Attributes +// DNS Resolver Attributes. const ( ServerTypeDNS = "dns" ServerTypeTCP = "tcp" @@ -30,10 +30,8 @@ const ( ServerSourceEnv = "env" ) -var ( - // FailThreshold is amount of errors a resolvers must experience in order to be regarded as failed. - FailThreshold = 20 -) +// FailThreshold is amount of errors a resolvers must experience in order to be regarded as failed. +var FailThreshold = 20 // Resolver holds information about an active resolver. type Resolver struct { @@ -73,7 +71,7 @@ type Resolver struct { // ResolverInfo is a subset of resolver attributes that is attached to answers // from that server in order to use it later for decision making. It must not // be changed by anyone after creation and initialization is complete. -type ResolverInfo struct { +type ResolverInfo struct { //nolint:golint,maligned // TODO // Name describes the name given to the resolver. The name is configured in the config URL using the name parameter. Name string @@ -178,7 +176,7 @@ func (resolver *Resolver) String() string { } // ResolverConn is an interface to implement different types of query backends. -type ResolverConn interface { //nolint:go-lint // TODO +type ResolverConn interface { //nolint:golint // TODO Query(ctx context.Context, q *Query) (*RRCache, error) ReportFailure() IsFailing() bool diff --git a/resolver/resolver_test.go b/resolver/resolver_test.go index 5070a248..f385e52e 100644 --- a/resolver/resolver_test.go +++ b/resolver/resolver_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "github.com/safing/portbase/log" - "github.com/miekg/dns" + + "github.com/safing/portbase/log" ) var ( @@ -27,10 +27,12 @@ func init() { } func startQuery(t *testing.T, wg *sync.WaitGroup, rc ResolverConn, q *Query) { + t.Helper() + start := time.Now() _, err := rc.Query(silencingTraceCtx, q) if err != nil { - t.Logf("client failed: %s", err) //nolint:staticcheck + t.Logf("client failed: %s", err) wg.Done() return } @@ -39,6 +41,8 @@ func startQuery(t *testing.T, wg *sync.WaitGroup, rc ResolverConn, q *Query) { } func TestSingleResolving(t *testing.T) { + t.Parallel() + // skip if short - this test depends on the Internet and might fail randomly if testing.Short() { t.Skip() @@ -48,7 +52,6 @@ func TestSingleResolving(t *testing.T) { // create separate resolver for this test resolver, _, err := createResolver(testResolver, "config") - if err != nil { t.Fatal(err) } @@ -59,7 +62,7 @@ func TestSingleResolving(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(100) for i := 0; i < 100; i++ { - startQuery(t, wg, resolver.Conn, &Query{ //nolint:staticcheck + startQuery(t, wg, resolver.Conn, &Query{ FQDN: <-domainFeed, QType: dns.Type(dns.TypeA), }) @@ -70,6 +73,8 @@ func TestSingleResolving(t *testing.T) { } func TestBulkResolving(t *testing.T) { + t.Parallel() + // skip if short - this test depends on the Internet and might fail randomly if testing.Short() { t.Skip() @@ -79,7 +84,6 @@ func TestBulkResolving(t *testing.T) { // create separate resolver for this test resolver, _, err := createResolver(testResolver, "config") - if err != nil { t.Fatal(err) } @@ -90,7 +94,7 @@ func TestBulkResolving(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(100) for i := 0; i < 100; i++ { - go startQuery(t, wg, resolver.Conn, &Query{ //nolint:staticcheck + go startQuery(t, wg, resolver.Conn, &Query{ FQDN: <-domainFeed, QType: dns.Type(dns.TypeA), }) diff --git a/resolver/resolvers.go b/resolver/resolvers.go index e6fdb814..7c26cb88 100644 --- a/resolver/resolvers.go +++ b/resolver/resolvers.go @@ -138,7 +138,7 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { return nil, false, fmt.Errorf("invalid value for upstream block detection (blockedif=)") } - new := &Resolver{ + newResolver := &Resolver{ ConfigURL: resolverURL, Info: &ResolverInfo{ Name: query.Get("name"), @@ -153,8 +153,8 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { UpstreamBlockDetection: blockType, } - new.Conn = resolverConnFactory(new) - return new, false, nil + newResolver.Conn = resolverConnFactory(newResolver) + return newResolver, false, nil } func configureSearchDomains(resolver *Resolver, searches []string) { diff --git a/resolver/resolvers_test.go b/resolver/resolvers_test.go index 93f411e3..29697440 100644 --- a/resolver/resolvers_test.go +++ b/resolver/resolvers_test.go @@ -3,8 +3,11 @@ package resolver import "testing" func TestCheckResolverSearchScope(t *testing.T) { + t.Parallel() test := func(t *testing.T, domain string, expectedResult bool) { + t.Helper() + if checkSearchScope(domain) != expectedResult { if expectedResult { t.Errorf("domain %s failed scope test", domain) diff --git a/resolver/reverse.go b/resolver/reverse.go index 88e67d3a..d6ded14d 100644 --- a/resolver/reverse.go +++ b/resolver/reverse.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/miekg/dns" + "github.com/safing/portbase/log" ) diff --git a/resolver/reverse_test.go b/resolver/reverse_test.go index b7426b9e..c6b05e71 100644 --- a/resolver/reverse_test.go +++ b/resolver/reverse_test.go @@ -8,6 +8,8 @@ import ( ) func testReverse(t *testing.T, ip, result, expectedErr string) { + t.Helper() + ctx, tracer := log.AddTracer(context.Background()) defer tracer.Submit() @@ -26,6 +28,8 @@ func testReverse(t *testing.T, ip, result, expectedErr string) { } func TestResolveIPAndValidate(t *testing.T) { + t.Parallel() + testReverse(t, "198.41.0.4", "a.root-servers.net.", "") // testReverse(t, "9.9.9.9", "dns.quad9.net.", "") // started resolving to dns9.quad9.net. // testReverse(t, "2620:fe::fe", "dns.quad9.net.", "") // fails sometimes for some (external) reason diff --git a/resolver/rrcache.go b/resolver/rrcache.go index f82b416b..c9e591c1 100644 --- a/resolver/rrcache.go +++ b/resolver/rrcache.go @@ -6,11 +6,11 @@ import ( "net" "time" + "github.com/miekg/dns" + "github.com/safing/portbase/log" "github.com/safing/portmaster/nameserver/nsutil" "github.com/safing/portmaster/netenv" - - "github.com/miekg/dns" ) // RRCache is a single-use structure to hold a DNS response. @@ -127,7 +127,7 @@ func (rrCache *RRCache) ExportAllARecords() (ips []net.IP) { // ToNameRecord converts the RRCache to a NameRecord for cleaner persistence. func (rrCache *RRCache) ToNameRecord() *NameRecord { - new := &NameRecord{ + newRecord := &NameRecord{ Domain: rrCache.Domain, Question: rrCache.Question.String(), RCode: rrCache.RCode, @@ -136,11 +136,11 @@ func (rrCache *RRCache) ToNameRecord() *NameRecord { } // Serialize RR entries to strings. - new.Answer = toNameRecordSection(rrCache.Answer) - new.Ns = toNameRecordSection(rrCache.Ns) - new.Extra = toNameRecordSection(rrCache.Extra) + newRecord.Answer = toNameRecordSection(rrCache.Answer) + newRecord.Ns = toNameRecordSection(rrCache.Ns) + newRecord.Extra = toNameRecordSection(rrCache.Extra) - return new + return newRecord } func toNameRecordSection(rrSection []dns.RR) []string { diff --git a/resolver/rrcache_test.go b/resolver/rrcache_test.go index 0d9c8413..a78df439 100644 --- a/resolver/rrcache_test.go +++ b/resolver/rrcache_test.go @@ -7,6 +7,8 @@ import ( ) func TestCaching(t *testing.T) { + t.Parallel() + testDomain := "Mk35mMqOWEHXSMk11MYcbjLOjTE8PQvDiAVUxf4BvwtgR.example.com." testQuestion := "A" diff --git a/resolver/scopes.go b/resolver/scopes.go index 4998ee5c..ee9f396e 100644 --- a/resolver/scopes.go +++ b/resolver/scopes.go @@ -5,22 +5,22 @@ import ( "errors" "strings" - "github.com/safing/portmaster/netenv" - "github.com/miekg/dns" + "github.com/safing/portbase/log" + "github.com/safing/portmaster/netenv" ) -// Domain Scopes +// Domain Scopes. var ( // Localhost Domain // Handling: Respond with 127.0.0.1 and ::1 to A and AAAA queries, respectively. - // RFC6761 + // See RFC6761. localhostDomain = ".localhost." // Invalid Domain // Handling: Always respond with NXDOMAIN. - // RFC6761 + // See RFC6761. invalidDomain = ".invalid." // Internal Special-Use Domain @@ -31,7 +31,7 @@ var ( // Multicast DNS // Handling: Send to nameservers with matching search scope, then MDNS - // RFC6762 + // See RFC6762. multicastDomains = []string{ ".local.", ".254.169.in-addr.arpa.", @@ -89,7 +89,7 @@ var ( } // Special-Service Domain Names - // Handling: Send to nameservers with matching search scope, then local and system assigned nameservers + // Handling: Send to nameservers with matching search scope, then local and system assigned nameservers. specialServiceDomains = []string{ // RFC7686: Tor Hidden Services ".onion.", diff --git a/status/config.go b/status/config.go index 26a9b4bb..4e626993 100644 --- a/status/config.go +++ b/status/config.go @@ -2,6 +2,7 @@ package status import "github.com/safing/portbase/config" +// Configuration Keys. var ( CfgEnableNetworkRatingSystemKey = "core/enableNetworkRating" cfgEnableNetworkRatingSystem config.BoolOption @@ -33,6 +34,6 @@ func NetworkRatingEnabled() bool { } // SetNetworkRating enables or disables the network rating system. -func SetNetworkRating(enabled bool) { - config.SetConfigOption(CfgEnableNetworkRatingSystemKey, enabled) +func SetNetworkRating(enabled bool) error { + return config.SetConfigOption(CfgEnableNetworkRatingSystemKey, enabled) } diff --git a/status/mitigation.go b/status/mitigation.go index bafb66d4..8157c18f 100644 --- a/status/mitigation.go +++ b/status/mitigation.go @@ -49,7 +49,7 @@ func getHighestMitigationLevel() uint8 { threats.RLock() defer threats.RUnlock() - var level uint8 = SecurityLevelNormal + level := SecurityLevelNormal for _, lvl := range threats.list { if lvl > level { level = lvl diff --git a/status/module.go b/status/module.go index c96d0e4b..28adeb41 100644 --- a/status/module.go +++ b/status/module.go @@ -9,9 +9,7 @@ import ( "github.com/safing/portmaster/netenv" ) -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register("status", prepare, start, nil, "base", "config") diff --git a/status/provider.go b/status/provider.go index 506d5987..43abb0c5 100644 --- a/status/provider.go +++ b/status/provider.go @@ -8,9 +8,7 @@ import ( "github.com/safing/portmaster/netenv" ) -var ( - pushUpdate runtime.PushFunc -) +var pushUpdate runtime.PushFunc func setupRuntimeProvider() (err error) { // register the system status getter diff --git a/ui/api.go b/ui/api.go index e81200df..68c9fbe9 100644 --- a/ui/api.go +++ b/ui/api.go @@ -2,6 +2,7 @@ package ui import ( resources "github.com/cookieo9/resources-go" + "github.com/safing/portbase/api" "github.com/safing/portbase/log" ) diff --git a/ui/module.go b/ui/module.go index 80494ca7..0e10ed75 100644 --- a/ui/module.go +++ b/ui/module.go @@ -2,18 +2,11 @@ package ui import ( "github.com/safing/portbase/dataroot" - "github.com/safing/portbase/log" "github.com/safing/portbase/modules" ) -const ( - eventReload = "reload" -) - -var ( - module *modules.Module -) +var module *modules.Module func init() { module = modules.Register("ui", prep, start, nil, "api", "updates") @@ -36,7 +29,7 @@ func start() error { // may seem dangerous, but proper permission on the parent directory provide // (some) protection. // Processes must _never_ read from this directory. - err := dataroot.Root().ChildDir("exec", 0777).Ensure() + err := dataroot.Root().ChildDir("exec", 0o0777).Ensure() if err != nil { log.Warningf("ui: failed to create safe exec dir: %s", err) } diff --git a/ui/serve.go b/ui/serve.go index 05c3af90..64509f30 100644 --- a/ui/serve.go +++ b/ui/serve.go @@ -1,6 +1,7 @@ package ui import ( + "errors" "fmt" "io" "net/http" @@ -94,7 +95,7 @@ func (bs *bundleServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { // get file from update system zipFile, err := updates.GetFile(fmt.Sprintf("ui/modules/%s.zip", moduleName)) if err != nil { - if err == updater.ErrNotFound { + if errors.Is(err, updater.ErrNotFound) { log.Tracef("ui: requested module %s does not exist", moduleName) http.Error(w, err.Error(), http.StatusNotFound) } else { @@ -124,7 +125,7 @@ func (bs *bundleServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { func ServeFileFromBundle(w http.ResponseWriter, r *http.Request, bundleName string, bundle *resources.BundleSequence, path string) { readCloser, err := bundle.Open(path) if err != nil { - if err == resources.ErrNotFound { + if errors.Is(err, resources.ErrNotFound) { // Check if there is a base index.html file we can serve instead. var indexErr error path = "index.html" @@ -164,7 +165,7 @@ func ServeFileFromBundle(w http.ResponseWriter, r *http.Request, bundleName stri } } - readCloser.Close() + _ = readCloser.Close() } // redirectToDefault redirects the request to the default UI module. diff --git a/updates/config.go b/updates/config.go index 62e3e124..e2d12da2 100644 --- a/updates/config.go +++ b/updates/config.go @@ -3,12 +3,12 @@ package updates import ( "context" - "github.com/safing/portbase/notifications" - "github.com/safing/portmaster/updates/helper" "github.com/tevino/abool" "github.com/safing/portbase/config" "github.com/safing/portbase/log" + "github.com/safing/portbase/notifications" + "github.com/safing/portmaster/updates/helper" ) const ( diff --git a/updates/helper/electron.go b/updates/helper/electron.go index a82f5bfd..fdc5e1b9 100644 --- a/updates/helper/electron.go +++ b/updates/helper/electron.go @@ -48,7 +48,7 @@ func EnsureChromeSandboxPermissions(reg *updater.ResourceRegistry) error { filepath.Ext(pmElectronUpdate.Path()), ) sandboxFile := filepath.Join(unpackedPath, "chrome-sandbox") - if err := os.Chmod(sandboxFile, 0755|os.ModeSetuid); err != nil { + if err := os.Chmod(sandboxFile, 0o0755|os.ModeSetuid); err != nil { return err } log.Infof("updates: fixed SUID permission for chrome-sandbox") @@ -56,7 +56,7 @@ func EnsureChromeSandboxPermissions(reg *updater.ResourceRegistry) error { return nil } -func checkSysctl(setting string, value byte) bool { +func checkSysctl(setting string, value byte) bool { //nolint:deadcode,unused // TODO: Do we still need this? c, err := sysctl(setting) if err != nil { return false @@ -67,7 +67,7 @@ func checkSysctl(setting string, value byte) bool { return c[0] == value } -func sysctl(setting string) ([]byte, error) { +func sysctl(setting string) ([]byte, error) { //nolint:unused // TODO: Do we still need this? parts := append([]string{"/proc", "sys"}, strings.Split(setting, ".")...) path := filepath.Join(parts...) content, err := ioutil.ReadFile(path) diff --git a/updates/helper/indexes.go b/updates/helper/indexes.go index 69443604..db97b84d 100644 --- a/updates/helper/indexes.go +++ b/updates/helper/indexes.go @@ -8,9 +8,14 @@ import ( "github.com/safing/portbase/updater" ) +// Release Channel Configuration Keys. const ( ReleaseChannelKey = "core/releaseChannel" ReleaseChannelJSONKey = "core.releaseChannel" +) + +// Release Channels. +const ( ReleaseChannelStable = "stable" ReleaseChannelBeta = "beta" ReleaseChannelStaging = "staging" @@ -90,7 +95,7 @@ func SetIndexes(registry *updater.ResourceRegistry, releaseChannel string, delet // Set pre-release usage. registry.SetUsePreReleases(usePreReleases) - return + return warning } func indexExists(registry *updater.ResourceRegistry, indexPath string) bool { diff --git a/updates/main.go b/updates/main.go index 46e9ec92..0352f54b 100644 --- a/updates/main.go +++ b/updates/main.go @@ -108,7 +108,7 @@ func start() error { registry.UserAgent = userAgentFromFlag } // initialize - err := registry.Initialize(dataroot.Root().ChildDir("updates", 0755)) + err := registry.Initialize(dataroot.Root().ChildDir("updates", 0o0755)) if err != nil { return err } @@ -241,7 +241,7 @@ func checkForUpdates(ctx context.Context) (err error) { }() if err = registry.UpdateIndexes(ctx); err != nil { - err = fmt.Errorf("failed to update indexes: %s", err) + err = fmt.Errorf("failed to update indexes: %w", err) return } diff --git a/updates/restart.go b/updates/restart.go index 8d6d98eb..ef954481 100644 --- a/updates/restart.go +++ b/updates/restart.go @@ -4,9 +4,10 @@ import ( "context" "time" + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" - "github.com/tevino/abool" ) const ( diff --git a/updates/upgrader.go b/updates/upgrader.go index 753bddde..a97f89a9 100644 --- a/updates/upgrader.go +++ b/updates/upgrader.go @@ -95,11 +95,11 @@ func upgradeCoreNotify() error { } // get newest portmaster-core - new, err := GetPlatformFile(identifier) + newFile, err := GetPlatformFile(identifier) if err != nil { return err } - pmCoreUpdate = new + pmCoreUpdate = newFile // check for new version if info.GetInfo().Version != pmCoreUpdate.Version() { @@ -162,11 +162,11 @@ func upgradeHub() error { } // get newest spn-hub - new, err := GetPlatformFile(identifier) + newFile, err := GetPlatformFile(identifier) if err != nil { return err } - spnHubUpdate = new + spnHubUpdate = newFile // check for new version if info.GetInfo().Version != spnHubUpdate.Version() { @@ -192,11 +192,11 @@ func upgradePortmasterStart() error { // check if we can upgrade if pmCtrlUpdate == nil || pmCtrlUpdate.UpgradeAvailable() { // get newest portmaster-start - new, err := GetPlatformFile("start/" + filename) // identifier, use forward slash! + newFile, err := GetPlatformFile("start/" + filename) // identifier, use forward slash! if err != nil { return err } - pmCtrlUpdate = new + pmCtrlUpdate = newFile } else { return nil } @@ -338,8 +338,8 @@ func upgradeFile(fileToUpgrade string, file *updater.File) error { if err != nil { return fmt.Errorf("failed to get file info on %s: %w", fileToUpgrade, err) } - if info.Mode() != 0755 { - err := os.Chmod(fileToUpgrade, 0755) + if info.Mode() != 0o0755 { + err := os.Chmod(fileToUpgrade, 0o0755) //nolint:gosec // Set execute permissions. if err != nil { return fmt.Errorf("failed to set permissions on %s: %w", fileToUpgrade, err) } @@ -370,7 +370,9 @@ func CopyFile(srcPath, dstPath string) error { if err != nil { return err } - defer srcFile.Close() + defer func() { + _ = srcFile.Close() + }() // copy data _, err = io.Copy(atomicDstFile, srcFile)