diff --git a/controllers/common.go b/controllers/common.go index 800b955a..7c155382 100644 --- a/controllers/common.go +++ b/controllers/common.go @@ -20,9 +20,9 @@ func GetPeersList(networkName string) ([]models.PeersResponse, error) { var peers []models.PeersResponse collection, err := database.FetchRecords(database.NODES_TABLE_NAME) - if err != nil { - log.Println(err) - } + if err != nil { + log.Println(err) + } udppeers, errN := serverctl.GetPeers(networkName) if errN != nil { log.Println(errN) @@ -38,7 +38,7 @@ func GetPeersList(networkName string) ([]models.PeersResponse, error) { if err != nil { continue } - if node.Network == networkName && !node.IsPending { + if node.Network == networkName && node.IsPending != "yes" { if node.UDPHolePunch == "yes" && errN == nil { endpointstring := udppeers[peer.PublicKey] endpointarr := strings.Split(endpointstring, ":") @@ -178,10 +178,10 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) { //returnErrorResponse(w, r, errorResponse) return node, err } - err = node.Validate(false) - if err != nil { - return node, err - } + err = node.Validate(false) + if err != nil { + return node, err + } key, err := functions.GetRecordKey(node.MacAddress, node.Network) if err != nil { @@ -195,7 +195,7 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) { if err != nil { return node, err } - if !node.IsPending { + if node.IsPending != "yes" { functions.DecrimentKey(node.Network, node.AccessKey) } SetNetworkNodesLastModified(node.Network) @@ -220,7 +220,7 @@ func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse, err = fmt.Errorf("%w; Couldnt Get Node "+node.MacAddress, err) return response, err } - if parentnode.IsPending { + if parentnode.IsPending == "yes" { err = fmt.Errorf("%w; Node checking in is still pending: "+node.MacAddress, err) response.IsPending = true return response, err diff --git a/controllers/extClientHttpController.go b/controllers/extClientHttpController.go index c7c04fbb..4b055370 100644 --- a/controllers/extClientHttpController.go +++ b/controllers/extClientHttpController.go @@ -73,7 +73,7 @@ func checkIngressExists(network string, macaddress string) bool { if err != nil { return false } - return node.IsIngressGateway + return node.IsIngressGateway == "yes" } //Gets all extclients associated with network, including pending extclients diff --git a/controllers/nodeGrpcController.go b/controllers/nodeGrpcController.go index e4809257..43a51b4b 100644 --- a/controllers/nodeGrpcController.go +++ b/controllers/nodeGrpcController.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "github.com/gravitl/netmaker/functions" nodepb "github.com/gravitl/netmaker/grpc" "github.com/gravitl/netmaker/models" @@ -50,8 +51,8 @@ func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.ReadNodeRe Postup: node.PostUp, Checkininterval: node.CheckInInterval, Dnsoff: !servercfg.IsDNSMode(), - Ispending: node.IsPending, - Isingressgateway: node.IsIngressGateway, + Ispending: node.IsPending == "yes", + Isingressgateway: node.IsIngressGateway == "yes", Ingressgatewayrange: node.IngressGatewayRange, Publickey: node.PublicKey, Listenport: node.ListenPort, @@ -83,7 +84,6 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo Password: data.GetPassword(), Interface: data.GetInterface(), Network: data.GetNodenetwork(), - IsPending: data.GetIspending(), PublicKey: data.GetPublickey(), ListenPort: data.GetListenport(), UDPHolePunch: data.GetUdpholepunch(), @@ -101,7 +101,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo //Check to see if network will allow manual sign up //may want to switch this up with the valid key check and avoid a DB call that way. if network.AllowManualSignUp == "yes" { - node.IsPending = true + node.IsPending = "yes" } else { return nil, status.Errorf( codes.Internal, @@ -133,7 +133,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo Interface: node.Interface, Nodenetwork: node.Network, Dnsoff: !servercfg.IsDNSMode(), - Ispending: node.IsPending, + Ispending: node.IsPending == "yes", Publickey: node.PublicKey, Listenport: node.ListenPort, Keepalive: node.PersistentKeepalive, @@ -157,7 +157,7 @@ func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) data := req.GetNode() //postchanges := req.GetPostchanges() // Now we have to convert this into a NodeItem type to convert into BSON - log.Println("checkin data:",data) + log.Println("checkin data:", data) node := models.Node{ // ID: primitive.NilObjectID, MacAddress: data.GetMacaddress(), @@ -171,7 +171,7 @@ func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) PersistentKeepalive: data.GetKeepalive(), PublicKey: data.GetPublickey(), UDPHolePunch: data.GetUdpholepunch(), - SaveConfig: data.GetSaveconfig(), + SaveConfig: data.GetSaveconfig(), } checkinresponse, err := NodeCheckIn(node, node.Network) @@ -203,7 +203,7 @@ func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNodeReq) (*nodepb.UpdateNodeRes, error) { // Get the node data from the request data := req.GetNode() - log.Println("DATA:",data) + log.Println("DATA:", data) // Now we have to convert this into a NodeItem type to convert into BSON newnode := models.Node{ // ID: primitive.NilObjectID, @@ -219,11 +219,10 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo Interface: data.GetInterface(), PostDown: data.GetPostdown(), PostUp: data.GetPostup(), - IsPending: data.GetIspending(), PublicKey: data.GetPublickey(), ListenPort: data.GetListenport(), UDPHolePunch: data.GetUdpholepunch(), - SaveConfig: data.GetSaveconfig(), + SaveConfig: data.GetSaveconfig(), } // Convert the Id string to a MongoDB ObjectId @@ -231,7 +230,7 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo networkName := newnode.Network network, _ := functions.GetParentNetwork(networkName) - log.Println("NODE SAVECONFIG:",newnode.SaveConfig) + log.Println("NODE SAVECONFIG:", newnode.SaveConfig) node, err := functions.GetNodeByMacAddress(networkName, macaddress) if err != nil { return nil, status.Errorf( @@ -261,7 +260,7 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo Postdown: newnode.PostDown, Postup: newnode.PostUp, Nodenetwork: newnode.Network, - Ispending: newnode.IsPending, + Ispending: newnode.IsPending == "yes", Publickey: newnode.PublicKey, Dnsoff: !servercfg.IsDNSMode(), Listenport: newnode.ListenPort, diff --git a/controllers/nodeHttpController.go b/controllers/nodeHttpController.go index 3f9c844a..10fdb9e2 100644 --- a/controllers/nodeHttpController.go +++ b/controllers/nodeHttpController.go @@ -83,7 +83,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { if err := json.Unmarshal([]byte(value), &result); err != nil { continue } - if result.MacAddress == authRequest.MacAddress && !result.IsPending && result.Network == networkname { + if result.MacAddress == authRequest.MacAddress && result.IsPending != "yes" && result.Network == networkname { break } } @@ -476,7 +476,7 @@ func createNode(w http.ResponseWriter, r *http.Request) { //Check to see if network will allow manual sign up //may want to switch this up with the valid key check and avoid a DB call that way. if network.AllowManualSignUp == "yes" { - node.IsPending = true + node.IsPending = "yes" } else { errorResponse = models.ErrorResponse{ Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.", @@ -517,7 +517,7 @@ func UncordonNode(network, macaddress string) (models.Node, error) { return models.Node{}, err } node.SetLastModified() - node.IsPending = false + node.IsPending = "no" data, err := json.Marshal(&node) if err != nil { return node, err @@ -561,7 +561,7 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro if err != nil { return models.Node{}, err } - node.IsEgressGateway = true + node.IsEgressGateway = "yes" node.EgressGatewayRanges = gateway.Ranges postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE" postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE" @@ -635,7 +635,7 @@ func DeleteEgressGateway(network, macaddress string) (models.Node, error) { return models.Node{}, err } - node.IsEgressGateway = false + node.IsEgressGateway = "no" node.EgressGatewayRanges = []string{} node.PostUp = "" node.PostDown = "" @@ -687,7 +687,7 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error) log.Println("Could not find network.") return models.Node{}, err } - node.IsIngressGateway = true + node.IsIngressGateway = "yes" node.IngressGatewayRange = network.AddressRange postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE" postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE" @@ -740,7 +740,7 @@ func DeleteIngressGateway(network, macaddress string) (models.Node, error) { return models.Node{}, err } node.LastModified = time.Now().Unix() - node.IsIngressGateway = false + node.IsIngressGateway = "no" key, err := functions.GetRecordKey(node.MacAddress, node.Network) if err != nil { return models.Node{}, err diff --git a/go.mod b/go.mod index 48cdfc6c..63118a1f 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.15 require ( github.com/aws/aws-sdk-go v1.34.28 - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/go-playground/validator/v10 v10.5.0 github.com/go-sql-driver/mysql v1.6.0 // indirect diff --git a/models/node.go b/models/node.go index 1c2cfd89..c57123d8 100644 --- a/models/node.go +++ b/models/node.go @@ -3,13 +3,15 @@ package models import ( "encoding/json" "errors" + "log" "math/rand" "net" "strings" "time" - "log" + "github.com/go-playground/validator/v10" "github.com/gravitl/netmaker/database" + "golang.org/x/crypto/bcrypt" ) const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" @@ -43,9 +45,9 @@ type Node struct { CheckInInterval int32 `json:"checkininterval" bson:"checkininterval"` Password string `json:"password" bson:"password" validate:"required,min=6"` Network string `json:"network" bson:"network" validate:"network_exists"` - IsPending bool `json:"ispending" bson:"ispending"` - IsEgressGateway bool `json:"isegressgateway" bson:"isegressgateway"` - IsIngressGateway bool `json:"isingressgateway" bson:"isingressgateway"` + IsPending string `json:"ispending" bson:"ispending"` + IsEgressGateway string `json:"isegressgateway" bson:"isegressgateway"` + IsIngressGateway string `json:"isingressgateway" bson:"isingressgateway"` EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges"` IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange"` PostChanges string `json:"postchanges" bson:"postchanges"` @@ -148,13 +150,126 @@ func (node *Node) SetDefaults() { node.KeyUpdateTimeStamp = time.Now().Unix() } +func (newNode *Node) Fill(currentNode *Node) { + if newNode.ID == "" { + newNode.ID = currentNode.ID + } + if newNode.Address == "" { + newNode.Address = currentNode.Address + } + if newNode.Address6 == "" { + newNode.Address6 = currentNode.Address6 + } + if newNode.LocalAddress == "" { + newNode.LocalAddress = currentNode.LocalAddress + } + if newNode.Name == "" { + newNode.Name = currentNode.Name + } + if newNode.ListenPort == 0 { + newNode.ListenPort = currentNode.ListenPort + } + if newNode.PublicKey == "" { + newNode.PublicKey = currentNode.PublicKey + } + if newNode.Endpoint == "" { + newNode.Endpoint = currentNode.Endpoint + } + if newNode.PostUp == "" { + newNode.PostUp = currentNode.PostUp + } + if newNode.PostDown == "" { + newNode.PostDown = currentNode.PostDown + } + if newNode.AllowedIPs == nil { + newNode.AllowedIPs = currentNode.AllowedIPs + } + if newNode.PersistentKeepalive == 0 { + newNode.PersistentKeepalive = currentNode.PersistentKeepalive + } + if newNode.SaveConfig == "" { + newNode.SaveConfig = currentNode.SaveConfig + } + if newNode.AccessKey == "" { + newNode.AccessKey = currentNode.AccessKey + } + if newNode.Interface == "" { + newNode.Interface = currentNode.Interface + } + if newNode.LastModified == 0 { + newNode.LastModified = currentNode.LastModified + } + if newNode.KeyUpdateTimeStamp == 0 { + newNode.LastModified = currentNode.LastModified + } + if newNode.ExpirationDateTime == 0 { + newNode.ExpirationDateTime = currentNode.ExpirationDateTime + } + if newNode.LastPeerUpdate == 0 { + newNode.LastPeerUpdate = currentNode.LastPeerUpdate + } + if newNode.LastCheckIn == 0 { + newNode.LastCheckIn = currentNode.LastCheckIn + } + if newNode.MacAddress == "" { + newNode.MacAddress = currentNode.MacAddress + } + if newNode.CheckInInterval == 0 { + newNode.CheckInInterval = currentNode.CheckInInterval + } + if newNode.Password != "" { + err := bcrypt.CompareHashAndPassword([]byte(newNode.Password), []byte(currentNode.Password)) + if err != nil && currentNode.Password != newNode.Password { + hash, err := bcrypt.GenerateFromPassword([]byte(newNode.Password), 5) + if err == nil { + newNode.Password = string(hash) + } + } + } else { + newNode.Password = currentNode.Password + } + if newNode.Network == "" { + newNode.Network = currentNode.Network + } + if newNode.IsPending == "" { + newNode.IsPending = currentNode.IsPending + } + if newNode.IsEgressGateway == "" { + newNode.IsEgressGateway = currentNode.IsEgressGateway + } + if newNode.IsIngressGateway == "" { + newNode.IsIngressGateway = currentNode.IsIngressGateway + } + if newNode.EgressGatewayRanges == nil { + newNode.EgressGatewayRanges = currentNode.EgressGatewayRanges + } + if newNode.IngressGatewayRange == "" { + newNode.IngressGatewayRange = currentNode.IngressGatewayRange + } + if newNode.StaticIP == "" { + newNode.StaticIP = currentNode.StaticIP + } + if newNode.StaticIP == "" { + newNode.StaticIP = currentNode.StaticIP + } + if newNode.StaticPubKey == "" { + newNode.StaticPubKey = currentNode.StaticPubKey + } + if newNode.UDPHolePunch == "" { + newNode.UDPHolePunch = currentNode.SaveConfig + } + + newNode.PostChanges = "no" +} + func (currentNode *Node) Update(newNode *Node) error { - log.Println("Node SaveConfig:",newNode.SaveConfig) + log.Println("Node SaveConfig:", newNode.SaveConfig) if err := newNode.Validate(true); err != nil { return err } newNode.SetID() if newNode.ID == currentNode.ID { + newNode.Fill(currentNode) if data, err := json.Marshal(newNode); err != nil { return err } else { @@ -183,7 +298,7 @@ func IsIpv4Net(host string) bool { } func (node *Node) Validate(isUpdate bool) error { - log.Println("Node SaveConfig:",node.SaveConfig) + log.Println("Node SaveConfig:", node.SaveConfig) v := validator.New() _ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool { if isUpdate { @@ -247,3 +362,29 @@ func GetAllNodes() ([]Node, error) { return nodes, nil } + +func GetNode(macaddress string, network string) (Node, error) { + + var node Node + + key, err := GetID(macaddress, network) + if err != nil { + return node, err + } + data, err := database.FetchRecord(database.NODES_TABLE_NAME, key) + if err != nil { + return node, err + } + if err = json.Unmarshal([]byte(data), &node); err != nil { + return node, err + } + + return node, err +} + +func GetID(macaddress string, network string) (string, error) { + if macaddress == "" || network == "" { + return "", errors.New("unable to get record key") + } + return macaddress + "###" + network, nil +}