Files
portmaster/spn/navigator/map_test.go

280 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.
var hubs []*hub.Hub
// 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 := 0; i < size; i++ {
// 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 := 0; i < 3; i++ {
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 i := 0; i < totalConnections; i++ {
// 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 i := 0; i < 100; i++ {
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)
}