Make own IP check more resistant
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
"github.com/safing/portmaster/network/netutils"
|
"github.com/safing/portmaster/network/netutils"
|
||||||
@@ -51,9 +52,11 @@ func GetAssignedGlobalAddresses() (ipv4 []net.IP, ipv6 []net.IP, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
myNetworks []*net.IPNet
|
myNetworks []*net.IPNet
|
||||||
myNetworksLock sync.Mutex
|
myNetworksLock sync.Mutex
|
||||||
myNetworksNetworkChangedFlag = GetNetworkChangedFlag()
|
myNetworksNetworkChangedFlag = GetNetworkChangedFlag()
|
||||||
|
myNetworksRefreshError error
|
||||||
|
myNetworksRefreshFailingUntil time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsMyIP returns whether the given unicast IP is currently configured on the local host.
|
// IsMyIP returns whether the given unicast IP is currently configured on the local host.
|
||||||
@@ -70,18 +73,33 @@ func IsMyIP(ip net.IP) (yes bool, err error) {
|
|||||||
myNetworksLock.Lock()
|
myNetworksLock.Lock()
|
||||||
defer myNetworksLock.Unlock()
|
defer myNetworksLock.Unlock()
|
||||||
|
|
||||||
// Check if the network changed.
|
// Check if current data matches IP.
|
||||||
if myNetworksNetworkChangedFlag.IsSet() {
|
// Matching on somewhat older data is not a problem, as these IPs would not
|
||||||
// Reset changed flag.
|
// just randomly pop up somewhere else that fast.
|
||||||
myNetworksNetworkChangedFlag.Refresh()
|
mine, matched := checkIfMyIP(ip)
|
||||||
} else if mine, matched := checkIfMyIP(ip); matched {
|
if matched {
|
||||||
// If the network did not change, check for match immediately.
|
|
||||||
return mine, nil
|
return mine, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the network changed.
|
||||||
|
if !myNetworksNetworkChangedFlag.IsSet() {
|
||||||
|
// Network did not change, return "no match".
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there was a recent error on the previous refresh.
|
||||||
|
if myNetworksRefreshError != nil && time.Now().Before(myNetworksRefreshFailingUntil) {
|
||||||
|
return false, fmt.Errorf("failed to previously refresh interface addresses: %s", myNetworksRefreshError)
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh assigned networks.
|
// Refresh assigned networks.
|
||||||
interfaceNetworks, err := net.InterfaceAddrs()
|
interfaceNetworks, err := net.InterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Save error for one second.
|
||||||
|
// In some cases the system blocks on this call, which piles up to
|
||||||
|
// literally over thousand goroutines wanting to try this again.
|
||||||
|
myNetworksRefreshError = err
|
||||||
|
myNetworksRefreshFailingUntil = time.Now().Add(1 * time.Second)
|
||||||
return false, fmt.Errorf("failed to refresh interface addresses: %s", err)
|
return false, fmt.Errorf("failed to refresh interface addresses: %s", err)
|
||||||
}
|
}
|
||||||
myNetworks = make([]*net.IPNet, 0, len(interfaceNetworks))
|
myNetworks = make([]*net.IPNet, 0, len(interfaceNetworks))
|
||||||
@@ -95,6 +113,12 @@ func IsMyIP(ip net.IP) (yes bool, err error) {
|
|||||||
myNetworks = append(myNetworks, net)
|
myNetworks = append(myNetworks, net)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset error.
|
||||||
|
myNetworksRefreshError = nil
|
||||||
|
|
||||||
|
// Reset changed flag.
|
||||||
|
myNetworksNetworkChangedFlag.Refresh()
|
||||||
|
|
||||||
// Check for match again.
|
// Check for match again.
|
||||||
if mine, matched := checkIfMyIP(ip); matched {
|
if mine, matched := checkIfMyIP(ip); matched {
|
||||||
return mine, nil
|
return mine, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user