safing-portmaster/spn/navigator/map_test.go
Daniel Hååvi 80664d1a27
Restructure modules ()
* Move portbase into monorepo

* Add new simple module mgr

* [WIP] Switch to new simple module mgr

* Add StateMgr and more worker variants

* [WIP] Switch more modules

* [WIP] Switch more modules

* [WIP] swtich more modules

* [WIP] switch all SPN modules

* [WIP] switch all service modules

* [WIP] Convert all workers to the new module system

* [WIP] add new task system to module manager

* [WIP] Add second take for scheduling workers

* [WIP] Add FIXME for bugs in new scheduler

* [WIP] Add minor improvements to scheduler

* [WIP] Add new worker scheduler

* [WIP] Fix more bug related to new module system

* [WIP] Fix start handing of the new module system

* [WIP] Improve startup process

* [WIP] Fix minor issues

* [WIP] Fix missing subsystem in settings

* [WIP] Initialize managers in constructor

* [WIP] Move module event initialization to constrictors

* [WIP] Fix setting for enabling and disabling the SPN module

* [WIP] Move API registeration into module construction

* [WIP] Update states mgr for all modules

* [WIP] Add CmdLine operation support

* Add state helper methods to module group and instance

* Add notification and module status handling to status package

* Fix starting issues

* Remove pilot widget and update security lock to new status data

* Remove debug logs

* Improve http server shutdown

* Add workaround for cleanly shutting down firewall+netquery

* Improve logging

* Add syncing states with notifications for new module system

* Improve starting, stopping, shutdown; resolve FIXMEs/TODOs

* [WIP] Fix most unit tests

* Review new module system and fix minor issues

* Push shutdown and restart events again via API

* Set sleep mode via interface

* Update example/template module

* [WIP] Fix spn/cabin unit test

* Remove deprecated UI elements

* Make log output more similar for the logging transition phase

* Switch spn hub and observer cmds to new module system

* Fix log sources

* Make worker mgr less error prone

* Fix tests and minor issues

* Fix observation hub

* Improve shutdown and restart handling

* Split up big connection.go source file

* Move varint and dsd packages to structures repo

* Improve expansion test

* Fix linter warnings

* Fix interception module on windows

* Fix linter errors

---------

Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
2024-08-09 18:15:48 +03:00

279 lines
6.1 KiB
Go

package navigator
import (
"fmt"
"net"
"sync"
"testing"
"time"
"github.com/brianvoe/gofakeit"
"github.com/safing/jess/lhash"
"github.com/safing/portmaster/service/intel/geoip"
"github.com/safing/portmaster/spn/hub"
)
var (
fakeLock sync.Mutex
defaultMapCreate sync.Once
defaultMap *Map
)
func getDefaultTestMap() *Map {
defaultMapCreate.Do(func() {
defaultMap = createRandomTestMap(1, 200)
})
return defaultMap
}
func TestRandomMapCreation(t *testing.T) {
t.Parallel()
m := getDefaultTestMap()
fmt.Println("All Pins:")
for _, pin := range m.all {
fmt.Printf("%s: %s %s\n", pin, pin.Hub.Info.IPv4, pin.Hub.Info.IPv6)
}
// Print stats
fmt.Printf("\n%s\n", m.Stats())
// Print home
fmt.Printf("Selected Home Hub: %s\n", m.home)
}
func createRandomTestMap(seed int64, size int) *Map {
fakeLock.Lock()
defer fakeLock.Unlock()
// Seed with parameter to make it reproducible.
gofakeit.Seed(seed)
// Enforce minimum size.
if size < 10 {
size = 10
}
// Create Hub list.
hubs := make([]*hub.Hub, 0, size)
// Create Intel data structure.
mapIntel := &hub.Intel{
Hubs: make(map[string]*hub.HubIntel),
}
// Define periodic values.
var currentGroup string
// Create [size] fake Hubs.
for i := range size {
// Change group every 5 Hubs.
if i%5 == 0 {
currentGroup = gofakeit.Username()
}
// Create new fake Hub and add to the list.
h := createFakeHub(currentGroup, true, mapIntel)
hubs = append(hubs, h)
}
// Fake three superseeded Hubs.
for i := range 3 {
h := hubs[size-1-i]
// Set FirstSeen in the past and copy an IP address of an existing Hub.
h.FirstSeen = time.Now().Add(-1 * time.Hour)
if i%2 == 0 {
h.Info.IPv4 = hubs[i].Info.IPv4
} else {
h.Info.IPv6 = hubs[i].Info.IPv6
}
}
// Create Lanes between Hubs in order to create the network.
totalConnections := size * 10
for range totalConnections {
// Get new random indexes.
indexA := gofakeit.Number(0, size-1)
indexB := gofakeit.Number(0, size-1)
if indexA == indexB {
continue
}
// Get Hubs and check if they are already connected.
hubA := hubs[indexA]
hubB := hubs[indexB]
if hubA.GetLaneTo(hubB.ID) != nil {
// already connected
continue
}
if hubB.GetLaneTo(hubA.ID) != nil {
// already connected
continue
}
// Create connections.
_ = hubA.AddLane(createLane(hubB.ID))
// Add the second connection in 99% of cases.
// If this is missing, the Pins should not show up as connected.
if gofakeit.Number(0, 100) != 0 {
_ = hubB.AddLane(createLane(hubA.ID))
}
}
// Parse constructed intel data
err := mapIntel.ParseAdvisories()
if err != nil {
panic(err)
}
// Create map and add Pins.
m := NewMap(fmt.Sprintf("Test-Map-%d", seed), true)
m.intel = mapIntel
for _, h := range hubs {
m.UpdateHub(h)
}
// Fake communication error with three Hubs.
var i int
for _, pin := range m.all {
pin.MarkAsFailingFor(1 * time.Hour)
pin.addStates(StateFailing)
if i++; i >= 3 {
break
}
}
// Set a Home Hub.
findFakeHomeHub(m)
return m
}
func createFakeHub(group string, randomFailes bool, mapIntel *hub.Intel) *hub.Hub {
// Create fake Hub ID.
idSrc := gofakeit.Password(true, true, true, true, true, 64)
id := lhash.Digest(lhash.BLAKE2b_256, []byte(idSrc)).Base58()
ip4, _ := createGoodIP(true)
ip6, _ := createGoodIP(false)
// Create and return new fake Hub.
h := &hub.Hub{
ID: id,
Info: &hub.Announcement{
ID: id,
Timestamp: time.Now().Unix(),
Name: gofakeit.Username(),
Group: group,
// ContactAddress // TODO
// ContactService // TODO
// Hosters []string // TODO
// Datacenter string // TODO
IPv4: ip4,
IPv6: ip6,
},
Status: &hub.Status{
Timestamp: time.Now().Unix(),
Keys: map[string]*hub.Key{
"a": {
Expires: time.Now().Add(48 * time.Hour).Unix(),
},
},
Load: gofakeit.Number(10, 100),
},
Measurements: hub.NewMeasurements(),
FirstSeen: time.Now(),
}
h.Measurements.Latency = createLatency()
h.Measurements.Capacity = createCapacity()
h.Measurements.CalculatedCost = CalculateLaneCost(
h.Measurements.Latency,
h.Measurements.Capacity,
)
// Return if not failures of any kind should be simulated.
if !randomFailes {
return h
}
// Set hub-based states.
if gofakeit.Number(0, 100) == 0 {
// Fake Info message error.
h.InvalidInfo = true
}
if gofakeit.Number(0, 100) == 0 {
// Fake Status message error.
h.InvalidStatus = true
}
if gofakeit.Number(0, 100) == 0 {
// Fake expired exchange keys.
for _, key := range h.Status.Keys {
key.Expires = time.Now().Add(-1 * time.Hour).Unix()
}
}
// Return if not failures of any kind should be simulated.
if mapIntel == nil {
return h
}
// Set advisory-based states.
if gofakeit.Number(0, 10) == 0 {
// Make Trusted State
mapIntel.Hubs[h.ID] = &hub.HubIntel{
Trusted: true,
}
}
if gofakeit.Number(0, 100) == 0 {
// Discourage any usage.
mapIntel.HubAdvisory = append(mapIntel.HubAdvisory, "- "+h.Info.IPv4.String())
}
if gofakeit.Number(0, 100) == 0 {
// Discourage Home Hub usage.
mapIntel.HomeHubAdvisory = append(mapIntel.HomeHubAdvisory, "- "+h.Info.IPv4.String())
}
if gofakeit.Number(0, 100) == 0 {
// Discourage Destination Hub usage.
mapIntel.DestinationHubAdvisory = append(mapIntel.DestinationHubAdvisory, "- "+h.Info.IPv4.String())
}
return h
}
func createGoodIP(v4 bool) (net.IP, *geoip.Location) {
var candidate net.IP
for range 100 {
if v4 {
candidate = net.ParseIP(gofakeit.IPv4Address())
} else {
candidate = net.ParseIP(gofakeit.IPv6Address())
}
loc, err := geoip.GetLocation(candidate)
if err == nil && loc.Coordinates.Latitude != 0 {
return candidate, loc
}
}
return candidate, nil
}
func createLane(toHubID string) *hub.Lane {
return &hub.Lane{
ID: toHubID,
Latency: createLatency(),
Capacity: createCapacity(),
}
}
func createLatency() time.Duration {
// Return a value between 10ms and 100ms.
return time.Duration(gofakeit.Float64Range(10, 100) * float64(time.Millisecond))
}
func createCapacity() int {
// Return a value between 10Mbit/s and 1Gbit/s.
return gofakeit.Number(10000000, 1000000000)
}