Browse Source

rebase fixes

Matthew R Kasun 3 years ago
parent
commit
d4399d1321
4 changed files with 224 additions and 143 deletions
  1. 3 3
      controllers/node_grpc.go
  2. 139 62
      logic/nodes.go
  3. 44 75
      logic/util.go
  4. 38 3
      models/node.go

+ 3 - 3
controllers/node_grpc.go

@@ -161,9 +161,9 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if node.IsServer == "yes" && logic.IsLeader(&node) {
-		logic.SetNetworkServerPeers(&node)
-	}
+	//if node.IsServer == "yes" && logic.IsLeader(&node) {
+	//	logic.setNetworkServerPeers(&node)
+	//}
 	excludeIsRelayed := node.IsRelay != "yes"
 	excludeIsRelayed := node.IsRelay != "yes"
 	var relayedNode string
 	var relayedNode string
 	if node.IsRelayed == "yes" {
 	if node.IsRelayed == "yes" {

+ 139 - 62
logic/nodes.go

@@ -4,38 +4,27 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"net"
 	"sort"
 	"sort"
-	"strconv"
 	"strings"
 	"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/servercfg"
 	"github.com/gravitl/netmaker/validation"
 	"github.com/gravitl/netmaker/validation"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"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 = []models.Node{}
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	var nodes, err = GetAllNodes()
 	if err != nil {
 	if err != nil {
-		if database.IsEmptyRecord(err) {
-			return []models.Node{}, nil
-		}
-		return nodes, err
+		return []models.Node{}, err
 	}
 	}
-	for _, value := range collection {
-
-		var node models.Node
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			continue
-		}
+	for _, node := range nodes {
 		if node.Network == network {
 		if node.Network == network {
 			nodes = append(nodes, node)
 			nodes = append(nodes, node)
 		}
 		}
@@ -77,7 +66,7 @@ func UncordonNode(nodeid string) (models.Node, error) {
 	node.SetLastModified()
 	node.SetLastModified()
 	node.IsPending = "no"
 	node.IsPending = "no"
 	node.PullChanges = "yes"
 	node.PullChanges = "yes"
- 	data, err := json.Marshal(&node)
+	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
 		return node, err
 		return node, err
 	}
 	}
@@ -86,52 +75,11 @@ func UncordonNode(nodeid string) (models.Node, error) {
 	return node, err
 	return node, err
 }
 }
 
 
-// GetWGNodePeers - gets the wg peers of a given node
-func GetWGNodePeers(node *models.Node) ([]wgtypes.PeerConfig, error){
-	var peers []wgtypes.PeerConfig
-	var peerData wgtypes.PeerConfig
-	nodes, err := GetPeers(node)
-	if err != nil {
-		return peers, err
-	}
-	logger.Log(0, "the peers of " + node.Name + " are:")
-	for _, peer := range nodes {
-		logger.Log(0, "peer: " + peer.Name)
-	}
-	for _, peer := range nodes {
-		//this should not happen but it does
-		if peer.Name == node.Name {
-			logger.Log(0, "GetPeers returned me " + node.Name)
-			continue
-		}
-		pubkey, err :=wgtypes.ParseKey(peer.PublicKey)
-		if err != nil {
-			logger.Log(0, "ParseKey failed " +err.Error())
-			continue
-		}
-		endpoint := peer.Endpoint + ":" + strconv.Itoa(int(peer.ListenPort))
-		address, err := net.ResolveUDPAddr("udp", endpoint)
-		if err != nil  {
-			logger.Log(0, "could not resolve endpoint " + err.Error())
-			continue
-		}
-		///Persitent Keepalive
-		//Allowed IPs
-		peerData = wgtypes.PeerConfig{
-			PublicKey: pubkey,
-			Endpoint: address,
-		}
-		peers = append (peers, peerData)
-	}
-	return peers, nil
-}
-
-// GetPeers - gets a list of nodes that are 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) {
-	//	logger.Log(0, node.Name + " is a leader")
-	//	SetNetworkServerPeers(node)
-	//}
+	if IsLeader(node) {
+		setNetworkServerPeers(node)
+	}
 	excludeIsRelayed := node.IsRelay != "yes"
 	excludeIsRelayed := node.IsRelay != "yes"
 	var relayedNode string
 	var relayedNode string
 	if node.IsRelayed == "yes" {
 	if node.IsRelayed == "yes" {
@@ -163,6 +111,13 @@ 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
@@ -210,6 +165,128 @@ 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

+ 44 - 75
logic/util.go

@@ -4,18 +4,19 @@ 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
@@ -31,15 +32,36 @@ func CheckEndpoint(endpoint string) bool {
 	return len(endpointarr) == 2
 	return len(endpointarr) == 2
 }
 }
 
 
-// SetNetworkServerPeers - sets the network server peers of a given node
-func SetNetworkServerPeers(node *models.Node) {
-	if currentPeersList, err := getSystemPeers(node); err == nil {
-		if database.SetPeers(currentPeersList, node.Network) {
-			logger.Log(1, "set new peers on network", node.Network)
-		}
+// FileExists - checks if local file exists
+func FileExists(f string) bool {
+	info, err := os.Stat(f)
+	if os.IsNotExist(err) {
+		return false
+	}
+	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 {
 	} else {
-		logger.Log(1, "could not set peers on network", node.Network, ":", err.Error())
+		if addrParts[addrPartLength-1] == "0" ||
+			addrParts[addrPartLength-1] == "255" {
+			return false
+		}
 	}
 	}
+	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
 // DeleteNodeByMacAddress - deletes a node from database or moves into delete nodes table
@@ -75,72 +97,6 @@ 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
-	}
-
-	// 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
-}
-
 // SetNetworkNodesLastModified - sets the network nodes last modified
 // SetNetworkNodesLastModified - sets the network nodes last modified
 func SetNetworkNodesLastModified(networkName string) error {
 func SetNetworkNodesLastModified(networkName string) error {
 
 
@@ -402,3 +358,16 @@ 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())
+	}
+}

+ 38 - 3
models/node.go

@@ -73,6 +73,7 @@ type Node struct {
 	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"`
 	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
@@ -107,78 +108,91 @@ 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"
@@ -187,28 +201,41 @@ 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
 	newNode.ID = currentNode.ID
 
 
@@ -354,8 +381,15 @@ 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 {
@@ -364,13 +398,14 @@ func StringWithCharset(length int, charset string) string {
 	return string(b)
 	return string(b)
 }
 }
 
 
-//Check for valid IPv4 address
-//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.
+// IsIpv4Net - check for valid IPv4 address
+// 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.
 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-"