mirror of
https://github.com/gravitl/netmaker.git
synced 2026-10-12 02:15:06 +00:00
Add TLS mode, listen addr, optional public hostname, and proxy-mode client port (443 / TCP_PROXY_PUBLIC_PORT) when building tcp_proxy_endpoint.
348 lines
15 KiB
Go
348 lines
15 KiB
Go
package models
|
|
|
|
import (
|
|
"bytes"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/gravitl/netmaker/schema"
|
|
"gorm.io/datatypes"
|
|
)
|
|
|
|
// LastCheckInThreshold - if node's checkin more than this threshold,then node is declared as offline
|
|
const LastCheckInThreshold = time.Minute * 10
|
|
|
|
// NodeCheckin - struct for node checkins with server
|
|
type NodeCheckin struct {
|
|
Version string
|
|
Connected bool
|
|
Ifaces []schema.Iface
|
|
}
|
|
|
|
// CommonNode - represents a commonn node data elements shared by netmaker and netclient
|
|
type CommonNode struct {
|
|
ID uuid.UUID `json:"id" yaml:"id"`
|
|
TenantID string `json:"tenant_id"`
|
|
HostID uuid.UUID `json:"hostid" yaml:"hostid"`
|
|
Network string `json:"network" yaml:"network"`
|
|
NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange" swaggertype:"primitive,integer"`
|
|
NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6" swaggertype:"primitive,number"`
|
|
Server string `json:"server" yaml:"server"`
|
|
Connected bool `json:"connected" yaml:"connected"`
|
|
Address net.IPNet `json:"address" yaml:"address"`
|
|
Address6 net.IPNet `json:"address6" yaml:"address6"`
|
|
Action string `json:"action" yaml:"action"`
|
|
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
|
|
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
|
|
EgressGatewayRanges []string `json:"egressgatewayranges" yaml:"egressgatewayranges"`
|
|
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
|
|
IsRelayed bool `json:"isrelayed" yaml:"isrelayed"`
|
|
RelayedBy string `json:"relayedby" yaml:"relayedby"`
|
|
IsRelay bool `json:"isrelay" yaml:"isrelay"`
|
|
IsGw bool `json:"is_gw" yaml:"is_gw"`
|
|
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
|
|
IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
|
|
AutoAssignGateway bool `json:"auto_assign_gw"`
|
|
TcpProxyEnabled bool `json:"tcp_proxy_enabled"`
|
|
TcpProxyListenPort int `json:"tcp_proxy_listen_port"`
|
|
TcpProxyTLSMode string `json:"tcp_proxy_tls_mode"`
|
|
TcpProxyListenAddr string `json:"tcp_proxy_listen_addr,omitempty"`
|
|
TcpProxyPublicHostname string `json:"tcp_proxy_public_hostname,omitempty"`
|
|
UseTcpUplink bool `json:"use_tcp_uplink"`
|
|
}
|
|
|
|
// Node - a model of a network node
|
|
type Node struct {
|
|
CommonNode
|
|
PendingDelete bool `json:"pendingdelete"`
|
|
LastModified time.Time `json:"lastmodified"`
|
|
LastCheckIn time.Time `json:"lastcheckin"`
|
|
LastPeerUpdate time.Time `json:"lastpeerupdate"`
|
|
ExpirationDateTime time.Time `json:"expdatetime"`
|
|
EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled"`
|
|
EgressGatewayRequest EgressGatewayRequest `json:"egressgatewayrequest"`
|
|
IngressGatewayRange string `json:"ingressgatewayrange"`
|
|
IngressGatewayRange6 string `json:"ingressgatewayrange6"`
|
|
IngressPersistentKeepalive int32 `json:"ingresspersistentkeepalive"`
|
|
IngressMTU int32 `json:"ingressmtu"`
|
|
Metadata string `json:"metadata"`
|
|
// == PRO ==
|
|
OwnerID string `json:"ownerid,omitempty"`
|
|
IsFailOver bool `json:"is_fail_over"`
|
|
IsAutoRelay bool `json:"is_auto_relay"`
|
|
//AutoRelayedPeers map[string]struct{} `json:"auto_relayed_peers"`
|
|
AutoRelayedPeers map[string]string `json:"auto_relayed_peers_v1"`
|
|
//AutoRelayedBy uuid.UUID `json:"auto_relayed_by"`
|
|
FailOverPeers map[string]struct{} `json:"fail_over_peers"`
|
|
FailedOverBy uuid.UUID `json:"failed_over_by"`
|
|
IsInternetGateway bool `json:"isinternetgateway"`
|
|
InetNodeReq InetNodeReq `json:"inet_node_req"`
|
|
InternetGwID string `json:"internetgw_node_id"`
|
|
// SelectedInternetEgressID is the internet-type egress this node uses as its exit node (empty = none).
|
|
SelectedInternetEgressID string `json:"selected_internet_egress_id"`
|
|
AdditionalRagIps []net.IP `json:"additional_rag_ips" swaggertype:"array,number"`
|
|
Tags map[TagID]struct{} `json:"tags"`
|
|
IsStatic bool `json:"is_static"`
|
|
IsUserNode bool `json:"is_user_node"`
|
|
StaticNode ExtClient `json:"static_node"`
|
|
Status schema.NodeStatus `json:"node_status"`
|
|
Mutex *sync.Mutex `json:"-"`
|
|
EgressDetails EgressDetails `json:"-"`
|
|
PostureChecksViolations []Violation `json:"posture_check_violations"`
|
|
PostureCheckViolationSeverityLevel schema.Severity `json:"posture_check_violation_severity_level"`
|
|
LastEvaluationCycleID string `json:"last_evaluation_cycle_id"`
|
|
LastEvaluatedAt time.Time `json:"last_evaluated_at"`
|
|
Location string `json:"location"` // Format: "lat,lon"
|
|
CountryCode string `json:"country_code"`
|
|
}
|
|
type EgressDetails struct {
|
|
EgressGatewayNatEnabled bool
|
|
EgressGatewayRequest EgressGatewayRequest
|
|
IsEgressGateway bool
|
|
EgressGatewayRanges []string
|
|
// IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
|
|
// InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
|
|
// InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
|
|
}
|
|
|
|
// NodesArray - used for node sorting
|
|
type NodesArray []Node
|
|
|
|
// NodesArray.Len - gets length of node array
|
|
func (a NodesArray) Len() int { return len(a) }
|
|
|
|
// NodesArray.Less - gets returns lower rank of two node addressesFill
|
|
func (a NodesArray) Less(i, j int) bool {
|
|
return isLess(a[i].Address.IP.String(), a[j].Address.IP.String())
|
|
}
|
|
|
|
// NodesArray.Swap - swaps two nodes in array
|
|
func (a NodesArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
func isLess(ipA string, ipB string) bool {
|
|
ipNetA := net.ParseIP(ipA)
|
|
ipNetB := net.ParseIP(ipB)
|
|
return bytes.Compare(ipNetA, ipNetB) < 0
|
|
}
|
|
|
|
// Node.PrimaryAddress - return ipv4 address if present, else return ipv6
|
|
func (node *Node) PrimaryAddressIPNet() net.IPNet {
|
|
if node.Address.IP != nil {
|
|
return node.Address
|
|
}
|
|
return node.Address6
|
|
}
|
|
|
|
// Node.PrimaryAddress - return ipv4 address if present, else return ipv6
|
|
func (node *Node) PrimaryAddress() string {
|
|
if node.Address.IP != nil {
|
|
return node.Address.IP.String()
|
|
}
|
|
return node.Address6.IP.String()
|
|
}
|
|
|
|
func (node *Node) AddressIPNet4() net.IPNet {
|
|
return net.IPNet{
|
|
IP: node.Address.IP,
|
|
Mask: net.CIDRMask(32, 32),
|
|
}
|
|
}
|
|
func (node *Node) AddressIPNet6() net.IPNet {
|
|
return net.IPNet{
|
|
IP: node.Address6.IP,
|
|
Mask: net.CIDRMask(128, 128),
|
|
}
|
|
}
|
|
|
|
// Node.PrimaryNetworkRange - returns node's parent network, returns ipv4 address if present, else return ipv6
|
|
func (node *Node) PrimaryNetworkRange() net.IPNet {
|
|
if node.NetworkRange.IP != nil {
|
|
return node.NetworkRange
|
|
}
|
|
return node.NetworkRange6
|
|
}
|
|
|
|
// Node.SetDefaultConnected
|
|
func (node *Node) SetDefaultConnected() {
|
|
node.Connected = true
|
|
}
|
|
|
|
// Node.SetLastModified - set last modified initial time
|
|
func (node *Node) SetLastModified() {
|
|
node.LastModified = time.Now().UTC()
|
|
}
|
|
|
|
// Node.SetLastCheckIn - set checkin time of node
|
|
func (node *Node) SetLastCheckIn() {
|
|
node.LastCheckIn = time.Now().UTC()
|
|
}
|
|
|
|
// Node.SetLastPeerUpdate - sets last peer update time
|
|
func (node *Node) SetLastPeerUpdate() {
|
|
node.LastPeerUpdate = time.Now().UTC()
|
|
}
|
|
|
|
// Node.SetExpirationDateTime - sets node expiry time
|
|
func (node *Node) SetExpirationDateTime() {
|
|
if node.ExpirationDateTime.IsZero() {
|
|
node.ExpirationDateTime = time.Now().AddDate(100, 1, 0)
|
|
}
|
|
}
|
|
|
|
// Node.Fill - fills other node data into calling node data if not set on calling node (skips DNSOn)
|
|
func (newNode *Node) Fill(
|
|
currentNode *Node,
|
|
isPro bool,
|
|
) { // TODO add new field for nftables present
|
|
newNode.ID = currentNode.ID
|
|
newNode.HostID = currentNode.HostID
|
|
// Revisit the logic for boolean values
|
|
// TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
// TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
if newNode.Address.String() == "" {
|
|
newNode.Address = currentNode.Address
|
|
}
|
|
if newNode.Address6.String() == "" {
|
|
newNode.Address6 = currentNode.Address6
|
|
}
|
|
if newNode.LastModified != currentNode.LastModified {
|
|
newNode.LastModified = currentNode.LastModified
|
|
}
|
|
if newNode.ExpirationDateTime.IsZero() {
|
|
newNode.ExpirationDateTime = currentNode.ExpirationDateTime
|
|
}
|
|
if newNode.LastPeerUpdate.IsZero() || currentNode.LastPeerUpdate.After(newNode.LastPeerUpdate) {
|
|
newNode.LastPeerUpdate = currentNode.LastPeerUpdate
|
|
}
|
|
if newNode.LastCheckIn.IsZero() || currentNode.LastCheckIn.After(newNode.LastCheckIn) {
|
|
newNode.LastCheckIn = currentNode.LastCheckIn
|
|
}
|
|
if newNode.Network == "" {
|
|
newNode.Network = currentNode.Network
|
|
}
|
|
if newNode.IsIngressGateway != currentNode.IsIngressGateway {
|
|
newNode.IsIngressGateway = currentNode.IsIngressGateway
|
|
}
|
|
if newNode.IngressGatewayRange == "" {
|
|
newNode.IngressGatewayRange = currentNode.IngressGatewayRange
|
|
}
|
|
if newNode.IngressGatewayRange6 == "" {
|
|
newNode.IngressGatewayRange6 = currentNode.IngressGatewayRange6
|
|
}
|
|
if newNode.Action == "" {
|
|
newNode.Action = currentNode.Action
|
|
}
|
|
if newNode.RelayedNodes == nil {
|
|
newNode.RelayedNodes = currentNode.RelayedNodes
|
|
}
|
|
if newNode.IsRelay != currentNode.IsRelay && isPro {
|
|
newNode.IsRelay = currentNode.IsRelay
|
|
}
|
|
if newNode.IsRelayed == currentNode.IsRelayed && isPro {
|
|
newNode.IsRelayed = currentNode.IsRelayed
|
|
}
|
|
if newNode.Server == "" {
|
|
newNode.Server = currentNode.Server
|
|
}
|
|
if newNode.IsFailOver != currentNode.IsFailOver {
|
|
newNode.IsFailOver = currentNode.IsFailOver
|
|
}
|
|
newNode.FailOverPeers = currentNode.FailOverPeers
|
|
if newNode.Tags == nil {
|
|
if currentNode.Tags == nil {
|
|
currentNode.Tags = make(map[TagID]struct{})
|
|
}
|
|
newNode.Tags = currentNode.Tags
|
|
}
|
|
if newNode.PostureCheckViolationSeverityLevel == 0 {
|
|
newNode.PostureCheckViolationSeverityLevel = currentNode.PostureCheckViolationSeverityLevel
|
|
}
|
|
if len(newNode.PostureChecksViolations) == 0 {
|
|
newNode.PostureChecksViolations = currentNode.PostureChecksViolations
|
|
}
|
|
if newNode.LastEvaluationCycleID == "" {
|
|
newNode.LastEvaluationCycleID = currentNode.LastEvaluationCycleID
|
|
}
|
|
if newNode.LastEvaluatedAt.IsZero() {
|
|
newNode.LastEvaluatedAt = currentNode.LastEvaluatedAt
|
|
}
|
|
}
|
|
|
|
// Node.NetworkSettings updates a node with network settings
|
|
func (node *Node) NetworkSettings(n Network) {
|
|
_, cidr, err := net.ParseCIDR(n.AddressRange)
|
|
if err == nil {
|
|
node.NetworkRange = *cidr
|
|
}
|
|
_, cidr, err = net.ParseCIDR(n.AddressRange6)
|
|
if err == nil {
|
|
node.NetworkRange6 = *cidr
|
|
}
|
|
}
|
|
|
|
type NodeWithHost struct {
|
|
ID string `json:"id"`
|
|
TenantID string `json:"tenant_id"`
|
|
HostID string `json:"host_id"`
|
|
Host *ApiHost `json:"host,omitempty"`
|
|
NetworkID string `json:"network_id"`
|
|
Address string `json:"address"`
|
|
Address6 string `json:"address6"`
|
|
Connected bool `json:"connected"`
|
|
Action string `json:"action"`
|
|
Status schema.NodeStatus `json:"status"`
|
|
PendingDelete bool `json:"pending_delete"`
|
|
AutoAssignGateway bool `json:"auto_assign_gateway"`
|
|
IsGateway bool `json:"is_gateway"`
|
|
IsAutoRelay bool `json:"is_auto_relay"`
|
|
IsInternetGateway bool `json:"is_internet_gateway"`
|
|
RelayedClients datatypes.JSONMap `json:"relayed_clients"`
|
|
RelayedIGWClients datatypes.JSONMap `json:"relayed_igw_clients"`
|
|
RelayedByNodeID *string `json:"relayed_by_node_id"`
|
|
IsIGWClient bool `json:"is_igw_client"`
|
|
SelectedInternetEgressID string `json:"selected_internet_egress_id"`
|
|
AutoRelayedPeers datatypes.JSONType[map[string]string] `json:"auto_relayed_peers"`
|
|
Tags datatypes.JSONMap `json:"tags"`
|
|
PostureCheckSeverity schema.Severity `json:"posture_check_severity"`
|
|
PostureCheckLastEvaluationCycleID string `json:"posture_check_last_evaluation_cycle_id"`
|
|
Metadata string `json:"metadata"`
|
|
LastCheckIn time.Time `json:"last_check_in"`
|
|
ExpirationDateTime time.Time `json:"expiration_date_time"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (n *NodeWithHost) Fill(_node *schema.Node) {
|
|
n.ID = _node.ID
|
|
n.TenantID = _node.TenantID
|
|
n.HostID = _node.HostID
|
|
n.Host = NewApiHostFromSchemaHost(_node.Host)
|
|
n.NetworkID = _node.NetworkID
|
|
n.Address = _node.Address
|
|
n.Address6 = _node.Address6
|
|
n.Connected = _node.Connected
|
|
n.Action = _node.Action
|
|
n.Status = _node.Status
|
|
n.PendingDelete = _node.PendingDelete
|
|
n.AutoAssignGateway = _node.AutoAssignGateway
|
|
n.IsGateway = _node.IsGateway
|
|
n.IsAutoRelay = _node.IsAutoRelay == "yes"
|
|
n.IsInternetGateway = _node.IsInternetGateway
|
|
n.RelayedClients = _node.RelayedClients
|
|
n.RelayedIGWClients = _node.RelayedIGWClients
|
|
n.RelayedByNodeID = _node.RelayedByNodeID
|
|
n.IsIGWClient = _node.IsIGWClient
|
|
n.SelectedInternetEgressID = _node.SelectedInternetEgressID
|
|
n.AutoRelayedPeers = _node.AutoRelayedPeers
|
|
n.Tags = _node.Tags
|
|
n.PostureCheckSeverity = _node.PostureCheckSeverity
|
|
n.PostureCheckLastEvaluationCycleID = _node.PostureCheckLastEvaluationCycleID
|
|
n.Metadata = _node.Metadata
|
|
n.LastCheckIn = _node.LastCheckIn
|
|
n.ExpirationDateTime = _node.ExpirationDateTime
|
|
n.CreatedAt = _node.CreatedAt
|
|
n.UpdatedAt = _node.UpdatedAt
|
|
}
|