mirror of
https://github.com/safing/portmaster
synced 2025-09-02 10:39:22 +00:00
Merge pull request #689 from safing/fix/patch-set-15
Improve support for IPv4 stack, location and geoip improvements
This commit is contained in:
commit
b58d7fb858
15 changed files with 236 additions and 160 deletions
|
@ -17,7 +17,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func initializeLogFile(logFilePath string, identifier string, version string) *os.File {
|
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 {
|
if err != nil {
|
||||||
log.Printf("failed to create log file %s: %s\n", logFilePath, err)
|
log.Printf("failed to create log file %s: %s\n", logFilePath, err)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -263,7 +263,7 @@ func UpdateIPsAndCNAMEs(q *resolver.Query, rrCache *resolver.RRCache, conn *netw
|
||||||
// Package IPs and CNAMEs into IPInfo structs.
|
// Package IPs and CNAMEs into IPInfo structs.
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
// Never save domain attributions for localhost IPs.
|
// Never save domain attributions for localhost IPs.
|
||||||
if netutils.ClassifyIP(ip) == netutils.HostLocal {
|
if netutils.GetIPScope(ip) == netutils.HostLocal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,13 @@ func (pkt *packet) Drop() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *packet) PermanentAccept() 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)
|
return pkt.mark(MarkAcceptAlways)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portbase/notifications"
|
|
||||||
"github.com/safing/portmaster/firewall/interception/nfq"
|
"github.com/safing/portmaster/firewall/interception/nfq"
|
||||||
|
"github.com/safing/portmaster/netenv"
|
||||||
"github.com/safing/portmaster/network/packet"
|
"github.com/safing/portmaster/network/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -141,14 +141,11 @@ func activateNfqueueFirewall() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if netenv.IPv6Enabled() {
|
||||||
if err := activateIPTables(iptables.ProtocolIPv6, v6rules, v6once, v6chains); err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -163,9 +160,11 @@ func DeactivateNfqueueFirewall() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPv6
|
// IPv6
|
||||||
|
if netenv.IPv6Enabled() {
|
||||||
if err := deactivateIPTables(iptables.ProtocolIPv6, v6once, v6chains); err != nil {
|
if err := deactivateIPTables(iptables.ProtocolIPv6, v6once, v6chains); err != nil {
|
||||||
result = multierror.Append(result, err)
|
result = multierror.Append(result, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result.ErrorOrNil()
|
return result.ErrorOrNil()
|
||||||
}
|
}
|
||||||
|
@ -264,6 +263,8 @@ func StartNfqueueInterception(packets chan<- packet.Packet) (err error) {
|
||||||
_ = Stop()
|
_ = Stop()
|
||||||
return fmt.Errorf("nfqueue(IPv4, in): %w", err)
|
return fmt.Errorf("nfqueue(IPv4, in): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if netenv.IPv6Enabled() {
|
||||||
out6Queue, err = nfq.New(17060, true)
|
out6Queue, err = nfq.New(17060, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = Stop()
|
_ = Stop()
|
||||||
|
@ -274,6 +275,11 @@ func StartNfqueueInterception(packets chan<- packet.Packet) (err error) {
|
||||||
_ = Stop()
|
_ = Stop()
|
||||||
return fmt.Errorf("nfqueue(IPv6, in): %w", err)
|
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)
|
go handleInterception(packets)
|
||||||
return nil
|
return nil
|
||||||
|
@ -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() {}
|
||||||
|
|
|
@ -24,6 +24,11 @@ var updateInProgress = abool.New()
|
||||||
func tryListUpdate(ctx context.Context) error {
|
func tryListUpdate(ctx context.Context) error {
|
||||||
err := performUpdate(ctx)
|
err := performUpdate(ctx)
|
||||||
if err != nil {
|
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
|
// Check if the module already has a failure status set. If not, set a
|
||||||
// generic one with the returned error.
|
// generic one with the returned error.
|
||||||
failureStatus, _, _ := module.FailureStatus()
|
failureStatus, _, _ := module.FailureStatus()
|
||||||
|
|
|
@ -26,3 +26,8 @@ func GetLocation(ip net.IP) (*Location, error) {
|
||||||
record.FillMissingInfo()
|
record.FillMissingInfo()
|
||||||
return record, nil
|
return record, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsInitialized returns whether the geoip database has been initialized.
|
||||||
|
func IsInitialized(v6, wait bool) bool {
|
||||||
|
return worker.GetReader(v6, wait) != nil
|
||||||
|
}
|
||||||
|
|
|
@ -259,7 +259,11 @@ func getListenAddresses(listenAddress string) (ip1, ip2 net.IP, port uint16, err
|
||||||
// listen separately for IPv4 and IPv6.
|
// listen separately for IPv4 and IPv6.
|
||||||
if ipString == "localhost" {
|
if ipString == "localhost" {
|
||||||
ip1 = net.IPv4(127, 0, 0, 17)
|
ip1 = net.IPv4(127, 0, 0, 17)
|
||||||
|
if netenv.IPv6Enabled() {
|
||||||
ip2 = net.IPv6loopback
|
ip2 = net.IPv6loopback
|
||||||
|
} else {
|
||||||
|
log.Warningf("nameserver: no IPv6 stack detected, disabling IPv6 nameserver listener")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ip1 = net.ParseIP(ipString)
|
ip1 = net.ParseIP(ipString)
|
||||||
if ip1 == nil {
|
if ip1 == nil {
|
||||||
|
|
|
@ -55,7 +55,7 @@ func registerAPIEndpoints() error {
|
||||||
Read: api.PermitUser,
|
Read: api.PermitUser,
|
||||||
BelongsTo: module,
|
BelongsTo: module,
|
||||||
StructFunc: func(ar *api.Request) (i interface{}, err error) {
|
StructFunc: func(ar *api.Request) (i interface{}, err error) {
|
||||||
return getLocationFromTraceroute()
|
return getLocationFromTraceroute(&DeviceLocations{})
|
||||||
},
|
},
|
||||||
Name: "Get Approximate Internet Location via Traceroute",
|
Name: "Get Approximate Internet Location via Traceroute",
|
||||||
Description: "Returns an approximation of where the device is on the Internet using a the traceroute technique.",
|
Description: "Returns an approximation of where the device is on the Internet using a the traceroute technique.",
|
||||||
|
|
|
@ -47,16 +47,16 @@ type DeviceLocations struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Best returns the best (most accurate) device location.
|
// Best returns the best (most accurate) device location.
|
||||||
func (dl *DeviceLocations) Best() *DeviceLocation {
|
func (dls *DeviceLocations) Best() *DeviceLocation {
|
||||||
if len(dl.All) > 0 {
|
if len(dls.All) > 0 {
|
||||||
return dl.All[0]
|
return dls.All[0]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BestV4 returns the best (most accurate) IPv4 device location.
|
// BestV4 returns the best (most accurate) IPv4 device location.
|
||||||
func (dl *DeviceLocations) BestV4() *DeviceLocation {
|
func (dls *DeviceLocations) BestV4() *DeviceLocation {
|
||||||
for _, loc := range dl.All {
|
for _, loc := range dls.All {
|
||||||
if loc.IPVersion == packet.IPv4 {
|
if loc.IPVersion == packet.IPv4 {
|
||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,8 @@ func (dl *DeviceLocations) BestV4() *DeviceLocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// BestV6 returns the best (most accurate) IPv6 device location.
|
// BestV6 returns the best (most accurate) IPv6 device location.
|
||||||
func (dl *DeviceLocations) BestV6() *DeviceLocation {
|
func (dls *DeviceLocations) BestV6() *DeviceLocation {
|
||||||
for _, loc := range dl.All {
|
for _, loc := range dls.All {
|
||||||
if loc.IPVersion == packet.IPv6 {
|
if loc.IPVersion == packet.IPv6 {
|
||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
|
@ -74,11 +74,8 @@ func (dl *DeviceLocations) BestV6() *DeviceLocation {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyDeviceLocations() *DeviceLocations {
|
// Copy creates a copy of the locations, but not the individual entries.
|
||||||
locationsLock.Lock()
|
func (dls *DeviceLocations) Copy() *DeviceLocations {
|
||||||
defer locationsLock.Unlock()
|
|
||||||
|
|
||||||
// Create a copy of the locations, but not the entries.
|
|
||||||
cp := &DeviceLocations{
|
cp := &DeviceLocations{
|
||||||
All: make([]*DeviceLocation, len(locations.All)),
|
All: make([]*DeviceLocation, len(locations.All)),
|
||||||
}
|
}
|
||||||
|
@ -87,6 +84,32 @@ func copyDeviceLocations() *DeviceLocations {
|
||||||
return cp
|
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
|
// DeviceLocation represents a single IP and metadata. It must not be changed
|
||||||
// once created.
|
// once created.
|
||||||
type DeviceLocation struct {
|
type DeviceLocation struct {
|
||||||
|
@ -147,6 +170,12 @@ func (dl *DeviceLocation) String() string {
|
||||||
return "<none>"
|
return "<none>"
|
||||||
case dl.Location == nil:
|
case dl.Location == nil:
|
||||||
return dl.IP.String()
|
return dl.IP.String()
|
||||||
|
case dl.Source == SourceTimezone:
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"TZ(%.0f/%.0f)",
|
||||||
|
dl.Location.Coordinates.Latitude,
|
||||||
|
dl.Location.Coordinates.Longitude,
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%s (AS%d in %s)", dl.IP, dl.Location.AutonomousSystemNumber, dl.Location.Country.ISOCode)
|
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.
|
// SetInternetLocation provides the location management system with a possible Internet location.
|
||||||
func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) {
|
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.
|
// Check if IP is global.
|
||||||
if netutils.GetIPScope(ip) != netutils.Global {
|
if netutils.GetIPScope(ip) != netutils.Global {
|
||||||
return nil, false
|
return nil, false
|
||||||
|
@ -222,38 +259,10 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLoca
|
||||||
}
|
}
|
||||||
loc.Location = geoLoc
|
loc.Location = geoLoc
|
||||||
|
|
||||||
addLocation(loc)
|
dls.AddLocation(loc)
|
||||||
return loc, true
|
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.
|
// GetApproximateInternetLocation returns the approximate Internet location.
|
||||||
// Deprecated: Please use GetInternetLocation instead.
|
// Deprecated: Please use GetInternetLocation instead.
|
||||||
func GetApproximateInternetLocation() (net.IP, error) {
|
func GetApproximateInternetLocation() (net.IP, error) {
|
||||||
|
@ -271,30 +280,21 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
|
||||||
|
|
||||||
// Check if the network changed, if not, return cache.
|
// Check if the network changed, if not, return cache.
|
||||||
if !locationNetworkChangedFlag.IsSet() {
|
if !locationNetworkChangedFlag.IsSet() {
|
||||||
return copyDeviceLocations(), true
|
locationsLock.Lock()
|
||||||
|
defer locationsLock.Unlock()
|
||||||
|
return locations.Copy(), true
|
||||||
}
|
}
|
||||||
locationNetworkChangedFlag.Refresh()
|
locationNetworkChangedFlag.Refresh()
|
||||||
|
|
||||||
// Reset locations.
|
// Create new location list.
|
||||||
func() {
|
dls := &DeviceLocations{}
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check interfaces for global addresses.
|
// Check interfaces for global addresses.
|
||||||
v4ok, v6ok := getLocationFromInterfaces()
|
v4ok, v6ok := getLocationFromInterfaces(dls)
|
||||||
|
|
||||||
// Try other methods for missing locations.
|
// Try other methods for missing locations.
|
||||||
if len(v4s) > 0 && !v4ok {
|
if !v4ok {
|
||||||
_, err = getLocationFromTraceroute()
|
_, err := getLocationFromTraceroute(dls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("netenv: failed to get IPv4 device location from traceroute: %s", err)
|
log.Warningf("netenv: failed to get IPv4 device location from traceroute: %s", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -303,35 +303,43 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
|
||||||
|
|
||||||
// Get location from timezone as final fallback.
|
// Get location from timezone as final fallback.
|
||||||
if !v4ok {
|
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
|
// TODO: Find more ways to get IPv6 device location
|
||||||
|
|
||||||
// Get location from timezone as final fallback.
|
// 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.
|
// Return gathered locations.
|
||||||
cp := copyDeviceLocations()
|
return locations.Copy(), true
|
||||||
return cp, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLocationFromInterfaces() (v4ok, v6ok bool) {
|
func getLocationFromInterfaces(dls *DeviceLocations) (v4ok, v6ok bool) {
|
||||||
globalIPv4, globalIPv6, err := GetAssignedGlobalAddresses()
|
globalIPv4, globalIPv6, err := GetAssignedGlobalAddresses()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("netenv: location: failed to get assigned global addresses: %s", err)
|
log.Warningf("netenv: location: failed to get assigned global addresses: %s", err)
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ip := range globalIPv4 {
|
for _, ip := range globalIPv4 {
|
||||||
if _, ok := SetInternetLocation(ip, SourceInterface); ok {
|
if _, ok := dls.AddIP(ip, SourceInterface); ok {
|
||||||
v4ok = true
|
v4ok = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, ip := range globalIPv6 {
|
for _, ip := range globalIPv6 {
|
||||||
if _, ok := SetInternetLocation(ip, SourceInterface); ok {
|
if _, ok := dls.AddIP(ip, SourceInterface); ok {
|
||||||
v6ok = true
|
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.
|
// Create connection.
|
||||||
conn, err := net.ListenPacket("ip4:icmp", "")
|
conn, err := net.ListenPacket("ip4:icmp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -470,7 +478,7 @@ nextHop:
|
||||||
// We have received a valid time exceeded error.
|
// We have received a valid time exceeded error.
|
||||||
// If message came from a global unicast, us it!
|
// If message came from a global unicast, us it!
|
||||||
if netutils.GetIPScope(remoteIP) == netutils.Global {
|
if netutils.GetIPScope(remoteIP) == netutils.Global {
|
||||||
dl, ok := SetInternetLocation(remoteIP, SourceTraceroute)
|
dl, ok := dls.AddIP(remoteIP, SourceTraceroute)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("invalid IP address")
|
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.
|
// Create base struct.
|
||||||
tzLoc := &DeviceLocation{
|
tzLoc := &DeviceLocation{
|
||||||
IPVersion: ipVersion,
|
IPVersion: ipVersion,
|
||||||
|
@ -531,6 +539,5 @@ func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { //nolint:un
|
||||||
tzLoc.Location.Coordinates.Latitude = 48
|
tzLoc.Location.Coordinates.Latitude = 48
|
||||||
tzLoc.Location.Coordinates.Longitude = float64(offsetSeconds) / 43200 * 180
|
tzLoc.Location.Coordinates.Longitude = float64(offsetSeconds) / 43200 * 180
|
||||||
|
|
||||||
addLocation(tzLoc)
|
dls.AddLocation(tzLoc)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package netenv
|
package netenv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/tevino/abool"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portbase/modules"
|
"github.com/safing/portbase/modules"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,6 +23,8 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func prep() error {
|
||||||
|
checkForIPv6Stack()
|
||||||
|
|
||||||
if err := registerAPIEndpoints(); err != nil {
|
if err := registerAPIEndpoints(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -46,3 +51,22 @@ func start() error {
|
||||||
|
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func Lookup(pktInfo *packet.Info, fast bool) (pid int, inbound bool, err error)
|
||||||
return udp6Table.lookup(pktInfo, fast)
|
return udp6Table.lookup(pktInfo, fast)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return socket.UndefinedProcessID, false, errors.New("unsupported protocol for finding process")
|
return socket.UndefinedProcessID, pktInfo.Inbound, errors.New("unsupported protocol for finding process")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portmaster/network/socket"
|
||||||
"github.com/safing/portmaster/profile"
|
"github.com/safing/portmaster/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +29,13 @@ const (
|
||||||
NetworkHostProcessID = -255
|
NetworkHostProcessID = -255
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Check required matching values.
|
||||||
|
if UndefinedProcessID != socket.UndefinedProcessID {
|
||||||
|
panic("UndefinedProcessID does not match socket.UndefinedProcessID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// unidentifiedProcess is used for non-attributed outgoing connections.
|
// unidentifiedProcess is used for non-attributed outgoing connections.
|
||||||
unidentifiedProcess = &Process{
|
unidentifiedProcess = &Process{
|
||||||
|
|
|
@ -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.
|
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
|
// Endpoint Filter List
|
||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Outgoing Rules",
|
Name: "Outgoing Rules",
|
||||||
|
@ -272,6 +278,7 @@ Important: DNS Requests are only matched against domain and filter list rules, a
|
||||||
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
|
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
|
||||||
config.DisplayOrderAnnotation: cfgOptionEndpointsOrder,
|
config.DisplayOrderAnnotation: cfgOptionEndpointsOrder,
|
||||||
config.CategoryAnnotation: "Rules",
|
config.CategoryAnnotation: "Rules",
|
||||||
|
endpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames,
|
||||||
},
|
},
|
||||||
ValidationRegex: endpoints.ListEntryValidationRegex,
|
ValidationRegex: endpoints.ListEntryValidationRegex,
|
||||||
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
|
ValidationFunc: endpoints.ValidateEndpointListConfigOption,
|
||||||
|
@ -283,6 +290,7 @@ Important: DNS Requests are only matched against domain and filter list rules, a
|
||||||
cfgStringArrayOptions[CfgOptionEndpointsKey] = cfgOptionEndpoints
|
cfgStringArrayOptions[CfgOptionEndpointsKey] = cfgOptionEndpoints
|
||||||
|
|
||||||
// Service Endpoint Filter List
|
// Service Endpoint Filter List
|
||||||
|
defaultIncomingRulesValue := []string{"+ Localhost"}
|
||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Incoming Rules",
|
Name: "Incoming Rules",
|
||||||
Key: CfgOptionServiceEndpointsKey,
|
Key: CfgOptionServiceEndpointsKey,
|
||||||
|
@ -290,13 +298,14 @@ Important: DNS Requests are only matched against domain and filter list rules, a
|
||||||
Help: rulesHelp,
|
Help: rulesHelp,
|
||||||
Sensitive: true,
|
Sensitive: true,
|
||||||
OptType: config.OptTypeStringArray,
|
OptType: config.OptTypeStringArray,
|
||||||
DefaultValue: []string{"+ Localhost"},
|
DefaultValue: defaultIncomingRulesValue,
|
||||||
ExpertiseLevel: config.ExpertiseLevelExpert,
|
ExpertiseLevel: config.ExpertiseLevelExpert,
|
||||||
Annotations: config.Annotations{
|
Annotations: config.Annotations{
|
||||||
config.StackableAnnotation: true,
|
config.StackableAnnotation: true,
|
||||||
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
|
config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList,
|
||||||
config.DisplayOrderAnnotation: cfgOptionServiceEndpointsOrder,
|
config.DisplayOrderAnnotation: cfgOptionServiceEndpointsOrder,
|
||||||
config.CategoryAnnotation: "Rules",
|
config.CategoryAnnotation: "Rules",
|
||||||
|
endpoints.EndpointListVerdictNamesAnnotation: rulesVerdictNames,
|
||||||
config.QuickSettingsAnnotation: []config.QuickSetting{
|
config.QuickSettingsAnnotation: []config.QuickSetting{
|
||||||
{
|
{
|
||||||
Name: "SSH",
|
Name: "SSH",
|
||||||
|
@ -313,6 +322,16 @@ Important: DNS Requests are only matched against domain and filter list rules, a
|
||||||
Action: config.QuickMergeTop,
|
Action: config.QuickMergeTop,
|
||||||
Value: []string{"+ * */3389"},
|
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,
|
ValidationRegex: endpoints.ListEntryValidationRegex,
|
||||||
|
@ -321,38 +340,17 @@ Important: DNS Requests are only matched against domain and filter list rules, a
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, []string{})
|
cfgOptionServiceEndpoints = config.Concurrent.GetAsStringArray(CfgOptionServiceEndpointsKey, defaultIncomingRulesValue)
|
||||||
cfgStringArrayOptions[CfgOptionServiceEndpointsKey] = cfgOptionServiceEndpoints
|
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
|
// Filter list IDs
|
||||||
|
defaultFilterListsValue := []string{"TRAC", "MAL", "BAD"}
|
||||||
err = config.Register(&config.Option{
|
err = config.Register(&config.Option{
|
||||||
Name: "Filter Lists",
|
Name: "Filter Lists",
|
||||||
Key: CfgOptionFilterListsKey,
|
Key: CfgOptionFilterListsKey,
|
||||||
Description: "Block connections that match enabled filter lists.",
|
Description: "Block connections that match enabled filter lists.",
|
||||||
Help: filterListsHelp,
|
|
||||||
OptType: config.OptTypeStringArray,
|
OptType: config.OptTypeStringArray,
|
||||||
DefaultValue: []string{"TRAC", "MAL", "BAD"},
|
DefaultValue: defaultFilterListsValue,
|
||||||
Annotations: config.Annotations{
|
Annotations: config.Annotations{
|
||||||
config.DisplayHintAnnotation: "filter list",
|
config.DisplayHintAnnotation: "filter list",
|
||||||
config.DisplayOrderAnnotation: cfgOptionFilterListsOrder,
|
config.DisplayOrderAnnotation: cfgOptionFilterListsOrder,
|
||||||
|
@ -363,7 +361,7 @@ The lists are automatically updated every hour using incremental updates.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListsKey, []string{})
|
cfgOptionFilterLists = config.Concurrent.GetAsStringArray(CfgOptionFilterListsKey, defaultFilterListsValue)
|
||||||
cfgStringArrayOptions[CfgOptionFilterListsKey] = cfgOptionFilterLists
|
cfgStringArrayOptions[CfgOptionFilterListsKey] = cfgOptionFilterLists
|
||||||
|
|
||||||
// Include CNAMEs
|
// Include CNAMEs
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portmaster/netenv"
|
||||||
"github.com/safing/portmaster/network/netutils"
|
"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})
|
unicast4Conn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: retry after some time
|
// TODO: retry after some time
|
||||||
|
@ -117,6 +105,20 @@ func listenToMDNS(ctx context.Context) error {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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})
|
unicast6Conn, err = net.ListenUDP("udp6", &net.UDPAddr{IP: net.IPv6zero, Port: 0})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: retry after some time
|
// TODO: retry after some time
|
||||||
|
@ -129,6 +131,9 @@ func listenToMDNS(ctx context.Context) error {
|
||||||
_ = unicast6Conn.Close()
|
_ = unicast6Conn.Close()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.Warningf("resolver: no IPv6 stack detected, disabling IPv6 mDNS resolver")
|
||||||
|
}
|
||||||
|
|
||||||
// start message handler
|
// start message handler
|
||||||
module.StartServiceWorker("mdns message handler", 0, func(ctx context.Context) error {
|
module.StartServiceWorker("mdns message handler", 0, func(ctx context.Context) error {
|
||||||
|
|
|
@ -33,6 +33,12 @@ func SetIndexes(registry *updater.ResourceRegistry, releaseChannel string, delet
|
||||||
// Reset indexes before adding them (again).
|
// Reset indexes before adding them (again).
|
||||||
registry.ResetIndexes()
|
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.
|
// Always add the stable index as a base.
|
||||||
registry.AddIndex(updater.Index{
|
registry.AddIndex(updater.Index{
|
||||||
Path: ReleaseChannelStable + ".json",
|
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.
|
// Set pre-release usage.
|
||||||
registry.SetUsePreReleases(usePreReleases)
|
registry.SetUsePreReleases(usePreReleases)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue