diff --git a/firewall/filter.go b/firewall/filter.go index 81f62454..9c0efdeb 100644 --- a/firewall/filter.go +++ b/firewall/filter.go @@ -3,6 +3,7 @@ package firewall import ( "github.com/safing/portbase/config" "github.com/safing/portbase/modules/subsystems" + "github.com/safing/spn/captain" "github.com/safing/portbase/modules" @@ -13,6 +14,7 @@ import ( var ( filterModule *modules.Module filterEnabled config.BoolOption + tunnelEnabled config.BoolOption ) func init() { @@ -28,8 +30,8 @@ func init() { Key: CfgOptionEnableFilterKey, Description: "Start the Privacy Filter module. If turned off, all privacy filter protections are fully disabled on this device.", OptType: config.OptTypeBool, - ExpertiseLevel: config.ExpertiseLevelUser, - ReleaseLevel: config.ReleaseLevelBeta, + ExpertiseLevel: config.ExpertiseLevelDeveloper, + ReleaseLevel: config.ReleaseLevelStable, DefaultValue: true, Annotations: config.Annotations{ config.CategoryAnnotation: "General", @@ -44,6 +46,7 @@ func filterPrep() (err error) { return err } - filterEnabled = config.GetAsBool(CfgOptionEnableFilterKey, true) + filterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true) + tunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false) return nil } diff --git a/firewall/interception.go b/firewall/interception.go index 007e3785..575179be 100644 --- a/firewall/interception.go +++ b/firewall/interception.go @@ -9,6 +9,8 @@ import ( "sync/atomic" "time" + "github.com/safing/spn/captain" + "github.com/google/gopacket/layers" "github.com/safing/portmaster/netenv" "golang.org/x/sync/singleflight" @@ -22,7 +24,7 @@ import ( "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/netutils" "github.com/safing/portmaster/network/packet" - "github.com/safing/spn/captain" + "github.com/safing/spn/crew" "github.com/safing/spn/sluice" // module dependencies @@ -346,32 +348,41 @@ func initialHandler(conn *network.Connection, pkt packet.Packet) { return } - // check if filtering is enabled - if !filterEnabled() { - conn.Inspecting = false + // TODO: enable inspecting again + conn.Inspecting = false + + // Filter, if enabled. + if filterEnabled() { + log.Tracer(pkt.Ctx()).Trace("filter: starting decision process") + DecideOnConnection(pkt.Ctx(), conn, pkt) + } else { conn.Accept("privacy filter disabled", noReasonOptionKey) - conn.StopFirewallHandler() - issueVerdict(conn, pkt, 0, true) - return } - log.Tracer(pkt.Ctx()).Trace("filter: starting decision process") - DecideOnConnection(pkt.Ctx(), conn, pkt) - conn.Inspecting = false // TODO: enable inspecting again + // Tunnel, if enabled. + if pkt.IsOutbound() && conn.Entity.IPScope.IsGlobal() && + tunnelEnabled() && conn.Verdict == network.VerdictAccept && + conn.Process().Profile() != nil && + conn.Process().Profile().UseSPN() { - // tunneling - // TODO: add implementation for forced tunneling - if pkt.IsOutbound() && - captain.ClientReady() && - conn.Entity.IPScope.IsGlobal() && - conn.Verdict == network.VerdictAccept { - // try to tunnel - err := sluice.AwaitRequest(pkt.Info(), conn.Entity.Domain) - if err != nil { - log.Tracer(pkt.Ctx()).Tracef("filter: not tunneling: %s", err) - } else { - log.Tracer(pkt.Ctx()).Trace("filter: tunneling request") - conn.Verdict = network.VerdictRerouteToTunnel + // Exclude requests of the SPN itself. + if !captain.IsExcepted(conn.Entity.IP) { + // Check if client is ready. + if captain.ClientReady() { + // Queue request in sluice. + err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest) + if err != nil { + log.Tracer(pkt.Ctx()).Warningf("failed to rqeuest tunneling: %s", err) + conn.Failed("failed to request tunneling", "") + } else { + log.Tracer(pkt.Ctx()).Trace("filter: tunneling requested") + conn.Verdict = network.VerdictRerouteToTunnel + } + } else { + // Block connection as SPN is not ready yet. + log.Tracer(pkt.Ctx()).Trace("SPN not ready for tunneling") + conn.Failed("SPN not ready for tunneling", "") + } } } diff --git a/intel/filterlists/lookup.go b/intel/filterlists/lookup.go index a975c281..94f4e129 100644 --- a/intel/filterlists/lookup.go +++ b/intel/filterlists/lookup.go @@ -30,7 +30,7 @@ func lookupBlockLists(entity, value string) ([]string, error) { return nil, nil } - log.Debugf("intel/filterlists: searching for entries with %s", key) + // log.Debugf("intel/filterlists: searching for entries with %s", key) entry, err := getEntityRecordByKey(key) if err != nil { if err == database.ErrNotFound { diff --git a/netenv/location.go b/netenv/location.go index b46728a7..f2e895b4 100644 --- a/netenv/location.go +++ b/netenv/location.go @@ -2,7 +2,9 @@ package netenv import ( "errors" + "fmt" "net" + "sort" "sync" "syscall" "time" @@ -22,9 +24,7 @@ var ( locationTestingIPv4 = "1.1.1.1" locationTestingIPv4Addr *net.IPAddr - locations = &DeviceLocations{ - All: make(map[string]*DeviceLocation), - } + locations = &DeviceLocations{} locationsLock sync.Mutex gettingLocationsLock sync.Mutex locationNetworkChangedFlag = GetNetworkChangedFlag() @@ -36,8 +36,32 @@ func prepLocation() (err error) { } type DeviceLocations struct { - Best *DeviceLocation - All map[string]*DeviceLocation + All []*DeviceLocation +} + +func (dl *DeviceLocations) Best() *DeviceLocation { + if len(dl.All) > 0 { + return dl.All[0] + } + return nil +} + +func (dl *DeviceLocations) BestV4() *DeviceLocation { + for _, loc := range dl.All { + if loc.IPVersion == packet.IPv4 { + return loc + } + } + return nil +} + +func (dl *DeviceLocations) BestV6() *DeviceLocation { + for _, loc := range dl.All { + if loc.IPVersion == packet.IPv6 { + return loc + } + } + return nil } func copyDeviceLocations() *DeviceLocations { @@ -45,23 +69,20 @@ func copyDeviceLocations() *DeviceLocations { defer locationsLock.Unlock() // Create a copy of the locations, but not the entries. - cp := *locations - cp.All = make(map[string]*DeviceLocation, len(locations.All)) - for k, v := range locations.All { - cp.All[k] = v + cp := &DeviceLocations{ + All: make([]*DeviceLocation, len(locations.All)), } + copy(cp.All, locations.All) - return &cp + return cp } // DeviceLocation represents a single IP and metadata. It must not be changed // once created. type DeviceLocation struct { IP net.IP - Continent string - Country string - ASN uint - ASOrg string + IPVersion packet.IPVersion + Location *geoip.Location Source DeviceLocationSource SourceAccuracy int } @@ -71,19 +92,43 @@ type DeviceLocation struct { func (dl *DeviceLocation) IsMoreAccurateThan(other *DeviceLocation) bool { switch { case dl.SourceAccuracy > other.SourceAccuracy: - // Higher accuracy is better. + // Higher source accuracy is better. return true - case dl.ASN != 0 && other.ASN == 0: + case dl.Location.AutonomousSystemNumber != 0 && other.Location.AutonomousSystemNumber == 0: // Having an ASN is better than having none. return true - case dl.Country == "" && other.Country != "": + case dl.Location.Continent.Code != "" && other.Location.Continent.Code == "": + // Having a Continent is better than having none. + return true + case dl.Location.Country.ISOCode != "" && other.Location.Country.ISOCode == "": // Having a Country is better than having none. return true + case dl.Location.Coordinates.AccuracyRadius < other.Location.Coordinates.AccuracyRadius: + // Higher geo accuracy is better. + return true } return false } +func (dl *DeviceLocation) LocationOrNil() *geoip.Location { + if dl == nil { + return nil + } + return dl.Location +} + +func (dl *DeviceLocation) String() string { + switch { + case dl == nil: + return "" + case dl.Location == nil: + return dl.IP.String() + default: + return fmt.Sprintf("%s (AS%d in %s)", dl.IP, dl.Location.AutonomousSystemNumber, dl.Location.Country.ISOCode) + } +} + type DeviceLocationSource string const ( @@ -111,6 +156,12 @@ func (dls DeviceLocationSource) Accuracy() int { } } +type sortLocationsByAccuracy []*DeviceLocation + +func (a sortLocationsByAccuracy) Len() int { return len(a) } +func (a sortLocationsByAccuracy) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a sortLocationsByAccuracy) Less(i, j int) bool { return a[j].IsMoreAccurateThan(a[i]) } + func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) { // Check if IP is global. if netutils.GetIPScope(ip) != netutils.Global { @@ -123,39 +174,41 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) { Source: source, SourceAccuracy: source.Accuracy(), } + if v4 := ip.To4(); v4 != nil { + loc.IPVersion = packet.IPv4 + } else { + loc.IPVersion = packet.IPv6 + } // Get geoip information, but continue if it fails. geoLoc, err := geoip.GetLocation(ip) if err != nil { log.Warningf("netenv: failed to get geolocation data of %s (from %s): %s", ip, source, err) } else { - loc.Continent = geoLoc.Continent.Code - loc.Country = geoLoc.Country.ISOCode - loc.ASN = geoLoc.AutonomousSystemNumber - loc.ASOrg = geoLoc.AutonomousSystemOrganization + loc.Location = geoLoc } locationsLock.Lock() defer locationsLock.Unlock() // Add to locations, if better. - key := loc.IP.String() - existing, ok := locations.All[key] - if ok && existing.IsMoreAccurateThan(loc) { - // Existing entry is more accurate, abort adding. - // Return true, because the IP address is already part of the locations. - return true - } - locations.All[key] = loc - - // Find best location. - best := loc - for _, dl := range locations.All { - if dl.IsMoreAccurateThan(best) { - best = dl + var exists bool + for i, existing := range locations.All { + if ip.Equal(existing.IP) { + exists = true + if loc.IsMoreAccurateThan(existing) { + // Replace + locations.All[i] = loc + break + } } } - locations.Best = best + if !exists { + locations.All = append(locations.All, loc) + } + + // Sort locations. + sort.Sort(sortLocationsByAccuracy(locations.All)) return true } @@ -163,10 +216,10 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (ok bool) { // DEPRECATED: Please use GetInternetLocation instead. func GetApproximateInternetLocation() (net.IP, error) { loc, ok := GetInternetLocation() - if !ok { + if !ok || loc.Best() == nil { return nil, errors.New("no location data available") } - return loc.Best.IP, nil + return loc.Best().IP, nil } func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) { @@ -179,38 +232,54 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) { } locationNetworkChangedFlag.Refresh() - // Check different sources, return on first success. - switch { - case getLocationFromInterfaces(): - case getLocationFromTraceroute(): - default: + // Get all assigned addresses. + v4s, v6s, err := GetAssignedAddresses() + if err != nil { + log.Warningf("netenv: failed to get assigned addresses: %s", err) + return nil, false + } + + // Check interfaces for global addresses. + v4ok, v6ok := getLocationFromInterfaces() + + // Try other methods for missing locations. + if len(v4s) > 0 && !v4ok { + v4ok = getLocationFromTraceroute() + } + if len(v6s) > 0 && !v6ok { + // TODO + log.Warningf("netenv: could not get IPv6 location") + } + + // Check if we have any locations. + if !v4ok && !v6ok { return nil, false } // Return gathered locations. cp := copyDeviceLocations() - return cp, cp.Best != nil + return cp, true } -func getLocationFromInterfaces() (ok bool) { +func getLocationFromInterfaces() (v4ok, v6ok bool) { globalIPv4, globalIPv6, err := GetAssignedGlobalAddresses() if err != nil { log.Warningf("netenv: location: failed to get assigned global addresses: %s", err) - return false + return false, false } for _, ip := range globalIPv4 { if SetInternetLocation(ip, SourceInterface) { - ok = true + v4ok = true } } for _, ip := range globalIPv6 { if SetInternetLocation(ip, SourceInterface) { - ok = true + v6ok = true } } - return ok + return } // TODO: Check feasibility of getting the external IP via UPnP. @@ -223,7 +292,7 @@ func getLocationFromUPnP() (ok bool) { } */ -func getLocationFromTraceroute() (ok bool) { +func getLocationFromTraceroute() (v4ok bool) { // Create connection. conn, err := net.ListenPacket("ip4:icmp", "") if err != nil { diff --git a/network/connection.go b/network/connection.go index 234849c5..e628578f 100644 --- a/network/connection.go +++ b/network/connection.go @@ -502,10 +502,14 @@ func (conn *Connection) SetVerdict(newVerdict Verdict, reason, reasonOptionKey s conn.Verdict = newVerdict conn.Reason.Msg = reason conn.Reason.Context = reasonCtx + + conn.Reason.Profile = "" + conn.Reason.OptionKey = "" if reasonOptionKey != "" && conn.Process() != nil { - conn.Reason.OptionKey = reasonOptionKey conn.Reason.Profile = conn.Process().Profile().GetProfileSource(conn.Reason.OptionKey) + conn.Reason.OptionKey = reasonOptionKey } + return true } return false diff --git a/network/iphelper/tables.go b/network/iphelper/tables.go index 30094588..f8f99802 100644 --- a/network/iphelper/tables.go +++ b/network/iphelper/tables.go @@ -206,7 +206,7 @@ func (ipHelper *IPHelper) getTable(ipVersion, protocol uint8) (connections []*so case winErrInsufficientBuffer: if i >= maxTries { return nil, nil, fmt.Errorf( - "insufficient buffer error (tried %d times): %s bytes required - [NT 0x%X] %s", + "insufficient buffer error (tried %d times): %d bytes required - [NT 0x%X] %s", i, bufSize, r1, err, ) } diff --git a/profile/config.go b/profile/config.go index 86321c4c..8952fe90 100644 --- a/profile/config.go +++ b/profile/config.go @@ -109,9 +109,9 @@ func registerConfiguration() error { // ask - ask mode: if not verdict is found, the user is consulted // block - allowlist mode: everything is blocked unless explicitly allowed err := config.Register(&config.Option{ - Name: "Default Action", + Name: "Default Network Action", Key: CfgOptionDefaultActionKey, - Description: `The default action when nothing else allows or blocks an outgoing connection. Incoming connections are always blocked by default.`, + Description: `The default network action is applied when nothing else allows or blocks an outgoing connection. Incoming connections are always blocked by default.`, OptType: config.OptTypeString, DefaultValue: "permit", Annotations: config.Annotations{ @@ -169,6 +169,7 @@ func registerConfiguration() error { - By address: "192.168.0.1" - By network: "192.168.0.1/24" +- By network scope: "Localhost", "LAN" or "Internet" - By domain: - Matching a distinct domain: "example.com" - Matching a domain with subdomains: ".example.com" @@ -176,6 +177,7 @@ func registerConfiguration() error { - Matching with a wildcard suffix: "example.*" - Matching domains containing text: "*example*" - By country (based on IP): "US" +- By AS number: "AS123456" - By filter list - use the filterlist ID prefixed with "L:": "L:MAL" - Match anything: "*" @@ -333,9 +335,9 @@ The lists are automatically updated every hour using incremental updates. // Block Scope Local err = config.Register(&config.Option{ - Name: "Block Device-Local Connections", + Name: "Force Block Device-Local Connections", Key: CfgOptionBlockScopeLocalKey, - Description: "Block all internal connections on your own device, ie. localhost. Is stronger than Rules (see below).", + Description: "Force Block all internal connections on your own device, ie. localhost. Is stronger than Rules (see below).", OptType: config.OptTypeInt, ExpertiseLevel: config.ExpertiseLevelExpert, DefaultValue: status.SecurityLevelOff, @@ -354,9 +356,9 @@ The lists are automatically updated every hour using incremental updates. // Block Scope LAN err = config.Register(&config.Option{ - Name: "Block LAN", + Name: "Force Block LAN", Key: CfgOptionBlockScopeLANKey, - Description: "Block all connections from and to the Local Area Network. Is stronger than Rules (see below).", + Description: "Force Block all connections from and to the Local Area Network. Is stronger than Rules (see below).", OptType: config.OptTypeInt, DefaultValue: status.SecurityLevelsHighAndExtreme, PossibleValues: status.AllSecurityLevelValues, @@ -374,9 +376,9 @@ The lists are automatically updated every hour using incremental updates. // Block Scope Internet err = config.Register(&config.Option{ - Name: "Block Internet Access", + Name: "Force Block Internet Access", Key: CfgOptionBlockScopeInternetKey, - Description: "Block connections from and to the Internet. Is stronger than Rules (see below).", + Description: "Force Block connections from and to the Internet. Is stronger than Rules (see below).", OptType: config.OptTypeInt, DefaultValue: status.SecurityLevelOff, PossibleValues: status.AllSecurityLevelValues, @@ -394,7 +396,7 @@ The lists are automatically updated every hour using incremental updates. // Block Peer to Peer Connections err = config.Register(&config.Option{ - Name: "Block P2P/Direct Connections", + Name: "Force Block P2P/Direct Connections", Key: CfgOptionBlockP2PKey, Description: "These are connections that are established directly to an IP address or peer on the Internet without resolving a domain name via DNS first. Is stronger than Rules (see below).", OptType: config.OptTypeInt, @@ -414,7 +416,7 @@ The lists are automatically updated every hour using incremental updates. // Block Inbound Connections err = config.Register(&config.Option{ - Name: "Block Incoming Connections", + Name: "Force Block Incoming Connections", Key: CfgOptionBlockInboundKey, Description: "Connections initiated towards your device from the LAN or Internet. This will usually only be the case if you are running a network service or are using peer to peer software. Is stronger than Rules (see below).", OptType: config.OptTypeInt, diff --git a/resolver/resolve.go b/resolver/resolve.go index 4bf5166f..d4a123bd 100644 --- a/resolver/resolve.go +++ b/resolver/resolve.go @@ -32,6 +32,8 @@ var ( ErrFailure = errors.New("query failed") // ErrContinue is returned when the resolver has no answer, and the next resolver should be asked ErrContinue = errors.New("resolver has no answer") + // ErrShuttingDown is returned when the resolver is shutting down. + ErrShuttingDown = errors.New("resolver is shutting down") // detailed errors @@ -275,6 +277,8 @@ retry: case <-time.After(maxRequestTimeout): // something went wrong with the query, retry goto retry + case <-ctx.Done(): + return nil } } else { // but that someone is taking too long @@ -331,7 +335,7 @@ resolveLoop: for i = 0; i < 2; i++ { for _, resolver := range resolvers { if module.IsStopping() { - return nil, errors.New("shutting down") + return nil, ErrShuttingDown } // check if resolver failed recently (on first run) @@ -364,6 +368,12 @@ resolveLoop: resolver.Conn.ReportFailure() log.Tracer(ctx).Debugf("resolver: query to %s timed out", resolver.Info.ID()) continue + case errors.Is(err, context.Canceled): + return nil, err + case errors.Is(err, context.DeadlineExceeded): + return nil, err + case errors.Is(err, ErrShuttingDown): + return nil, err default: resolver.Conn.ReportFailure() log.Tracer(ctx).Debugf("resolver: query to %s failed: %s", resolver.Info.ID(), err) diff --git a/resolver/resolver-mdns.go b/resolver/resolver-mdns.go index 88549176..59f20884 100644 --- a/resolver/resolver-mdns.go +++ b/resolver/resolver-mdns.go @@ -418,6 +418,8 @@ func queryMulticastDNS(ctx context.Context, q *Query) (*RRCache, error) { if err != nil { return rrCache, nil } + case <-ctx.Done(): + return nil, ctx.Err() } // Respond with NXDomain. diff --git a/resolver/resolver-tcp.go b/resolver/resolver-tcp.go index c9062ebf..418b0bad 100644 --- a/resolver/resolver-tcp.go +++ b/resolver/resolver-tcp.go @@ -105,7 +105,7 @@ func (tr *TCPResolver) UseTLS() *TCPResolver { return tr } -func (tr *TCPResolver) getOrCreateResolverConn() (*tcpResolverConn, error) { +func (tr *TCPResolver) getOrCreateResolverConn(ctx context.Context) (*tcpResolverConn, error) { tr.Lock() defer tr.Unlock() @@ -117,6 +117,10 @@ func (tr *TCPResolver) getOrCreateResolverConn() (*tcpResolverConn, error) { return tr.resolverConn, nil case <-time.After(heartbeatTimeout): log.Warningf("resolver: heartbeat for dns client %s failed", tr.resolver.Info.DescriptiveName()) + case <-ctx.Done(): + return nil, ctx.Err() + case <-module.Stopping(): + return nil, ErrShuttingDown } } @@ -130,7 +134,6 @@ func (tr *TCPResolver) getOrCreateResolverConn() (*tcpResolverConn, error) { } // Connect to server. - var err error conn, err := tr.dnsClient.Dial(tr.resolver.ServerAddress) if err != nil { log.Debugf("resolver: failed to connect to %s", tr.resolver.Info.DescriptiveName()) @@ -171,7 +174,7 @@ func (tr *TCPResolver) getOrCreateResolverConn() (*tcpResolverConn, error) { // Query executes the given query against the resolver. func (tr *TCPResolver) Query(ctx context.Context, q *Query) (*RRCache, error) { // Get resolver connection. - resolverConn, err := tr.getOrCreateResolverConn() + resolverConn, err := tr.getOrCreateResolverConn(ctx) if err != nil { return nil, err } @@ -185,6 +188,10 @@ func (tr *TCPResolver) Query(ctx context.Context, q *Query) (*RRCache, error) { // Submit query request to live connection. select { case resolverConn.queries <- tq: + case <-ctx.Done(): + return nil, ctx.Err() + case <-module.Stopping(): + return nil, ErrShuttingDown case <-time.After(defaultRequestTimeout): return nil, ErrTimeout } @@ -193,6 +200,10 @@ func (tr *TCPResolver) Query(ctx context.Context, q *Query) (*RRCache, error) { var reply *dns.Msg select { case reply = <-tq.Response: + case <-ctx.Done(): + return nil, ctx.Err() + case <-module.Stopping(): + return nil, ErrShuttingDown case <-time.After(defaultRequestTimeout): return nil, ErrTimeout } diff --git a/updates/helper/updates.go b/updates/helper/updates.go index bce82e4b..7477c51c 100644 --- a/updates/helper/updates.go +++ b/updates/helper/updates.go @@ -3,11 +3,18 @@ package helper import ( "fmt" "runtime" + + "github.com/tevino/abool" ) -const ( - onWindows = runtime.GOOS == "windows" -) +const onWindows = runtime.GOOS == "windows" + +var intelOnly = abool.New() + +// IntelOnly specifies that only intel data is mandatory. +func IntelOnly() { + intelOnly.Set() +} // PlatformIdentifier converts identifier for the current platform. func PlatformIdentifier(identifier string) string { @@ -20,33 +27,10 @@ func PlatformIdentifier(identifier string) string { // MandatoryUpdates returns mandatory updates that should be loaded on install // or reset. func MandatoryUpdates() (identifiers []string) { - // Binaries - if onWindows { - identifiers = []string{ - PlatformIdentifier("core/portmaster-core.exe"), - PlatformIdentifier("kext/portmaster-kext.dll"), - PlatformIdentifier("kext/portmaster-kext.sys"), - PlatformIdentifier("start/portmaster-start.exe"), - PlatformIdentifier("notifier/portmaster-notifier.exe"), - PlatformIdentifier("notifier/portmaster-snoretoast.exe"), - } - } else { - identifiers = []string{ - PlatformIdentifier("core/portmaster-core"), - PlatformIdentifier("start/portmaster-start"), - PlatformIdentifier("notifier/portmaster-notifier"), - } - } - - // Components, Assets and Data + // Intel identifiers = append( identifiers, - // User interface components - PlatformIdentifier("app/portmaster-app.zip"), - "all/ui/modules/portmaster.zip", - "all/ui/modules/assets.zip", - // Filter lists data "all/intel/lists/index.dsd", "all/intel/lists/base.dsdl", @@ -58,11 +42,50 @@ func MandatoryUpdates() (identifiers []string) { "all/intel/geoip/geoipv6.mmdb.gz", ) + // Stop here if we only want intel data. + if intelOnly.IsSet() { + return + } + + // Binaries + if onWindows { + identifiers = append( + identifiers, + PlatformIdentifier("core/portmaster-core.exe"), + PlatformIdentifier("kext/portmaster-kext.dll"), + PlatformIdentifier("kext/portmaster-kext.sys"), + PlatformIdentifier("start/portmaster-start.exe"), + PlatformIdentifier("notifier/portmaster-notifier.exe"), + PlatformIdentifier("notifier/portmaster-snoretoast.exe"), + ) + } else { + identifiers = append( + identifiers, + PlatformIdentifier("core/portmaster-core"), + PlatformIdentifier("start/portmaster-start"), + PlatformIdentifier("notifier/portmaster-notifier"), + ) + } + + // Components, Assets and Data + identifiers = append( + identifiers, + + // User interface components + PlatformIdentifier("app/portmaster-app.zip"), + "all/ui/modules/portmaster.zip", + "all/ui/modules/assets.zip", + ) + return identifiers } // AutoUnpackUpdates returns assets that need unpacking. func AutoUnpackUpdates() []string { + if intelOnly.IsSet() { + return []string{} + } + return []string{ PlatformIdentifier("app/portmaster-app.zip"), }