Improve online status and location checks

This commit is contained in:
Daniel
2021-11-17 14:13:16 +01:00
parent 8d753808e1
commit bbf9d7ca72
2 changed files with 69 additions and 25 deletions

View File

@@ -241,7 +241,7 @@ func addLocation(dl *DeviceLocation) {
func GetApproximateInternetLocation() (net.IP, error) {
loc, ok := GetInternetLocation()
if !ok || loc.Best() == nil {
return nil, errors.New("no location data available")
return nil, errors.New("no device location data available")
}
return loc.Best().IP, nil
}
@@ -259,7 +259,7 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
// Get all assigned addresses.
v4s, v6s, err := GetAssignedAddresses()
if err != nil {
log.Warningf("netenv: failed to get assigned addresses: %s", err)
log.Warningf("netenv: failed to get assigned addresses for device location: %s", err)
return nil, false
}
@@ -267,27 +267,24 @@ func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
v4ok, v6ok := getLocationFromInterfaces()
// Try other methods for missing locations.
if len(v4s) > 0 {
if !v4ok {
_, err = getLocationFromTraceroute()
if err != nil {
log.Warningf("netenv: failed to get IPv4 from traceroute: %s", err)
} else {
v4ok = true
}
if len(v4s) > 0 && !v4ok {
_, err = getLocationFromTraceroute()
if err != nil {
log.Warningf("netenv: failed to get IPv4 device location from traceroute: %s", err)
} else {
v4ok = true
}
// Get location from timezone as final fallback.
if !v4ok {
v4ok = getLocationFromTimezone(packet.IPv4)
getLocationFromTimezone(packet.IPv4)
}
}
if len(v6s) > 0 && !v6ok {
// TODO
log.Warningf("netenv: could not get IPv6 location")
}
// TODO: Find more ways to get IPv6 device location
// Check if we have any locations.
if !v4ok && !v6ok {
return nil, false
// Get location from timezone as final fallback.
getLocationFromTimezone(packet.IPv6)
}
// Return gathered locations.

View File

@@ -145,6 +145,7 @@ var (
onlineStatusInvestigationTrigger = make(chan struct{}, 1)
onlineStatusInvestigationInProgress = abool.NewBool(false)
onlineStatusInvestigationWg sync.WaitGroup
onlineStatusNotification *notifications.Notification
captivePortal = &CaptivePortal{}
captivePortalLock sync.Mutex
@@ -186,7 +187,7 @@ func CheckAndGetOnlineStatus() OnlineStatus {
func updateOnlineStatus(status OnlineStatus, portalURL *url.URL, comment string) {
changed := false
// status
// Update online status.
currentStatus := atomic.LoadInt32(onlineStatus)
if status != OnlineStatus(currentStatus) && atomic.CompareAndSwapInt32(onlineStatus, currentStatus, int32(status)) {
// status changed!
@@ -196,10 +197,10 @@ func updateOnlineStatus(status OnlineStatus, portalURL *url.URL, comment string)
changed = true
}
// captive portal
// Update captive portal.
setCaptivePortal(portalURL)
// trigger event
// Trigger events.
if changed {
module.TriggerEvent(OnlineStatusChangedEvent, status)
if status == StatusPortal {
@@ -209,6 +210,9 @@ func updateOnlineStatus(status OnlineStatus, portalURL *url.URL, comment string)
}
triggerNetworkChangeCheck()
// Notify user.
notifyOnlineStatus(status)
// Trigger update check when coming (semi) online.
if Online() {
_ = updates.TriggerUpdate(false)
@@ -216,11 +220,54 @@ func updateOnlineStatus(status OnlineStatus, portalURL *url.URL, comment string)
}
}
func notifyOnlineStatus(status OnlineStatus) {
var eventID, title, message string
// Check if status is worth notifying.
switch status {
case StatusOffline:
eventID = "netenv:online-status:offline"
title = "Device is Offline"
message = "Portmaster did not detect any network connectivity."
case StatusLimited:
eventID = "netenv:online-status:limited"
title = "Limited network connectivity."
message = "Portmaster did detect local network connectivity, but could not detect connectivity to the Internet."
default:
// Delete notification, if present.
if onlineStatusNotification != nil {
onlineStatusNotification.Delete()
onlineStatusNotification = nil
}
return
}
// Update notification if not present or online status changed.
switch {
case onlineStatusNotification == nil:
// Continue creating new notification.
case onlineStatusNotification.EventID == eventID:
// Notification stays the same, stick with the old one.
return
default:
// Delete old notification before triggering updated one.
onlineStatusNotification.Delete()
}
// Create update status notification.
onlineStatusNotification = notifications.Notify(&notifications.Notification{
EventID: eventID,
Type: notifications.Info,
Title: title,
Message: message,
})
}
func setCaptivePortal(portalURL *url.URL) {
captivePortalLock.Lock()
defer captivePortalLock.Unlock()
// delete
// Delete captive portal if no url is supplied.
if portalURL == nil {
captivePortal = &CaptivePortal{}
if captivePortalNotification != nil {
@@ -230,12 +277,12 @@ func setCaptivePortal(portalURL *url.URL) {
return
}
// return if unchanged
if portalURL.String() == captivePortal.URL {
// Only set captive portal once per detection.
if captivePortal.URL != "" {
return
}
// set
// Compile captive portal data.
captivePortal = &CaptivePortal{
URL: portalURL.String(),
}
@@ -247,7 +294,7 @@ func setCaptivePortal(portalURL *url.URL) {
captivePortal.Domain = portalURL.Hostname()
}
// notify
// Notify user about portal.
captivePortalNotification = notifications.Notify(&notifications.Notification{
EventID: "netenv:captive-portal",
Type: notifications.Info,