safing-portmaster/spn/hub/intel.go

191 lines
6 KiB
Go

package hub
import (
"errors"
"fmt"
"net"
"github.com/ghodss/yaml"
"github.com/safing/jess/lhash"
"github.com/safing/portmaster/service/profile/endpoints"
)
// Intel holds a collection of various security related data collections on Hubs.
type Intel struct {
// BootstrapHubs is list of transports that also contain an IP and the Hub's ID.
BootstrapHubs []string
// Hubs holds intel regarding specific Hubs.
Hubs map[string]*HubIntel
// AdviseOnlyTrustedHubs advises to only use trusted Hubs regardless of intended purpose.
AdviseOnlyTrustedHubs bool
// AdviseOnlyTrustedHomeHubs advises to only use trusted Hubs for Home Hubs.
AdviseOnlyTrustedHomeHubs bool
// AdviseOnlyTrustedDestinationHubs advises to only use trusted Hubs for Destination Hubs.
AdviseOnlyTrustedDestinationHubs bool
// Hub Advisories advise on the usage of Hubs and take the form of Endpoint Lists that match on both IPv4 and IPv6 addresses and their related data.
// HubAdvisory always affects all Hubs.
HubAdvisory []string
// HomeHubAdvisory is only taken into account when selecting a Home Hub.
HomeHubAdvisory []string
// DestinationHubAdvisory is only taken into account when selecting a Destination Hub.
DestinationHubAdvisory []string
// Regions defines regions to assist network optimization.
Regions []*RegionConfig
// VirtualNetworks holds network configurations for virtual cloud networks.
VirtualNetworks []*VirtualNetworkConfig
parsed *ParsedIntel
}
// HubIntel holds Hub-related data.
type HubIntel struct { //nolint:golint
// Trusted specifies if the Hub is specially designated for more sensitive tasks, such as handling unencrypted traffic.
Trusted bool
// Discontinued specifies if the Hub has been discontinued and should be marked as offline and removed.
Discontinued bool
// VerifiedOwner holds the name of the verified owner / operator of the Hub.
VerifiedOwner string
// Override is used to override certain Hub information.
Override *InfoOverride
}
// RegionConfig holds the configuration of a region.
type RegionConfig struct {
// ID is the internal identifier of the region.
ID string
// Name is a human readable name of the region.
Name string
// MemberPolicy specifies a list for including members.
MemberPolicy []string
// RegionalMinLanes specifies how many lanes other regions should build
// to this region.
RegionalMinLanes int
// RegionalMinLanesPerHub specifies how many lanes other regions should
// build to this region, per Hub in this region.
// This value will usually be below one.
RegionalMinLanesPerHub float64
// RegionalMaxLanesOnHub specifies how many lanes from or to another region may be
// built on one Hub per region.
RegionalMaxLanesOnHub int
// SatelliteMinLanes specifies how many lanes satellites (Hubs without
// region) should build to this region.
SatelliteMinLanes int
// SatelliteMinLanesPerHub specifies how many lanes satellites (Hubs without
// region) should build to this region, per Hub in this region.
// This value will usually be below one.
SatelliteMinLanesPerHub float64
// InternalMinLanesOnHub specifies how many lanes every Hub should create
// within the region at minimum.
InternalMinLanesOnHub int
// InternalMaxHops specifies the max hop constraint for internally optimizing
// the region.
InternalMaxHops int
}
// VirtualNetworkConfig holds configuration of a virtual network that binds multiple Hubs together.
type VirtualNetworkConfig struct {
// Name is a human readable name of the virtual network.
Name string
// Force forces the use of the mapped IP addresses after the Hub's IPs have been verified.
Force bool
// Mapping maps Hub IDs to internal IP addresses.
Mapping map[string]net.IP
}
// ParsedIntel holds a collection of parsed intel data.
type ParsedIntel struct {
// HubAdvisory always affects all Hubs.
HubAdvisory endpoints.Endpoints
// HomeHubAdvisory is only taken into account when selecting a Home Hub.
HomeHubAdvisory endpoints.Endpoints
// DestinationHubAdvisory is only taken into account when selecting a Destination Hub.
DestinationHubAdvisory endpoints.Endpoints
}
// Parsed returns the collection of parsed intel data.
func (i *Intel) Parsed() *ParsedIntel {
return i.parsed
}
// ParseIntel parses Hub intelligence data.
func ParseIntel(data []byte) (*Intel, error) {
// Load data into struct.
intel := &Intel{}
err := yaml.Unmarshal(data, intel)
if err != nil {
return nil, fmt.Errorf("failed to parse data: %w", err)
}
// Parse all endpoint lists.
err = intel.ParseAdvisories()
if err != nil {
return nil, err
}
return intel, nil
}
// ParseAdvisories parses all advisory endpoint lists.
func (i *Intel) ParseAdvisories() (err error) {
i.parsed = &ParsedIntel{}
i.parsed.HubAdvisory, err = endpoints.ParseEndpoints(i.HubAdvisory)
if err != nil {
return fmt.Errorf("failed to parse HubAdvisory list: %w", err)
}
i.parsed.HomeHubAdvisory, err = endpoints.ParseEndpoints(i.HomeHubAdvisory)
if err != nil {
return fmt.Errorf("failed to parse HomeHubAdvisory list: %w", err)
}
i.parsed.DestinationHubAdvisory, err = endpoints.ParseEndpoints(i.DestinationHubAdvisory)
if err != nil {
return fmt.Errorf("failed to parse DestinationHubAdvisory list: %w", err)
}
return nil
}
// ParseBootstrapHub parses a bootstrap hub.
func ParseBootstrapHub(bootstrapTransport string) (t *Transport, hubID string, hubIP net.IP, err error) {
// Parse transport and check Hub ID.
t, err = ParseTransport(bootstrapTransport)
if err != nil {
return nil, "", nil, fmt.Errorf("failed to parse transport: %w", err)
}
if t.Option == "" {
return nil, "", nil, errors.New("missing hub ID in URL fragment")
}
if _, err := lhash.FromBase58(t.Option); err != nil {
return nil, "", nil, fmt.Errorf("hub ID is invalid: %w", err)
}
// Parse IP address from transport.
ip := net.ParseIP(t.Domain)
if ip == nil {
return nil, "", nil, errors.New("invalid IP address (domains are not supported for bootstrapping)")
}
// Clean up transport for hub info.
id := t.Option
t.Domain = ""
t.Option = ""
return t, id, ip, nil
}