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 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 } 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) } 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/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() 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 +} 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/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) } diff --git a/netenv/main.go b/netenv/main.go index 0d831e76..3363754a 100644 --- a/netenv/main.go +++ b/netenv/main.go @@ -1,6 +1,9 @@ package netenv import ( + "github.com/tevino/abool" + + "github.com/safing/portbase/log" "github.com/safing/portbase/modules" ) @@ -20,6 +23,8 @@ func init() { } func prep() error { + checkForIPv6Stack() + if err := registerAPIEndpoints(); err != nil { return err } @@ -46,3 +51,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/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") } } 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{ diff --git a/profile/config.go b/profile/config.go index 987594d4..e371a175 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,38 +340,17 @@ 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. - -**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{ 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 +361,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 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 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)