Fix tests and linters

This commit is contained in:
Daniel
2022-02-02 12:48:42 +01:00
parent f2fcad4d11
commit 60d8664e7b
171 changed files with 944 additions and 874 deletions

View File

@@ -55,7 +55,7 @@ var (
myNetworks []*net.IPNet
myNetworksLock sync.Mutex
myNetworksNetworkChangedFlag = GetNetworkChangedFlag()
myNetworksRefreshError error
myNetworksRefreshError error //nolint:errname // Not what the linter thinks this is for.
myNetworksRefreshFailingUntil time.Time
)
@@ -63,7 +63,7 @@ var (
// Broadcast or multicast addresses will never match, even if valid in in use.
func IsMyIP(ip net.IP) (yes bool, err error) {
// Check for IPs that don't need extra checks.
switch netutils.GetIPScope(ip) {
switch netutils.GetIPScope(ip) { //nolint:exhaustive // Only looking for specific values.
case netutils.HostLocal:
return true, nil
case netutils.LocalMulticast, netutils.GlobalMulticast:
@@ -90,7 +90,7 @@ func IsMyIP(ip net.IP) (yes bool, err error) {
// 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)
return false, fmt.Errorf("failed to previously refresh interface addresses: %w", myNetworksRefreshError)
}
// Refresh assigned networks.
@@ -101,7 +101,7 @@ func IsMyIP(ip net.IP) (yes bool, err error) {
// 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: %w", err)
}
myNetworks = make([]*net.IPNet, 0, len(interfaceNetworks))
for _, ifNet := range interfaceNetworks {

View File

@@ -5,6 +5,8 @@ import (
)
func TestGetAssignedAddresses(t *testing.T) {
t.Parallel()
ipv4, ipv6, err := GetAssignedAddresses()
t.Logf("all v4: %v", ipv4)
t.Logf("all v6: %v", ipv6)
@@ -17,6 +19,8 @@ func TestGetAssignedAddresses(t *testing.T) {
}
func TestGetAssignedGlobalAddresses(t *testing.T) {
t.Parallel()
ipv4, ipv6, err := GetAssignedGlobalAddresses()
t.Logf("all global v4: %v", ipv4)
t.Logf("all global v6: %v", ipv6)

View File

@@ -1,4 +1,4 @@
// +build !server
// go:build !server
package netenv
@@ -8,9 +8,9 @@ import (
"net"
"sync"
"github.com/safing/portbase/log"
"github.com/godbus/dbus/v5"
"github.com/safing/portbase/log"
)
var (
@@ -36,7 +36,7 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO
primaryConnectionVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.PrimaryConnection")
if err != nil {
return nil, fmt.Errorf("dbus: failed to access NetworkManager.PrimaryConnection: %s", err)
return nil, fmt.Errorf("dbus: failed to access NetworkManager.PrimaryConnection: %w", err)
}
primaryConnection, ok := primaryConnectionVariant.Value().(dbus.ObjectPath)
if !ok {
@@ -45,7 +45,7 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO
activeConnectionsVariant, err := getNetworkManagerProperty(dbusConn, dbus.ObjectPath("/org/freedesktop/NetworkManager"), "org.freedesktop.NetworkManager.ActiveConnections")
if err != nil {
return nil, fmt.Errorf("dbus: failed to access NetworkManager.ActiveConnections: %s", err)
return nil, fmt.Errorf("dbus: failed to access NetworkManager.ActiveConnections: %w", err)
}
activeConnections, ok := activeConnectionsVariant.Value().([]dbus.ObjectPath)
if !ok {
@@ -60,18 +60,18 @@ func getNameserversFromDbus() ([]Nameserver, error) { //nolint:gocognit // TODO
}
for _, activeConnection := range sortedConnections {
new, err := dbusGetInterfaceNameservers(dbusConn, activeConnection, 4)
newNameservers, err := dbusGetInterfaceNameservers(dbusConn, activeConnection, 4)
if err != nil {
log.Warningf("failed to get nameserver: %s", err)
} else {
ns = append(ns, new...)
ns = append(ns, newNameservers...)
}
new, err = dbusGetInterfaceNameservers(dbusConn, activeConnection, 6)
newNameservers, err = dbusGetInterfaceNameservers(dbusConn, activeConnection, 6)
if err != nil {
log.Warningf("failed to get nameserver: %s", err)
} else {
ns = append(ns, new...)
ns = append(ns, newNameservers...)
}
}
@@ -87,7 +87,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec
// Get Interface Configuration.
ipConfigVariant, err := getNetworkManagerProperty(dbusConn, interfaceObject, ipConfigPropertyKey)
if err != nil {
return nil, fmt.Errorf("failed to access %s:%s: %s", interfaceObject, ipConfigPropertyKey, err)
return nil, fmt.Errorf("failed to access %s:%s: %w", interfaceObject, ipConfigPropertyKey, err)
}
ipConfig, ok := ipConfigVariant.Value().(dbus.ObjectPath)
if !ok {
@@ -102,7 +102,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec
// Get Nameserver IPs
nameserverIPsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversIPsPropertyKey)
if err != nil {
return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversIPsPropertyKey, err)
return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversIPsPropertyKey, err)
}
var nameserverIPs []net.IP
switch ipVersion {
@@ -134,7 +134,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec
// Get Nameserver Domains
nameserverDomainsVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversDomainsPropertyKey)
if err != nil {
return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversDomainsPropertyKey, err)
return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversDomainsPropertyKey, err)
}
nameserverDomains, ok := nameserverDomainsVariant.Value().([]string)
if !ok {
@@ -144,7 +144,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec
// Get Nameserver Searches
nameserverSearchesVariant, err := getNetworkManagerProperty(dbusConn, ipConfig, nameserversSearchesPropertyKey)
if err != nil {
return nil, fmt.Errorf("failed to access %s:%s: %s", ipConfig, nameserversSearchesPropertyKey, err)
return nil, fmt.Errorf("failed to access %s:%s: %w", ipConfig, nameserversSearchesPropertyKey, err)
}
nameserverSearches, ok := nameserverSearchesVariant.Value().([]string)
if !ok {
@@ -152,7 +152,7 @@ func dbusGetInterfaceNameservers(dbusConn *dbus.Conn, interfaceObject dbus.Objec
}
ns := make([]Nameserver, 0, len(nameserverIPs))
searchDomains := append(nameserverDomains, nameserverSearches...)
searchDomains := append(nameserverDomains, nameserverSearches...) //nolint:gocritic
for _, nameserverIP := range nameserverIPs {
ns = append(ns, Nameserver{
IP: nameserverIP,

View File

@@ -6,6 +6,8 @@ import (
)
func TestDbus(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip("skipping test in short mode because it fails in the CI")
}

View File

@@ -2,9 +2,7 @@ package netenv
import "net"
var (
localAddrFactory func(network string) net.Addr
)
var localAddrFactory func(network string) net.Addr
// SetLocalAddrFactory supplies the environment package with a function to get permitted local addresses for connections.
func SetLocalAddrFactory(laf func(network string) net.Addr) {

View File

@@ -43,7 +43,9 @@ func Gateways() []net.IP {
log.Warningf("environment: could not read /proc/net/route: %s", err)
return gateways
}
defer route.Close()
defer func() {
_ = route.Close()
}()
// file scanner
scanner := bufio.NewScanner(route)
@@ -76,7 +78,9 @@ func Gateways() []net.IP {
log.Warningf("environment: could not read /proc/net/ipv6_route: %s", err)
return gateways
}
defer v6route.Close()
defer func() {
_ = v6route.Close()
}()
// file scanner
scanner = bufio.NewScanner(v6route)
@@ -149,7 +153,9 @@ func getNameserversFromResolvconf() ([]Nameserver, error) {
log.Warningf("environment: could not read /etc/resolv.conf: %s", err)
return nil, err
}
defer resolvconf.Close()
defer func() {
_ = resolvconf.Close()
}()
// file scanner
scanner := bufio.NewScanner(resolvconf)
@@ -186,7 +192,6 @@ func getNameserversFromResolvconf() ([]Nameserver, error) {
})
}
return nameservers, nil
}
func addNameservers(nameservers, newNameservers []Nameserver) []Nameserver {

View File

@@ -3,6 +3,8 @@ package netenv
import "testing"
func TestLinuxEnvironment(t *testing.T) {
t.Parallel()
nameserversTest, err := getNameserversFromResolvconf()
if err != nil {
t.Errorf("failed to get namerservers from resolvconf: %s", err)

View File

@@ -3,6 +3,8 @@ package netenv
import "testing"
func TestEnvironment(t *testing.T) {
t.Parallel()
nameserversTest := Nameservers()
t.Logf("nameservers: %+v", nameserversTest)

View File

@@ -9,10 +9,10 @@ import (
"syscall"
"time"
"github.com/google/gopacket/layers"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"github.com/google/gopacket/layers"
"github.com/safing/portbase/log"
"github.com/safing/portbase/rng"
"github.com/safing/portmaster/intel/geoip"
@@ -41,10 +41,12 @@ func prepLocation() (err error) {
return err
}
// DeviceLocations holds multiple device locations.
type DeviceLocations struct {
All []*DeviceLocation
}
// Best returns the best (most accurate) device location.
func (dl *DeviceLocations) Best() *DeviceLocation {
if len(dl.All) > 0 {
return dl.All[0]
@@ -52,6 +54,7 @@ func (dl *DeviceLocations) Best() *DeviceLocation {
return nil
}
// BestV4 returns the best (most accurate) IPv4 device location.
func (dl *DeviceLocations) BestV4() *DeviceLocation {
for _, loc := range dl.All {
if loc.IPVersion == packet.IPv4 {
@@ -61,6 +64,7 @@ func (dl *DeviceLocations) BestV4() *DeviceLocation {
return nil
}
// BestV6 returns the best (most accurate) IPv6 device location.
func (dl *DeviceLocations) BestV6() *DeviceLocation {
for _, loc := range dl.All {
if loc.IPVersion == packet.IPv6 {
@@ -129,6 +133,7 @@ func (dl *DeviceLocation) IsMoreAccurateThan(other *DeviceLocation) bool {
return false
}
// LocationOrNil or returns the geoip location, or nil if not present.
func (dl *DeviceLocation) LocationOrNil() *geoip.Location {
if dl == nil {
return nil
@@ -147,8 +152,10 @@ func (dl *DeviceLocation) String() string {
}
}
// DeviceLocationSource is a location source.
type DeviceLocationSource string
// Location Sources.
const (
SourceInterface DeviceLocationSource = "interface"
SourcePeer DeviceLocationSource = "peer"
@@ -158,6 +165,7 @@ const (
SourceOther DeviceLocationSource = "other"
)
// Accuracy returns the location accuracy of the source.
func (dls DeviceLocationSource) Accuracy() int {
switch dls {
case SourceInterface:
@@ -183,6 +191,7 @@ 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]) }
// SetInternetLocation provides the location management system with a possible Internet location.
func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLocation, ok bool) {
// Check if IP is global.
if netutils.GetIPScope(ip) != netutils.Global {
@@ -206,9 +215,8 @@ func SetInternetLocation(ip net.IP, source DeviceLocationSource) (dl *DeviceLoca
if err != nil {
log.Warningf("netenv: failed to get geolocation data of %s (from %s): %s", ip, source, err)
return nil, false
} else {
loc.Location = geoLoc
}
loc.Location = geoLoc
addLocation(loc)
return loc, true
@@ -242,7 +250,8 @@ func addLocation(dl *DeviceLocation) {
sort.Sort(sortLocationsByAccuracy(locations.All))
}
// DEPRECATED: Please use GetInternetLocation instead.
// GetApproximateInternetLocation returns the approximate Internet location.
// Deprecated: Please use GetInternetLocation instead.
func GetApproximateInternetLocation() (net.IP, error) {
loc, ok := GetInternetLocation()
if !ok || loc.Best() == nil {
@@ -251,6 +260,7 @@ func GetApproximateInternetLocation() (net.IP, error) {
return loc.Best().IP, nil
}
// GetInternetLocation returns the possible device locations.
func GetInternetLocation() (deviceLocations *DeviceLocations, ok bool) {
gettingLocationsLock.Lock()
defer gettingLocationsLock.Unlock()
@@ -323,7 +333,7 @@ func getLocationFromInterfaces() (v4ok, v6ok bool) {
func getLocationFromUPnP() (ok bool) {
// Endoint: urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress
// A first test showed that a router did offer that endpoint, but did not
// return an IP addres.
// return an IP address.
return false
}
*/
@@ -332,14 +342,14 @@ func getLocationFromTraceroute() (dl *DeviceLocation, err error) {
// Create connection.
conn, err := net.ListenPacket("ip4:icmp", "")
if err != nil {
return nil, fmt.Errorf("failed to open icmp conn: %s", err)
return nil, fmt.Errorf("failed to open icmp conn: %w", err)
}
v4Conn := ipv4.NewPacketConn(conn)
// Generate a random ID for the ICMP packets.
generatedID, err := rng.Number(0xFFFF) // uint16
if err != nil {
return nil, fmt.Errorf("failed to generate icmp msg ID: %s", err)
return nil, fmt.Errorf("failed to generate icmp msg ID: %w", err)
}
msgID := int(generatedID)
var msgSeq int
@@ -368,28 +378,27 @@ nextHop:
for j := 1; j <= 2; j++ { // Try every hop twice.
// Increase sequence number.
msgSeq++
pingMessage.Body.(*icmp.Echo).Seq = msgSeq
pingMessage.Body.(*icmp.Echo).Seq = msgSeq //nolint:forcetypeassert // Can only be *icmp.Echo.
// Make packet data.
pingPacket, err := pingMessage.Marshal(nil)
if err != nil {
return nil, fmt.Errorf("failed to build icmp packet: %s", err)
return nil, fmt.Errorf("failed to build icmp packet: %w", err)
}
// Set TTL on IP packet.
err = v4Conn.SetTTL(i)
if err != nil {
return nil, fmt.Errorf("failed to set icmp packet TTL: %s", err)
return nil, fmt.Errorf("failed to set icmp packet TTL: %w", err)
}
// Send ICMP packet.
if _, err := conn.WriteTo(pingPacket, locationTestingIPv4Addr); err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Err == syscall.ENOBUFS {
continue
}
var opErr *net.OpError
if errors.As(err, &opErr) && errors.Is(opErr.Err, syscall.ENOBUFS) {
continue
}
return nil, fmt.Errorf("failed to send icmp packet: %s", err)
return nil, fmt.Errorf("failed to send icmp packet: %w", err)
}
// Listen for replies of the ICMP packet.
@@ -433,7 +442,7 @@ nextHop:
continue listen
}
// Check if the ID and sequence match.
if originalEcho.ID != int(msgID) {
if originalEcho.ID != msgID {
continue listen
}
if originalEcho.Seq < minSeq {
@@ -469,8 +478,8 @@ nextHop:
}
func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) (
remoteIP net.IP, imcpPacket *layers.ICMPv4, ok bool) {
remoteIP net.IP, imcpPacket *layers.ICMPv4, ok bool,
) {
for {
select {
case pkt := <-icmpPacketsViaFirewall:
@@ -496,7 +505,7 @@ func recvICMP(currentHop int, icmpPacketsViaFirewall chan packet.Packet) (
}
}
func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) {
func getLocationFromTimezone(ipVersion packet.IPVersion) (ok bool) { //nolint:unparam // This is documentation.
// Create base struct.
tzLoc := &DeviceLocation{
IPVersion: ipVersion,

View File

@@ -1,9 +1,9 @@
//+build !windows
// go:build !windows
package netenv
import "net"
func newICMPListener(_ string) (net.PacketConn, error) {
func newICMPListener(_ string) (net.PacketConn, error) { //nolint:unused,deadcode // TODO: clean with Windows code later.
return net.ListenPacket("ip4:icmp", "0.0.0.0")
}

View File

@@ -5,15 +5,15 @@ import (
"testing"
)
var (
privileged bool
)
var privileged bool
func init() {
flag.BoolVar(&privileged, "privileged", false, "run tests that require root/admin privileges")
}
func TestGetInternetLocation(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}

View File

@@ -4,16 +4,14 @@ import (
"github.com/safing/portbase/modules"
)
// Event Names
// Event Names.
const (
ModuleName = "netenv"
NetworkChangedEvent = "network changed"
OnlineStatusChangedEvent = "online status changed"
)
var (
module *modules.Module
)
var module *modules.Module
func init() {
module = modules.Register(ModuleName, prep, start, nil)

View File

@@ -3,7 +3,7 @@ package netenv
import (
"bytes"
"context"
"crypto/sha1" //nolint:gosec // not used for security
"crypto/sha1"
"io"
"net"
"time"
@@ -17,6 +17,7 @@ var (
networkChangedBroadcastFlag = utils.NewBroadcastFlag()
)
// GetNetworkChangedFlag returns a flag to be notified about a network change.
func GetNetworkChangedFlag() *utils.Flag {
return networkChangedBroadcastFlag.NewFlag()
}

View File

@@ -2,6 +2,7 @@ package netenv
import (
"context"
"errors"
"fmt"
"net"
"net/http"
@@ -21,7 +22,7 @@ import (
// OnlineStatus represent a state of connectivity to the Internet.
type OnlineStatus uint8
// Online Status Values
// Online Status Values.
const (
StatusUnknown OnlineStatus = 0
StatusOffline OnlineStatus = 1
@@ -31,7 +32,7 @@ const (
StatusOnline OnlineStatus = 5
)
// Online Status and Resolver
// Online Status and Resolver.
var (
PortalTestIP = net.IPv4(192, 0, 2, 1)
PortalTestURL = fmt.Sprintf("http://%s/", PortalTestIP)
@@ -124,8 +125,6 @@ func IsConnectivityDomain(domain string) bool {
func (os OnlineStatus) String() string {
switch os {
default:
return "Unknown"
case StatusOffline:
return "Offline"
case StatusLimited:
@@ -136,6 +135,10 @@ func (os OnlineStatus) String() string {
return "SemiOnline"
case StatusOnline:
return "Online"
case StatusUnknown:
fallthrough
default:
return "Unknown"
}
}
@@ -175,7 +178,7 @@ func GetOnlineStatus() OnlineStatus {
return OnlineStatus(atomic.LoadInt32(onlineStatus))
}
// CheckAndGetOnlineStatus triggers a new online status check and returns the result
// CheckAndGetOnlineStatus triggers a new online status check and returns the result.
func CheckAndGetOnlineStatus() OnlineStatus {
// trigger new investigation
triggerOnlineStatusInvestigation()
@@ -225,7 +228,7 @@ func notifyOnlineStatus(status OnlineStatus) {
var eventID, title, message string
// Check if status is worth notifying.
switch status {
switch status { //nolint:exhaustive // Checking for selection only.
case StatusOffline:
eventID = "netenv:online-status:offline"
title = "Device is Offline"
@@ -419,7 +422,7 @@ func checkOnlineStatus(ctx context.Context) {
} else {
var lan bool
for _, ip := range ipv4 {
switch netutils.GetIPScope(ip) {
switch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only.
case netutils.SiteLocal:
lan = true
case netutils.Global:
@@ -429,7 +432,7 @@ func checkOnlineStatus(ctx context.Context) {
}
}
for _, ip := range ipv6 {
switch netutils.GetIPScope(ip) {
switch netutils.GetIPScope(ip) { //nolint:exhaustive // Checking to specific values only.
case netutils.SiteLocal, netutils.Global:
// IPv6 global addresses are also used in local networks
lan = true
@@ -470,14 +473,16 @@ func checkOnlineStatus(ctx context.Context) {
response, err := client.Do(request)
if err != nil {
nErr, ok := err.(net.Error)
if !ok || !nErr.Timeout() {
var netErr net.Error
if !errors.As(err, &netErr) || !netErr.Timeout() {
// Timeout is the expected error when there is no portal
log.Debugf("netenv: http portal test failed: %s", err)
// TODO: discern between errors to detect StatusLimited
}
} else {
defer response.Body.Close()
defer func() {
_ = response.Body.Close()
}()
// Got a response, something is messing with the request
// check location

View File

@@ -6,6 +6,8 @@ import (
)
func TestCheckOnlineStatus(t *testing.T) {
t.Parallel()
checkOnlineStatus(context.Background())
t.Logf("online status: %s", GetOnlineStatus())
t.Logf("captive portal: %+v", GetCaptivePortal())