From c9b9a0b1d19506d6b985e8b58ba182e2601410b6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 9 Jun 2022 13:48:55 +0200 Subject: [PATCH 01/22] Improve read rights on log files --- cmds/portmaster-start/logs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/portmaster-start/logs.go b/cmds/portmaster-start/logs.go index d14f1250..09fa01c6 100644 --- a/cmds/portmaster-start/logs.go +++ b/cmds/portmaster-start/logs.go @@ -17,7 +17,7 @@ import ( ) func initializeLogFile(logFilePath string, identifier string, version string) *os.File { - logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0o0444) + logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0o0440) if err != nil { log.Printf("failed to create log file %s: %s\n", logFilePath, err) return nil From 0439894efc3097214178a31e70718f66b81c4c09 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 9 Jun 2022 13:49:34 +0200 Subject: [PATCH 02/22] Suppress error when stopping during filterlist update --- intel/filterlists/updater.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/intel/filterlists/updater.go b/intel/filterlists/updater.go index ff5ce3e9..7d15e85e 100644 --- a/intel/filterlists/updater.go +++ b/intel/filterlists/updater.go @@ -24,6 +24,11 @@ var updateInProgress = abool.New() func tryListUpdate(ctx context.Context) error { err := performUpdate(ctx) if err != nil { + // Check if we are shutting down. + if module.IsStopping() { + return nil + } + // Check if the module already has a failure status set. If not, set a // generic one with the returned error. failureStatus, _, _ := module.FailureStatus() From c442a7e51c1c605a6f016ebe9a7591ffb5840e73 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 9 Jun 2022 13:50:18 +0200 Subject: [PATCH 03/22] Deactivate IPv6 integrations when no IPv6 stack is detected --- firewall/interception/nfqueue_linux.go | 52 ++++++++++++++++---------- nameserver/module.go | 6 ++- netenv/main.go | 23 ++++++++++++ resolver/resolver-mdns.go | 51 +++++++++++++------------ 4 files changed, 89 insertions(+), 43 deletions(-) diff --git a/firewall/interception/nfqueue_linux.go b/firewall/interception/nfqueue_linux.go index f117cd67..9d731648 100644 --- a/firewall/interception/nfqueue_linux.go +++ b/firewall/interception/nfqueue_linux.go @@ -10,8 +10,8 @@ import ( "github.com/hashicorp/go-multierror" "github.com/safing/portbase/log" - "github.com/safing/portbase/notifications" "github.com/safing/portmaster/firewall/interception/nfq" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/packet" ) @@ -141,13 +141,10 @@ func activateNfqueueFirewall() error { return err } - if err := activateIPTables(iptables.ProtocolIPv6, v6rules, v6once, v6chains); err != nil { - notifications.NotifyError( - "interception:ipv6-possibly-disabled", - "Is IPv6 enabled?", - "The Portmaster succeeded with IPv4 network integration, but failed with IPv6 integration. Please make sure IPv6 is enabled on your device.", - ) - return err + if netenv.IPv6Enabled() { + if err := activateIPTables(iptables.ProtocolIPv6, v6rules, v6once, v6chains); err != nil { + return err + } } return nil @@ -163,8 +160,10 @@ func DeactivateNfqueueFirewall() error { } // IPv6 - if err := deactivateIPTables(iptables.ProtocolIPv6, v6once, v6chains); err != nil { - result = multierror.Append(result, err) + if netenv.IPv6Enabled() { + if err := deactivateIPTables(iptables.ProtocolIPv6, v6once, v6chains); err != nil { + result = multierror.Append(result, err) + } } return result.ErrorOrNil() @@ -264,15 +263,22 @@ func StartNfqueueInterception(packets chan<- packet.Packet) (err error) { _ = Stop() return fmt.Errorf("nfqueue(IPv4, in): %w", err) } - out6Queue, err = nfq.New(17060, true) - if err != nil { - _ = Stop() - return fmt.Errorf("nfqueue(IPv6, out): %w", err) - } - in6Queue, err = nfq.New(17160, true) - if err != nil { - _ = Stop() - return fmt.Errorf("nfqueue(IPv6, in): %w", err) + + if netenv.IPv6Enabled() { + out6Queue, err = nfq.New(17060, true) + if err != nil { + _ = Stop() + return fmt.Errorf("nfqueue(IPv6, out): %w", err) + } + in6Queue, err = nfq.New(17160, true) + if err != nil { + _ = Stop() + return fmt.Errorf("nfqueue(IPv6, in): %w", err) + } + } else { + log.Warningf("interception: no IPv6 stack detected, disabling IPv6 network integration") + out6Queue = &disabledNfQueue{} + in6Queue = &disabledNfQueue{} } go handleInterception(packets) @@ -327,3 +333,11 @@ func handleInterception(packets chan<- packet.Packet) { } } } + +type disabledNfQueue struct{} + +func (dnfq *disabledNfQueue) PacketChannel() <-chan packet.Packet { + return nil +} + +func (dnfq *disabledNfQueue) Destroy() {} diff --git a/nameserver/module.go b/nameserver/module.go index f5165585..ed7eb740 100644 --- a/nameserver/module.go +++ b/nameserver/module.go @@ -259,7 +259,11 @@ func getListenAddresses(listenAddress string) (ip1, ip2 net.IP, port uint16, err // listen separately for IPv4 and IPv6. if ipString == "localhost" { ip1 = net.IPv4(127, 0, 0, 17) - ip2 = net.IPv6loopback + if netenv.IPv6Enabled() { + ip2 = net.IPv6loopback + } else { + log.Warningf("nameserver: no IPv6 stack detected, disabling IPv6 nameserver listener") + } } else { ip1 = net.ParseIP(ipString) if ip1 == nil { diff --git a/netenv/main.go b/netenv/main.go index 0d831e76..232696cd 100644 --- a/netenv/main.go +++ b/netenv/main.go @@ -1,7 +1,9 @@ package netenv import ( + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" + "github.com/tevino/abool" ) // Event Names. @@ -20,6 +22,8 @@ func init() { } func prep() error { + checkForIPv6Stack() + if err := registerAPIEndpoints(); err != nil { return err } @@ -46,3 +50,22 @@ func start() error { return nil } + +var ipv6Enabled = abool.NewBool(true) + +// IPv6Enabled returns whether the device has an active IPv6 stack. +// This is only checked once on startup in order to maintain consistency. +func IPv6Enabled() bool { + return ipv6Enabled.IsSet() +} + +func checkForIPv6Stack() { + _, v6IPs, err := GetAssignedAddresses() + if err != nil { + log.Warningf("netenv: failed to get assigned addresses to check for ipv6 stack: %s", err) + return + } + + // Set IPv6 as enabled if any IPv6 addresses are found. + ipv6Enabled.SetTo(len(v6IPs) > 0) +} diff --git a/resolver/resolver-mdns.go b/resolver/resolver-mdns.go index ce0eab6d..29677350 100644 --- a/resolver/resolver-mdns.go +++ b/resolver/resolver-mdns.go @@ -12,6 +12,7 @@ import ( "github.com/miekg/dns" "github.com/safing/portbase/log" + "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network/netutils" ) @@ -91,19 +92,6 @@ func listenToMDNS(ctx context.Context) error { }() } - 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}) - if err != nil { - // TODO: retry after some time - log.Warningf("intel(mdns): failed to create udp6 listen multicast socket: %s", err) - } else { - module.StartServiceWorker("mdns udp6 multicast listener", 0, func(ctx context.Context) error { - return listenForDNSPackets(ctx, multicast6Conn, messages) - }) - defer func() { - _ = multicast6Conn.Close() - }() - } - unicast4Conn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { // TODO: retry after some time @@ -117,17 +105,34 @@ func listenToMDNS(ctx context.Context) error { }() } - unicast6Conn, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0}) - if err != nil { - // TODO: retry after some time - log.Warningf("intel(mdns): failed to create udp6 listen socket: %s", err) + if netenv.IPv6Enabled() { + 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}) + if err != nil { + // TODO: retry after some time + log.Warningf("intel(mdns): failed to create udp6 listen multicast socket: %s", err) + } else { + module.StartServiceWorker("mdns udp6 multicast listener", 0, func(ctx context.Context) error { + return listenForDNSPackets(ctx, multicast6Conn, messages) + }) + defer func() { + _ = multicast6Conn.Close() + }() + } + + unicast6Conn, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0}) + if err != nil { + // TODO: retry after some time + log.Warningf("intel(mdns): failed to create udp6 listen socket: %s", err) + } else { + module.StartServiceWorker("mdns udp6 unicast listener", 0, func(ctx context.Context) error { + return listenForDNSPackets(ctx, unicast6Conn, messages) + }) + defer func() { + _ = unicast6Conn.Close() + }() + } } else { - module.StartServiceWorker("mdns udp6 unicast listener", 0, func(ctx context.Context) error { - return listenForDNSPackets(ctx, unicast6Conn, messages) - }) - defer func() { - _ = unicast6Conn.Close() - }() + log.Warningf("resolver: no IPv6 stack detected, disabling IPv6 mDNS resolver") } // start message handler From b392a1e8fff5a6dae3a1f1619a1865fc7b24f0cd Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 9 Jun 2022 13:59:50 +0200 Subject: [PATCH 04/22] Add geoip.IsInitialized to expose if the databases have been loaded --- intel/geoip/lookup.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/intel/geoip/lookup.go b/intel/geoip/lookup.go index 7210bc79..c635b574 100644 --- a/intel/geoip/lookup.go +++ b/intel/geoip/lookup.go @@ -26,3 +26,8 @@ func GetLocation(ip net.IP) (*Location, error) { record.FillMissingInfo() return record, nil } + +// IsInitialized returns whether the geoip database has been initialized. +func IsInitialized(v6, wait bool) bool { + return worker.GetReader(v6, wait) != nil +} From 86d4f64d429ea37e43d899dc5b12f21a2553609a Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 9 Jun 2022 14:36:03 +0200 Subject: [PATCH 05/22] Improve device location system with more safeguards --- netenv/api.go | 2 +- netenv/location.go | 151 ++++++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/netenv/api.go b/netenv/api.go index 237dee57..20a2f688 100644 --- a/netenv/api.go +++ b/netenv/api.go @@ -55,7 +55,7 @@ func registerAPIEndpoints() error { Read: api.PermitUser, BelongsTo: module, StructFunc: func(ar *api.Request) (i interface{}, err error) { - return getLocationFromTraceroute() + return getLocationFromTraceroute(&DeviceLocations{}) }, Name: "Get Approximate Internet Location via Traceroute", Description: "Returns an approximation of where the device is on the Internet using a the traceroute technique.", diff --git a/netenv/location.go b/netenv/location.go index 6245ab45..8c8c5d56 100644 --- a/netenv/location.go +++ b/netenv/location.go @@ -47,16 +47,16 @@ type DeviceLocations struct { } // Best returns the best (most accurate) device location. -func (dl *DeviceLocations) Best() *DeviceLocation { - if len(dl.All) > 0 { - return dl.All[0] +func (dls *DeviceLocations) Best() *DeviceLocation { + if len(dls.All) > 0 { + return dls.All[0] } return nil } // BestV4 returns the best (most accurate) IPv4 device location. -func (dl *DeviceLocations) BestV4() *DeviceLocation { - for _, loc := range dl.All { +func (dls *DeviceLocations) BestV4() *DeviceLocation { + for _, loc := range dls.All { if loc.IPVersion == packet.IPv4 { return loc } @@ -65,8 +65,8 @@ func (dl *DeviceLocations) BestV4() *DeviceLocation { } // BestV6 returns the best (most accurate) IPv6 device location. -func (dl *DeviceLocations) BestV6() *DeviceLocation { - for _, loc := range dl.All { +func (dls *DeviceLocations) BestV6() *DeviceLocation { + for _, loc := range dls.All { if loc.IPVersion == packet.IPv6 { return loc } @@ -74,11 +74,8 @@ func (dl *DeviceLocations) BestV6() *DeviceLocation { return nil } -func copyDeviceLocations() *DeviceLocations { - locationsLock.Lock() - defer locationsLock.Unlock() - - // Create a copy of the locations, but not the entries. +// Copy creates a copy of the locations, but not the individual entries. +func (dls *DeviceLocations) Copy() *DeviceLocations { cp := &DeviceLocations{ All: make([]*DeviceLocation, len(locations.All)), } @@ -87,6 +84,32 @@ func copyDeviceLocations() *DeviceLocations { return cp } +// AddLocation adds a location. +func (dls *DeviceLocations) AddLocation(dl *DeviceLocation) { + if dls == nil { + return + } + + // Add to locations, if better. + var exists bool + for i, existing := range dls.All { + if (dl.IP == nil && existing.IP == nil) || dl.IP.Equal(existing.IP) { + exists = true + if dl.IsMoreAccurateThan(existing) { + // Replace + dls.All[i] = dl + break + } + } + } + if !exists { + dls.All = append(dls.All, dl) + } + + // Sort locations. + sort.Sort(sortLocationsByAccuracy(dls.All)) +} + // DeviceLocation represents a single IP and metadata. It must not be changed // once created. type DeviceLocation struct { @@ -147,6 +170,12 @@ func (dl *DeviceLocation) String() string { return "" case dl.Location == nil: return dl.IP.String() + case dl.Source == SourceTimezone: + return fmt.Sprintf( + "TZ(%.0f/%.0f)", + dl.Location.Coordinates.Latitude, + dl.Location.Coordinates.Longitude, + ) default: return fmt.Sprintf("%s (AS%d in %s)", dl.IP, dl.Location.AutonomousSystemNumber, dl.Location.Country.ISOCode) } @@ -193,6 +222,14 @@ func (a sortLocationsByAccuracy) Less(i, j int) bool { return !a[j].IsMoreAccura // SetInternetLocation provides the location management system with a possible Internet location. func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) { + locationsLock.Lock() + defer locationsLock.Unlock() + + return locations.AddIP(ip, source) +} + +// AddIP adds a new location based on the given IP. +func (dls *DeviceLocations) AddIP(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) { // Check if IP is global. if netutils.GetIPScope(ip) != netutils.Global { return nil, false @@ -222,38 +259,10 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLoca } loc.Location = geoLoc - addLocation(loc) + dls.AddLocation(loc) return loc, true } -func addLocation(dl *DeviceLocation) { - if dl == nil { - return - } - - locationsLock.Lock() - defer locationsLock.Unlock() - - // Add to locations, if better. - var exists bool - for i, existing := range locations.All { - if (dl.IP == nil && existing.IP == nil) || dl.IP.Equal(existing.IP) { - exists = true - if dl.IsMoreAccurateThan(existing) { - // Replace - locations.All[i] = dl - break - } - } - } - if !exists { - locations.All = append(locations.All, dl) - } - - // Sort locations. - sort.Sort(sortLocationsByAccuracy(locations.All)) -} - // GetApproximateInternetLocation returns the approximate Internet location. // Deprecated: Please use GetInternetLocation instead. func GetApproximateInternetLocation() (net.IP, error) { @@ -271,30 +280,21 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) { // Check if the network changed, if not, return cache. if !locationNetworkChangedFlag.IsSet() { - return copyDeviceLocations(), true + locationsLock.Lock() + defer locationsLock.Unlock() + return locations.Copy(), true } locationNetworkChangedFlag.Refresh() - // Reset locations. - func() { - locationsLock.Lock() - defer locationsLock.Unlock() - locations = &DeviceLocations{} - }() - - // Get all assigned addresses. - v4s, v6s, err := GetAssignedAddresses() - if err != nil { - log.Warningf("netenv: failed to get assigned addresses for device location: %s", err) - return nil, false - } + // Create new location list. + dls := &DeviceLocations{} // Check interfaces for global addresses. - v4ok, v6ok := getLocationFromInterfaces() + v4ok, v6ok := getLocationFromInterfaces(dls) // Try other methods for missing locations. - if len(v4s) > 0 && !v4ok { - _, err = getLocationFromTraceroute() + if !v4ok { + _, err := getLocationFromTraceroute(dls) if err != nil { log.Warningf("netenv: failed to get IPv4 device location from traceroute: %s", err) } else { @@ -303,35 +303,43 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) { // Get location from timezone as final fallback. if !v4ok { - getLocationFromTimezone(packet.IPv4) + getLocationFromTimezone(dls, packet.IPv4) } } - if len(v6s) > 0 && !v6ok { + if !v6ok && IPv6Enabled() { // TODO: Find more ways to get IPv6 device location // Get location from timezone as final fallback. - getLocationFromTimezone(packet.IPv6) + getLocationFromTimezone(dls, packet.IPv6) } + // As a last guard, make sure there is at least one location in the list. + if len(dls.All) == 0 { + getLocationFromTimezone(dls, packet.IPv4) + } + + // Set new locations. + locationsLock.Lock() + defer locationsLock.Unlock() + locations = dls + // Return gathered locations. - cp := copyDeviceLocations() - return cp, true + return locations.Copy(), true } -func getLocationFromInterfaces() (v4ok, v6ok bool) { +func getLocationFromInterfaces(dls *DeviceLocations) (v4ok, v6ok bool) { globalIPv4, globalIPv6, err := GetAssignedGlobalAddresses() if err != nil { log.Warningf("netenv: location: failed to get assigned global addresses: %s", err) return false, false } - for _, ip := range globalIPv4 { - if _, ok := SetInternetLocation(ip, SourceInterface); ok { + if _, ok := dls.AddIP(ip, SourceInterface); ok { v4ok = true } } for _, ip := range globalIPv6 { - if _, ok := SetInternetLocation(ip, SourceInterface); ok { + if _, ok := dls.AddIP(ip, SourceInterface); ok { v6ok = true } } @@ -349,7 +357,7 @@ func getLocationFromUPnP() (ok bool) { } */ -func getLocationFromTraceroute() (dl *DeviceLocation, err error) { +func getLocationFromTraceroute(dls *DeviceLocations) (dl *DeviceLocation, err error) { // Create connection. conn, err := net.ListenPacket("ip4:icmp", "") if err != nil { @@ -470,7 +478,7 @@ nextHop: // We have received a valid time exceeded error. // If message came from a global unicast, us it! if netutils.GetIPScope(remoteIP) == netutils.Global { - dl, ok := SetInternetLocation(remoteIP, SourceTraceroute) + dl, ok := dls.AddIP(remoteIP, SourceTraceroute) if !ok { return nil, errors.New("invalid IP address") } @@ -516,7 +524,7 @@ func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) ( } } -func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { //nolint:unparam // This is documentation. +func getLocationFromTimezone(dls *DeviceLocations, ipVersion packet.IPVersion) { // Create base struct. tzLoc := &DeviceLocation{ IPVersion: ipVersion, @@ -531,6 +539,5 @@ func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { //nolint:un tzLoc.Location.Coordinates.Latitude = 48 tzLoc.Location.Coordinates.Longitude = float64(offsetSeconds) / 43200 * 180 - addLocation(tzLoc) - return true + dls.AddLocation(tzLoc) } From 9c0b7ddf51085fa536af97cac3cbcb40cb17359a Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 09:56:21 +0200 Subject: [PATCH 06/22] Fix direction detection for unsupported protocols --- network/state/lookup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/state/lookup.go b/network/state/lookup.go index 6e2525f1..46aac9a6 100644 --- a/network/state/lookup.go +++ b/network/state/lookup.go @@ -60,7 +60,7 @@ func Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error) return udp6Table.lookup(pktInfo, fast) default: - return socket.UndefinedProcessID, false, errors.New("unsupported protocol for finding process") + return socket.UndefinedProcessID, pktInfo.Inbound, errors.New("unsupported protocol for finding process") } } From bb782ba98fc23bcad1e2edfe5670d8920c9f2444 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 09:56:47 +0200 Subject: [PATCH 07/22] Add check to ensure matching PID constants --- process/special.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/process/special.go b/process/special.go index 4b6a89e4..7d2c3e93 100644 --- a/process/special.go +++ b/process/special.go @@ -8,6 +8,7 @@ import ( "golang.org/x/sync/singleflight" "github.com/safing/portbase/log" + "github.com/safing/portmaster/network/socket" "github.com/safing/portmaster/profile" ) @@ -28,6 +29,13 @@ const ( NetworkHostProcessID = -255 ) +func init() { + // Check required matching values. + if UndefinedProcessID != socket.UndefinedProcessID { + panic("UndefinedProcessID does not match socket.UndefinedProcessID") + } +} + var ( // unidentifiedProcess is used for non-attributed outgoing connections. unidentifiedProcess = &Process{ From 3a98b2cc054bdb100da322e0fdd1eda108f42f7a Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 09:57:55 +0200 Subject: [PATCH 08/22] Make intel index override-able by other indexes --- updates/helper/indexes.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/updates/helper/indexes.go b/updates/helper/indexes.go index db97b84d..e925be1a 100644 --- a/updates/helper/indexes.go +++ b/updates/helper/indexes.go @@ -33,6 +33,12 @@ func SetIndexes(registry *updater.ResourceRegistry, releaseChannel string, delet // Reset indexes before adding them (again). registry.ResetIndexes() + // Add the intel index first, in order to be able to override it with the + // other indexes when needed. + registry.AddIndex(updater.Index{ + Path: "all/intel/intel.json", + }) + // Always add the stable index as a base. registry.AddIndex(updater.Index{ Path: ReleaseChannelStable + ".json", @@ -85,13 +91,6 @@ func SetIndexes(registry *updater.ResourceRegistry, releaseChannel string, delet } } - // Add the intel index last, as it updates the fastest and should not be - // crippled by other faulty indexes. It can only specify versions for its - // scope anyway. - registry.AddIndex(updater.Index{ - Path: "all/intel/intel.json", - }) - // Set pre-release usage. registry.SetUsePreReleases(usePreReleases) From 0dce13d18fd22b29a140833816933b0ae4dff3ff Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 10:40:21 +0200 Subject: [PATCH 09/22] Fix detection of incoming localhost packets on Linux --- firewall/interception/nfq/packet.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firewall/interception/nfq/packet.go b/firewall/interception/nfq/packet.go index 46ca3ea5..528f2e3c 100644 --- a/firewall/interception/nfq/packet.go +++ b/firewall/interception/nfq/packet.go @@ -141,6 +141,13 @@ func (pkt *packet) Drop() error { } func (pkt *packet) PermanentAccept() error { + // If the packet is localhost only, do not permanently accept the outgoing + // packet, as the packet mark will be copied to the connection mark, which + // will stick and it will bypass the incoming queue. + if !pkt.Info().Inbound && pkt.Info().Dst.IsLoopback() { + return pkt.Accept() + } + return pkt.mark(MarkAcceptAlways) } From 65974e989dd883c8b6fde8835d45b7914d279113 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 10:41:35 +0200 Subject: [PATCH 10/22] Stop using deprecated function --- firewall/dns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firewall/dns.go b/firewall/dns.go index cb78e5c4..d8c4b582 100644 --- a/firewall/dns.go +++ b/firewall/dns.go @@ -263,7 +263,7 @@ func UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *netw // Package IPs and CNAMEs into IPInfo structs. for _, ip := range ips { // Never save domain attributions for localhost IPs. - if netutils.ClassifyIP(ip) == netutils.HostLocal { + if netutils.GetIPScope(ip) == netutils.HostLocal { continue } From d40ad3125d7b00b5e3310cb71e7cba6bca910f08 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 14:33:09 +0200 Subject: [PATCH 11/22] Improve rules and filterlists config options --- profile/config.go | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/profile/config.go b/profile/config.go index 987594d4..f03fca74 100644 --- a/profile/config.go +++ b/profile/config.go @@ -258,6 +258,12 @@ Examples: "192.168.0.1 TCP/HTTP", "LAN UDP/50000-55000", "example.com */HTTPS", Important: DNS Requests are only matched against domain and filter list rules, all others require an IP address and are checked only with the following IP connection. `, `"`, "`") + // rulesVerdictNames defines the verdicts names to be used for filter rules. + rulesVerdictNames := map[string]string{ + "-": "Block", // Default. + "+": "Allow", + } + // Endpoint Filter List err = config.Register(&config.Option{ Name: "Outgoing Rules", @@ -268,10 +274,11 @@ Important: DNS Requests are only matched against domain and filter list rules, a OptType: config.OptTypeStringArray, DefaultValue: []string{}, Annotations: config.Annotations{ - config.StackableAnnotation: true, - config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList, - config.DisplayOrderAnnotation: cfgOptionEndpointsOrder, - config.CategoryAnnotation: "Rules", + config.StackableAnnotation: true, + config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList, + config.DisplayOrderAnnotation: cfgOptionEndpointsOrder, + config.CategoryAnnotation: "Rules", + endpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames, }, ValidationRegex: endpoints.ListEntryValidationRegex, ValidationFunc: endpoints.ValidateEndpointListConfigOption, @@ -283,6 +290,7 @@ Important: DNS Requests are only matched against domain and filter list rules, a cfgStringArrayOptions[CfgOptionEndpointsKey] = cfgOptionEndpoints // Service Endpoint Filter List + defaultIncomingRulesValue := []string{"+ Localhost"} err = config.Register(&config.Option{ Name: "Incoming Rules", Key: CfgOptionServiceEndpointsKey, @@ -290,13 +298,14 @@ Important: DNS Requests are only matched against domain and filter list rules, a Help: rulesHelp, Sensitive: true, OptType: config.OptTypeStringArray, - DefaultValue: []string{"+ Localhost"}, + DefaultValue: defaultIncomingRulesValue, ExpertiseLevel: config.ExpertiseLevelExpert, Annotations: config.Annotations{ - config.StackableAnnotation: true, - config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList, - config.DisplayOrderAnnotation: cfgOptionServiceEndpointsOrder, - config.CategoryAnnotation: "Rules", + config.StackableAnnotation: true, + config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList, + config.DisplayOrderAnnotation: cfgOptionServiceEndpointsOrder, + config.CategoryAnnotation: "Rules", + endpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames, config.QuickSettingsAnnotation: []config.QuickSetting{ { Name: "SSH", @@ -313,6 +322,16 @@ Important: DNS Requests are only matched against domain and filter list rules, a Action: config.QuickMergeTop, Value: []string{"+ * */3389"}, }, + { + Name: "Allow all from LAN", + Action: config.QuickMergeTop, + Value: []string{"+ LAN"}, + }, + { + Name: "Allow all from Internet", + Action: config.QuickMergeTop, + Value: []string{"+ Internet"}, + }, }, }, ValidationRegex: endpoints.ListEntryValidationRegex, @@ -321,7 +340,7 @@ Important: DNS Requests are only matched against domain and filter list rules, a if err != nil { return err } - cfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, []string{}) + cfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, defaultIncomingRulesValue) cfgStringArrayOptions[CfgOptionServiceEndpointsKey] = cfgOptionServiceEndpoints filterListsHelp := strings.ReplaceAll(`Filter lists contain domains and IP addresses that are known to be used adversarial. The data is collected from many public sources and put into the following categories. In order to active a category, add it's "ID" to the list. @@ -346,13 +365,13 @@ The lists are automatically updated every hour using incremental updates. `, `"`, "`") // Filter list IDs + defaultFilterListsValue := []string{"TRAC", "MAL", "BAD"} err = config.Register(&config.Option{ Name: "Filter Lists", Key: CfgOptionFilterListsKey, Description: "Block connections that match enabled filter lists.", - Help: filterListsHelp, OptType: config.OptTypeStringArray, - DefaultValue: []string{"TRAC", "MAL", "BAD"}, + DefaultValue: defaultFilterListsValue, Annotations: config.Annotations{ config.DisplayHintAnnotation: "filter list", config.DisplayOrderAnnotation: cfgOptionFilterListsOrder, @@ -363,7 +382,7 @@ The lists are automatically updated every hour using incremental updates. if err != nil { return err } - cfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListsKey, []string{}) + cfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListsKey, defaultFilterListsValue) cfgStringArrayOptions[CfgOptionFilterListsKey] = cfgOptionFilterLists // Include CNAMEs From 6339eb0c49e01ea627319f25e6725f9495291876 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 14:33:28 +0200 Subject: [PATCH 12/22] Remove filter lists help --- profile/config.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/profile/config.go b/profile/config.go index f03fca74..e371a175 100644 --- a/profile/config.go +++ b/profile/config.go @@ -343,27 +343,6 @@ Important: DNS Requests are only matched against domain and filter list rules, a cfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, defaultIncomingRulesValue) cfgStringArrayOptions[CfgOptionServiceEndpointsKey] = cfgOptionServiceEndpoints - filterListsHelp := strings.ReplaceAll(`Filter lists contain domains and IP addresses that are known to be used adversarial. The data is collected from many public sources and put into the following categories. In order to active a category, add it's "ID" to the list. - -**Ads & Trackers** - ID: "TRAC" -Services that track and profile people online, including as ads, analytics and telemetry. - -**Malware** - ID: "MAL" -Services that are (ab)used for attacking devices through technical means. - -**Deception** - ID: "DECEP" -Services that trick humans into thinking the service is genuine, while it is not, including phishing, fake news and fraud. - -**Bad Stuff (Mixed)** - ID: "BAD" -Miscellaneous services that are believed to be harmful to security or privacy, but their exact use is unknown, not categorized, or lists have mixed categories. - -**NSFW** - ID: "NSFW" -Services that are generally not accepted in work environments, including pornography, violence and gambling. - -The lists are automatically updated every hour using incremental updates. -[See here](https://github.com/safing/intel-data) for more detail about these lists, their sources and how to help to improve them. -`, `"`, "`") - // Filter list IDs defaultFilterListsValue := []string{"TRAC", "MAL", "BAD"} err = config.Register(&config.Option{ From dac6b3c6fe31bb9e333c18abcaa3e5eac28163a9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 22 Jun 2022 14:49:36 +0200 Subject: [PATCH 13/22] Fix linter error --- netenv/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netenv/main.go b/netenv/main.go index 232696cd..3363754a 100644 --- a/netenv/main.go +++ b/netenv/main.go @@ -1,9 +1,10 @@ package netenv import ( + "github.com/tevino/abool" + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" - "github.com/tevino/abool" ) // Event Names. From 9f4e921609e65f4f2a08127249f013691075f7ba Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 21 Jun 2022 16:55:19 +0200 Subject: [PATCH 14/22] Simplify and improve update version export --- updates/export.go | 179 +++++++++++++++++++++++----------------------- updates/main.go | 12 +++- 2 files changed, 98 insertions(+), 93 deletions(-) diff --git a/updates/export.go b/updates/export.go index e00dee33..0c03b365 100644 --- a/updates/export.go +++ b/updates/export.go @@ -2,11 +2,8 @@ package updates import ( "context" - "errors" "sync" - "github.com/safing/portbase/database" - "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" "github.com/safing/portbase/info" "github.com/safing/portbase/log" @@ -14,48 +11,95 @@ import ( "github.com/safing/portmaster/updates/helper" ) -// Database key for update information. const ( + // versionsDBKey is the database key for update version information. versionsDBKey = "core:status/versions" + + // versionsDBKey is the database key for simple update version information. + simpleVersionsDBKey = "core:status/simple-versions" ) -var ( - versionExport *versions - versionExportDB = database.NewInterface(&database.Options{ - Local: true, - Internal: true, - }) - versionExportHook *database.RegisteredHook -) - -// versions holds updates status information. -type versions struct { +// Versions holds update versions and status information. +type Versions struct { record.Base - lock sync.Mutex + sync.Mutex Core *info.Info Resources map[string]*updater.Resource Channel string Beta bool Staging bool +} - internalSave bool +// SimpleVersions holds simplified update versions and status information. +type SimpleVersions struct { + record.Base + sync.Mutex + + Build *info.Info + Resources map[string]*SimplifiedResourceVersion + Channel string +} + +// SimplifiedResourceVersion holds version information about one resource. +type SimplifiedResourceVersion struct { + Version string +} + +// GetVersions returns the update versions and status information. +// Resources must be locked when accessed. +func GetVersions() *Versions { + return &Versions{ + Core: info.GetInfo(), + Resources: registry.Export(), + Channel: initialReleaseChannel, + Beta: initialReleaseChannel == helper.ReleaseChannelBeta, + Staging: initialReleaseChannel == helper.ReleaseChannelStaging, + } +} + +// GetSimpleVersions returns the simplified update versions and status information. +func GetSimpleVersions() *SimpleVersions { + // Fill base info. + v := &SimpleVersions{ + Build: info.GetInfo(), + Resources: make(map[string]*SimplifiedResourceVersion), + Channel: initialReleaseChannel, + } + + // Iterate through all versions and add version info. + for id, resource := range registry.Export() { + func() { + resource.Lock() + defer resource.Unlock() + + // Get current in-used or selected version. + var rv *updater.ResourceVersion + switch { + case resource.ActiveVersion != nil: + rv = resource.ActiveVersion + case resource.SelectedVersion != nil: + rv = resource.SelectedVersion + } + + // Get information from resource. + if rv != nil { + v.Resources[id] = &SimplifiedResourceVersion{ + Version: rv.VersionNumber, + } + } + }() + } + + return v } func initVersionExport() (err error) { - // init export struct - versionExport = &versions{ - internalSave: true, - Channel: initialReleaseChannel, - Beta: initialReleaseChannel == helper.ReleaseChannelBeta, - Staging: initialReleaseChannel == helper.ReleaseChannelStaging, + if err := GetVersions().save(); err != nil { + log.Warningf("updates: failed to export version information: %s", err) } - versionExport.SetKey(versionsDBKey) - - // attach hook to database - versionExportHook, err = database.RegisterHook(query.New(versionsDBKey), &exportHook{}) - if err != nil { - return err + if err := GetSimpleVersions().save(); err != nil { + log.Warningf("updates: failed to export version information: %s", err) } return module.RegisterEventHook( @@ -66,71 +110,24 @@ func initVersionExport() (err error) { ) } -func stopVersionExport() error { - return versionExportHook.Cancel() +func (v *Versions) save() error { + if !v.KeyIsSet() { + v.SetKey(versionsDBKey) + } + return db.Put(v) +} + +func (v *SimpleVersions) save() error { + if !v.KeyIsSet() { + v.SetKey(simpleVersionsDBKey) + } + return db.Put(v) } // export is an event hook. func export(_ context.Context, _ interface{}) error { - // populate - versionExport.lock.Lock() - versionExport.Core = info.GetInfo() - versionExport.Resources = registry.Export() - versionExport.lock.Unlock() - - // save - err := versionExportDB.Put(versionExport) - if err != nil { - log.Warningf("updates: failed to export versions: %s", err) + if err := GetVersions().save(); err != nil { + return err } - - return nil -} - -// Lock locks the versionExport and all associated resources. -func (v *versions) Lock() { - // lock self - v.lock.Lock() - - // lock all resources - for _, res := range v.Resources { - res.Lock() - } -} - -// Lock unlocks the versionExport and all associated resources. -func (v *versions) Unlock() { - // unlock all resources - for _, res := range v.Resources { - res.Unlock() - } - - // unlock self - v.lock.Unlock() -} - -type exportHook struct { - database.HookBase -} - -// UsesPrePut implements the Hook interface. -func (eh *exportHook) UsesPrePut() bool { - return true -} - -var errInternalRecord = errors.New("may not modify internal record") - -// PrePut implements the Hook interface. -func (eh *exportHook) PrePut(r record.Record) (record.Record, error) { - if r.IsWrapped() { - return nil, errInternalRecord - } - ve, ok := r.(*versions) - if !ok { - return nil, errInternalRecord - } - if !ve.internalSave { - return nil, errInternalRecord - } - return r, nil + return GetSimpleVersions().save() } diff --git a/updates/main.go b/updates/main.go index 550e23ac..bee808a0 100644 --- a/updates/main.go +++ b/updates/main.go @@ -7,6 +7,7 @@ import ( "runtime" "time" + "github.com/safing/portbase/database" "github.com/safing/portbase/dataroot" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" @@ -48,6 +49,11 @@ var ( updateASAP bool disableTaskSchedule bool + db = database.NewInterface(&database.Options{ + Local: true, + Internal: true, + }) + // UserAgent is an HTTP User-Agent that is used to add // more context to requests made by the registry when // fetching resources from the update server. @@ -55,6 +61,8 @@ var ( ) const ( + updatesDirName = "updates" + updateFailed = "updates:failed" updateSuccess = "updates:success" ) @@ -108,7 +116,7 @@ func start() error { registry.UserAgent = userAgentFromFlag } // initialize - err := registry.Initialize(dataroot.Root().ChildDir("updates", 0o0755)) + err := registry.Initialize(dataroot.Root().ChildDir(updatesDirName, 0o0755)) if err != nil { return err } @@ -275,7 +283,7 @@ func stop() error { } } - return stopVersionExport() + return nil } // RootPath returns the root path used for storing updates. From 959bb012b87b7b8e05053ac1eb6141dd234e6015 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 21 Jun 2022 16:56:00 +0200 Subject: [PATCH 15/22] Add broadcasts module --- broadcasts/api.go | 116 +++++++++++++++ broadcasts/data.go | 102 +++++++++++++ broadcasts/install_info.go | 175 +++++++++++++++++++++++ broadcasts/module.go | 46 ++++++ broadcasts/notify.go | 285 +++++++++++++++++++++++++++++++++++++ broadcasts/state.go | 64 +++++++++ core/core.go | 3 +- 7 files changed, 790 insertions(+), 1 deletion(-) create mode 100644 broadcasts/api.go create mode 100644 broadcasts/data.go create mode 100644 broadcasts/install_info.go create mode 100644 broadcasts/module.go create mode 100644 broadcasts/notify.go create mode 100644 broadcasts/state.go diff --git a/broadcasts/api.go b/broadcasts/api.go new file mode 100644 index 00000000..f855ddfc --- /dev/null +++ b/broadcasts/api.go @@ -0,0 +1,116 @@ +package broadcasts + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + + "github.com/safing/portbase/api" + "github.com/safing/portbase/database" + "github.com/safing/portbase/database/accessor" +) + +func registerAPIEndpoints() error { + if err := api.RegisterEndpoint(api.Endpoint{ + Path: `broadcasts/matching-data`, + Read: api.PermitAdmin, + BelongsTo: module, + StructFunc: handleMatchingData, + Name: "Get Broadcast Notifications Matching Data", + Description: "Returns the data used by the broadcast notifications to match the instance.", + }); err != nil { + return err + } + + if err := api.RegisterEndpoint(api.Endpoint{ + Path: `broadcasts/reset-state`, + Write: api.PermitAdmin, + WriteMethod: http.MethodPost, + BelongsTo: module, + ActionFunc: handleResetState, + Name: "Resets the Broadcast Notification States", + Description: "Delete the cache of Broadcast Notifications, making them appear again.", + }); err != nil { + return err + } + + if err := api.RegisterEndpoint(api.Endpoint{ + Path: `broadcasts/simulate`, + Write: api.PermitAdmin, + WriteMethod: http.MethodPost, + BelongsTo: module, + ActionFunc: handleSimulate, + Name: "Simulate Broadcast Notifications", + Description: "Test broadcast notifications by sending a valid source file in the body.", + Parameters: []api.Parameter{ + { + Method: http.MethodPost, + Field: "state", + Value: "true", + Description: "Check against state when deciding to display a broadcast notification. Acknowledgements are always saved.", + }, + }, + }); err != nil { + return err + } + + return nil +} + +func handleMatchingData(ar *api.Request) (i interface{}, err error) { + return collectData(), nil +} + +func handleResetState(ar *api.Request) (msg string, err error) { + err = db.Delete(broadcastStatesDBKey) + if err != nil { + return "", err + } + return "Reset complete.", nil +} + +func handleSimulate(ar *api.Request) (msg string, err error) { + // Parse broadcast notification data. + broadcasts, err := parseBroadcastSource(ar.InputData) + if err != nil { + return "", fmt.Errorf("failed to parse broadcast notifications update: %w", err) + } + + // Get and marshal matching data. + matchingData := collectData() + matchingJSON, err := json.Marshal(matchingData) + if err != nil { + return "", fmt.Errorf("failed to marshal broadcast notifications matching data: %w", err) + } + matchingDataAccessor := accessor.NewJSONBytesAccessor(&matchingJSON) + + var bss *BroadcastStates + if ar.URL.Query().Get("state") == "true" { + // Get broadcast notification states. + bss, err = getBroadcastStates() + if err != nil { + if !errors.Is(err, database.ErrNotFound) { + return "", fmt.Errorf("failed to get broadcast notifications states: %w", err) + } + bss = newBroadcastStates() + } + } + + // Go through all broadcast nofications and check if they match. + var results []string + for _, bn := range broadcasts.Notifications { + err := handleBroadcast(bn, matchingDataAccessor, bss) + switch { + case err == nil: + results = append(results, fmt.Sprintf("%30s: displayed", bn.id)) + case errors.Is(err, ErrSkip): + results = append(results, fmt.Sprintf("%30s: %s", bn.id, err)) + default: + results = append(results, fmt.Sprintf("FAILED %23s: %s", bn.id, err)) + } + } + + return strings.Join(results, "\n"), nil +} diff --git a/broadcasts/data.go b/broadcasts/data.go new file mode 100644 index 00000000..73da1bb9 --- /dev/null +++ b/broadcasts/data.go @@ -0,0 +1,102 @@ +package broadcasts + +import ( + "time" + + "github.com/safing/portbase/config" + "github.com/safing/portmaster/intel/geoip" + "github.com/safing/portmaster/netenv" + "github.com/safing/portmaster/updates" + "github.com/safing/spn/access" + "github.com/safing/spn/captain" +) + +var portmasterStarted = time.Now() + +func collectData() interface{} { + data := make(map[string]interface{}) + + // Get data about versions. + versions := updates.GetSimpleVersions() + data["Updates"] = versions + data["Version"] = versions.Build.Version + numericVersion, err := MakeNumericVersion(versions.Build.Version) + if err != nil { + data["NumericVersion"] = &DataError{ + Error: err, + } + } else { + data["NumericVersion"] = numericVersion + } + + // Get data about install. + installInfo, err := GetInstallInfo() + if err != nil { + data["Install"] = &DataError{ + Error: err, + } + } else { + data["Install"] = installInfo + } + + // Get global configuration. + data["Config"] = config.GetActiveConfigValues() + + // Get data about device location. + locs, ok := netenv.GetInternetLocation() + if ok && locs.Best().LocationOrNil() != nil { + loc := locs.Best() + data["Location"] = &Location{ + Country: loc.Location.Country.ISOCode, + Coordinates: loc.Location.Coordinates, + ASN: loc.Location.AutonomousSystemNumber, + ASOrg: loc.Location.AutonomousSystemOrganization, + Source: loc.Source, + SourceAccuracy: loc.SourceAccuracy, + } + } + + // Get data about SPN status. + data["SPN"] = captain.GetSPNStatus() + + // Get data about account. + userRecord, err := access.GetUser() + if err != nil { + data["Account"] = &DataError{ + Error: err, + } + } else { + data["Account"] = &Account{ + UserRecord: userRecord, + UpToDate: userRecord.Meta().Modified > time.Now().Add(-7*24*time.Hour).Unix(), + MayUseUSP: userRecord.MayUseSPN(), + } + } + + // Time running. + data["UptimeHours"] = int(time.Since(portmasterStarted).Hours()) + + return data +} + +// Location holds location matching data. +type Location struct { + Country string + Coordinates geoip.Coordinates + ASN uint + ASOrg string + Source netenv.DeviceLocationSource + SourceAccuracy int +} + +// Account holds SPN account matching data. +type Account struct { + *access.UserRecord + UpToDate bool + MayUseUSP bool +} + +// DataError represents an error getting some matching data. +type DataError struct { + Error error +} diff --git a/broadcasts/install_info.go b/broadcasts/install_info.go new file mode 100644 index 00000000..2f667a17 --- /dev/null +++ b/broadcasts/install_info.go @@ -0,0 +1,175 @@ +package broadcasts + +import ( + "errors" + "fmt" + "strconv" + "sync" + "time" + + semver "github.com/hashicorp/go-version" + + "github.com/safing/portbase/database" + "github.com/safing/portbase/database/query" + "github.com/safing/portbase/database/record" + "github.com/safing/portbase/info" + "github.com/safing/portbase/log" +) + +const installInfoDBKey = "core:status/install-info" + +// InstallInfo holds generic info about the install. +type InstallInfo struct { + record.Base + sync.Mutex + + Version string + NumericVersion int64 + + Time time.Time + NumericDate int64 + DaysSinceInstall int64 + UnixTimestamp int64 +} + +// GetInstallInfo returns the install info from the database. +func GetInstallInfo() (*InstallInfo, error) { + r, err := db.Get(installInfoDBKey) + if err != nil { + return nil, err + } + + // Unwrap. + if r.IsWrapped() { + // Only allocate a new struct, if we need it. + newRecord := &InstallInfo{} + err = record.Unwrap(r, newRecord) + if err != nil { + return nil, err + } + return newRecord, nil + } + + // or adjust type + newRecord, ok := r.(*InstallInfo) + if !ok { + return nil, fmt.Errorf("record not of type *InstallInfo, but %T", r) + } + return newRecord, nil +} + +func ensureInstallInfo() { + // Get current install info from database. + installInfo, err := GetInstallInfo() + if err != nil { + installInfo = &InstallInfo{} + if !errors.Is(err, database.ErrNotFound) { + log.Warningf("updates: failed to load install info: %s", err) + } + } + + // Fill in missing data and save. + installInfo.checkAll() + if err := installInfo.save(); err != nil { + log.Warningf("updates: failed to save install info: %s", err) + } +} + +func (ii *InstallInfo) save() error { + if !ii.KeyIsSet() { + ii.SetKey(installInfoDBKey) + } + return db.Put(ii) +} + +func (ii *InstallInfo) checkAll() { + ii.checkVersion() + ii.checkInstallDate() +} + +func (ii *InstallInfo) checkVersion() { + // Check if everything is present. + if ii.Version != "" && ii.NumericVersion > 0 { + return + } + + // Update version information. + versionInfo := info.GetInfo() + ii.Version = versionInfo.Version + + // Update numeric version. + if versionInfo.Version != "" { + numericVersion, err := MakeNumericVersion(versionInfo.Version) + if err != nil { + log.Warningf("updates: failed to make numeric version: %s", err) + } else { + ii.NumericVersion = numericVersion + } + } +} + +// MakeNumericVersion makes a numeric version with the first three version +// segment always using three digits. +func MakeNumericVersion(version string) (numericVersion int64, err error) { + // Parse version string. + ver, err := semver.NewVersion(version) + if err != nil { + return 0, fmt.Errorf("failed to parse core version: %w", err) + } + + // Transform version for numeric representation. + segments := ver.Segments() + for i := 0; i < 3 && i < len(segments); i++ { + segmentNumber := int64(segments[i]) + if segmentNumber > 999 { + segmentNumber = 999 + } + switch i { + case 0: + numericVersion += segmentNumber * 1000000 + case 1: + numericVersion += segmentNumber * 1000 + case 2: + numericVersion += segmentNumber + } + } + + return numericVersion, nil +} + +func (ii *InstallInfo) checkInstallDate() { + // Check if everything is present. + if ii.UnixTimestamp > 0 && + ii.NumericDate > 0 && + ii.DaysSinceInstall > 0 && + !ii.Time.IsZero() { + return + } + + // Find oldest created database entry and use it as install time. + oldest := time.Now().Unix() + it, err := db.Query(query.New("core")) + if err != nil { + log.Warningf("updates: failed to create iterator for searching DB for install time: %s", err) + return + } + defer it.Cancel() + for r := range it.Next { + if oldest > r.Meta().Created { + oldest = r.Meta().Created + } + } + + // Set data. + ii.UnixTimestamp = oldest + ii.Time = time.Unix(oldest, 0) + ii.DaysSinceInstall = int64(time.Since(ii.Time).Hours()) / 24 + + // Transform date for numeric representation. + numericDate, err := strconv.ParseInt(ii.Time.Format("20060102"), 10, 64) + if err != nil { + log.Warningf("updates: failed to make numeric date from %s: %s", ii.Time, err) + } else { + ii.NumericDate = numericDate + } +} diff --git a/broadcasts/module.go b/broadcasts/module.go new file mode 100644 index 00000000..360bc912 --- /dev/null +++ b/broadcasts/module.go @@ -0,0 +1,46 @@ +package broadcasts + +import ( + "sync" + "time" + + "github.com/safing/portbase/database" + "github.com/safing/portbase/modules" +) + +var ( + module *modules.Module + + db = database.NewInterface(&database.Options{ + Local: true, + Internal: true, + }) + + startOnce sync.Once +) + +func init() { + module = modules.Register("broadcasts", prep, start, nil, "updates", "netenv", "notifications") +} + +func prep() error { + // Register API endpoints. + if err := registerAPIEndpoints(); err != nil { + return err + } + + return nil +} + +func start() error { + // Ensure the install info is up to date. + ensureInstallInfo() + + // Start broadcast notifier task. + startOnce.Do(func() { + module.NewTask("broadcast notifier", broadcastNotify). + Repeat(10 * time.Minute).Queue() + }) + + return nil +} diff --git a/broadcasts/notify.go b/broadcasts/notify.go new file mode 100644 index 00000000..c7b7d661 --- /dev/null +++ b/broadcasts/notify.go @@ -0,0 +1,285 @@ +package broadcasts + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "strings" + "sync" + "time" + + "github.com/ghodss/yaml" + + "github.com/safing/portbase/database" + "github.com/safing/portbase/database/accessor" + "github.com/safing/portbase/database/query" + "github.com/safing/portbase/log" + "github.com/safing/portbase/modules" + "github.com/safing/portbase/notifications" + "github.com/safing/portmaster/updates" +) + +const ( + broadcastsResourcePath = "intel/portmaster/notifications.yaml" + + broadcastNotificationIDPrefix = "broadcasts:" + + minRepeatDuration = 1 * time.Hour +) + +// Errors. +var ( + ErrSkip = errors.New("broadcast skipped") + ErrSkipDoesNotMatch = fmt.Errorf("%w: does not match", ErrSkip) + ErrSkipAlreadyActive = fmt.Errorf("%w: already active", ErrSkip) + ErrSkipAlreadyShown = fmt.Errorf("%w: already shown", ErrSkip) + ErrSkipRemovedByMismatch = fmt.Errorf("%w: removed due to mismatch", ErrSkip) + ErrSkipRemovedBySource = fmt.Errorf("%w: removed by source", ErrSkip) +) + +// BroadcastNotifications holds the data structure of the broadcast +// notifications update file. +type BroadcastNotifications struct { + Notifications map[string]*BroadcastNotification +} + +// BroadcastNotification is a single broadcast notification. +type BroadcastNotification struct { + *notifications.Notification + id string + + // Match holds a query string that needs to match the local matching data in + // order for the broadcast to be displayed. + Match string + matchingQuery *query.Query + // AttachToModule signifies if the broadcast notification should be attached to the module. + AttachToModule bool + // Remove signifies that the broadcast should be canceled and its state removed. + Remove bool + // Permanent signifies that the broadcast cannot be acknowledge by the user + // and remains in the UI indefinitely. + Permanent bool + // Repeat specifies a duration after which the broadcast should be shown again. + Repeat string + repeatDuration time.Duration +} + +func broadcastNotify(ctx context.Context, t *modules.Task) error { + // Get broadcast notifications file, load it from disk and parse it. + broadcastsResource, err := updates.GetFile(broadcastsResourcePath) + if err != nil { + return fmt.Errorf("failed to get broadcast notifications update: %w", err) + } + broadcastsData, err := ioutil.ReadFile(broadcastsResource.Path()) + if err != nil { + return fmt.Errorf("failed to load broadcast notifications update: %w", err) + } + broadcasts, err := parseBroadcastSource(broadcastsData) + if err != nil { + return fmt.Errorf("failed to parse broadcast notifications update: %w", err) + } + + // Get and marshal matching data. + matchingData := collectData() + matchingJSON, err := json.Marshal(matchingData) + if err != nil { + return fmt.Errorf("failed to marshal broadcast notifications matching data: %w", err) + } + matchingDataAccessor := accessor.NewJSONBytesAccessor(&matchingJSON) + + // Get broadcast notification states. + bss, err := getBroadcastStates() + if err != nil { + if !errors.Is(err, database.ErrNotFound) { + return fmt.Errorf("failed to get broadcast notifications states: %w", err) + } + bss = newBroadcastStates() + } + + // Go through all broadcast nofications and check if they match. + for _, bn := range broadcasts.Notifications { + err := handleBroadcast(bn, matchingDataAccessor, bss) + switch { + case err == nil: + log.Infof("broadcasts: displaying broadcast %s", bn.id) + case errors.Is(err, ErrSkip): + log.Tracef("broadcasts: skipped displaying broadcast %s: %s", bn.id, err) + default: + log.Warningf("broadcasts: failed to handle broadcast %s: %s", bn.id, err) + } + } + + return nil +} + +func parseBroadcastSource(yamlData []byte) (*BroadcastNotifications, error) { + // Parse data. + broadcasts := &BroadcastNotifications{} + err := yaml.Unmarshal(yamlData, broadcasts) + if err != nil { + return nil, err + } + + // Add IDs to struct for easier handling. + for id, bn := range broadcasts.Notifications { + bn.id = id + + // Parse matching query. + if bn.Match != "" { + q, err := query.ParseQuery("query / where " + bn.Match) + if err != nil { + return nil, fmt.Errorf("failed to parse query of broadcast notification %s: %w", bn.id, err) + } + bn.matchingQuery = q + } + + // Parse the repeat duration. + if bn.Repeat != "" { + duration, err := time.ParseDuration(bn.Repeat) + if err != nil { + return nil, fmt.Errorf("failed to parse repeat duration of broadcast notification %s: %w", bn.id, err) + } + bn.repeatDuration = duration + // Raise duration to minimum. + if bn.repeatDuration < minRepeatDuration { + bn.repeatDuration = minRepeatDuration + } + } + } + + return broadcasts, nil +} + +func handleBroadcast(bn *BroadcastNotification, matchingDataAccessor accessor.Accessor, bss *BroadcastStates) error { + // Check if broadcast was already shown. + if bss != nil { + state, ok := bss.States[bn.id] + switch { + case !ok || state.Read.IsZero(): + // Was never shown, continue. + case bn.repeatDuration == 0 && !state.Read.IsZero(): + // Was already shown and is not repeated, skip. + return ErrSkipAlreadyShown + case bn.repeatDuration > 0 && time.Now().Add(-bn.repeatDuration).After(state.Read): + // Was already shown, but should be repeated now, continue. + } + } + + // Check if broadcast should be removed. + if bn.Remove { + removeBroadcast(bn, bss) + return ErrSkipRemovedBySource + } + + // Skip if broadcast does not match. + if bn.matchingQuery != nil && !bn.matchingQuery.MatchesAccessor(matchingDataAccessor) { + removed := removeBroadcast(bn, bss) + if removed { + return ErrSkipRemovedByMismatch + } + return ErrSkipDoesNotMatch + } + + // Check if there is already an active notification for this. + eventID := broadcastNotificationIDPrefix + bn.id + n := notifications.Get(eventID) + if n != nil { + // Already active! + return ErrSkipAlreadyActive + } + + // Prepare notification for displaying. + n = bn.Notification + n.EventID = eventID + n.GUID = "" + n.State = "" + n.SelectedActionID = "" + + // It is okay to edit the notification, as they are loaded from the file every time. + // Add dismiss button if the notification is not permanent. + if !bn.Permanent { + n.AvailableActions = append(n.AvailableActions, ¬ifications.Action{ + ID: "ack", + Text: "Got it!", + }) + } + n.SetActionFunction(markBroadcastAsRead) + + // Display notification. + n.Save() + + // Attach to module to raise more awareness. + if bn.AttachToModule { + n.AttachToModule(module) + } + + return nil +} + +func removeBroadcast(bn *BroadcastNotification, bss *BroadcastStates) (removed bool) { + // Remove any active notification. + n := notifications.Get(broadcastNotificationIDPrefix + bn.id) + if n != nil { + removed = true + n.Delete() + } + + // Remove any state. + if bss != nil { + delete(bss.States, bn.id) + } + + return +} + +var savingBroadcastStateLock sync.Mutex + +func markBroadcastAsRead(ctx context.Context, n *notifications.Notification) error { + // Lock persisting broadcast state. + savingBroadcastStateLock.Lock() + defer savingBroadcastStateLock.Unlock() + + // Get notification data. + var broadcastID, actionID string + func() { + n.Lock() + defer n.Unlock() + broadcastID = strings.TrimPrefix(n.EventID, broadcastNotificationIDPrefix) + actionID = n.SelectedActionID + }() + + // Check response. + switch actionID { + case "ack": + case "": + return fmt.Errorf("no action ID for %s", broadcastID) + default: + return fmt.Errorf("unexpected action ID for %s: %s", broadcastID, actionID) + } + + // Get broadcast notification states. + bss, err := getBroadcastStates() + if err != nil { + if !errors.Is(err, database.ErrNotFound) { + return fmt.Errorf("failed to get broadcast notifications states: %w", err) + } + bss = newBroadcastStates() + } + + // Get state for this notification. + bs, ok := bss.States[broadcastID] + if !ok { + bs = &BroadcastState{} + bss.States[broadcastID] = bs + } + + // Delete to allow for timely repeats. + n.Delete() + + // Mark as read and save to DB. + log.Infof("broadcasts: user acknowledged broadcast %s", broadcastID) + bs.Read = time.Now() + return bss.save() +} diff --git a/broadcasts/state.go b/broadcasts/state.go new file mode 100644 index 00000000..afe8994c --- /dev/null +++ b/broadcasts/state.go @@ -0,0 +1,64 @@ +package broadcasts + +import ( + "fmt" + "sync" + "time" + + "github.com/safing/portbase/database/record" +) + +const broadcastStatesDBKey = "core:broadcasts/state" + +// BroadcastStates holds states for broadcast notifications. +type BroadcastStates struct { + record.Base + sync.Mutex + + States map[string]*BroadcastState +} + +// BroadcastState holds state for a single broadcast notifications. +type BroadcastState struct { + Read time.Time +} + +func (bss *BroadcastStates) save() error { + return db.Put(bss) +} + +// getbroadcastStates returns the broadcast states from the database. +func getBroadcastStates() (*BroadcastStates, error) { + r, err := db.Get(broadcastStatesDBKey) + if err != nil { + return nil, err + } + + // Unwrap. + if r.IsWrapped() { + // Only allocate a new struct, if we need it. + newRecord := &BroadcastStates{} + err = record.Unwrap(r, newRecord) + if err != nil { + return nil, err + } + return newRecord, nil + } + + // or adjust type + newRecord, ok := r.(*BroadcastStates) + if !ok { + return nil, fmt.Errorf("record not of type *BroadcastStates, but %T", r) + } + return newRecord, nil +} + +// newBroadcastStates returns a new BroadcastStates. +func newBroadcastStates() *BroadcastStates { + bss := &BroadcastStates{ + States: make(map[string]*BroadcastState), + } + bss.SetKey(broadcastStatesDBKey) + + return bss +} diff --git a/core/core.go b/core/core.go index 80bd6343..8b70cba6 100644 --- a/core/core.go +++ b/core/core.go @@ -7,6 +7,7 @@ import ( "github.com/safing/portbase/modules" "github.com/safing/portbase/modules/subsystems" + _ "github.com/safing/portmaster/broadcasts" _ "github.com/safing/portmaster/netenv" _ "github.com/safing/portmaster/status" _ "github.com/safing/portmaster/ui" @@ -25,7 +26,7 @@ var ( ) func init() { - module = modules.Register("core", prep, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui", "netenv", "network", "interception", "compat") + module = modules.Register("core", prep, start, nil, "base", "subsystems", "status", "updates", "api", "notifications", "ui", "netenv", "network", "interception", "compat", "broadcasts") subsystems.Register( "core", "Core", From 92cc733aca318f45c8bef06b66be0cadb915039d Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 23 Jun 2022 16:30:55 +0200 Subject: [PATCH 16/22] Add broadcast notifications test data --- broadcasts/testdata/README.md | 9 +++++++++ broadcasts/testdata/notifications.yaml | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 broadcasts/testdata/README.md create mode 100644 broadcasts/testdata/notifications.yaml diff --git a/broadcasts/testdata/README.md b/broadcasts/testdata/README.md new file mode 100644 index 00000000..1752a7f6 --- /dev/null +++ b/broadcasts/testdata/README.md @@ -0,0 +1,9 @@ +# Testing Broadcast Notifications + +``` +# Reset state +curl -X POST http://127.0.0.1:817/api/v1/broadcasts/reset-state + +# Simulate notifications +curl --upload-file notifications.yaml http://127.0.0.1:817/api/v1/broadcasts/simulate +``` diff --git a/broadcasts/testdata/notifications.yaml b/broadcasts/testdata/notifications.yaml new file mode 100644 index 00000000..6c60d6b5 --- /dev/null +++ b/broadcasts/testdata/notifications.yaml @@ -0,0 +1,22 @@ +notifications: + test1: + title: "[TEST] Normal Broadcast" + message: "This is a normal broadcast without matching. (#1)" + test2: + title: "[TEST] Permanent Broadcast" + message: "This is a permanent broadcast without matching. (#2)" + type: 1 # Warning + permanent: true + test3: + title: "[TEST] Repeating Broadcast" + message: "This is a repeating broadcast without matching. (#3)" + repeat: "1m" + test4: + title: "[TEST] Matching Broadcast: PM version" + message: "This is a normal broadcast that matches the PM version. (#4)" + match: "NumericVersion > 8000" + test5: + title: "[TEST] Important Update" + message: "A criticial update has been released, please update immediately. (#5)" + type: 3 # Error + attachToModule: true From 492afc6dcfa2882749cc5ecbe5ddff19c676c612 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 23 Jun 2022 16:31:04 +0200 Subject: [PATCH 17/22] Update dependencies --- go.mod | 25 ++++++++++++------------- go.sum | 45 ++++++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 997bdcb0..ab267425 100644 --- a/go.mod +++ b/go.mod @@ -7,23 +7,24 @@ require ( github.com/cookieo9/resources-go v0.0.0-20150225115733-d27c04069d0d github.com/coreos/go-iptables v0.6.0 github.com/florianl/go-nfqueue v1.3.1 + github.com/ghodss/yaml v1.0.0 github.com/godbus/dbus/v5 v5.1.0 github.com/google/gopacket v1.1.19 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-version v1.4.0 - github.com/miekg/dns v1.1.49 + github.com/hashicorp/go-version v1.5.0 + github.com/miekg/dns v1.1.50 github.com/oschwald/maxminddb-golang v1.9.0 - github.com/safing/portbase v0.14.4 - github.com/safing/spn v0.4.11 + github.com/safing/portbase v0.14.5 + github.com/safing/spn v0.4.12 github.com/shirou/gopsutil v3.21.11+incompatible - github.com/spf13/cobra v1.4.0 + github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.7.1 github.com/tannerryan/ring v1.1.2 github.com/tevino/abool v1.2.0 github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 - golang.org/x/net v0.0.0-20220513224357-95641704303c - golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 - golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a + golang.org/x/net v0.0.0-20220622184535-263ec571b305 + golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f + golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 ) require ( @@ -35,7 +36,6 @@ require ( github.com/bluele/gcache v0.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/google/go-cmp v0.5.8 // indirect @@ -71,10 +71,9 @@ require ( github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/tools v0.1.11 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 7fe99705..40b1435d 100644 --- a/go.sum +++ b/go.sum @@ -250,6 +250,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -530,8 +531,9 @@ github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -688,8 +690,9 @@ github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7Xn github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8= github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -818,8 +821,9 @@ github.com/safing/portbase v0.14.0/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6X github.com/safing/portbase v0.14.1/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= github.com/safing/portbase v0.14.2/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= github.com/safing/portbase v0.14.3/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= -github.com/safing/portbase v0.14.4 h1:yEWlvh2w0gVdjrA9oo5QPFV5oluJ6YDoKRPtmFb9B4c= github.com/safing/portbase v0.14.4/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= +github.com/safing/portbase v0.14.5 h1:+8H+mQ7AFjA04M7UPq0490pj3/+nvJj3pEUP1PYTMYc= +github.com/safing/portbase v0.14.5/go.mod h1:z9sRR/vqohAGdYSSx2B+o8tND4WVvcxPL6XBBtN3bDI= github.com/safing/portmaster v0.7.3/go.mod h1:o//kZ8eE+5vT1V22mgnxHIAdlEz42sArsK5OF2Lf/+s= github.com/safing/portmaster v0.7.4/go.mod h1:Q93BWdF1oAL0oUMukshl8W1aPZhmrlTGi6tFTFc3pTw= github.com/safing/portmaster v0.7.6/go.mod h1:qOs9hQtvAzTVICRbwLg3vddqOaqJHeWBjWQ0C+TJ/Bw= @@ -837,6 +841,7 @@ github.com/safing/portmaster v0.8.5/go.mod h1:MqOlFwHcIx/109Ugutz/CG23znuuXCRVHc github.com/safing/portmaster v0.8.7/go.mod h1:RUgCWt5v22jDUOtJfOwApi//Kt8RTZQhlREcBc+L4z8= github.com/safing/portmaster v0.8.9-interdep/go.mod h1:1hK7QpvFVlb/sglkc3SKj+RXMGBuk0wqO2s3pvMg1Xs= github.com/safing/portmaster v0.8.9/go.mod h1:tv0rxO76hrpBLdArN7YTypOaseH6zgQ2gLI2zCknk9Q= +github.com/safing/portmaster v0.8.14-interdep/go.mod h1:HIkaE8wCXr8ULyZSWFkQNNY9obpMufxizXZugnjHLK0= github.com/safing/spn v0.3.4/go.mod h1:TfzNsZCbnlWv0UFDILFOUSudVKJZlnBVoR1fDXrjOK0= github.com/safing/spn v0.3.5/go.mod h1:jHkFF2Yu1fnjFu4KXjVA+iagMr/z4eB4p3jiwikvKj8= github.com/safing/spn v0.3.6/go.mod h1:RSeFb/h5Wt3yDVezXj3lhXJ/Iwd7FbtsGf5E+p5J2YQ= @@ -854,14 +859,10 @@ github.com/safing/spn v0.4.3/go.mod h1:YHtg3FkZviN8T7db4BdRffbYO1pO7w9SydQatLmvW github.com/safing/spn v0.4.5/go.mod h1:mkQA5pYM1SUd4JkTyuwXFycFMGQXLTd9RUJuY2vqccM= github.com/safing/spn v0.4.6/go.mod h1:AmZ+rore+6DQp0GSchIAXPn8ij0Knyw7uy4PbMLljXg= github.com/safing/spn v0.4.7/go.mod h1:NoSG9K0OK9hrPC76yqWFS6RtvbqZdIc/KGOsC4T3hV8= -github.com/safing/spn v0.4.8 h1:C5QOl03hypDaC4qvFtWjAKmSJIOjfqYVGT+sTnUIO/E= -github.com/safing/spn v0.4.8/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= -github.com/safing/spn v0.4.9 h1:p+TRS2y1yAY4CYyHiVuy+V3NcA9p826NtYksuBaSl64= -github.com/safing/spn v0.4.9/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= -github.com/safing/spn v0.4.10 h1:nZuWPBn1z0aBUDnnpG9pKZCmPAH2hgNE4cqiSB7JGU8= -github.com/safing/spn v0.4.10/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= github.com/safing/spn v0.4.11 h1:Er3ZtBCqKaf0G6lmRKpm1LenlrWeaWUp8612bpeG+aM= github.com/safing/spn v0.4.11/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= +github.com/safing/spn v0.4.12 h1:Tw7TUZEZR4yZy7L+ICRCketDk5L5x0s0pvrSUHFaKs4= +github.com/safing/spn v0.4.12/go.mod h1:AUNgBrRwCcspC98ljptDnrPuHLn/BHSG+rSprV/5Wlc= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -905,8 +906,9 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1094,8 +1096,10 @@ golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c= golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1133,8 +1137,9 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1215,8 +1220,10 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220513224357-95641704303c h1:nF9mHSvoKBLkQNQhJZNsc66z2UzAMUbLGjC95CF3pU0= golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220621193019-9d032be2e588/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220622184535-263ec571b305 h1:dAgbJ2SP4jD6XYfMNLVj0BF21jo2PjChrtGaAvF5M3I= +golang.org/x/net v0.0.0-20220622184535-263ec571b305/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1248,8 +1255,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1374,8 +1382,11 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1471,13 +1482,13 @@ golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= From 1dfab49024137381ee288cd27279d63beecbe94b Mon Sep 17 00:00:00 2001 From: Dave Gson <3080765+davegson@users.noreply.github.com> Date: Tue, 28 Jun 2022 11:49:29 +0000 Subject: [PATCH 18/22] Update Primary Tag-Line brings it up to speed with the website --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 621b7007..92d99b2e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Take Back Control of Your Computer +# Control Your Computer,
[Get Peace of Mind](https://safing.io/portmaster/) Portmaster is a free and open-source application that puts you back in charge over all your computer's network connections. Developed in the EU đŸ‡ĒđŸ‡ē, Austria. From d48d511dfe78e1892a80beb62f9acdf8ba4cf6c8 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 30 Jun 2022 11:17:01 +0200 Subject: [PATCH 19/22] Create dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..f6150ead --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "daily" From f57facc374d5634d27a3f9c37304058314c1c2a7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 30 Jun 2022 11:17:23 +0200 Subject: [PATCH 20/22] Create codeql-analysis.yml --- .github/workflows/codeql-analysis.yml | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..fd52cfbc --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,72 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "develop", master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "develop" ] + schedule: + - cron: '43 14 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 From 44b54067d3d50d27bfec77b735ea65ce05250833 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 09:18:02 +0000 Subject: [PATCH 21/22] Bump github.com/hashicorp/go-version from 1.5.0 to 1.6.0 Bumps [github.com/hashicorp/go-version](https://github.com/hashicorp/go-version) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/hashicorp/go-version/releases) - [Changelog](https://github.com/hashicorp/go-version/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/go-version/compare/v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/go-version dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ab267425..6561634a 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 github.com/google/gopacket v1.1.19 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/go-version v1.5.0 + github.com/hashicorp/go-version v1.6.0 github.com/miekg/dns v1.1.50 github.com/oschwald/maxminddb-golang v1.9.0 github.com/safing/portbase v0.14.5 diff --git a/go.sum b/go.sum index 40b1435d..ad502342 100644 --- a/go.sum +++ b/go.sum @@ -532,8 +532,9 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -859,7 +860,6 @@ github.com/safing/spn v0.4.3/go.mod h1:YHtg3FkZviN8T7db4BdRffbYO1pO7w9SydQatLmvW github.com/safing/spn v0.4.5/go.mod h1:mkQA5pYM1SUd4JkTyuwXFycFMGQXLTd9RUJuY2vqccM= github.com/safing/spn v0.4.6/go.mod h1:AmZ+rore+6DQp0GSchIAXPn8ij0Knyw7uy4PbMLljXg= github.com/safing/spn v0.4.7/go.mod h1:NoSG9K0OK9hrPC76yqWFS6RtvbqZdIc/KGOsC4T3hV8= -github.com/safing/spn v0.4.11 h1:Er3ZtBCqKaf0G6lmRKpm1LenlrWeaWUp8612bpeG+aM= github.com/safing/spn v0.4.11/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= github.com/safing/spn v0.4.12 h1:Tw7TUZEZR4yZy7L+ICRCketDk5L5x0s0pvrSUHFaKs4= github.com/safing/spn v0.4.12/go.mod h1:AUNgBrRwCcspC98ljptDnrPuHLn/BHSG+rSprV/5Wlc= From 20b9bdc74347bf88d59c44fb2b80a33f5a726db1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 09:18:11 +0000 Subject: [PATCH 22/22] Bump github.com/stretchr/testify from 1.7.1 to 1.8.0 Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.1 to 1.8.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.7.1...v1.8.0) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index ab267425..25ac29e3 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/safing/spn v0.4.12 github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cobra v1.5.0 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.8.0 github.com/tannerryan/ring v1.1.2 github.com/tevino/abool v1.2.0 github.com/umahmood/haversine v0.0.0-20151105152445-808ab04add26 @@ -75,5 +75,5 @@ require ( golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/tools v0.1.11 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 40b1435d..c052dbcf 100644 --- a/go.sum +++ b/go.sum @@ -859,7 +859,6 @@ github.com/safing/spn v0.4.3/go.mod h1:YHtg3FkZviN8T7db4BdRffbYO1pO7w9SydQatLmvW github.com/safing/spn v0.4.5/go.mod h1:mkQA5pYM1SUd4JkTyuwXFycFMGQXLTd9RUJuY2vqccM= github.com/safing/spn v0.4.6/go.mod h1:AmZ+rore+6DQp0GSchIAXPn8ij0Knyw7uy4PbMLljXg= github.com/safing/spn v0.4.7/go.mod h1:NoSG9K0OK9hrPC76yqWFS6RtvbqZdIc/KGOsC4T3hV8= -github.com/safing/spn v0.4.11 h1:Er3ZtBCqKaf0G6lmRKpm1LenlrWeaWUp8612bpeG+aM= github.com/safing/spn v0.4.11/go.mod h1:nro/I6b2JnafeeqoMsQRqf6TaQeL9uLLZkUREtxLVDE= github.com/safing/spn v0.4.12 h1:Tw7TUZEZR4yZy7L+ICRCketDk5L5x0s0pvrSUHFaKs4= github.com/safing/spn v0.4.12/go.mod h1:AUNgBrRwCcspC98ljptDnrPuHLn/BHSG+rSprV/5Wlc= @@ -924,6 +923,7 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -931,8 +931,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tannerryan/ring v1.1.2 h1:iXayOjqHQOLzuy9GwSKuG3nhWfzQkldMlQivcgIr7gQ= github.com/tannerryan/ring v1.1.2/go.mod h1:DkELJEjbZhJBtFKR9Xziwj3HKZnb/knRgljNqp65vH4= @@ -1684,8 +1685,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=