began transition

This commit is contained in:
0xdcarns 2022-01-10 10:55:05 -05:00 committed by Matthew R Kasun
parent ef32150cc5
commit de4e317aea
5 changed files with 210 additions and 428 deletions

9
go.mod
View file

@ -3,11 +3,9 @@ module github.com/gravitl/netmaker
go 1.17 go 1.17
require ( require (
github.com/eclipse/paho.mqtt.golang v1.3.5
github.com/go-playground/validator/v10 v10.10.0 github.com/go-playground/validator/v10 v10.10.0
github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0
github.com/gorilla/handlers v1.5.1 github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/lib/pq v1.10.4 github.com/lib/pq v1.10.4
@ -27,7 +25,6 @@ require (
google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
google.golang.org/grpc v1.43.0 google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
gopkg.in/ini.v1 v1.66.2
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )
@ -35,13 +32,11 @@ require (
cloud.google.com/go v0.34.0 // indirect cloud.google.com/go v0.34.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/eclipse/paho.mqtt.golang v1.3.5 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 // indirect
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/google/go-cmp v0.5.5 // indirect github.com/google/go-cmp v0.5.5 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/mdlayher/genetlink v1.0.0 // indirect github.com/mdlayher/genetlink v1.0.0 // indirect
@ -49,7 +44,5 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
google.golang.org/appengine v1.4.0 // indirect google.golang.org/appengine v1.4.0 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
) )

View file

@ -5,26 +5,32 @@ import (
"errors" "errors"
"fmt" "fmt"
"sort" "sort"
"strings"
"time" "time"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
"github.com/gravitl/netmaker/validation" "github.com/gravitl/netmaker/validation"
"golang.org/x/crypto/bcrypt"
) )
// GetNetworkNodes - gets the nodes of a network // GetNetworkNodes - gets the nodes of a network
func GetNetworkNodes(network string) ([]models.Node, error) { func GetNetworkNodes(network string) ([]models.Node, error) {
var nodes, err = GetAllNodes() var nodes []models.Node
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
if err != nil { if err != nil {
return []models.Node{}, err if database.IsEmptyRecord(err) {
return []models.Node{}, nil
}
return nodes, err
} }
for _, node := range nodes { for _, value := range collection {
var node models.Node
err := json.Unmarshal([]byte(value), &node)
if err != nil {
continue
}
if node.Network == network { if node.Network == network {
nodes = append(nodes, node) nodes = append(nodes, node)
} }
@ -58,8 +64,8 @@ func GetSortedNetworkServerNodes(network string) ([]models.Node, error) {
} }
// UncordonNode - approves a node to join a network // UncordonNode - approves a node to join a network
func UncordonNode(nodeid string) (models.Node, error) { func UncordonNode(network, macaddress string) (models.Node, error) {
node, err := GetNodeByID(nodeid) node, err := GetNodeByMacAddress(network, macaddress)
if err != nil { if err != nil {
return models.Node{}, err return models.Node{}, err
} }
@ -70,15 +76,19 @@ func UncordonNode(nodeid string) (models.Node, error) {
if err != nil { if err != nil {
return node, err return node, err
} }
key, err := GetRecordKey(node.MacAddress, node.Network)
if err != nil {
return node, err
}
err = database.Insert(node.ID, string(data), database.NODES_TABLE_NAME) err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
return node, err return node, err
} }
// GetPeers - gets the peers of a given node // GetPeers - gets the peers of a given node
func GetPeers(node *models.Node) ([]models.Node, error) { func GetPeers(node *models.Node) ([]models.Node, error) {
if IsLeader(node) { if IsLeader(node) {
setNetworkServerPeers(node) SetNetworkServerPeers(node)
} }
excludeIsRelayed := node.IsRelay != "yes" excludeIsRelayed := node.IsRelay != "yes"
var relayedNode string var relayedNode string
@ -111,13 +121,6 @@ func IsLeader(node *models.Node) bool {
// UpdateNode - takes a node and updates another node with it's values // UpdateNode - takes a node and updates another node with it's values
func UpdateNode(currentNode *models.Node, newNode *models.Node) error { func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
if newNode.Address != currentNode.Address {
if network, err := GetParentNetwork(newNode.Network); err == nil {
if !IsAddressInCIDR(newNode.Address, network.AddressRange) {
return fmt.Errorf("invalid address provided; out of network range for node %s", newNode.ID)
}
}
}
newNode.Fill(currentNode) newNode.Fill(currentNode)
if err := ValidateNode(newNode, true); err != nil { if err := ValidateNode(newNode, true); err != nil {
return err return err
@ -165,128 +168,6 @@ func ValidateNode(node *models.Node, isUpdate bool) error {
return err return err
} }
// CreateNode - creates a node in database
func CreateNode(node *models.Node) error {
//encrypt that password so we never see it
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
if err != nil {
return err
}
//set password to encrypted password
node.Password = string(hash)
if node.Name == models.NODE_SERVER_NAME {
node.IsServer = "yes"
}
if node.DNSOn == "" {
if servercfg.IsDNSMode() {
node.DNSOn = "yes"
} else {
node.DNSOn = "no"
}
}
SetNodeDefaults(node)
node.Address, err = UniqueAddress(node.Network)
if err != nil {
return err
}
node.Address6, err = UniqueAddress6(node.Network)
if err != nil {
return err
}
// TODO: This covers legacy nodes, eventually want to remove legacy check
if node.IsServer == "yes" {
node.ID = uuid.NewString()
} else if node.IsServer != "yes" || (node.ID == "" || strings.Contains(node.ID, "###")) {
node.ID = uuid.NewString()
}
//Create a JWT for the node
tokenString, _ := CreateJWT(node.ID, node.MacAddress, node.Network)
if tokenString == "" {
//returnErrorResponse(w, r, errorResponse)
return err
}
err = ValidateNode(node, false)
if err != nil {
return err
}
nodebytes, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(node.ID, string(nodebytes), database.NODES_TABLE_NAME)
if err != nil {
return err
}
if node.IsPending != "yes" {
DecrimentKey(node.Network, node.AccessKey)
}
SetNetworkNodesLastModified(node.Network)
if servercfg.IsDNSMode() {
err = SetDNS()
}
return err
}
// ShouldPeersUpdate - takes old node and sees if certain fields changing would trigger a peer update
func ShouldPeersUpdate(currentNode *models.Node, newNode *models.Node) bool {
SetNodeDefaults(newNode)
// single comparison statements
if newNode.Endpoint != currentNode.Endpoint ||
newNode.LocalAddress != currentNode.LocalAddress ||
newNode.PublicKey != currentNode.PublicKey ||
newNode.Address != currentNode.Address ||
newNode.IsEgressGateway != currentNode.IsEgressGateway ||
newNode.IsIngressGateway != currentNode.IsIngressGateway ||
newNode.IsRelay != currentNode.IsRelay ||
newNode.UDPHolePunch != currentNode.UDPHolePunch ||
newNode.IsPending != currentNode.IsPending ||
len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
return true
}
// multi-comparison statements
if newNode.IsDualStack == "yes" {
if newNode.Address6 != currentNode.Address6 {
return true
}
}
if newNode.IsEgressGateway == "yes" {
if len(currentNode.EgressGatewayRanges) != len(newNode.EgressGatewayRanges) {
return true
}
for _, address := range newNode.EgressGatewayRanges {
if !StringSliceContains(currentNode.EgressGatewayRanges, address) {
return true
}
}
}
if newNode.IsRelay == "yes" {
if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) {
return true
}
for _, address := range newNode.RelayAddrs {
if !StringSliceContains(currentNode.RelayAddrs, address) {
return true
}
}
}
for _, address := range newNode.AllowedIPs {
if !StringSliceContains(currentNode.AllowedIPs, address) {
return true
}
}
return false
}
// GetAllNodes - returns all nodes in the DB // GetAllNodes - returns all nodes in the DB
func GetAllNodes() ([]models.Node, error) { func GetAllNodes() ([]models.Node, error) {
var nodes []models.Node var nodes []models.Node
@ -415,7 +296,6 @@ func SetNodeDefaults(node *models.Node) {
} }
// GetRecordKey - get record key // GetRecordKey - get record key
// depricated
func GetRecordKey(id string, network string) (string, error) { func GetRecordKey(id string, network string) (string, error) {
if id == "" || network == "" { if id == "" || network == "" {
return "", errors.New("unable to get record key") return "", errors.New("unable to get record key")
@ -499,30 +379,6 @@ func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
return relay, errors.New("could not find relay for node " + relayedNodeAddr) return relay, errors.New("could not find relay for node " + relayedNodeAddr)
} }
// GetNodeByIDorMacAddress - gets the node, if a mac address exists, but not id, then it should delete it and recreate in DB with new ID
func GetNodeByIDorMacAddress(uuid string, macaddress string, network string) (models.Node, error) {
var node models.Node
var err error
node, err = GetNodeByID(uuid)
if err != nil && macaddress != "" && network != "" {
node, err = GetNodeByMacAddress(network, macaddress)
if err != nil {
return models.Node{}, err
}
err = DeleteNodeByMacAddress(&node, true) // remove node
if err != nil {
return models.Node{}, err
}
err = CreateNode(&node)
if err != nil {
return models.Node{}, err
}
logger.Log(2, "rewriting legacy node data; node now has id,", node.ID)
node.PullChanges = "yes"
}
return node, err
}
// GetNodeByID - get node by uuid, should have been set by create // GetNodeByID - get node by uuid, should have been set by create
func GetNodeByID(uuid string) (models.Node, error) { func GetNodeByID(uuid string) (models.Node, error) {
var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid) var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid)
@ -535,47 +391,3 @@ func GetNodeByID(uuid string) (models.Node, error) {
} }
return node, nil return node, nil
} }
// GetDeletedNodeByID - get a deleted node
func GetDeletedNodeByID(uuid string) (models.Node, error) {
var node models.Node
record, err := database.FetchRecord(database.DELETED_NODES_TABLE_NAME, uuid)
if err != nil {
return models.Node{}, err
}
if err = json.Unmarshal([]byte(record), &node); err != nil {
return models.Node{}, err
}
SetNodeDefaults(&node)
return node, nil
}
// GetNetworkServerNodeID - get network server node ID if exists
func GetNetworkServerNodeID(network string) (string, error) {
var nodes, err = GetNetworkNodes(network)
if err != nil {
return "", err
}
for _, node := range nodes {
if node.IsServer == "yes" {
if servercfg.GetNodeID() != "" {
if servercfg.GetNodeID() == node.MacAddress {
if strings.Contains(node.ID, "###") {
DeleteNodeByMacAddress(&node, true)
logger.Log(1, "deleted legacy server node on network "+node.Network)
return "", errors.New("deleted legacy server node on network " + node.Network)
}
return node.ID, nil
}
continue
}
return node.ID, nil
}
}
return "", errors.New("could not find server node")
}

View file

@ -17,7 +17,6 @@ import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
// == Public ==
// == Join, Checkin, and Leave for Server == // == Join, Checkin, and Leave for Server ==
// KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range // KUBERNETES_LISTEN_PORT - starting port for Kubernetes in order to use NodePort range
@ -27,26 +26,23 @@ const KUBERNETES_LISTEN_PORT = 31821
const KUBERNETES_SERVER_MTU = 1024 const KUBERNETES_SERVER_MTU = 1024
// ServerJoin - responsible for joining a server to a network // ServerJoin - responsible for joining a server to a network
func ServerJoin(networkSettings *models.Network) error { func ServerJoin(networkSettings *models.Network, serverID string) error {
if networkSettings == nil || networkSettings.NetID == "" { if networkSettings == nil || networkSettings.NetID == "" {
return errors.New("no network provided") return errors.New("no network provided")
} }
var err error var err error
var node = &models.Node{ var node = &models.Node{
IsServer: "yes", IsServer: "yes",
DNSOn: "no", DNSOn: "no",
IsStatic: "yes", IsStatic: "yes",
Name: models.NODE_SERVER_NAME, Name: models.NODE_SERVER_NAME,
MacAddress: servercfg.GetNodeID(), MacAddress: serverID,
ID: "", // will be set to new uuid
UDPHolePunch: "no", UDPHolePunch: "no",
IsLocal: networkSettings.IsLocal, IsLocal: networkSettings.IsLocal,
LocalRange: networkSettings.LocalRange, LocalRange: networkSettings.LocalRange,
} }
SetNodeDefaults(node) SetNodeDefaults(node)
if servercfg.GetPlatform() == "Kubernetes" { if servercfg.GetPlatform() == "Kubernetes" {
@ -120,7 +116,7 @@ func ServerJoin(networkSettings *models.Network) error {
if err = StorePrivKey(node.ID, privateKey); err != nil { if err = StorePrivKey(node.ID, privateKey); err != nil {
return err return err
} }
if err = serverPush(node); err != nil { if err = ServerPush(node); err != nil {
return err return err
} }
@ -138,12 +134,18 @@ func ServerJoin(networkSettings *models.Network) error {
return nil return nil
} }
// ServerUpdate - updates the server // ServerCheckin - runs pulls and pushes for server
// replaces legacy Checkin code func ServerCheckin(mac string, network string) error {
func ServerUpdate(serverNode *models.Node, shouldPeerUpdate bool) error { var serverNode = &models.Node{}
var err = serverPull(serverNode, shouldPeerUpdate) var currentNode, err = GetNode(mac, network)
if err != nil {
return err
}
serverNode = &currentNode
err = ServerPull(serverNode, false)
if isDeleteError(err) { if isDeleteError(err) {
return DeleteNodeByID(serverNode, true) return ServerLeave(mac, network)
} else if err != nil { } else if err != nil {
return err return err
} }
@ -153,7 +155,66 @@ func ServerUpdate(serverNode *models.Node, shouldPeerUpdate bool) error {
return errors.New("node has been removed") return errors.New("node has been removed")
} }
return serverPush(serverNode) return ServerPush(serverNode)
}
// ServerPull - pulls current config/peers for server
func ServerPull(serverNode *models.Node, onErr bool) error {
var err error
if serverNode.IPForwarding == "yes" {
if err = setIPForwardingLinux(); err != nil {
return err
}
}
serverNode.OS = runtime.GOOS
if serverNode.PullChanges == "yes" || onErr {
// check for interface change
// checks if address is in use by another interface
var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
if !isIfacePresent {
if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
logger.Log(1, "could not delete old interface", oldIfaceName)
}
logger.Log(1, "removed old interface", oldIfaceName)
}
serverNode.PullChanges = "no"
if err = setWGConfig(serverNode, false); err != nil {
return err
}
// handle server side update
if err = UpdateNode(serverNode, serverNode); err != nil {
return err
}
} else {
if err = setWGConfig(serverNode, true); err != nil {
if errors.Is(err, os.ErrNotExist) {
return ServerPull(serverNode, true)
} else {
return err
}
}
}
return nil
}
// ServerPush - pushes config changes for server checkins/join
func ServerPush(serverNode *models.Node) error {
serverNode.OS = runtime.GOOS
serverNode.SetLastCheckIn()
return UpdateNode(serverNode, serverNode)
}
// ServerLeave - removes a server node
func ServerLeave(mac string, network string) error {
var serverNode, err = GetNode(mac, network)
if err != nil {
return err
}
return DeleteNode(&serverNode, true)
} }
/** /**
@ -167,14 +228,17 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
var gateways []string var gateways []string
var peers []wgtypes.PeerConfig var peers []wgtypes.PeerConfig
var nodes []models.Node // fill above fields from server or client var nodes []models.Node // fill above fields from server or client
var err error
nodes, err = GetPeers(serverNode) var nodecfg, err = GetNode(serverNode.MacAddress, serverNode.Network)
if err != nil {
return nil, hasGateway, gateways, err
}
nodes, err = GetPeers(&nodecfg)
if err != nil { if err != nil {
return nil, hasGateway, gateways, err return nil, hasGateway, gateways, err
} }
keepalive := serverNode.PersistentKeepalive keepalive := nodecfg.PersistentKeepalive
keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s") keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
if err != nil { if err != nil {
logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error()) logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error())
@ -188,11 +252,11 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
return peers, hasGateway, gateways, err return peers, hasGateway, gateways, err
} }
if serverNode.PublicKey == node.PublicKey { if nodecfg.PublicKey == node.PublicKey {
continue continue
} }
if serverNode.Endpoint == node.Endpoint { if nodecfg.Endpoint == node.Endpoint {
if serverNode.LocalAddress != node.LocalAddress && node.LocalAddress != "" { if nodecfg.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
node.Endpoint = node.LocalAddress node.Endpoint = node.LocalAddress
} else { } else {
continue continue
@ -237,8 +301,8 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting") logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting")
continue // skip adding egress range if overlaps with node's ip continue // skip adding egress range if overlaps with node's ip
} }
if ipnet.Contains(net.ParseIP(serverNode.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
logger.Log(2, "egress IP range of", iprange, "overlaps with", serverNode.LocalAddress, ", omitting") logger.Log(2, "egress IP range of", iprange, "overlaps with", nodecfg.LocalAddress, ", omitting")
continue // skip adding egress range if overlaps with node's local ip continue // skip adding egress range if overlaps with node's local ip
} }
gateways = append(gateways, iprange) gateways = append(gateways, iprange)
@ -284,7 +348,7 @@ func GetServerExtPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, error) {
var err error var err error
var tempPeers []models.ExtPeersResponse var tempPeers []models.ExtPeersResponse
tempPeers, err = GetExtPeersList(serverNode) tempPeers, err = GetExtPeersList(serverNode.MacAddress, serverNode.Network)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -355,7 +419,7 @@ func checkNodeActions(node *models.Node) string {
} }
} }
if node.Action == models.NODE_DELETE { if node.Action == models.NODE_DELETE {
err := DeleteNodeByID(node, true) err := ServerLeave(node.MacAddress, node.Network)
if err != nil { if err != nil {
logger.Log(1, "error deleting locally:", err.Error()) logger.Log(1, "error deleting locally:", err.Error())
} }
@ -364,49 +428,6 @@ func checkNodeActions(node *models.Node) string {
return "" return ""
} }
// == Private ==
func serverPull(serverNode *models.Node, onErr bool) error {
var err error
if serverNode.IPForwarding == "yes" {
if err = setIPForwardingLinux(); err != nil {
return err
}
}
serverNode.OS = runtime.GOOS
if serverNode.PullChanges == "yes" || onErr {
// check for interface change
// checks if address is in use by another interface
var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
if !isIfacePresent {
if err = deleteInterface(oldIfaceName, serverNode.PostDown); err != nil {
logger.Log(1, "could not delete old interface", oldIfaceName)
}
logger.Log(1, "removed old interface", oldIfaceName)
}
serverNode.PullChanges = "no"
if err = setWGConfig(serverNode, false); err != nil {
return err
}
// handle server side update
if err = UpdateNode(serverNode, serverNode); err != nil {
return err
}
} else {
if err = setWGConfig(serverNode, true); err != nil {
if errors.Is(err, os.ErrNotExist) {
return serverPull(serverNode, true)
} else {
return err
}
}
}
return nil
}
func getServerLocalIP(networkSettings *models.Network) (string, error) { func getServerLocalIP(networkSettings *models.Network) (string, error) {
var networkCIDR = networkSettings.LocalRange var networkCIDR = networkSettings.LocalRange
@ -428,9 +449,3 @@ func getServerLocalIP(networkSettings *models.Network) (string, error) {
} }
return "", errors.New("could not find a local ip for server") return "", errors.New("could not find a local ip for server")
} }
func serverPush(serverNode *models.Node) error {
serverNode.OS = runtime.GOOS
serverNode.SetLastCheckIn()
return UpdateNode(serverNode, serverNode)
}

View file

@ -4,19 +4,18 @@ package logic
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt"
"math/rand" "math/rand"
"net"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils" "github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"golang.org/x/crypto/bcrypt"
) )
// IsBase64 - checks if a string is in base64 format // IsBase64 - checks if a string is in base64 format
@ -32,45 +31,24 @@ func CheckEndpoint(endpoint string) bool {
return len(endpointarr) == 2 return len(endpointarr) == 2
} }
// FileExists - checks if local file exists // SetNetworkServerPeers - sets the network server peers of a given node
func FileExists(f string) bool { func SetNetworkServerPeers(node *models.Node) {
info, err := os.Stat(f) if currentPeersList, err := GetSystemPeers(node); err == nil {
if os.IsNotExist(err) { if database.SetPeers(currentPeersList, node.Network) {
return false logger.Log(1, "set new peers on network", node.Network)
}
return !info.IsDir()
}
// IsAddressInCIDR - util to see if an address is in a cidr or not
func IsAddressInCIDR(address, cidr string) bool {
var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
if cidrErr != nil {
return false
}
var addrParts = strings.Split(address, ".")
var addrPartLength = len(addrParts)
if addrPartLength != 4 {
return false
} else {
if addrParts[addrPartLength-1] == "0" ||
addrParts[addrPartLength-1] == "255" {
return false
} }
} else {
logger.Log(1, "could not set peers on network", node.Network, ":", err.Error())
} }
ip, _, err := net.ParseCIDR(fmt.Sprintf("%s/32", address))
if err != nil {
return false
}
return currentCIDR.Contains(ip)
} }
// DeleteNodeByMacAddress - deletes a node from database or moves into delete nodes table // DeleteNode - deletes a node from database or moves into delete nodes table
func DeleteNodeByMacAddress(node *models.Node, exterminate bool) error { func DeleteNode(node *models.Node, exterminate bool) error {
var err error var err error
var key = node.ID var key = node.ID
if !exterminate { if !exterminate {
args := strings.Split(key, "###") args := strings.Split(key, "###")
node, err := GetNodeByMacAddress(args[0], args[1]) node, err := GetNode(args[0], args[1])
if err != nil { if err != nil {
return err return err
} }
@ -97,6 +75,66 @@ func DeleteNodeByMacAddress(node *models.Node, exterminate bool) error {
return removeLocalServer(node) return removeLocalServer(node)
} }
// CreateNode - creates a node in database
func CreateNode(node *models.Node) error {
//encrypt that password so we never see it
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
if err != nil {
return err
}
//set password to encrypted password
node.Password = string(hash)
if node.Name == models.NODE_SERVER_NAME {
node.IsServer = "yes"
}
if node.DNSOn == "" {
if servercfg.IsDNSMode() {
node.DNSOn = "yes"
} else {
node.DNSOn = "no"
}
}
SetNodeDefaults(node)
node.Address, err = UniqueAddress(node.Network)
if err != nil {
return err
}
node.Address6, err = UniqueAddress6(node.Network)
if err != nil {
return err
}
//Create a JWT for the node
tokenString, _ := CreateJWT(node.MacAddress, node.Network)
if tokenString == "" {
//returnErrorResponse(w, r, errorResponse)
return err
}
err = ValidateNode(node, false)
if err != nil {
return err
}
node.ID = uuid.NewString()
nodebytes, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(node.ID, string(nodebytes), database.NODES_TABLE_NAME)
if err != nil {
return err
}
if node.IsPending != "yes" {
DecrimentKey(node.Network, node.AccessKey)
}
SetNetworkNodesLastModified(node.Network)
if servercfg.IsDNSMode() {
err = SetDNS()
}
return err
}
// SetNetworkNodesLastModified - sets the network nodes last modified // SetNetworkNodesLastModified - sets the network nodes last modified
func SetNetworkNodesLastModified(networkName string) error { func SetNetworkNodesLastModified(networkName string) error {
@ -118,56 +156,28 @@ func SetNetworkNodesLastModified(networkName string) error {
return nil return nil
} }
// // GetNode - fetches a node from database // GetNode - fetches a node from database
// func GetNode(macaddress string, network string) (models.Node, error) { func GetNode(macaddress string, network string) (models.Node, error) {
// var node models.Node var node models.Node
// key, err := GetRecordKey(macaddress, network) key, err := GetRecordKey(macaddress, network)
// if err != nil { if err != nil {
// return node, err return node, err
// } }
// data, err := database.FetchRecord(database.NODES_TABLE_NAME, key) data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
// if err != nil { if err != nil {
// if data == "" { if data == "" {
// data, _ = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key) data, _ = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
// err = json.Unmarshal([]byte(data), &node) err = json.Unmarshal([]byte(data), &node)
// } }
// return node, err return node, err
// } }
// if err = json.Unmarshal([]byte(data), &node); err != nil { if err = json.Unmarshal([]byte(data), &node); err != nil {
// return node, err return node, err
// } }
// SetNodeDefaults(&node) SetNodeDefaults(&node)
// return node, err return node, err
// }
// DeleteNodeByID - deletes a node from database or moves into delete nodes table
func DeleteNodeByID(node *models.Node, exterminate bool) error {
var err error
var key = node.ID
if !exterminate {
node.Action = models.NODE_DELETE
nodedata, err := json.Marshal(&node)
if err != nil {
return err
}
err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
if err != nil {
return err
}
} else {
if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
logger.Log(2, err.Error())
}
}
if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
return err
}
if servercfg.IsDNSMode() {
SetDNS()
}
return removeLocalServer(node)
} }
// GetNodePeers - fetches peers for a given node // GetNodePeers - fetches peers for a given node
@ -358,16 +368,3 @@ func StringSliceContains(slice []string, item string) bool {
} }
return false return false
} }
// == private ==
// sets the network server peers of a given node
func setNetworkServerPeers(serverNode *models.Node) {
if currentPeersList, err := getSystemPeers(serverNode); err == nil {
if database.SetPeers(currentPeersList, serverNode.Network) {
logger.Log(1, "set new peers on network", serverNode.Network)
}
} else {
logger.Log(1, "could not set peers on network", serverNode.Network, ":", err.Error())
}
}

View file

@ -23,9 +23,9 @@ const NODE_NOOP = "noop"
var seededRand *rand.Rand = rand.New( var seededRand *rand.Rand = rand.New(
rand.NewSource(time.Now().UnixNano())) rand.NewSource(time.Now().UnixNano()))
// Node - struct for node model // node struct
type Node struct { type Node struct {
ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5"` ID string `json:"id,omitempty" bson:"id,omitempty"`
Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"` Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"` Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"` LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
@ -46,7 +46,7 @@ type Node struct {
ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"` ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"` LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"` LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
MacAddress string `json:"macaddress" bson:"macaddress" yaml:"macaddress"` MacAddress string `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"required,min=5,macaddress_unique"`
// checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL // checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL
CheckInInterval int32 `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"` CheckInInterval int32 `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"` Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
@ -72,8 +72,6 @@ type Node struct {
IPForwarding string `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"` IPForwarding string `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
OS string `json:"os" bson:"os" yaml:"os"` OS string `json:"os" bson:"os" yaml:"os"`
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"` MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
Version string `json:"version" bson:"version" yaml:"version"`
ExcludedAddrs []string `json:"excludedaddrs" bson:"excludedaddrs" yaml:"excludedaddrs"`
} }
// NodesArray - used for node sorting // NodesArray - used for node sorting
@ -108,91 +106,78 @@ func (node *Node) SetDefaulIsPending() {
} }
} }
// Node.SetDefaultIsRelayed - set default is relayed
func (node *Node) SetDefaultIsRelayed() { func (node *Node) SetDefaultIsRelayed() {
if node.IsRelayed == "" { if node.IsRelayed == "" {
node.IsRelayed = "no" node.IsRelayed = "no"
} }
} }
// Node.SetDefaultIsRelay - set default isrelay
func (node *Node) SetDefaultIsRelay() { func (node *Node) SetDefaultIsRelay() {
if node.IsRelay == "" { if node.IsRelay == "" {
node.IsRelay = "no" node.IsRelay = "no"
} }
} }
// Node.SetDefaultEgressGateway - sets default egress gateway status
func (node *Node) SetDefaultEgressGateway() { func (node *Node) SetDefaultEgressGateway() {
if node.IsEgressGateway == "" { if node.IsEgressGateway == "" {
node.IsEgressGateway = "no" node.IsEgressGateway = "no"
} }
} }
// Node.SetDefaultIngressGateway - sets default ingress gateway status
func (node *Node) SetDefaultIngressGateway() { func (node *Node) SetDefaultIngressGateway() {
if node.IsIngressGateway == "" { if node.IsIngressGateway == "" {
node.IsIngressGateway = "no" node.IsIngressGateway = "no"
} }
} }
// Node.SetDefaultAction - sets default action status
func (node *Node) SetDefaultAction() { func (node *Node) SetDefaultAction() {
if node.Action == "" { if node.Action == "" {
node.Action = NODE_NOOP node.Action = NODE_NOOP
} }
} }
// Node.SetRoamingDefault - sets default roaming status
func (node *Node) SetRoamingDefault() { func (node *Node) SetRoamingDefault() {
if node.Roaming == "" { if node.Roaming == "" {
node.Roaming = "yes" node.Roaming = "yes"
} }
} }
// Node.SetPullChangesDefault - sets default pull changes status
func (node *Node) SetPullChangesDefault() { func (node *Node) SetPullChangesDefault() {
if node.PullChanges == "" { if node.PullChanges == "" {
node.PullChanges = "no" node.PullChanges = "no"
} }
} }
// Node.SetIPForwardingDefault - set ip forwarding default
func (node *Node) SetIPForwardingDefault() { func (node *Node) SetIPForwardingDefault() {
if node.IPForwarding == "" { if node.IPForwarding == "" {
node.IPForwarding = "yes" node.IPForwarding = "yes"
} }
} }
// Node.SetIsLocalDefault - set is local default
func (node *Node) SetIsLocalDefault() { func (node *Node) SetIsLocalDefault() {
if node.IsLocal == "" { if node.IsLocal == "" {
node.IsLocal = "no" node.IsLocal = "no"
} }
} }
// Node.SetDNSOnDefault - sets dns on default
func (node *Node) SetDNSOnDefault() { func (node *Node) SetDNSOnDefault() {
if node.DNSOn == "" { if node.DNSOn == "" {
node.DNSOn = "yes" node.DNSOn = "yes"
} }
} }
// Node.SetIsDualStackDefault - set is dual stack default status
func (node *Node) SetIsDualStackDefault() { func (node *Node) SetIsDualStackDefault() {
if node.IsDualStack == "" { if node.IsDualStack == "" {
node.IsDualStack = "no" node.IsDualStack = "no"
} }
} }
// Node.SetIsServerDefault - sets node isserver default
func (node *Node) SetIsServerDefault() { func (node *Node) SetIsServerDefault() {
if node.IsServer != "yes" { if node.IsServer != "yes" {
node.IsServer = "no" node.IsServer = "no"
} }
} }
// Node.SetIsStaticDefault - set is static default
func (node *Node) SetIsStaticDefault() { func (node *Node) SetIsStaticDefault() {
if node.IsServer == "yes" { if node.IsServer == "yes" {
node.IsStatic = "yes" node.IsStatic = "yes"
@ -201,44 +186,32 @@ func (node *Node) SetIsStaticDefault() {
} }
} }
// Node.SetLastModified - set last modified initial time
func (node *Node) SetLastModified() { func (node *Node) SetLastModified() {
node.LastModified = time.Now().Unix() node.LastModified = time.Now().Unix()
} }
// Node.SetLastCheckIn - time.Now().Unix()
func (node *Node) SetLastCheckIn() { func (node *Node) SetLastCheckIn() {
node.LastCheckIn = time.Now().Unix() node.LastCheckIn = time.Now().Unix()
} }
// Node.SetLastPeerUpdate - sets last peer update time
func (node *Node) SetLastPeerUpdate() { func (node *Node) SetLastPeerUpdate() {
node.LastPeerUpdate = time.Now().Unix() node.LastPeerUpdate = time.Now().Unix()
} }
// Node.SetExpirationDateTime - sets node expiry time
func (node *Node) SetExpirationDateTime() { func (node *Node) SetExpirationDateTime() {
node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS
} }
// Node.SetDefaultName - sets a random name to node
func (node *Node) SetDefaultName() { func (node *Node) SetDefaultName() {
if node.Name == "" { if node.Name == "" {
node.Name = GenerateNodeName() node.Name = GenerateNodeName()
} }
} }
// Node.SetDefaultExcludedAddrs - sets ExcludedAddrs to empty array if nil
func (node *Node) SetDefaultExcludedAddrs() {
if node.ExcludedAddrs == nil {
node.ExcludedAddrs = make([]string, 0)
}
}
// Node.Fill - fills other node data into calling node data if not set on calling node
func (newNode *Node) Fill(currentNode *Node) { func (newNode *Node) Fill(currentNode *Node) {
newNode.ID = currentNode.ID if newNode.ID == "" {
newNode.ID = currentNode.ID
}
if newNode.Address == "" && newNode.IsStatic != "yes" { if newNode.Address == "" && newNode.IsStatic != "yes" {
newNode.Address = currentNode.Address newNode.Address = currentNode.Address
} }
@ -381,15 +354,8 @@ func (newNode *Node) Fill(currentNode *Node) {
if newNode.IsRelayed == "" { if newNode.IsRelayed == "" {
newNode.IsRelayed = currentNode.IsRelayed newNode.IsRelayed = currentNode.IsRelayed
} }
if newNode.Version == "" {
newNode.Version = currentNode.Version
}
if newNode.ExcludedAddrs == nil || len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) {
newNode.ExcludedAddrs = currentNode.ExcludedAddrs
}
} }
// StringWithCharset - returns random string inside defined charset
func StringWithCharset(length int, charset string) string { func StringWithCharset(length int, charset string) string {
b := make([]byte, length) b := make([]byte, length)
for i := range b { for i := range b {
@ -398,14 +364,13 @@ func StringWithCharset(length int, charset string) string {
return string(b) return string(b)
} }
// IsIpv4Net - check for valid IPv4 address //Check for valid IPv4 address
// Note: We dont handle IPv6 AT ALL!!!!! This definitely is needed at some point //Note: We dont handle IPv6 AT ALL!!!!! This definitely is needed at some point
// But for iteration 1, lets just stick to IPv4. Keep it simple stupid. //But for iteration 1, lets just stick to IPv4. Keep it simple stupid.
func IsIpv4Net(host string) bool { func IsIpv4Net(host string) bool {
return net.ParseIP(host) != nil return net.ParseIP(host) != nil
} }
// Node.NameInNodeCharset - returns if name is in charset below or not
func (node *Node) NameInNodeCharSet() bool { func (node *Node) NameInNodeCharSet() bool {
charset := "abcdefghijklmnopqrstuvwxyz1234567890-" charset := "abcdefghijklmnopqrstuvwxyz1234567890-"